limine_protocol_for_rust/
lib.rs

1/*!
2This crate implements a couple of utilities for making something compatible with the Limine Boot Protocol.
3It serves as an equivalent to the *'limine.h'* file, along with some extra utilities for making response retrieval and reading provided data easier.
4
5For more information read [The Limine Boot Protocol](https://codeberg.org/Limine/limine-protocol/src/branch/trunk/PROTOCOL.md).
6
7Example Usage:
8```
9const REVISION: u64 = 4;
10
11#[used]
12#[unsafe(link_section = ".limine_reqs")]
13static LIMINE_BASE_REVISION: [u64; 4] = use_base_revision(4);
14
15#[used]
16#[unsafe(link_section = ".limine_req_start")]
17static LIMINE_REQUEST_START_MARKER: [u64; 4] = REQUEST_START_MARKER;
18
19#[used]
20#[unsafe(link_section = ".limine_reqs")]
21pub static MEMORY_MAP_REQUEST: MemoryMapRequest = MemoryMapRequest::new(REVISION);
22
23#[used]
24#[unsafe(link_section = ".limine_reqs")]
25pub static FRAMEBUFFER_REQUEST: FramebufferRequest = FramebufferRequest::new(REVISION);
26
27#[used]
28#[unsafe(link_section = ".limine_reqs")]
29pub static BOOTLOADER_INFO_REQUEST: BootloaderInfoRequest = BootloaderInfoRequest::new(REVISION);
30
31#[used]
32#[unsafe(link_section = ".limine_req_end")]
33static LIMINE_REQUEST_END_MARKER: [u64; 2] = REQUEST_END_MARKER;
34
35pub fn kernel_main() -> ! {
36    let bootloader_info_resp = BOOTLOADER_INFO_REQUEST.get_response().expect("BootloaderInfo request had no response");
37    kprint!("Bootloader: {} {}",bootloader_info_resp.get_name(), bootloader_info_resp.get_version())
38
39    let memory_map_resp = MEMORY_MAP_REQUEST.get_response().expect("Memory map request had no response");
40    let memory_map = memory_map_resp.get_entries();
41}
42```
43
44*/
45
46
47
48#![no_std]
49
50mod util;
51
52use crate::util::null_terminated_string;
53use core::mem::MaybeUninit;
54use core::slice::from_raw_parts;
55
56pub const REQUEST_START_MARKER: [u64; 4] = [ 0xf6b8f4b39de7d1ae, 0xfab91a6940fcb9cf, 0x785c6ed015d3e316, 0x181e920a7852b9d9 ];
57pub const REQUEST_END_MARKER: [u64; 2] = [ 0xadc0e0531bb10d03, 0x9572709f31764c62 ];
58
59
60///Wrapper for the Limine Base Revision magic number
61pub const fn use_base_revision(revision: u64) -> [u64; 4]{
62    [ 0xf9562b2d5c95a6c8, 0x6a7b384944536bdc, revision, 0 ]
63}
64
65#[repr(C, align(8))]
66struct LimineReqId {
67    common_magic: [u64; 2],
68    other: [u64; 2]
69}
70
71impl LimineReqId {
72    const fn new(other: [u64; 2]) -> Self {
73        Self {
74            common_magic: [0xc7b1dd30df4c8b88, 0x0a82e883a194f07b],
75            other
76        }
77    }
78}
79
80macro_rules! gen_get_response {
81    ($get:ty) => {
82        pub fn get_response(&self) -> Option<&$get> {
83            unsafe {
84                if self.resp.assume_init() == 0 {
85                   return None
86                }
87                (self.resp.assume_init() as *const $get).as_ref()
88            }
89        }
90    };
91}
92
93
94#[repr(C, align(8))]
95pub struct MemoryMapRequest {
96    id: LimineReqId,
97    revision: u64,
98    resp: MaybeUninit<usize>
99}
100
101impl MemoryMapRequest {
102    pub const fn new(revision: u64) -> Self {
103        Self {
104            id: LimineReqId::new([0x67cf3d9d378a806f, 0xe304acdfc50c3c62]),
105            revision,
106            resp: MaybeUninit::uninit()
107        }
108    }
109
110    gen_get_response!(MemoryMapResponse);
111}
112
113
114#[repr(C, align(8))]
115pub struct MemoryMapResponse {
116    revision: u64,
117    entry_count: u64,
118    entries: *const *const MemoryMapEntry
119}
120
121impl MemoryMapResponse {
122    fn get_entries(&self) -> &[*const MemoryMapEntry] {
123        unsafe {
124            from_raw_parts(self.entries, self.entry_count as usize)
125        }
126    }
127
128    pub fn get_entry(&self, entry: usize) -> Option<&MemoryMapEntry> {
129        if (0..self.entry_count).contains(&(entry as u64)) {
130            unsafe {
131                self.get_entries()[entry].as_ref()
132            }
133        } else {
134            None
135        }
136    }
137}
138
139#[repr(C, align(8))]
140pub struct MemoryMapEntry {
141    base: u64,
142    length: u64,
143    memmap_type: u64
144}
145
146impl MemoryMapEntry {
147    pub fn type_as_enum(&self) -> MemoryMapType {
148        match self.memmap_type {
149            0 => MemoryMapType::Usable,
150            1 => MemoryMapType::Reserved,
151            2 => MemoryMapType::AcpiReclaimable,
152            3 => MemoryMapType::AcpiNvs,
153            4 => MemoryMapType::BadMemory,
154            5 => MemoryMapType::BootloaderReclaimable,
155            6 => MemoryMapType::ExecutableAndModules,
156            7 => MemoryMapType::Framebuffer,
157            8 => MemoryMapType::AcpiTables,
158            _ => panic!("Obtained invalid MemoryMap Type")
159        }
160    }
161}
162
163pub enum MemoryMapType {
164    Usable,
165    Reserved,
166    AcpiReclaimable,
167    AcpiNvs,
168    BadMemory,
169    BootloaderReclaimable,
170    ExecutableAndModules,
171    Framebuffer,
172    AcpiTables
173}
174
175#[repr(C, align(8))]
176pub struct FramebufferRequest {
177    id: LimineReqId,
178    revision: u64,
179    resp: MaybeUninit<usize>
180}
181
182impl FramebufferRequest {
183    pub const fn new(revision: u64) -> Self {
184        Self {
185            id: LimineReqId::new([0x9d5827dcd881dd75, 0xa3148604f6fab11b]),
186            revision,
187            resp: MaybeUninit::uninit()
188        }
189    }
190
191    gen_get_response!(FramebufferResponse);
192}
193
194
195#[repr(C, align(8))]
196pub struct FramebufferResponse {
197    revision: u64,
198    entry_count: u64,
199    entries: *const *const Framebuffer
200}
201
202impl FramebufferResponse {
203    fn get_framebuffers(&self) -> &[*const Framebuffer] {
204        unsafe {
205            from_raw_parts(self.entries, self.entry_count as usize)
206        }
207    }
208
209    pub fn get_framebuffer(&self, index: usize) -> Option<&Framebuffer> {
210        if (0..self.entry_count).contains(&(index as u64)) {
211            unsafe {
212                self.get_framebuffers()[index].as_ref()
213            }
214        } else {
215            None
216        }
217    }
218}
219
220#[repr(C, align(8))]
221#[derive(Debug)]
222pub struct Framebuffer {
223    pub address: usize,
224    pub width: u64,
225    pub height: u64,
226    pub pitch: u64,
227    pub bpp: u16,
228    pub memory_model: u8,
229    pub red_mask_size: u8,
230    pub red_mask_shift: u8,
231    pub green_mask_size: u8,
232    pub green_mask_shift: u8,
233    pub blue_mask_size: u8,
234    pub blue_mask_shift: u8,
235    _unused: [u8; 7],
236    pub edid_size: u64,
237    pub edid_address: usize,
238
239    //Response revision 1
240    pub mode_count: u64,
241    modes: *const *const VideoMode
242}
243
244impl Framebuffer {
245    fn get_modes(&self) -> &[*const VideoMode] {
246        unsafe {
247            from_raw_parts(self.modes, self.mode_count as usize)
248        }
249    }
250
251    pub fn get_mode(&self, mode: usize) -> Option<&VideoMode> {
252        if (0..self.mode_count).contains(&(mode as u64)) {
253            unsafe {
254                self.get_modes()[mode].as_ref()
255            }
256        } else {
257            None
258        }
259    }
260}
261
262#[repr(C, align(8))]
263pub struct VideoMode {
264    pitch: u64,
265    width: u64,
266    height: u64,
267    bpp: u16,
268    memory_model: u8,
269    red_mask_size: u8,
270    red_mask_shift: u8,
271    green_mask_size: u8,
272    green_mask_shift: u8,
273    blue_mask_size: u8,
274    blue_mask_shift: u8,
275}
276
277#[repr(C, align(8))]
278pub struct BootloaderInfoRequest{
279    id: LimineReqId,
280    revision: u64,
281    resp: MaybeUninit<usize>
282}
283
284impl BootloaderInfoRequest {
285    pub const fn new(revision: u64) -> Self {
286        Self {
287            id: LimineReqId::new([0xf55038d8e2a1202f, 0x279426fcf5f59740]),
288            revision,
289            resp: MaybeUninit::uninit()
290        }
291    }
292
293    gen_get_response!(BootloaderInfoResponse);
294}
295
296#[repr(C, align(8))]
297pub struct BootloaderInfoResponse {
298    revision: u64,
299    name: *const u8,
300    version: *const u8
301}
302
303impl BootloaderInfoResponse {
304    pub fn get_name(&self) -> &str {
305        null_terminated_string(self.name).unwrap()
306    }
307
308    pub fn get_version(&self) -> &str {
309        null_terminated_string(self.version).unwrap()
310    }
311}
312