:: commit cfb1734f4350c750c66302b022b5bac85c3ac4a2

mintsuki <mintsuki@protonmail.com> — 2020-11-08 10:59

parents: 6d232193cf

vbe: Implement more expressive framebuffer tag (fixes #37)

diff --git a/STIVALE2.md b/STIVALE2.md
index db4d8972..9afffdc0 100644
--- a/STIVALE2.md
+++ b/STIVALE2.md
@@ -323,10 +323,17 @@ struct stivale2_struct_tag_framebuffer {
     uint64_t identifier;          // Identifier: 0x506461d2950408fa
     uint64_t next;
     uint64_t framebuffer_addr;    // Address of the framebuffer and related info
-    uint16_t framebuffer_width;
+    uint16_t framebuffer_width;   // Width and height in pixels
     uint16_t framebuffer_height;
-    uint16_t framebuffer_pitch;
-    uint16_t framebuffer_bpp;
+    uint16_t framebuffer_pitch;   // Pitch in bytes
+    uint16_t framebuffer_bpp;     // Bits per pixel
+    uint8_t  memory_model;        // Memory model: 1=RGB, all other values undefined
+    uint8_t  red_mask_size;       // RGB mask sizes and left shifts
+    uint8_t  red_mask_shift;
+    uint8_t  green_mask_size;
+    uint8_t  green_mask_shift;
+    uint8_t  blue_mask_size;
+    uint8_t  blue_mask_shift;
 } __attribute__((packed));
 ```
 
diff --git a/limine-pxe.bin b/limine-pxe.bin
index 00835233..daccaffa 100644
Binary files a/limine-pxe.bin and b/limine-pxe.bin differ
diff --git a/limine.bin b/limine.bin
index f8687d24..41cb7f2c 100644
Binary files a/limine.bin and b/limine.bin differ
diff --git a/stage2/drivers/vbe.c b/stage2/drivers/vbe.c
index 8561a899..1ffd2cb6 100644
--- a/stage2/drivers/vbe.c
+++ b/stage2/drivers/vbe.c
@@ -31,11 +31,12 @@ static void vga_font_retrieve(void) {
 
 static uint32_t ansi_colours[8];
 
+static struct vbe_framebuffer_info fbinfo;
 static uint32_t *vbe_framebuffer;
 static uint16_t  vbe_pitch;
-static uint16_t  vbe_width = 0;
-static uint16_t  vbe_height = 0;
-static uint16_t  vbe_bpp = 0;
+static uint16_t  vbe_width;
+static uint16_t  vbe_height;
+static uint16_t  vbe_bpp;
 
 static int frame_height, frame_width;
 
@@ -316,7 +317,13 @@ void vbe_putchar(char c) {
 }
 
 void vbe_tty_init(int *_rows, int *_cols, uint32_t *_colours, int _margin, int _margin_gradient, struct image *_background) {
-    init_vbe(&vbe_framebuffer, &vbe_pitch, &vbe_width, &vbe_height, &vbe_bpp);
+    init_vbe(&fbinfo, 0, 0, 0);
+
+    vbe_framebuffer = (void *)fbinfo.framebuffer_addr;
+    vbe_width       = fbinfo.framebuffer_width;
+    vbe_height      = fbinfo.framebuffer_height;
+    vbe_bpp         = fbinfo.framebuffer_bpp;
+    vbe_pitch       = fbinfo.framebuffer_pitch;
 
     mtrr_set_range((uint64_t)(size_t)vbe_framebuffer,
                    (uint64_t)vbe_pitch * vbe_height, MTRR_MEMORY_TYPE_WC);
@@ -365,15 +372,55 @@ struct vbe_info_struct {
 } __attribute__((packed));
 
 struct vbe_mode_info_struct {
-    uint8_t pad0[16];
-    uint16_t pitch;
+    uint16_t mode_attributes;
+    uint8_t  wina_attributes;
+    uint8_t  winb_attributes;
+    uint16_t win_granularity;
+    uint16_t win_size;
+    uint16_t wina_segment;
+    uint16_t winb_segment;
+    uint32_t win_farptr;
+    uint16_t bytes_per_scanline;
+
     uint16_t res_x;
     uint16_t res_y;
-    uint8_t pad1[3];
-    uint8_t bpp;
-    uint8_t pad2[14];
-    uint32_t framebuffer;
-    uint8_t pad3[212];
+    uint8_t  charsize_x;
+    uint8_t  charsize_y;
+    uint8_t  plane_count;
+    uint8_t  bpp;
+    uint8_t  bank_count;
+    uint8_t  memory_model;
+    uint8_t  bank_size;
+    uint8_t  image_count;
+    uint8_t  reserved0;
+
+    uint8_t  red_mask_size;
+    uint8_t  red_mask_shift;
+    uint8_t  green_mask_size;
+    uint8_t  green_mask_shift;
+    uint8_t  blue_mask_size;
+    uint8_t  blue_mask_shift;
+    uint8_t  rsvd_mask_size;
+    uint8_t  rsvd_mask_shift;
+    uint8_t  direct_color_info;
+
+    uint32_t framebuffer_addr;
+    uint8_t  reserved1[6];
+
+    uint16_t lin_bytes_per_scanline;
+    uint8_t  banked_image_count;
+    uint8_t  lin_image_count;
+    uint8_t  lin_red_mask_size;
+    uint8_t  lin_red_mask_shift;
+    uint8_t  lin_green_mask_size;
+    uint8_t  lin_green_mask_shift;
+    uint8_t  lin_blue_mask_size;
+    uint8_t  lin_blue_mask_shift;
+    uint8_t  lin_rsvd_mask_size;
+    uint8_t  lin_rsvd_mask_shift;
+    uint32_t max_pixel_clock;
+
+    uint8_t  reserved2[189];
 } __attribute__((packed));
 
 static void get_vbe_info(struct vbe_info_struct *buf) {
@@ -394,12 +441,14 @@ static void get_vbe_mode_info(struct vbe_mode_info_struct *buf,
     rm_int(0x10, &r, &r);
 }
 
-static void set_vbe_mode(uint16_t mode) {
+static int set_vbe_mode(uint16_t mode) {
     struct rm_regs r = {0};
 
     r.eax = 0x4f02;
     r.ebx = (uint32_t)mode | (1 << 14);
     rm_int(0x10, &r, &r);
+
+    return r.eax & 0xff;
 }
 
 struct edid_info_struct {
@@ -457,7 +506,8 @@ static struct resolution fallback_resolutions[] = {
     { 640,  480, 32 }
 };
 
-int init_vbe(uint32_t **framebuffer, uint16_t *pitch, uint16_t *target_width, uint16_t *target_height, uint16_t *target_bpp) {
+bool init_vbe(struct vbe_framebuffer_info *ret,
+              uint16_t target_width, uint16_t target_height, uint16_t target_bpp) {
     print("vbe: Initialising...\n");
 
     size_t current_fallback = 0;
@@ -466,31 +516,37 @@ int init_vbe(uint32_t **framebuffer, uint16_t *pitch, uint16_t *target_width, ui
     get_vbe_info(&vbe_info);
 
     print("vbe: Version: %u.%u\n", vbe_info.version_maj, vbe_info.version_min);
+
+    if (vbe_info.version_maj < 3) {
+        print("vbe: We do not support VBE versions older than 3.0\n");
+        return false;
+    }
+
     print("vbe: OEM: %s\n", (char *)rm_desegment(vbe_info.oem_seg, vbe_info.oem_off));
     print("vbe: Graphics vendor: %s\n", (char *)rm_desegment(vbe_info.vendor_seg, vbe_info.vendor_off));
     print("vbe: Product name: %s\n", (char *)rm_desegment(vbe_info.prod_name_seg, vbe_info.prod_name_off));
     print("vbe: Product revision: %s\n", (char *)rm_desegment(vbe_info.prod_rev_seg, vbe_info.prod_rev_off));
 
     struct edid_info_struct edid_info;
-    if (!*target_width || !*target_height || !*target_bpp) {
-        *target_width  = 1024;
-        *target_height = 768;
-        *target_bpp    = 32;
+    if (!target_width || !target_height || !target_bpp) {
+        target_width  = 1024;
+        target_height = 768;
+        target_bpp    = 32;
         if (!get_edid_info(&edid_info)) {
             int edid_width   = (int)edid_info.det_timing_desc1[2];
                 edid_width  += ((int)edid_info.det_timing_desc1[4] & 0xf0) << 4;
             int edid_height  = (int)edid_info.det_timing_desc1[5];
                 edid_height += ((int)edid_info.det_timing_desc1[7] & 0xf0) << 4;
             if (edid_width && edid_height) {
-                *target_width  = edid_width;
-                *target_height = edid_height;
+                target_width  = edid_width;
+                target_height = edid_height;
                 print("vbe: EDID detected screen resolution of %ux%u\n",
-                      *target_width, *target_height);
+                      target_width, target_height);
             }
         }
     } else {
         print("vbe: Requested resolution of %ux%ux%u\n",
-              *target_width, *target_height, *target_bpp);
+              target_width, target_height, target_bpp);
     }
 
 retry:;
@@ -500,22 +556,38 @@ retry:;
     for (size_t i = 0; vid_modes[i] != 0xffff; i++) {
         struct vbe_mode_info_struct vbe_mode_info;
         get_vbe_mode_info(&vbe_mode_info, vid_modes[i]);
-        if  (vbe_mode_info.res_x == *target_width
-          && vbe_mode_info.res_y == *target_height
-          && vbe_mode_info.bpp   == *target_bpp) {
-            print("vbe: Found matching mode %x, attempting to set\n", vid_modes[i]);
-            *framebuffer = (uint32_t *)vbe_mode_info.framebuffer;
-            *pitch       = (int)vbe_mode_info.pitch;
-            print("vbe: Framebuffer address: %x\n", vbe_mode_info.framebuffer);
-            set_vbe_mode(vid_modes[i]);
-            return 0;
+        if  (vbe_mode_info.res_x == target_width
+          && vbe_mode_info.res_y == target_height
+          && vbe_mode_info.bpp   == target_bpp) {
+            // We only support RGB for now
+            if (vbe_mode_info.memory_model != 0x06)
+                continue;
+            print("vbe: Found matching mode %x, attempting to set...\n", vid_modes[i]);
+            if (set_vbe_mode(vid_modes[i]) == 0x01) {
+                print("vbe: Failed to set video mode %x, moving on...\n", vid_modes[i]);
+                continue;
+            }
+            print("vbe: Framebuffer address: %x\n", vbe_mode_info.framebuffer_addr);
+            ret->memory_model       = vbe_mode_info.memory_model;
+            ret->framebuffer_addr   = vbe_mode_info.framebuffer_addr;
+            ret->framebuffer_pitch  = vbe_mode_info.lin_bytes_per_scanline;
+            ret->framebuffer_width  = vbe_mode_info.res_x;
+            ret->framebuffer_height = vbe_mode_info.res_y;
+            ret->framebuffer_bpp    = vbe_mode_info.bpp;
+            ret->red_mask_size      = vbe_mode_info.lin_red_mask_size;
+            ret->red_mask_shift     = vbe_mode_info.lin_red_mask_shift;
+            ret->green_mask_size    = vbe_mode_info.lin_green_mask_size;
+            ret->green_mask_shift   = vbe_mode_info.lin_green_mask_shift;
+            ret->blue_mask_size     = vbe_mode_info.lin_blue_mask_size;
+            ret->blue_mask_shift    = vbe_mode_info.lin_blue_mask_shift;
+            return true;
         }
     }
 
     if (current_fallback < SIZEOF_ARRAY(fallback_resolutions)) {
-        *target_width  = fallback_resolutions[current_fallback].width;
-        *target_height = fallback_resolutions[current_fallback].height;
-        *target_bpp    = fallback_resolutions[current_fallback].bpp;
+        target_width  = fallback_resolutions[current_fallback].width;
+        target_height = fallback_resolutions[current_fallback].height;
+        target_bpp    = fallback_resolutions[current_fallback].bpp;
         current_fallback++;
         goto retry;
     }
diff --git a/stage2/drivers/vbe.h b/stage2/drivers/vbe.h
index faefe05a..ead7f284 100644
--- a/stage2/drivers/vbe.h
+++ b/stage2/drivers/vbe.h
@@ -5,7 +5,23 @@
 #include <stdbool.h>
 #include <lib/image.h>
 
-int init_vbe(uint32_t **framebuffer, uint16_t *pitch, uint16_t *target_width, uint16_t *target_height, uint16_t *target_bpp);
+struct vbe_framebuffer_info {
+    uint8_t  memory_model;
+    uint32_t framebuffer_addr;
+    uint16_t framebuffer_pitch;
+    uint16_t framebuffer_width;
+    uint16_t framebuffer_height;
+    uint16_t framebuffer_bpp;
+    uint8_t  red_mask_size;
+    uint8_t  red_mask_shift;
+    uint8_t  green_mask_size;
+    uint8_t  green_mask_shift;
+    uint8_t  blue_mask_size;
+    uint8_t  blue_mask_shift;
+};
+
+bool init_vbe(struct vbe_framebuffer_info *ret,
+              uint16_t target_width, uint16_t target_height, uint16_t target_bpp);
 
 void vbe_tty_init(int *rows, int *cols, uint32_t *colours, int margin, int margin_gradient, struct image *background);
 
diff --git a/stage2/protos/stivale.c b/stage2/protos/stivale.c
index 2b8697b0..6bc579f5 100644
--- a/stage2/protos/stivale.c
+++ b/stage2/protos/stivale.c
@@ -173,13 +173,16 @@ void stivale_load(char *cmdline) {
     term_deinit();
 
     if (stivale_hdr.flags & (1 << 0)) {
-        uint32_t *fb32;
-        init_vbe(&fb32,
-                 &stivale_struct.framebuffer_pitch,
-                 &stivale_struct.framebuffer_width,
-                 &stivale_struct.framebuffer_height,
-                 &stivale_struct.framebuffer_bpp);
-        stivale_struct.framebuffer_addr = (uint64_t)(size_t)fb32;
+        struct vbe_framebuffer_info fbinfo;
+        init_vbe(&fbinfo,
+                 stivale_struct.framebuffer_width,
+                 stivale_struct.framebuffer_height,
+                 stivale_struct.framebuffer_bpp);
+        stivale_struct.framebuffer_addr   = (uint64_t)fbinfo.framebuffer_addr;
+        stivale_struct.framebuffer_width  = fbinfo.framebuffer_width;
+        stivale_struct.framebuffer_height = fbinfo.framebuffer_height;
+        stivale_struct.framebuffer_bpp    = fbinfo.framebuffer_bpp;
+        stivale_struct.framebuffer_pitch  = fbinfo.framebuffer_pitch;
     }
 
     bool want_5lv = level5pg && (stivale_hdr.flags & (1 << 1));
diff --git a/stage2/protos/stivale2.c b/stage2/protos/stivale2.c
index 04781fd9..5ed09637 100644
--- a/stage2/protos/stivale2.c
+++ b/stage2/protos/stivale2.c
@@ -256,22 +256,28 @@ void stivale2_load(char *cmdline) {
     term_deinit();
 
     if (hdrtag != NULL) {
-        struct stivale2_struct_tag_framebuffer *tag = conv_mem_alloc(sizeof(struct stivale2_struct_tag_framebuffer));
-        tag->tag.identifier = STIVALE2_STRUCT_TAG_FRAMEBUFFER_ID;
-
-        tag->framebuffer_width  = hdrtag->framebuffer_width;
-        tag->framebuffer_height = hdrtag->framebuffer_height;
-        tag->framebuffer_bpp    = hdrtag->framebuffer_bpp;
-
-        uint32_t *fb32;
-        init_vbe(&fb32,
-                 &tag->framebuffer_pitch,
-                 &tag->framebuffer_width,
-                 &tag->framebuffer_height,
-                 &tag->framebuffer_bpp);
-        tag->framebuffer_addr = (uint64_t)(size_t)fb32;
-
-        append_tag(&stivale2_struct, (struct stivale2_tag *)tag);
+        struct vbe_framebuffer_info fbinfo;
+        if (init_vbe(&fbinfo,
+                     hdrtag->framebuffer_width,
+                     hdrtag->framebuffer_height,
+                     hdrtag->framebuffer_bpp)) {
+            struct stivale2_struct_tag_framebuffer *tag = conv_mem_alloc(sizeof(struct stivale2_struct_tag_framebuffer));
+            tag->tag.identifier = STIVALE2_STRUCT_TAG_FRAMEBUFFER_ID;
+
+            tag->memory_model       = STIVALE2_FBUF_MMODEL_RGB;
+            tag->framebuffer_width  = fbinfo.framebuffer_width;
+            tag->framebuffer_height = fbinfo.framebuffer_height;
+            tag->framebuffer_bpp    = fbinfo.framebuffer_bpp;
+            tag->framebuffer_pitch  = fbinfo.framebuffer_pitch;
+            tag->red_mask_size      = fbinfo.red_mask_size;
+            tag->red_mask_shift     = fbinfo.red_mask_shift;
+            tag->green_mask_size    = fbinfo.green_mask_size;
+            tag->green_mask_shift   = fbinfo.green_mask_shift;
+            tag->blue_mask_size     = fbinfo.blue_mask_size;
+            tag->blue_mask_shift    = fbinfo.blue_mask_shift;
+
+            append_tag(&stivale2_struct, (struct stivale2_tag *)tag);
+        }
     }
     }
 
diff --git a/stivale/stivale2.h b/stivale/stivale2.h
index 03decded..4c5485e1 100644
--- a/stivale/stivale2.h
+++ b/stivale/stivale2.h
@@ -83,6 +83,10 @@ struct stivale2_struct_tag_memmap {
 
 #define STIVALE2_STRUCT_TAG_FRAMEBUFFER_ID 0x506461d2950408fa
 
+enum {
+    STIVALE2_FBUF_MMODEL_RGB  = 1
+};
+
 struct stivale2_struct_tag_framebuffer {
     struct stivale2_tag tag;
     uint64_t framebuffer_addr;
@@ -90,6 +94,13 @@ struct stivale2_struct_tag_framebuffer {
     uint16_t framebuffer_height;
     uint16_t framebuffer_pitch;
     uint16_t framebuffer_bpp;
+    uint8_t  memory_model;
+    uint8_t  red_mask_size;
+    uint8_t  red_mask_shift;
+    uint8_t  green_mask_size;
+    uint8_t  green_mask_shift;
+    uint8_t  blue_mask_size;
+    uint8_t  blue_mask_shift;
 } __attribute__((packed));
 
 #define STIVALE2_STRUCT_TAG_MODULES_ID 0x4b6fe466aade04ce
diff --git a/test/stivale2.c b/test/stivale2.c
index c2b83b97..4da0e0c4 100644
--- a/test/stivale2.c
+++ b/test/stivale2.c
@@ -73,6 +73,13 @@ void stivale2_main(struct stivale2_struct *info) {
                 e9_printf("\tHeight:  %d", f->framebuffer_height);
                 e9_printf("\tPitch:   %d", f->framebuffer_pitch);
                 e9_printf("\tBPP:     %d", f->framebuffer_bpp);
+                e9_printf("\tMemory model:    %d", f->memory_model);
+                e9_printf("\tRed mask size:   %d", f->red_mask_size);
+                e9_printf("\tRed mask size:   %d", f->red_mask_shift);
+                e9_printf("\tGreen mask size: %d", f->green_mask_size);
+                e9_printf("\tGreen mask size: %d", f->green_mask_shift);
+                e9_printf("\tBlue mask size:  %d", f->blue_mask_size);
+                e9_printf("\tBlue mask size:  %d", f->blue_mask_shift);
                 break;
             }
             case STIVALE2_STRUCT_TAG_MODULES_ID: {
tab: 248 wrap: offon