Browse Source

Fix bugs in FramebufferTag, add VBEInfoTag.

tuomas56 6 years ago
parent
commit
48d9b17aeb
3 changed files with 436 additions and 13 deletions
  1. 3 3
      src/framebuffer.rs
  2. 302 10
      src/lib.rs
  3. 131 0
      src/vbe_info.rs

+ 3 - 3
src/framebuffer.rs

@@ -54,13 +54,13 @@ pub fn framebuffer_tag<'a>(tag: &'a Tag) -> FramebufferTag<'a> {
         0 =>  {
             let num_colors = reader.read_u32();
             let palette = unsafe {
-                slice::from_raw_parts(reader.read_u32() as usize as *const FramebufferColor, num_colors as usize)
+                slice::from_raw_parts(reader.current_address() as *const FramebufferColor, num_colors as usize)
             } as &'static [FramebufferColor];
             FramebufferType::Indexed { palette }
         },
         1 => {
-            let red_pos = reader.read_u8();     // These refer to the bit positions of the MSB of each field
-            let red_mask = reader.read_u8();    // And then the length of the field from MSB to LSB
+            let red_pos = reader.read_u8();     // These refer to the bit positions of the LSB of each field
+            let red_mask = reader.read_u8();    // And then the length of the field from LSB to MSB
             let green_pos = reader.read_u8();   
             let green_mask = reader.read_u8();  
             let blue_pos = reader.read_u8();

+ 302 - 10
src/lib.rs

@@ -12,6 +12,8 @@ pub use memory_map::{MemoryMapTag, MemoryArea, MemoryAreaIter};
 pub use module::{ModuleTag, ModuleIter};
 pub use command_line::CommandLineTag;
 pub use rsdp::{RsdpV1Tag, RsdpV2Tag};
+pub use vbe_info::{VBEInfoTag, VBEControlInfo, VBEModeInfo, VBEField, VBECapabilities, 
+                   VBEModeAttributes, VBEWindowAttributes, VBEDirectColorAttributes, VBEMemoryModel};
 
 #[macro_use]
 extern crate bitflags;
@@ -24,6 +26,7 @@ mod module;
 mod command_line;
 mod rsdp;
 mod framebuffer;
+mod vbe_info;
 
 pub unsafe fn load(address: usize) -> BootInformation {
     assert_eq!(0, address & 0b111);
@@ -102,6 +105,10 @@ impl BootInformation {
         self.get_tag(15).map(|tag| unsafe { &*(tag as *const Tag as *const RsdpV2Tag) })
     }
 
+    pub fn vbe_info_tag(&self) -> Option<&'static VBEInfoTag> {
+        self.get_tag(7).map(|tag| unsafe { &*(tag as *const Tag as *const VBEInfoTag) })
+    }
+
     fn get(&self) -> &BootInformationInner {
         unsafe { &*self.inner }
     }
@@ -204,6 +211,12 @@ impl Reader {
     pub(crate) fn skip(&mut self, n: usize) {
         self.off += n;
     }
+
+    pub(crate) fn current_address(&self) -> usize {
+        unsafe {
+            self.ptr.offset(self.off as isize) as usize
+        }
+    }
 }
 
 #[cfg(test)]
@@ -363,20 +376,22 @@ mod tests {
         // this is synthetic, as I can't get QEMU
         // to run in indexed color mode.
         #[repr(C, align(8))]
-        struct Bytes([u8; 56]);
+        struct Bytes([u8; 64]);
         let bytes: Bytes = Bytes([
-            56, 0, 0, 0,  // total size
+            64, 0, 0, 0,  // total size
             0, 0, 0, 0,   // reserved
             8, 0, 0, 0,   // framebuffer tag type
-            40, 0, 0, 0,  // framebuffer tag size
+            48, 0, 0, 0,  // framebuffer tag size
             0, 0, 0, 253, // framebuffer low dword of address
             0, 0, 0, 0,   // framebuffer high dword of address
             0, 20, 0, 0,  // framebuffer pitch
             0, 5, 0, 0,   // framebuffer width
             208, 2, 0, 0, // framebuffer height
             32, 0, 0, 0,  // framebuffer bpp, type, reserved word
-            0, 1, 0, 0,   // framebuffer palette length
-            0, 24, 1, 0,  // framebuffer palette address
+            4, 0, 0, 0,   // framebuffer palette length
+            255, 0, 0, 0,  // framebuffer palette
+            255, 0, 0, 0,
+            255, 0, 0, 0, 
             0, 0, 0, 0,   // end tag type
             8, 0, 0, 0    // end tag size
         ]);
@@ -385,7 +400,7 @@ mod tests {
         assert_eq!(addr, bi.start_address());
         assert_eq!(addr + bytes.0.len(), bi.end_address());
         assert_eq!(bytes.0.len(), bi.total_size());
-        use framebuffer::FramebufferType;
+        use framebuffer::{FramebufferType, FramebufferColor};
         assert!(bi.framebuffer_tag().is_some());
         let fbi = bi.framebuffer_tag().unwrap();
         assert_eq!(fbi.address, 4244635648);
@@ -394,14 +409,291 @@ mod tests {
         assert_eq!(fbi.height, 720);
         assert_eq!(fbi.bpp, 32);
         match fbi.buffer_type {
-            FramebufferType::Indexed { palette } => {
-                assert_eq!(palette.as_ptr() as usize, 71680);
-                assert_eq!(palette.len(), 256);
-            },
+            FramebufferType::Indexed { palette } => assert_eq!(palette, [
+                FramebufferColor { red: 255, green: 0, blue: 0 },
+                FramebufferColor { red: 0, green: 255, blue: 0 },
+                FramebufferColor { red: 0, green: 0, blue: 255 },
+                FramebufferColor { red: 0, green: 0, blue: 0}
+            ]),
             _ => panic!("Expected indexed framebuffer type.")
         }
     }
 
+    #[test]
+    fn vbe_info_tag() {
+        //Taken from GRUB2 running in QEMU.
+        #[repr(C, align(8))]
+        struct Bytes([u8; 800]);
+        let bytes = Bytes([
+            32, 3, 0, 0,        // Total size.
+            0, 0, 0, 0,         // Reserved
+            7, 0, 0, 0,         // Tag type.
+            16, 3, 0, 0,        // Tag size.
+            122, 65, 255, 255,  // VBE mode, protected mode interface segment,
+            0, 96, 79, 0,       // protected mode interface offset, and length.
+            86, 69, 83, 65,     // "VESA" signature.
+            0, 3, 220, 87,      // VBE version, lower half of OEM string ptr,
+            0, 192, 1, 0,       // upper half of OEM string ptr, lower half of capabilities
+            0, 0, 34, 128,      // upper half of capabilities, lower half of vide mode ptr,
+            0, 96, 0, 1,        // upper half of video mode ptr, number of 64kb memory blocks
+            0, 0, 240, 87,      // OEM software revision, lower half of OEM vendor string ptr,
+            0, 192, 3, 88,      // upper half of OEM vendor string ptr, lower half of OEM product string ptr,
+            0, 192, 23, 88,     // upper half of OEM product string ptr, lower half of OEM revision string ptr,
+            0, 192, 0, 1,       // upper half of OEM revision string ptr.
+            1, 1, 2, 1,         // Reserved data....
+            3, 1, 4, 1, 
+            5, 1, 6, 1, 
+            7, 1, 13, 1, 
+            14, 1, 15, 1, 
+            16, 1, 17, 1, 
+            18, 1, 19, 1, 
+            20, 1, 21, 1, 
+            22, 1, 23, 1, 
+            24, 1, 25, 1, 
+            26, 1, 27, 1, 
+            28, 1, 29, 1, 
+            30, 1, 31, 1, 
+            64, 1, 65, 1, 
+            66, 1, 67, 1, 
+            68, 1, 69, 1, 
+            70, 1, 71, 1, 
+            72, 1, 73, 1, 
+            74, 1, 75, 1, 
+            76, 1, 117, 1, 
+            118, 1, 119, 1, 
+            120, 1, 121, 1, 
+            122, 1, 123, 1, 
+            124, 1, 125, 1, 
+            126, 1, 127, 1, 
+            128, 1, 129, 1, 
+            130, 1, 131, 1, 
+            132, 1, 133, 1, 
+            134, 1, 135, 1, 
+            136, 1, 137, 1, 
+            138, 1, 139, 1, 
+            140, 1, 141, 1, 
+            142, 1, 143, 1, 
+            144, 1, 145, 1, 
+            146, 1, 0, 0, 
+            1, 0, 2, 0, 
+            3, 0, 4, 0, 
+            5, 0, 6, 0, 
+            7, 0, 13, 0, 
+            14, 0, 15, 0, 
+            16, 0, 17, 0, 
+            18, 0, 19, 0, 
+            106, 0, 255, 255, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0,         // Until Here
+            187, 0, 7, 0,       // Mode attributes, window A and B attributes
+            64, 0, 64, 0,       // Window granularity and size.
+            0, 160, 0, 0,       // Window A and B segments.
+            186, 84, 0, 192,    // Window relocation function pointer.
+            0, 20, 0, 5,        // Pitch, X resolution.
+            32, 3, 8, 16,       // Y resolution, X char size, Y char size.
+            1, 32, 1, 6,        // Number of planes, BPP, number of banks, memory model.
+            0, 3, 1, 8,         // Bank size, number of images, reserved, red mask size.
+            16, 8, 8, 8,        // Red mask position, green mask size, green mask position, blue mask size,
+            0, 8, 24, 2,        // blue mask position, reserved mask size, reserved mask position, color attributes.
+            0, 0, 0, 253,       // Frame buffer base address.
+            0, 0, 0, 0,         // Off screen memory offset.
+            0, 0, 0, 20,        // Off screen memory size, reserved data...
+            0, 0, 8, 16, 
+            8, 8, 8, 0, 
+            8, 24, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0, 
+            0, 0, 0, 0,         // Until here.
+            0, 0, 0, 0,         // End tag type.
+            8, 0, 0, 0          // End tag size.
+        ]);
+
+        let addr = bytes.0.as_ptr() as usize;
+        let bi = unsafe { load(addr) };
+        assert_eq!(addr, bi.start_address());
+        assert_eq!(addr + bytes.0.len(), bi.end_address());
+        assert_eq!(bytes.0.len(), bi.total_size());
+        assert!(bi.vbe_info_tag().is_some());
+        let vbe = bi.vbe_info_tag().unwrap();
+        use vbe_info::*;
+        unsafe {
+            assert_eq!(vbe.mode, 16762);
+            assert_eq!(vbe.interface_segment, 65535);
+            assert_eq!(vbe.interface_offset, 24576);
+            assert_eq!(vbe.interface_length, 79);
+            assert_eq!(vbe.control_info.signature, [86, 69, 83, 65]);
+            assert_eq!(vbe.control_info.version, 768);
+            assert_eq!(vbe.control_info.oem_string_ptr, 3221247964);
+            assert_eq!(vbe.control_info.capabilities, VBECapabilities::SWITCHABLE_DAC);
+            assert_eq!(vbe.control_info.mode_list_ptr, 1610645538);
+            assert_eq!(vbe.control_info.total_memory, 256);
+            assert_eq!(vbe.control_info.oem_software_revision, 0);
+            assert_eq!(vbe.control_info.oem_vendor_name_ptr, 3221247984);
+            assert_eq!(vbe.control_info.oem_product_name_ptr, 3221248003);
+            assert_eq!(vbe.control_info.oem_product_revision_ptr, 3221248023);
+            assert!(vbe.mode_info.mode_attributes.contains(
+                VBEModeAttributes::SUPPORTED 
+                | VBEModeAttributes::COLOR
+                | VBEModeAttributes::GRAPHICS
+                | VBEModeAttributes::NOT_VGA_COMPATIBLE
+                | VBEModeAttributes::LINEAR_FRAMEBUFFER
+            ));
+            assert!(vbe.mode_info.window_a_attributes.contains(
+                VBEWindowAttributes::RELOCATABLE
+                | VBEWindowAttributes::READABLE
+                | VBEWindowAttributes::WRITEABLE
+            ));
+            assert_eq!(vbe.mode_info.window_granularity, 64);
+            assert_eq!(vbe.mode_info.window_size, 64);
+            assert_eq!(vbe.mode_info.window_a_segment, 40960);
+            assert_eq!(vbe.mode_info.window_function_ptr, 3221247162);
+            assert_eq!(vbe.mode_info.pitch, 5120);
+            assert_eq!(vbe.mode_info.resolution, (1280, 800));
+            assert_eq!(vbe.mode_info.character_size, (8, 16));
+            assert_eq!(vbe.mode_info.number_of_planes, 1);
+            assert_eq!(vbe.mode_info.bpp, 32);
+            assert_eq!(vbe.mode_info.number_of_banks, 1);
+            assert_eq!(vbe.mode_info.memory_model, VBEMemoryModel::DirectColor);
+            assert_eq!(vbe.mode_info.bank_size, 0);
+            assert_eq!(vbe.mode_info.number_of_image_pages, 3);
+            assert_eq!(vbe.mode_info.red_field, VBEField {
+                position: 16, size: 8
+            });
+            assert_eq!(vbe.mode_info.green_field, VBEField {
+                position: 8, size: 8
+            });
+            assert_eq!(vbe.mode_info.blue_field, VBEField {
+                position: 0, size: 8
+            });
+            assert_eq!(vbe.mode_info.reserved_field, VBEField {
+                position: 24, size: 8
+            });
+            assert_eq!(vbe.mode_info.direct_color_attributes, VBEDirectColorAttributes::RESERVED_USABLE);
+            assert_eq!(vbe.mode_info.framebuffer_base_ptr, 4244635648);
+            assert_eq!(vbe.mode_info.offscreen_memory_offset, 0);
+            assert_eq!(vbe.mode_info.offscreen_memory_size, 0);
+        }
+    }
+
     #[test]
     fn grub2() {
         #[repr(C, align(8))]

+ 131 - 0
src/vbe_info.rs

@@ -0,0 +1,131 @@
+use core::fmt;
+
+// Use this for implementing Debug on fields which are too large, or should not be printed.
+// Although I haven't found anything explicitly saying that this will _definitely_ have the same
+// representation as T, in my tests it always has. I don't know quite how alignment works either
+// for this type, the rust docs aren't totally clear, and #[repr(C, packed)] is not valid.
+#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+struct NoDebug<T>(T);
+
+impl<T> fmt::Debug for NoDebug<T> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "...") // Write something, otherwise this looks funky in structs.
+    }
+}
+
+#[derive(Debug, Copy, Clone)]
+#[repr(C, packed)]
+pub struct VBEInfoTag {
+    typ: NoDebug<u32>,
+    length: NoDebug<u32>,
+    pub mode: u16,
+    pub interface_segment: u16,
+    pub interface_offset: u16,
+    pub interface_length: u16,
+    pub control_info: VBEControlInfo,
+    pub mode_info: VBEModeInfo
+}
+
+#[derive(Debug, Copy, Clone)]
+#[repr(C, packed)]
+pub struct VBEControlInfo {
+    pub signature: [u8; 4],
+    pub version: u16,
+    pub oem_string_ptr: u32,
+    pub capabilities: VBECapabilities,
+    pub mode_list_ptr: u32,
+    pub total_memory: u16, // Measured in 64kb blocks.
+    pub oem_software_revision: u16,  
+    pub oem_vendor_name_ptr: u32,
+    pub oem_product_name_ptr: u32,
+    pub oem_product_revision_ptr: u32,
+    reserved: NoDebug<[u8; 222]>,
+    oem_data: NoDebug<[u8; 256]>
+}
+
+#[derive(Debug, Copy, Clone)]
+#[repr(C, packed)]
+pub struct VBEModeInfo {
+    pub mode_attributes: VBEModeAttributes,
+    pub window_a_attributes: VBEWindowAttributes,
+    pub window_b_attributes: VBEWindowAttributes,
+    pub window_granularity: u16, // Measured in kilobytes.
+    pub window_size: u16,
+    pub window_a_segment: u16,
+    pub window_b_segment: u16,
+    pub window_function_ptr: u32,
+    pub pitch: u16,
+    pub resolution: (u16, u16),
+    pub character_size: (u8, u8),
+    pub number_of_planes: u8,
+    pub bpp: u8,
+    pub number_of_banks: u8,
+    pub memory_model: VBEMemoryModel,
+    pub bank_size: u8, // Measured in kilobytes.
+    pub number_of_image_pages: u8,
+    reserved0: NoDebug<u8>,
+    pub red_field: VBEField,
+    pub green_field: VBEField,
+    pub blue_field: VBEField,
+    pub reserved_field: VBEField,
+    pub direct_color_attributes: VBEDirectColorAttributes,
+    pub framebuffer_base_ptr: u32,
+    pub offscreen_memory_offset: u32,
+    pub offscreen_memory_size: u16,
+    reserved1: NoDebug<[u8; 206]>
+}
+
+#[derive(Debug, PartialEq, Copy, Clone)]
+#[repr(C, packed)]
+pub struct VBEField {
+    pub size: u8,
+    pub position: u8
+}
+
+bitflags! {
+    pub struct VBECapabilities: u32 {
+        const SWITCHABLE_DAC = 0x1;     // The DAC can be switched between 6 and 8-bit modes.
+        const NOT_VGA_COMPATIBLE = 0x2; // The controller can be switched into VGA modes.
+        const RAMDAC_FIX = 0x4;         // When writing lots of information to the palette, the blank bit should be used.
+    }
+}
+
+bitflags! {
+    pub struct VBEModeAttributes: u16 {
+        const SUPPORTED = 0x1;           // This mode is supported by the hardware.
+        const TTY_SUPPORTED = 0x4;       // TTY output is supported.
+        const COLOR = 0x8;
+        const GRAPHICS = 0x10;
+        const NOT_VGA_COMPATIBLE = 0x20;
+        const NO_VGA_WINDOW = 0x40;      // If this is set, the window A and B fields of VBEModeInfo are invalid.
+        const LINEAR_FRAMEBUFFER = 0x80; // A linear framebuffer is available for this mode.
+    }
+}
+
+bitflags! {
+    pub struct VBEWindowAttributes: u8 {
+        const RELOCATABLE = 0x1;
+        const READABLE = 0x2;
+        const WRITEABLE = 0x4;
+    }
+}
+
+bitflags! {
+    pub struct VBEDirectColorAttributes: u8 {
+        const PROGRAMMABLE = 0x1;       // The color ramp of the DAC is programmable.
+        const RESERVED_USABLE = 0x2;    // The bits of the 'reserved' field are usable by the application.
+    }
+}
+
+#[derive(Debug, PartialEq, Copy, Clone)]
+#[repr(u8)]
+pub enum VBEMemoryModel {
+    Text = 0x00,
+    CGAGraphics = 0x01,
+    HerculesGraphics = 0x02,
+    Planar = 0x03,
+    PackedPixel = 0x04,
+    Unchained = 0x05,
+    DirectColor = 0x06,
+    YUV = 0x07
+}