Skip to content

Commit bb21998

Browse files
committed
multiboot2: Implement setting the framebuffer tag
1 parent 08df6c2 commit bb21998

File tree

4 files changed

+214
-124
lines changed

4 files changed

+214
-124
lines changed

multiboot2/src/builder/information.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Exports item [`Multiboot2InformationBuilder`].
22
use crate::builder::traits::StructAsBytes;
3-
use crate::{BootLoaderNameTag, CommandLineTag, ElfSectionsTag, ModuleTag};
3+
use crate::{BootLoaderNameTag, CommandLineTag, ElfSectionsTag, FramebufferTag, ModuleTag};
44

55
use alloc::boxed::Box;
66
use alloc::vec::Vec;
@@ -13,6 +13,7 @@ pub struct Multiboot2InformationBuilder {
1313
boot_loader_name_tag: Option<Box<BootLoaderNameTag>>,
1414
command_line_tag: Option<Box<CommandLineTag>>,
1515
elf_sections_tag: Option<Box<ElfSectionsTag>>,
16+
framebuffer_tag: Option<Box<FramebufferTag>>,
1617
module_tags: Vec<Box<ModuleTag>>,
1718
}
1819

@@ -22,6 +23,7 @@ impl Multiboot2InformationBuilder {
2223
boot_loader_name_tag: None,
2324
command_line_tag: None,
2425
elf_sections_tag: None,
26+
framebuffer_tag: None,
2527
module_tags: Vec::new(),
2628
}
2729
}
@@ -38,6 +40,10 @@ impl Multiboot2InformationBuilder {
3840
self.elf_sections_tag = Some(elf_sections_tag);
3941
}
4042

43+
pub fn framebuffer_tag(&mut self, framebuffer_tag: Box<FramebufferTag>) {
44+
self.framebuffer_tag = Some(framebuffer_tag);
45+
}
46+
4147
pub fn add_module_tag(&mut self, module_tag: Box<ModuleTag>) {
4248
self.module_tags.push(module_tag);
4349
}

multiboot2/src/builder/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Module for the builder-feature.
22
33
mod information;
4-
pub(self) mod traits;
4+
pub(crate) mod traits;
55

66
pub use information::Multiboot2InformationBuilder;
77

multiboot2/src/framebuffer.rs

Lines changed: 162 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,152 @@
1-
use crate::tag_type::Tag;
2-
use crate::Reader;
1+
use crate::{Reader, Tag, TagTrait, TagType, TagTypeId};
2+
3+
use core::mem::size_of;
34
use core::slice;
45
use derive_more::Display;
56

