Skip to content

Commit 86d1db7

Browse files
committed
Make boot info FFI-safe
1 parent 0c33cec commit 86d1db7

File tree

3 files changed

+92
-19
lines changed

3 files changed

+92
-19
lines changed

src/binary/mod.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -281,17 +281,16 @@ where
281281
version_minor: env!("CARGO_PKG_VERSION_MINOR").parse().unwrap(),
282282
version_patch: env!("CARGO_PKG_VERSION_PATCH").parse().unwrap(),
283283
pre_release: !env!("CARGO_PKG_VERSION_PRE").is_empty(),
284-
memory_regions,
284+
memory_regions: memory_regions.into(),
285285
framebuffer: mappings.framebuffer.map(|addr| FrameBuffer {
286286
buffer_start: addr.as_u64(),
287287
buffer_byte_len: system_info.framebuffer_info.byte_len,
288288
info: system_info.framebuffer_info,
289-
}),
290-
physical_memory_offset: mappings.physical_memory_offset.map(VirtAddr::as_u64),
291-
recursive_index: mappings.recursive_index.map(Into::into),
292-
rsdp_addr: system_info.rsdp_addr.map(|addr| addr.as_u64()),
293-
tls_template: mappings.tls_template,
294-
_non_exhaustive: (),
289+
}).into(),
290+
physical_memory_offset: mappings.physical_memory_offset.map(VirtAddr::as_u64).into(),
291+
recursive_index: mappings.recursive_index.map(Into::into).into(),
292+
rsdp_addr: system_info.rsdp_addr.map(|addr| addr.as_u64()).into(),
293+
tls_template: mappings.tls_template.into(),
295294
});
296295

297296
(boot_info, two_frames)

src/boot_info.rs

Lines changed: 84 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::memory_region::MemoryRegion;
2-
use core::slice;
2+
use core::{ops, slice};
33

44
/// This structure represents the information that the bootloader passes to the kernel.
55
///
@@ -14,6 +14,8 @@ use core::slice;
1414
/// use the correct argument types. To ensure that the entry point function has the correct
1515
/// signature, use the [`entry_point`] macro.
1616
#[derive(Debug)]
17+
#[repr(C)]
18+
#[non_exhaustive]
1719
pub struct BootInfo {
1820
/// Bootloader version (major).
1921
pub version_major: u16,
@@ -32,9 +34,9 @@ pub struct BootInfo {
3234
/// information to Rust types. It also marks any memory regions that the bootloader uses in
3335
/// the memory map before passing it to the kernel. Regions marked as usable can be freely
3436
/// used by the kernel.
35-
pub memory_regions: &'static mut [MemoryRegion],
37+
pub memory_regions: MemoryRegions,
3638
/// Information about the framebuffer for screen output if available.
37-
pub framebuffer: Option<FrameBuffer>,
39+
pub framebuffer: Optional<FrameBuffer>,
3840
/// The virtual address at which the mapping of the physical memory starts.
3941
///
4042
/// Physical addresses can be converted to virtual addresses by adding this offset to them.
@@ -45,21 +47,63 @@ pub struct BootInfo {
4547
/// can be safely accessed.
4648
///
4749
/// Only available if the `map-physical-memory` config option is enabled.
48-
pub physical_memory_offset: Option<u64>,
50+
pub physical_memory_offset: Optional<u64>,
4951
/// The virtual address of the recursively mapped level 4 page table.
5052
///
5153
/// Only available if the `map-page-table-recursively` config option is enabled.
52-
pub recursive_index: Option<u16>,
54+
pub recursive_index: Optional<u16>,
5355
/// The address of the `RSDP` data structure, which can be use to find the ACPI tables.
5456
///
5557
/// This field is `None` if no `RSDP` was found (for BIOS) or reported (for UEFI).
56-
pub rsdp_addr: Option<u64>,
58+
pub rsdp_addr: Optional<u64>,
5759
/// The thread local storage (TLS) template of the kernel executable, if present.
58-
pub tls_template: Option<TlsTemplate>,
59-
pub(crate) _non_exhaustive: (),
60+
pub tls_template: Optional<TlsTemplate>,
61+
}
62+
63+
/// FFI-safe slice of [`MemoryRegion`] structs, semantically equivalent to
64+
/// `&'static mut [MemoryRegion]`.
65+
///
66+
/// This type implements the [`Deref`][core::ops::Deref] and [`DerefMut`][core::ops::DerefMut]
67+
/// traits, so it can be used like a `&mut [MemoryRegion]` slice. It also implements [`From`]
68+
/// and [`Into`] for easy conversions from and to `&'static mut [MemoryRegion]`.
69+
#[derive(Debug)]
70+
#[repr(C)]
71+
pub struct MemoryRegions {
72+
pub(crate) ptr: *mut MemoryRegion,
73+
pub(crate) len: usize,
74+
}
75+
76+
impl ops::Deref for MemoryRegions {
77+
type Target = [MemoryRegion];
78+
79+
fn deref(&self) -> &Self::Target {
80+
unsafe { slice::from_raw_parts(self.ptr, self.len) }
81+
}
82+
}
83+
84+
impl ops::DerefMut for MemoryRegions {
85+
fn deref_mut(&mut self) -> &mut Self::Target {
86+
unsafe { slice::from_raw_parts_mut(self.ptr, self.len )}
87+
}
88+
}
89+
90+
impl From<&'static mut [MemoryRegion]> for MemoryRegions {
91+
fn from(regions: &'static mut [MemoryRegion]) -> Self {
92+
MemoryRegions {
93+
ptr: regions.as_mut_ptr(),
94+
len: regions.len(),
95+
}
96+
}
97+
}
98+
99+
impl Into<&'static mut [MemoryRegion]> for MemoryRegions {
100+
fn into(self) -> &'static mut [MemoryRegion] {
101+
unsafe { slice::from_raw_parts_mut(self.ptr, self.len )}
102+
}
60103
}
61104

