|
@@ -1,32 +1,152 @@
|
|
|
-use crate::tag_type::Tag;
|
|
|
-use crate::Reader;
|
|
|
+use crate::{Reader, Tag, TagTrait, TagType, TagTypeId};
|
|
|
+
|
|
|
+use core::mem::size_of;
|
|
|
use core::slice;
|
|
|
use derive_more::Display;
|
|
|
|
|
|
+#[cfg(feature = "builder")]
|
|
|
+use {
|
|
|
+ crate::builder::boxed_dst_tag, crate::builder::traits::StructAsBytes, alloc::boxed::Box,
|
|
|
+ alloc::vec::Vec,
|
|
|
+};
|
|
|
+
|
|
|
+const METADATA_SIZE: usize = size_of::<TagTypeId>()
|
|
|
+ + 4 * size_of::<u32>()
|
|
|
+ + size_of::<u64>()
|
|
|
+ + size_of::<u16>()
|
|
|
+ + 2 * size_of::<u8>();
|
|
|
+
|
|
|
/// The VBE Framebuffer information Tag.
|
|
|
-#[derive(Debug, PartialEq, Eq)]
|
|
|
-pub struct FramebufferTag<'a> {
|
|
|
+#[derive(Debug, PartialEq, Eq, ptr_meta::Pointee)]
|
|
|
+#[repr(C, packed)]
|
|
|
+pub struct FramebufferTag {
|
|
|
+ typ: TagTypeId,
|
|
|
+ size: u32,
|
|
|
+
|
|
|
/// Contains framebuffer physical address.
|
|
|
///
|
|
|
/// This field is 64-bit wide but bootloader should set it under 4GiB if
|
|
|
/// possible for compatibility with payloads which aren’t aware of PAE or
|
|
|
/// amd64.
|
|
|
- pub address: u64,
|
|
|
+ address: u64,
|
|
|
|
|
|
/// Contains the pitch in bytes.
|
|
|
- pub pitch: u32,
|
|
|
+ pitch: u32,
|
|
|
|
|
|
/// Contains framebuffer width in pixels.
|
|
|
- pub width: u32,
|
|
|
+ width: u32,
|
|
|
|
|
|
/// Contains framebuffer height in pixels.
|
|
|
- pub height: u32,
|
|
|
+ height: u32,
|
|
|
|
|
|
/// Contains number of bits per pixel.
|
|
|
- pub bpp: u8,
|
|
|
+ bpp: u8,
|
|
|
|
|
|
/// The type of framebuffer, one of: `Indexed`, `RGB` or `Text`.
|
|
|
- pub buffer_type: FramebufferType<'a>,
|
|
|
+ type_no: u8,
|
|
|
+
|
|
|
+ // In the multiboot spec, it has this listed as a u8 _NOT_ a u16.
|
|
|
+ // Reading the GRUB2 source code reveals it is in fact a u16.
|
|
|
+ _reserved: u16,
|
|
|
+
|
|
|
+ buffer: [u8],
|
|
|
+}
|
|
|
+
|
|
|
+impl FramebufferTag {
|
|
|
+ #[cfg(feature = "builder")]
|
|
|
+ pub fn new(
|
|
|
+ address: u64,
|
|
|
+ pitch: u32,
|
|
|
+ width: u32,
|
|
|
+ height: u32,
|
|
|
+ bpp: u8,
|
|
|
+ buffer_type: FramebufferType,
|
|
|
+ ) -> Box<Self> {
|
|
|
+ let mut bytes: Vec<u8> = address.to_le_bytes().into();
|
|
|
+ bytes.extend(pitch.to_le_bytes());
|
|
|
+ bytes.extend(width.to_le_bytes());
|
|
|
+ bytes.extend(height.to_le_bytes());
|
|
|
+ bytes.extend(bpp.to_le_bytes());
|
|
|
+ bytes.extend(buffer_type.to_bytes());
|
|
|
+ boxed_dst_tag(TagType::Framebuffer, &bytes)
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Contains framebuffer physical address.
|
|
|
+ ///
|
|
|
+ /// This field is 64-bit wide but bootloader should set it under 4GiB if
|
|
|
+ /// possible for compatibility with payloads which aren’t aware of PAE or
|
|
|
+ /// amd64.
|
|
|
+ pub fn address(&self) -> u64 {
|
|
|
+ self.address
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Contains the pitch in bytes.
|
|
|
+ pub fn pitch(&self) -> u32 {
|
|
|
+ self.pitch
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Contains framebuffer width in pixels.
|
|
|
+ pub fn width(&self) -> u32 {
|
|
|
+ self.width
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Contains framebuffer height in pixels.
|
|
|
+ pub fn height(&self) -> u32 {
|
|
|
+ self.height
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Contains number of bits per pixel.
|
|
|
+ pub fn bpp(&self) -> u8 {
|
|
|
+ self.bpp
|
|
|
+ }
|
|
|
+
|
|
|
+ /// The type of framebuffer, one of: `Indexed`, `RGB` or `Text`.
|
|
|
+ pub fn buffer_type(&self) -> Result<FramebufferType, UnknownFramebufferType> {
|
|
|
+ let mut reader = Reader::new(self.buffer.as_ptr());
|
|
|
+ match self.type_no {
|
|
|
+ 0 => {
|
|
|
+ let num_colors = reader.read_u32();
|
|
|
+ let palette = unsafe {
|
|
|
+ slice::from_raw_parts(
|
|
|
+ reader.current_address() as *const FramebufferColor,
|
|
|
+ num_colors as usize,
|
|
|
+ )
|
|
|
+ } as &'static [FramebufferColor];
|
|
|
+ Ok(FramebufferType::Indexed { palette })
|
|
|
+ }
|
|
|
+ 1 => {
|
|
|
+ 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();
|
|
|
+ let blue_mask = reader.read_u8();
|
|
|
+ Ok(FramebufferType::RGB {
|
|
|
+ red: FramebufferField {
|
|
|
+ position: red_pos,
|
|
|
+ size: red_mask,
|
|
|
+ },
|
|
|
+ green: FramebufferField {
|
|
|
+ position: green_pos,
|
|
|
+ size: green_mask,
|
|
|
+ },
|
|
|
+ blue: FramebufferField {
|
|
|
+ position: blue_pos,
|
|
|
+ size: blue_mask,
|
|
|
+ },
|
|
|
+ })
|
|
|
+ }
|
|
|
+ 2 => Ok(FramebufferType::Text),
|
|
|
+ no => Err(UnknownFramebufferType(no)),
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+impl TagTrait for FramebufferTag {
|
|
|
+ fn dst_size(base_tag: &Tag) -> usize {
|
|
|
+ assert!(base_tag.size as usize >= METADATA_SIZE);
|
|
|
+ base_tag.size as usize - METADATA_SIZE
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/// Helper struct for [`FramebufferType`].
|
|
@@ -67,6 +187,35 @@ pub enum FramebufferType<'a> {
|
|
|
Text,
|
|
|
}
|
|
|
|
|
|
+impl<'a> FramebufferType<'a> {
|
|
|
+ #[cfg(feature = "builder")]
|
|
|
+ fn to_bytes(&self) -> Vec<u8> {
|
|
|
+ let mut v = Vec::new();
|
|
|
+ match self {
|
|
|
+ FramebufferType::Indexed { palette } => {
|
|
|
+ v.extend(0u8.to_le_bytes()); // type
|
|
|
+ v.extend(0u16.to_le_bytes()); // reserved
|
|
|
+ v.extend((palette.len() as u32).to_le_bytes());
|
|
|
+ for color in palette.iter() {
|
|
|
+ v.extend(color.struct_as_bytes());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ FramebufferType::RGB { red, green, blue } => {
|
|
|
+ v.extend(1u8.to_le_bytes()); // type
|
|
|
+ v.extend(0u16.to_le_bytes()); // reserved
|
|
|
+ v.extend(red.struct_as_bytes());
|
|
|
+ v.extend(green.struct_as_bytes());
|
|
|
+ v.extend(blue.struct_as_bytes());
|
|
|
+ }
|
|
|
+ FramebufferType::Text => {
|
|
|
+ v.extend(2u8.to_le_bytes()); // type
|
|
|
+ v.extend(0u16.to_le_bytes()); // reserved
|
|
|
+ }
|
|
|
+ }
|
|
|
+ v
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/// An RGB color type field.
|
|
|
#[derive(Debug, PartialEq, Eq)]
|
|
|
pub struct FramebufferField {
|
|
@@ -77,6 +226,8 @@ pub struct FramebufferField {
|
|
|
pub size: u8,
|
|
|
}
|
|
|
|
|
|
+impl StructAsBytes for FramebufferField {}
|
|
|
+
|
|
|
/// A framebuffer color descriptor in the palette.
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
|
#[repr(C, packed)] // only repr(C) would add unwanted padding at the end
|
|
@@ -99,67 +250,4 @@ pub struct UnknownFramebufferType(u8);
|
|
|
#[cfg(feature = "unstable")]
|
|
|
impl core::error::Error for UnknownFramebufferType {}
|
|
|
|
|
|
-/// Transforms a [`Tag`] into a [`FramebufferTag`].
|
|
|
-pub fn framebuffer_tag(tag: &Tag) -> Result<FramebufferTag, UnknownFramebufferType> {
|
|
|
- let mut reader = Reader::new(tag as *const Tag);
|
|
|
- reader.skip(8);
|
|
|
- let address = reader.read_u64();
|
|
|
- let pitch = reader.read_u32();
|
|
|
- let width = reader.read_u32();
|
|
|
- let height = reader.read_u32();
|
|
|
- let bpp = reader.read_u8();
|
|
|
- let type_no = reader.read_u8();
|
|
|
- // In the multiboot spec, it has this listed as a u8 _NOT_ a u16.
|
|
|
- // Reading the GRUB2 source code reveals it is in fact a u16.
|
|
|
- reader.skip(2);
|
|
|
- let buffer_type_id = match type_no {
|
|
|
- 0 => Ok(FramebufferTypeId::Indexed),
|
|
|
- 1 => Ok(FramebufferTypeId::RGB),
|
|
|
- 2 => Ok(FramebufferTypeId::Text),
|
|
|
- id => Err(UnknownFramebufferType(id)),
|
|
|
- }?;
|
|
|
- let buffer_type = match buffer_type_id {
|
|
|
- FramebufferTypeId::Indexed => {
|
|
|
- let num_colors = reader.read_u32();
|
|
|
- let palette = unsafe {
|
|
|
- slice::from_raw_parts(
|
|
|
- reader.current_address() as *const FramebufferColor,
|
|
|
- num_colors as usize,
|
|
|
- )
|
|
|
- } as &[FramebufferColor];
|
|
|
- FramebufferType::Indexed { palette }
|
|
|
- }
|
|
|
- FramebufferTypeId::RGB => {
|
|
|
- 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();
|
|
|
- let blue_mask = reader.read_u8();
|
|
|
- FramebufferType::RGB {
|
|
|
- red: FramebufferField {
|
|
|
- position: red_pos,
|
|
|
- size: red_mask,
|
|
|
- },
|
|
|
- green: FramebufferField {
|
|
|
- position: green_pos,
|
|
|
- size: green_mask,
|
|
|
- },
|
|
|
- blue: FramebufferField {
|
|
|
- position: blue_pos,
|
|
|
- size: blue_mask,
|
|
|
- },
|
|
|
- }
|
|
|
- }
|
|
|
- FramebufferTypeId::Text => FramebufferType::Text,
|
|
|
- };
|
|
|
-
|
|
|
- Ok(FramebufferTag {
|
|
|
- address,
|
|
|
- pitch,
|
|
|
- width,
|
|
|
- height,
|
|
|
- bpp,
|
|
|
- buffer_type,
|
|
|
- })
|
|
|
-}
|
|
|
+impl StructAsBytes for FramebufferColor {}
|