7+
#[cfg(feature = "builder")]
8+
use {
9+
crate::builder::boxed_dst_tag, crate::builder::traits::StructAsBytes, alloc::boxed::Box,
10+
alloc::vec::Vec,
11+
};
12+
13+
const METADATA_SIZE: usize = size_of::<TagTypeId>()
14+
+ 4 * size_of::<u32>()
15+
+ size_of::<u64>()
16+
+ size_of::<u16>()
17+
+ 2 * size_of::<u8>();
18+
619
/// The VBE Framebuffer information Tag.
7-
#[derive(Debug, PartialEq, Eq)]
8-
pub struct FramebufferTag<'a> {
20+
#[derive(Debug, PartialEq, Eq, ptr_meta::Pointee)]
21+
#[repr(C, packed)]
22+
pub struct FramebufferTag {
23+
typ: TagTypeId,
24+
size: u32,
25+
926
/// Contains framebuffer physical address.
1027
///
1128
/// This field is 64-bit wide but bootloader should set it under 4GiB if
1229
/// possible for compatibility with payloads which aren’t aware of PAE or
1330
/// amd64.
14-
pub address: u64,
31+
address: u64,
1532

1633
/// Contains the pitch in bytes.
17-
pub pitch: u32,
34+
pitch: u32,
1835

1936
/// Contains framebuffer width in pixels.
20-
pub width: u32,
37+
width: u32,
2138

2239
/// Contains framebuffer height in pixels.
23-
pub height: u32,
40+
height: u32,
2441

2542
/// Contains number of bits per pixel.
26-
pub bpp: u8,
43+
bpp: u8,
2744

2845
/// The type of framebuffer, one of: `Indexed`, `RGB` or `Text`.
29-
pub buffer_type: FramebufferType<'a>,
46+
type_no: u8,
47+
48+
// In the multiboot spec, it has this listed as a u8 _NOT_ a u16.
49+
// Reading the GRUB2 source code reveals it is in fact a u16.
50+
_reserved: u16,
51+
52+
buffer: [u8],
53+
}
54+
55+
impl FramebufferTag {
56+
#[cfg(feature = "builder")]
57+
pub fn new(
58+
address: u64,
59+
pitch: u32,
60+
width: u32,
61+
height: u32,
62+
bpp: u8,
63+
buffer_type: FramebufferType,
64+
) -> Box<Self> {
65+
let mut bytes: Vec<u8> = address.to_le_bytes().into();
66+
bytes.extend(pitch.to_le_bytes());
67+
bytes.extend(width.to_le_bytes());
68+
bytes.extend(height.to_le_bytes());
69+
bytes.extend(bpp.to_le_bytes());
70+
bytes.extend(buffer_type.to_bytes());
71+
boxed_dst_tag(TagType::Framebuffer, &bytes)
72+
}
73+
74+
/// Contains framebuffer physical address.
75+
///
76+
/// This field is 64-bit wide but bootloader should set it under 4GiB if
77+
/// possible for compatibility with payloads which aren’t aware of PAE or
78+
/// amd64.
79+
pub fn address(&self) -> u64 {
80+
self.address
81+
}
82+
83+
/// Contains the pitch in bytes.
84+
pub fn pitch(&self) -> u32 {
85+
self.pitch
86+
}
87+
88+
/// Contains framebuffer width in pixels.
89+
pub fn width(&self) -> u32 {
90+
self.width
91+
}
92+
93+
/// Contains framebuffer height in pixels.
94+
pub fn height(&self) -> u32 {
95+
self.height
96+
}
97+
98+
/// Contains number of bits per pixel.
99+
pub fn bpp(&self) -> u8 {
100+
self.bpp
101+
}
102+
103+
/// The type of framebuffer, one of: `Indexed`, `RGB` or `Text`.
104+
pub fn buffer_type(&self) -> Result<FramebufferType, UnknownFramebufferType> {
105+
let mut reader = Reader::new(self.buffer.as_ptr());
106+
match self.type_no {
107+
0 => {
108+
let num_colors = reader.read_u32();
109+
let palette = unsafe {
110+
slice::from_raw_parts(
111+
reader.current_address() as *const FramebufferColor,
112+
num_colors as usize,
113+
)
114+
} as &'static [FramebufferColor];
115+
Ok(FramebufferType::Indexed { palette })
116+
}
117+
1 => {
118+
let red_pos = reader.read_u8(); // These refer to the bit positions of the LSB of each field
119+
let red_mask = reader.read_u8(); // And then the length of the field from LSB to MSB
120+
let green_pos = reader.read_u8();
121+
let green_mask = reader.read_u8();
122+
let blue_pos = reader.read_u8();
123+
let blue_mask = reader.read_u8();
124+
Ok(FramebufferType::RGB {
125+
red: FramebufferField {
126+
position: red_pos,
127+
size: red_mask,
128+
},
129+
green: FramebufferField {
130+
position: green_pos,
131+
size: green_mask,
132+
},
133+
blue: FramebufferField {
134+
position: blue_pos,
135+
size: blue_mask,
136+
},
137+
})
138+
}
139+
2 => Ok(FramebufferType::Text),
140+
no => Err(UnknownFramebufferType(no)),
141+
}
142+
}
143+
}
144+
145+
impl TagTrait for FramebufferTag {
146+
fn dst_size(base_tag: &Tag) -> usize {
147+
assert!(base_tag.size as usize >= METADATA_SIZE);
148+
base_tag.size as usize - METADATA_SIZE
149+
}
30150
}
31151

32152
/// Helper struct for [`FramebufferType`].
@@ -67,6 +187,35 @@ pub enum FramebufferType<'a> {
67187
Text,
68188
}
69189

