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 MemoryMapEntry
119}
120
121impl MemoryMapResponse {
122    pub fn get_entries(&self) -> &[MemoryMapEntry] {
123        unsafe {
124            from_raw_parts(self.entries, self.entry_count as usize)
125        }
126    }
127}
128
129#[repr(C, align(8))]
130pub struct MemoryMapEntry {
131    base: u64,
132    length: u64,
133    memmap_type: u64
134}
135
136impl MemoryMapEntry {
137    pub fn type_as_enum(&self) -> MemoryMapType {
138        match self.memmap_type {
139            0 => MemoryMapType::Usable,
140            1 => MemoryMapType::Reserved,
141            2 => MemoryMapType::AcpiReclaimable,
142            3 => MemoryMapType::AcpiNvs,
143            4 => MemoryMapType::BadMemory,
144            5 => MemoryMapType::BootloaderReclaimable,
145            6 => MemoryMapType::ExecutableAndModules,
146            7 => MemoryMapType::Framebuffer,
147            8 => MemoryMapType::AcpiTables,
148            _ => panic!("Obtained invalid MemoryMap Type")
149        }
150    }
151}
152
153pub enum MemoryMapType {
154    Usable,
155    Reserved,
156    AcpiReclaimable,
157    AcpiNvs,
158    BadMemory,
159    BootloaderReclaimable,
160    ExecutableAndModules,
161    Framebuffer,
162    AcpiTables
163}
164
165#[repr(C, align(8))]
166pub struct FramebufferRequest {
167    id: LimineReqId,
168    revision: u64,
169    resp: MaybeUninit<usize>
170}
171
172impl FramebufferRequest {
173    pub const fn new(revision: u64) -> Self {
174        Self {
175            id: LimineReqId::new([0x9d5827dcd881dd75, 0xa3148604f6fab11b]),
176            revision,
177            resp: MaybeUninit::uninit()
178        }
179    }
180
181    gen_get_response!(FramebufferResponse);
182}
183
184
185#[repr(C, align(8))]
186#[derive(Debug)]
187pub struct FramebufferResponse {
188    revision: u64,
189    entry_count: u64,
190    entries: *const Framebuffer
191}
192
193impl FramebufferResponse {
194    pub fn get_entries(&self) -> &[Framebuffer] {
195        unsafe {
196            from_raw_parts(self.entries, self.entry_count as usize)
197        }
198    }
199}
200
201#[repr(C, align(8))]
202#[derive(Debug)]
203pub struct Framebuffer {
204    pub address: usize,
205    pub width: u64,
206    pub height: u64,
207    pub pitch: u64,
208    pub bpp: u16,
209    pub memory_model: u8,
210    pub red_mask_size: u8,
211    pub red_mask_shift: u8,
212    pub green_mask_size: u8,
213    pub green_mask_shift: u8,
214    pub blue_mask_size: u8,
215    pub blue_mask_shift: u8,
216    _unused: [u8; 7],
217    pub edid_size: u64,
218    pub edid_address: usize,
219
220    //Response revision 1
221    pub mode_count: u64,
222    modes: *const VideoMode
223}
224
225impl Framebuffer {
226    pub fn get_modes(&self) -> &[VideoMode] {
227        unsafe {
228            from_raw_parts(self.modes, self.mode_count as usize)
229        }
230    }
231}
232
233#[repr(C, align(8))]
234pub struct VideoMode {
235    pitch: u64,
236    width: u64,
237    height: u64,
238    bpp: u16,
239    memory_model: u8,
240    red_mask_size: u8,
241    red_mask_shift: u8,
242    green_mask_size: u8,
243    green_mask_shift: u8,
244    blue_mask_size: u8,
245    blue_mask_shift: u8,
246}
247
248#[repr(C, align(8))]
249pub struct BootloaderInfoRequest{
250    id: LimineReqId,
251    revision: u64,
252    resp: MaybeUninit<usize>
253}
254
255impl BootloaderInfoRequest {
256    pub const fn new(revision: u64) -> Self {
257        Self {
258            id: LimineReqId::new([0xf55038d8e2a1202f, 0x279426fcf5f59740]),
259            revision,
260            resp: MaybeUninit::uninit()
261        }
262    }
263
264    gen_get_response!(BootloaderInfoResponse);
265}
266
267#[repr(C, align(8))]
268pub struct BootloaderInfoResponse {
269    revision: u64,
270    name: *const u8,
271    version: *const u8
272}
273
274impl BootloaderInfoResponse {
275    pub fn get_name(&self) -> &str {
276        null_terminated_string(self.name).unwrap()
277    }
278
279    pub fn get_version(&self) -> &str {
280        null_terminated_string(self.version).unwrap()
281    }
282}
283