:: commit ee5096ed843213bbf8ceca136085afd133bb7646

Kacper Słomiński <kacper.slominski72@gmail.com> — 2024-06-28 02:14

parents: 68ad2db755

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.
tab: 248 wrap: offon