62105
#[derive(Debug)]
106+
#[repr(C)]
63107
pub struct FrameBuffer {
64108
pub(crate) buffer_start: u64,
65109
pub(crate) buffer_byte_len: usize,
@@ -81,6 +125,7 @@ impl FrameBuffer {
81125
}
82126

83127
#[derive(Debug, Clone, Copy)]
128+
#[repr(C)]
84129
pub struct FrameBufferInfo {
85130
pub byte_len: usize,
86131
pub horizontal_resolution: usize,
@@ -92,6 +137,7 @@ pub struct FrameBufferInfo {
92137

93138
#[derive(Debug, Clone, Copy)]
94139
#[non_exhaustive]
140+
#[repr(C)]
95141
pub enum PixelFormat {
96142
RGB,
97143
BGR,
@@ -106,6 +152,7 @@ pub enum PixelFormat {
106152
/// ___location. The additional `mem_size - file_size` bytes must be initialized with
107153
/// zero.
108154
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
155+
#[repr(C)]
109156
pub struct TlsTemplate {
110157
/// The virtual start address of the thread local storage template.
111158
pub start_addr: u64,
@@ -119,8 +166,33 @@ pub struct TlsTemplate {
119166
pub mem_size: u64,
120167
}
121168

122-
/// Check that the _pointer_ is FFI-safe.
169+
/// FFI-safe variant of [`Option`].
123170
///
124-
/// Note that the `BootInfo` struct is not FFI-safe, so it needs to be compiled by the same Rust
125-
/// compiler as the kernel in order to be safely accessed.
126-
extern "C" fn _assert_ffi(_boot_info: &'static mut BootInfo) {}
171+
/// Implements the [`From`] and [`Into`] traits for easy conversion to and from [`Option`].
172+
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
173+
#[repr(C)]
174+
pub enum Optional<T> {
175+
Some(T),
176+
None,
177+
}
178+
179+
impl<T> From<Option<T>> for Optional<T> {
180+
fn from(v: Option<T>) -> Self {
181+
match v {
182+
Some(v) => Optional::Some(v),
183+
None => Optional::None,
184+
}
185+
}
186+
}
187+
188+
impl<T> Into<Option<T>> for Optional<T> {
189+
fn into(self) -> Option<T> {
190+
match self {
191+
Optional::Some(v) => Some(v),
192+
Optional::None => None,
193+
}
194+
}
195+
}
196+
197+
/// Check that bootinfo is FFI-safe
198+
extern "C" fn _assert_ffi(_boot_info: BootInfo) {}

src/memory_region.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
2+
#[repr(C)]
23
pub struct MemoryRegion {
34
pub start: u64,
45
pub end: u64,
@@ -17,6 +18,7 @@ impl MemoryRegion {
1718

1819
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
1920
#[non_exhaustive]
21+
#[repr(C)]
2022
pub enum MemoryRegionKind {
2123
/// Unused conventional memory, can be used by the kernel.
2224
Usable,

0 commit comments

Comments
 (0)