190+
impl<'a> FramebufferType<'a> {
191+
#[cfg(feature = "builder")]
192+
fn to_bytes(&self) -> Vec<u8> {
193+
let mut v = Vec::new();
194+
match self {
195+
FramebufferType::Indexed { palette } => {
196+
v.extend(0u8.to_le_bytes()); // type
197+
v.extend(0u16.to_le_bytes()); // reserved
198+
v.extend((palette.len() as u32).to_le_bytes());
199+
for color in palette.iter() {
200+
v.extend(color.struct_as_bytes());
201+
}
202+
}
203+
FramebufferType::RGB { red, green, blue } => {
204+
v.extend(1u8.to_le_bytes()); // type
205+
v.extend(0u16.to_le_bytes()); // reserved
206+
v.extend(red.struct_as_bytes());
207+
v.extend(green.struct_as_bytes());
208+
v.extend(blue.struct_as_bytes());
209+
}
210+
FramebufferType::Text => {
211+
v.extend(2u8.to_le_bytes()); // type
212+
v.extend(0u16.to_le_bytes()); // reserved
213+
}
214+
}
215+
v
216+
}
217+
}
218+
70219
/// An RGB color type field.
71220
#[derive(Debug, PartialEq, Eq)]
72221
pub struct FramebufferField {
@@ -77,6 +226,8 @@ pub struct FramebufferField {
77226
pub size: u8,
78227
}
79228

229+
impl StructAsBytes for FramebufferField {}
230+
80231
/// A framebuffer color descriptor in the palette.
81232
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
82233
#[repr(C, packed)] // only repr(C) would add unwanted padding at the end
@@ -99,67 +250,4 @@ pub struct UnknownFramebufferType(u8);
99250
#[cfg(feature = "unstable")]
100251
impl core::error::Error for UnknownFramebufferType {}
101252

102-
/// Transforms a [`Tag`] into a [`FramebufferTag`].
103-
pub fn framebuffer_tag(tag: &Tag) -> Result<FramebufferTag, UnknownFramebufferType> {
104-
let mut reader = Reader::new(tag as *const Tag);
105-
reader.skip(8);
106-
let address = reader.read_u64();
107-
let pitch = reader.read_u32();
108-
let width = reader.read_u32();
109-
let height = reader.read_u32();
110-
let bpp = reader.read_u8();
111-
let type_no = reader.read_u8();
112-
// In the multiboot spec, it has this listed as a u8 _NOT_ a u16.
113-
// Reading the GRUB2 source code reveals it is in fact a u16.
114-
reader.skip(2);
115-
let buffer_type_id = match type_no {
116-
0 => Ok(FramebufferTypeId::Indexed),
117-
1 => Ok(FramebufferTypeId::RGB),
118-
2 => Ok(FramebufferTypeId::Text),
119-
id => Err(UnknownFramebufferType(id)),
120-
}?;
121-
let buffer_type = match buffer_type_id {
122-
FramebufferTypeId::Indexed => {
123-
let num_colors = reader.read_u32();
124-
let palette = unsafe {
125-
slice::from_raw_parts(
126-
reader.current_address() as *const FramebufferColor,
127-
num_colors as usize,
128-
)
129-
} as &[FramebufferColor];
130-
FramebufferType::Indexed { palette }
131-
}
132-
FramebufferTypeId::RGB => {
133-
let red_pos = reader.read_u8(); // These refer to the bit positions of the LSB of each field
134-
let red_mask = reader.read_u8(); // And then the length of the field from LSB to MSB
135-
let green_pos = reader.read_u8();
136-
let green_mask = reader.read_u8();
137-
let blue_pos = reader.read_u8();
138-
let blue_mask = reader.read_u8();
139-
FramebufferType::RGB {
140-
red: FramebufferField {
141-
position: red_pos,
142-
size: red_mask,
143-
},
144-
green: FramebufferField {
145-
position: green_pos,
146-
size: green_mask,
147-
},
148-
blue: FramebufferField {
149-
position: blue_pos,
150-
size: blue_mask,
151-
},
152-
}
153-
}
154-
FramebufferTypeId::Text => FramebufferType::Text,
155-
};
156-
157-
Ok(FramebufferTag {
158-
address,
159-
pitch,
160-
width,
161-
height,
162-
bpp,
163-
buffer_type,
164-
})
165-
}
253+
impl StructAsBytes for FramebufferColor {}

0 commit comments

Comments
 (0)