Skip to content

Commit 92b069a

Browse files
committed
Start providing API docs for all public items
1 parent 86d1db7 commit 92b069a

File tree

6 files changed

+113
-7
lines changed

6 files changed

+113
-7
lines changed

src/binary/legacy_memory_region.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,13 @@ use x86_64::{
55
PhysAddr,
66
};
77

8+
/// Abstraction trait for a memory region returned by the UEFI or BIOS firmware.
89
pub trait LegacyMemoryRegion: Copy + core::fmt::Debug {
10+
/// Returns the physical start address of the region.
911
fn start(&self) -> PhysAddr;
12+
/// Returns the size of the region in bytes.
1013
fn len(&self) -> u64;
14+
/// Returns the type of the region, e.g. whether it is usable or reserved.
1115
fn kind(&self) -> MemoryRegionKind;
1216

1317
fn set_start(&mut self, new_start: PhysAddr);
@@ -25,12 +29,19 @@ where
2529
I: ExactSizeIterator<Item = D> + Clone,
2630
I::Item: LegacyMemoryRegion,
2731
{
32+
/// Creates a new frame allocator based on the given legacy memory regions.
33+
///
34+
/// Skips the frame at physical address zero to avoid potential problems. For example
35+
/// identity-mapping the frame at address zero is not valid in Rust, because Rust's `core`
36+
/// library assumes that references can never point to virtual address `0`.
2837
pub fn new(memory_map: I) -> Self {
2938
// skip frame 0 because the rust core library does not see 0 as a valid address
3039
let start_frame = PhysFrame::containing_address(PhysAddr::new(0x1000));
3140
Self::new_starting_at(start_frame, memory_map)
3241
}
3342

43+
/// Creates a new frame allocator based on the given legacy memory regions. Skips any frames
44+
/// before the given `frame`.
3445
pub fn new_starting_at(frame: PhysFrame, memory_map: I) -> Self {
3546
Self {
3647
original: memory_map.clone(),
@@ -72,6 +83,14 @@ where
7283
.unwrap()
7384
}
7485

86+
/// Converts this type to a boot info memory map.
87+
///
88+
/// The memory map is placed in the given `regions` slice. The length of the given slice
89+
/// must be at least the value returned by [`len`]. Be aware that the value returned by
90+
/// `len` might increase by 1 whenever [`allocate_frame`] is called, so the length should be
91+
/// queried as late as possible.
92+
///
93+
/// The return slice is a subslice of `regions`, shortened to the actual number of regions.
7594
pub fn construct_memory_map(
7695
self,
7796
regions: &mut [MaybeUninit<MemoryRegion>],

src/binary/level_4_entries.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,17 @@ use x86_64::{
55
};
66
use xmas_elf::program::ProgramHeader;
77

8+
/// Keeps track of used entries in a level 4 page table.
9+
///
10+
/// Useful for determining a free virtual memory block, e.g. for mapping additional data.
811
pub struct UsedLevel4Entries {
912
entry_state: [bool; 512], // whether an entry is in use by the kernel
1013
}
1114

1215
impl UsedLevel4Entries {
16+
/// Initializes a new instance from the given ELF program segments.
17+
///
18+
/// Marks the virtual address range of all segments as used.
1319
pub fn new<'a>(segments: impl Iterator<Item = ProgramHeader<'a>>) -> Self {
1420
let mut used = UsedLevel4Entries {
1521
entry_state: [false; 512],
@@ -31,6 +37,10 @@ impl UsedLevel4Entries {
3137
used
3238
}
3339

40+
/// Returns a unused level 4 entry and marks it as used.
41+
///
42+
/// Since this method marks each returned index as used, it can be used multiple times
43+
/// to determine multiple unused virtual memory regions.
3444
pub fn get_free_entry(&mut self) -> PageTableIndex {
3545
let (idx, entry) = self
3646
.entry_state
@@ -43,6 +53,10 @@ impl UsedLevel4Entries {
4353
PageTableIndex::new(idx.try_into().unwrap())
4454
}
4555

56+
/// Returns the virtual start address of an unused level 4 entry and marks it as used.
57+
///
58+
/// This is a convenience method around [`get_free_entry`], so all of its docs applies here
59+
/// too.
4660
pub fn get_free_address(&mut self) -> VirtAddr {
4761
Page::from_page_table_indices_1gib(self.get_free_entry(), PageTableIndex::new(0))
4862
.start_address()

src/binary/load_kernel.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,10 @@ where
269269
}
270270
}
271271

272+
/// Loads the kernel ELF file given in `bytes` in the given `page_table`.
273+
///
274+
/// Returns the kernel entry point address, it's thread local storage template (if any),
275+
/// and a structure describing which level 4 page table entries are in use.
272276
pub fn load_kernel(
273277
bytes: &[u8],
274278
page_table: &mut impl MapperAllSizes,

src/binary/logger.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ use core::{
77
use font8x8::UnicodeFonts;
88
use spinning_top::Spinlock;
99

10+
/// The global logger instance used for the `log` crate.
1011
pub static LOGGER: OnceCell<LockedLogger> = OnceCell::uninit();
1112

13+
/// A [`Logger`] instance protected by a spinlock.
1214
pub struct LockedLogger(Spinlock<Logger>);
1315

1416
/// Additional vertical space between lines
@@ -17,10 +19,14 @@ const LINE_SPACING: usize = 0;
1719
const LOG_SPACING: usize = 2;
1820

1921
impl LockedLogger {
22+
/// Create a new instance that logs to the given framebuffer.
2023
pub fn new(framebuffer: &'static mut [u8], info: FrameBufferInfo) -> Self {
2124
LockedLogger(Spinlock::new(Logger::new(framebuffer, info)))
2225
}
2326

27+
/// Force-unlocks the logger to prevent a deadlock.
28+
///
29+
/// This method is not memory safe and should be only used when absolutely necessary.
2430
pub unsafe fn force_unlock(&self) {
2531
unsafe { self.0.force_unlock() };
2632
}
@@ -40,6 +46,7 @@ impl log::Log for LockedLogger {
4046
fn flush(&self) {}
4147
}
4248

49+
/// Allows logging text to a pixel-based framebuffer.
4350
pub struct Logger {
4451
framebuffer: &'static mut [u8],
4552
info: FrameBufferInfo,
@@ -48,6 +55,7 @@ pub struct Logger {
4855
}
4956

5057
impl Logger {
58+
/// Creates a new logger that uses the given framebuffer.
5159
pub fn new(framebuffer: &'static mut [u8], info: FrameBufferInfo) -> Self {
5260
let mut logger = Self {
5361
framebuffer,
@@ -72,7 +80,7 @@ impl Logger {
7280
self.x_pos = 0;
7381
}
7482

75-
/// Erases all text on the screen
83+
/// Erases all text on the screen.
7684
pub fn clear(&mut self) {
7785
self.x_pos = 0;
7886
self.y_pos = 0;

src/binary/mod.rs

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,11 @@ pub mod bios;
2323
pub mod uefi;
2424

2525
pub mod legacy_memory_region;
26+
/// Provides a type to keep track of used entries in a level 4 page table.
2627
pub mod level_4_entries;
28+
/// Implements a loader for the kernel ELF binary.
2729
pub mod load_kernel;
30+
/// Provides a logger type that logs output as text to pixel-based framebuffers.
2831
pub mod logger;
2932

3033
// Contains the parsed configuration table from the kernel's Cargo.toml.
@@ -42,19 +45,29 @@ include!(concat!(env!("OUT_DIR"), "/bootloader_config.rs"));
4245

4346
const PAGE_SIZE: u64 = 4096;
4447

48+
/// Initialize a text-based logger using the given pixel-based framebuffer as output.
4549
pub fn init_logger(framebuffer: &'static mut [u8], info: FrameBufferInfo) {
4650
let logger = logger::LOGGER.get_or_init(move || logger::LockedLogger::new(framebuffer, info));
4751
log::set_logger(logger).expect("logger already set");
4852
log::set_max_level(log::LevelFilter::Trace);
4953
}
5054

55+
/// Required system information that should be queried from the BIOS or UEFI firmware.
5156
#[derive(Debug, Copy, Clone)]
5257
pub struct SystemInfo {
58+
/// Start address of the pixel-based framebuffer.
5359
pub framebuffer_addr: PhysAddr,
60+
/// Information about the framebuffer, including layout and pixel format.
5461
pub framebuffer_info: FrameBufferInfo,
62+
/// Address of the _Root System Description Pointer_ structure of the ACPI standard.
5563
pub rsdp_addr: Option<PhysAddr>,
5664
}
5765

66+
/// Loads the kernel ELF executable into memory and switches to it.
67+
///
68+
/// This function is a convenience function that first calls [`set_up_mappings`], then
69+
/// [`create_boot_info`], and finally [`switch_to_kernel`]. The given arguments are passed
70+
/// directly to these functions, so see their docs for more info.
5871
pub fn load_and_switch_to_kernel<I, D>(
5972
kernel_bytes: &[u8],
6073
mut frame_allocator: LegacyFrameAllocator<I, D>,
@@ -81,7 +94,20 @@ where
8194
switch_to_kernel(page_tables, mappings, boot_info, two_frames);
8295
}
8396

84-
/// Sets up mappings for a kernel stack and the framebuffer
97+
/// Sets up mappings for a kernel stack and the framebuffer.
98+
///
99+
/// The `kernel_bytes` slice should contain the raw bytes of the kernel ELF executable. The
100+
/// `frame_allocator` argument should be created from the memory map. The `page_tables`
101+
/// argument should point to the bootloader and kernel page tables. The function tries to parse
102+
/// the ELF file and create all specified mappings in the kernel-level page table.
103+
///
104+
/// The `framebuffer_addr` and `framebuffer_size` fields should be set to the start address and
105+
/// byte length the pixel-based framebuffer. These arguments are required because the functions
106+
/// maps this framebuffer in the kernel-level page table, unless the `map_framebuffer` config
107+
/// option is disabled.
108+
///
109+
/// This function reacts to unexpected situations (e.g. invalid kernel ELF file) with a panic, so
110+
/// errors are not recoverable.
85111
pub fn set_up_mappings<I, D>(
86112
kernel_bytes: &[u8],
87113
frame_allocator: &mut LegacyFrameAllocator<I, D>,
@@ -201,17 +227,31 @@ where
201227
}
202228
}
203229

230+
/// Contains the addresses of all memory mappings set up by [`set_up_mappings`].
204231
pub struct Mappings {
232+
/// The entry point address of the kernel.
205233
pub entry_point: VirtAddr,
234+
/// The stack end page of the kernel.
206235
pub stack_end: Page,
236+
/// Keeps track of used entries in the level 4 page table, useful for finding a free
237+
/// virtual memory when needed.
207238
pub used_entries: UsedLevel4Entries,
239+
/// The start address of the framebuffer, if any.
208240
pub framebuffer: Option<VirtAddr>,
241+
/// The start address of the physical memory mapping, if enabled.
209242
pub physical_memory_offset: Option<VirtAddr>,
243+
/// The level 4 page table index of the recursive mapping, if enabled.
210244
pub recursive_index: Option<PageTableIndex>,
245+
/// The thread local storage template of the kernel executable, if it contains one.
211246
pub tls_template: Option<TlsTemplate>,
212247
}
213248

214-
/// Allocates and initializes the boot info struct and the memory map
249+
/// Allocates and initializes the boot info struct and the memory map.
250+
///
251+
/// The boot info and memory map are mapped to both the kernel and bootloader
252+
/// address space at the same address. This makes it possible to return a Rust
253+
/// reference that is valid in both address spaces. The necessary physical frames
254+
/// are taken from the given `frame_allocator`.
215255
pub fn create_boot_info<I, D>(
216256
mut frame_allocator: LegacyFrameAllocator<I, D>,
217257
page_tables: &mut PageTables,
@@ -325,15 +365,26 @@ pub fn switch_to_kernel(
325365
}
326366
}
327367

368+
/// Provides access to the page tables of the bootloader and kernel address space.
328369
pub struct PageTables {
370+
/// Provides access to the page tables of the bootloader address space.
329371
pub bootloader: OffsetPageTable<'static>,
372+
/// Provides access to the page tables of the kernel address space (not active).
330373
pub kernel: OffsetPageTable<'static>,
374+
/// The physical frame where the level 4 page table of the kernel address space is stored.
375+
///
376+
/// Must be the page table that the `kernel` field of this struct refers to.
377+
///
378+
/// This frame is loaded into the `CR3` register on the final context switch to the kernel.
331379
pub kernel_level_4_frame: PhysFrame,
332380
}
333381

334-
/// Performs the actual context switch
382+
/// Performs the actual context switch.
335383
///
336-
/// This function should stay small because it needs to be identity-mapped.
384+
/// This function uses the given `frame_allocator` to identity map itself in the kernel-level
385+
/// page table. This is required to avoid a page fault after the context switch. Since this
386+
/// function is relatively small, only up to two physical frames are required from the frame
387+
/// allocator, so the [`TwoFrames`] type can be used here.
337388
unsafe fn context_switch(
338389
addresses: Addresses,
339390
mut kernel_page_table: OffsetPageTable,
@@ -367,18 +418,28 @@ unsafe fn context_switch(
367418
unreachable!();
368419
}
369420

370-
pub struct Addresses {
421+
/// Memory addresses required for the context switch.
422+
struct Addresses {
371423
page_table: PhysFrame,
372424
stack_top: VirtAddr,
373425
entry_point: VirtAddr,
374426
boot_info: &'static mut crate::boot_info::BootInfo,
375427
}
376428

429+
/// Used for reversing two physical frames for identity mapping the context switch function.
430+
///
431+
/// In order to prevent a page fault, the context switch function must be mapped identically in
432+
/// both address spaces. The context switch function is small, so this mapping requires only
433+
/// two physical frames (one frame is not enough because the linker might place the function
434+
/// directly before a page boundary). Since the frame allocator no longer exists when the
435+
/// context switch function is invoked, we use this type to reserve two physical frames
436+
/// beforehand.
377437
pub struct TwoFrames {
378438
frames: [Option<PhysFrame>; 2],
379439
}
380440

381441
impl TwoFrames {
442+
/// Creates a new instance by allocating two physical frames from the given frame allocator.
382443
pub fn new(frame_allocator: &mut impl FrameAllocator<Size4KiB>) -> Self {
383444
TwoFrames {
384445
frames: [

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
#![feature(maybe_uninit_extra)]
1212
#![feature(maybe_uninit_slice)]
1313
#![deny(unsafe_op_in_unsafe_fn)]
14-
//#![warn(missing_docs)]
14+
#![warn(missing_docs)]
1515

1616
pub use crate::boot_info::BootInfo;
1717

0 commit comments

Comments
 (0)