protos/linux_risc: Tell Linux about the framebuffer
diff --git a/common/protos/linux.c b/common/protos/linux.c
index bd055d8b..66482057 100644
--- a/common/protos/linux.c
+++ b/common/protos/linux.c
@@ -72,71 +72,6 @@ struct setup_header {
uint32_t kernel_info_offset;
} __attribute__((packed));
-struct screen_info {
- uint8_t orig_x; /* 0x00 */
- uint8_t orig_y; /* 0x01 */
- uint16_t ext_mem_k; /* 0x02 */
- uint16_t orig_video_page; /* 0x04 */
- uint8_t orig_video_mode; /* 0x06 */
- uint8_t orig_video_cols; /* 0x07 */
- uint8_t flags; /* 0x08 */
- uint8_t unused2; /* 0x09 */
- uint16_t orig_video_ega_bx;/* 0x0a */
- uint16_t unused3; /* 0x0c */
- uint8_t orig_video_lines; /* 0x0e */
- uint8_t orig_video_isVGA; /* 0x0f */
- uint16_t orig_video_points;/* 0x10 */
-
- /* VESA graphic mode -- linear frame buffer */
- uint16_t lfb_width; /* 0x12 */
- uint16_t lfb_height; /* 0x14 */
- uint16_t lfb_depth; /* 0x16 */
- uint32_t lfb_base; /* 0x18 */
- uint32_t lfb_size; /* 0x1c */
- uint16_t cl_magic, cl_offset; /* 0x20 */
- uint16_t lfb_linelength; /* 0x24 */
- uint8_t red_size; /* 0x26 */
- uint8_t red_pos; /* 0x27 */
- uint8_t green_size; /* 0x28 */
- uint8_t green_pos; /* 0x29 */
- uint8_t blue_size; /* 0x2a */
- uint8_t blue_pos; /* 0x2b */
- uint8_t rsvd_size; /* 0x2c */
- uint8_t rsvd_pos; /* 0x2d */
- uint16_t vesapm_seg; /* 0x2e */
- uint16_t vesapm_off; /* 0x30 */
- uint16_t pages; /* 0x32 */
- uint16_t vesa_attributes; /* 0x34 */
- uint32_t capabilities; /* 0x36 */
- uint32_t ext_lfb_base; /* 0x3a */
- uint8_t _reserved[2]; /* 0x3e */
-} __attribute__((packed));
-
-#define VIDEO_TYPE_MDA 0x10 /* Monochrome Text Display */
-#define VIDEO_TYPE_CGA 0x11 /* CGA Display */
-#define VIDEO_TYPE_EGAM 0x20 /* EGA/VGA in Monochrome Mode */
-#define VIDEO_TYPE_EGAC 0x21 /* EGA in Color Mode */
-#define VIDEO_TYPE_VGAC 0x22 /* VGA+ in Color Mode */
-#define VIDEO_TYPE_VLFB 0x23 /* VESA VGA in graphic mode */
-
-#define VIDEO_TYPE_PICA_S3 0x30 /* ACER PICA-61 local S3 video */
-#define VIDEO_TYPE_MIPS_G364 0x31 /* MIPS Magnum 4000 G364 video */
-#define VIDEO_TYPE_SGI 0x33 /* Various SGI graphics hardware */
-
-#define VIDEO_TYPE_TGAC 0x40 /* DEC TGA */
-
-#define VIDEO_TYPE_SUN 0x50 /* Sun frame buffer. */
-#define VIDEO_TYPE_SUNPCI 0x51 /* Sun PCI based frame buffer. */
-
-#define VIDEO_TYPE_PMAC 0x60 /* PowerMacintosh frame buffer. */
-
-#define VIDEO_TYPE_EFI 0x70 /* EFI graphic mode */
-
-#define VIDEO_FLAGS_NOCURSOR (1 << 0) /* The video mode has no cursor set */
-
-#define VIDEO_CAPABILITY_SKIP_QUIRKS (1 << 0)
-#define VIDEO_CAPABILITY_64BIT_BASE (1 << 1) /* Frame buffer base is 64-bit */
-
struct apm_bios_info {
uint16_t version;
uint16_t cseg;
diff --git a/common/protos/linux.h b/common/protos/linux.h
index 03de0d8a..f214c25d 100644
--- a/common/protos/linux.h
+++ b/common/protos/linux.h
@@ -3,6 +3,71 @@
#include <stdnoreturn.h>
+struct screen_info {
+ uint8_t orig_x; /* 0x00 */
+ uint8_t orig_y; /* 0x01 */
+ uint16_t ext_mem_k; /* 0x02 */
+ uint16_t orig_video_page; /* 0x04 */
+ uint8_t orig_video_mode; /* 0x06 */
+ uint8_t orig_video_cols; /* 0x07 */
+ uint8_t flags; /* 0x08 */
+ uint8_t unused2; /* 0x09 */
+ uint16_t orig_video_ega_bx;/* 0x0a */
+ uint16_t unused3; /* 0x0c */
+ uint8_t orig_video_lines; /* 0x0e */
+ uint8_t orig_video_isVGA; /* 0x0f */
+ uint16_t orig_video_points;/* 0x10 */
+
+ /* VESA graphic mode -- linear frame buffer */
+ uint16_t lfb_width; /* 0x12 */
+ uint16_t lfb_height; /* 0x14 */
+ uint16_t lfb_depth; /* 0x16 */
+ uint32_t lfb_base; /* 0x18 */
+ uint32_t lfb_size; /* 0x1c */
+ uint16_t cl_magic, cl_offset; /* 0x20 */
+ uint16_t lfb_linelength; /* 0x24 */
+ uint8_t red_size; /* 0x26 */
+ uint8_t red_pos; /* 0x27 */
+ uint8_t green_size; /* 0x28 */
+ uint8_t green_pos; /* 0x29 */
+ uint8_t blue_size; /* 0x2a */
+ uint8_t blue_pos; /* 0x2b */
+ uint8_t rsvd_size; /* 0x2c */
+ uint8_t rsvd_pos; /* 0x2d */
+ uint16_t vesapm_seg; /* 0x2e */
+ uint16_t vesapm_off; /* 0x30 */
+ uint16_t pages; /* 0x32 */
+ uint16_t vesa_attributes; /* 0x34 */
+ uint32_t capabilities; /* 0x36 */
+ uint32_t ext_lfb_base; /* 0x3a */
+ uint8_t _reserved[2]; /* 0x3e */
+} __attribute__((packed));
+
+#define VIDEO_TYPE_MDA 0x10 /* Monochrome Text Display */
+#define VIDEO_TYPE_CGA 0x11 /* CGA Display */
+#define VIDEO_TYPE_EGAM 0x20 /* EGA/VGA in Monochrome Mode */
+#define VIDEO_TYPE_EGAC 0x21 /* EGA in Color Mode */
+#define VIDEO_TYPE_VGAC 0x22 /* VGA+ in Color Mode */
+#define VIDEO_TYPE_VLFB 0x23 /* VESA VGA in graphic mode */
+
+#define VIDEO_TYPE_PICA_S3 0x30 /* ACER PICA-61 local S3 video */
+#define VIDEO_TYPE_MIPS_G364 0x31 /* MIPS Magnum 4000 G364 video */
+#define VIDEO_TYPE_SGI 0x33 /* Various SGI graphics hardware */
+
+#define VIDEO_TYPE_TGAC 0x40 /* DEC TGA */
+
+#define VIDEO_TYPE_SUN 0x50 /* Sun frame buffer. */
+#define VIDEO_TYPE_SUNPCI 0x51 /* Sun PCI based frame buffer. */
+
+#define VIDEO_TYPE_PMAC 0x60 /* PowerMacintosh frame buffer. */
+
+#define VIDEO_TYPE_EFI 0x70 /* EFI graphic mode */
+
+#define VIDEO_FLAGS_NOCURSOR (1 << 0) /* The video mode has no cursor set */
+
+#define VIDEO_CAPABILITY_SKIP_QUIRKS (1 << 0)
+#define VIDEO_CAPABILITY_64BIT_BASE (1 << 1) /* Frame buffer base is 64-bit */
+
noreturn void linux_load(char *config, char *cmdline);
#endif
diff --git a/common/protos/linux_risc.c b/common/protos/linux_risc.c
index 95f6e05a..226a8e0b 100644
--- a/common/protos/linux_risc.c
+++ b/common/protos/linux_risc.c
@@ -46,6 +46,35 @@ struct linux_header {
#define LINUX_HEADER_MAGIC2 0x644d5241
#endif
+void add_framebuffer(struct fb_info *fb) {
+ struct screen_info *screen_info = ext_mem_alloc(sizeof(struct screen_info));
+
+ screen_info->capabilities = VIDEO_CAPABILITY_64BIT_BASE | VIDEO_CAPABILITY_SKIP_QUIRKS;
+ screen_info->flags = VIDEO_FLAGS_NOCURSOR;
+ screen_info->lfb_base = (uint32_t)fb->framebuffer_addr;
+ screen_info->ext_lfb_base = (uint32_t)(fb->framebuffer_addr >> 32);
+ screen_info->lfb_size = fb->framebuffer_pitch * fb->framebuffer_height;
+ screen_info->lfb_width = fb->framebuffer_width;
+ screen_info->lfb_height = fb->framebuffer_height;
+ screen_info->lfb_depth = fb->framebuffer_bpp;
+ screen_info->lfb_linelength = fb->framebuffer_pitch;
+ screen_info->red_size = fb->red_mask_size;
+ screen_info->red_pos = fb->red_mask_shift;
+ screen_info->green_size = fb->green_mask_size;
+ screen_info->green_pos = fb->green_mask_shift;
+ screen_info->blue_size = fb->blue_mask_size;
+ screen_info->blue_pos = fb->blue_mask_shift;
+
+ screen_info->orig_video_isVGA = VIDEO_TYPE_EFI;
+
+ EFI_GUID screen_info_table_guid = {0xe03fc20a, 0x85dc, 0x406e, {0xb9, 0x0e, 0x4a, 0xb5, 0x02, 0x37, 0x1d, 0x95}};
+ EFI_STATUS ret = gBS->InstallConfigurationTable(&screen_info_table_guid, screen_info);
+
+ if (ret != EFI_SUCCESS) {
+ panic(true, "linux: failed to install screen info configuration table: '%x'", ret);
+ }
+}
+
void *prepare_device_tree_blob(char *config, char *cmdline) {
// Hopefully 4K should be enough (mainly depends on the length of cmdline).
void *dtb = get_device_tree_blob(0x1000);
@@ -70,6 +99,25 @@ void *prepare_device_tree_blob(char *config, char *cmdline) {
}
}
+ size_t req_width = 0, req_height = 0, req_bpp = 0;
+
+ char *resolution = config_get_value(config, 0, "RESOLUTION");
+ if (resolution != NULL) {
+ parse_resolution(&req_width, &req_height, &req_bpp, resolution);
+ }
+
+ struct fb_info *fbs;
+ size_t fbs_count;
+
+ term_notready();
+
+ fb_init(&fbs, &fbs_count, req_width, req_height, req_bpp);
+
+ // TODO(qookie): Let the user pick a framebuffer if there's > 1
+ if (fbs_count > 0) {
+ add_framebuffer(&fbs[0]);
+ }
+
// Load an initrd if requested and add it to the device tree.
char *module_path = config_get_value(config, 0, "MODULE_PATH");
if (module_path) {
@@ -104,9 +152,6 @@ void *prepare_device_tree_blob(char *config, char *cmdline) {
panic(true, "linux: failed to set bootargs: '%s'", fdt_strerror(ret));
}
- // TODO(qookie): Once I figure out how, give Linux the framebuffer through
- // the device tree here.
-
efi_exit_boot_services();
// Tell Linux about the UEFI memory map and system table.
