@@ -23,8 +23,11 @@ pub mod bios;
23
23
pub mod uefi;
24
24
25
25
pub mod legacy_memory_region;
26
+ /// Provides a type to keep track of used entries in a level 4 page table.
26
27
pub mod level_4_entries;
28
+ /// Implements a loader for the kernel ELF binary.
27
29
pub mod load_kernel;
30
+ /// Provides a logger type that logs output as text to pixel-based framebuffers.
28
31
pub mod logger;
29
32
30
33
// Contains the parsed configuration table from the kernel's Cargo.toml.
@@ -42,19 +45,29 @@ include!(concat!(env!("OUT_DIR"), "/bootloader_config.rs"));
42
45
43
46
const PAGE_SIZE : u64 = 4096 ;
44
47
48
+ /// Initialize a text-based logger using the given pixel-based framebuffer as output.
45
49
pub fn init_logger ( framebuffer : & ' static mut [ u8 ] , info : FrameBufferInfo ) {
46
50
let logger = logger:: LOGGER . get_or_init ( move || logger:: LockedLogger :: new ( framebuffer, info) ) ;
47
51
log:: set_logger ( logger) . expect ( "logger already set" ) ;
48
52
log:: set_max_level ( log:: LevelFilter :: Trace ) ;
49
53
}
50
54
55
+ /// Required system information that should be queried from the BIOS or UEFI firmware.
51
56
#[ derive( Debug , Copy , Clone ) ]
52
57
pub struct SystemInfo {
58
+ /// Start address of the pixel-based framebuffer.
53
59
pub framebuffer_addr : PhysAddr ,
60
+ /// Information about the framebuffer, including layout and pixel format.
54
61
pub framebuffer_info : FrameBufferInfo ,
62
+ /// Address of the _Root System Description Pointer_ structure of the ACPI standard.
55
63
pub rsdp_addr : Option < PhysAddr > ,
56
64
}
57
65
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.
58
71
pub fn load_and_switch_to_kernel < I , D > (
59
72
kernel_bytes : & [ u8 ] ,
60
73
mut frame_allocator : LegacyFrameAllocator < I , D > ,
81
94
switch_to_kernel ( page_tables, mappings, boot_info, two_frames) ;
82
95
}
83
96
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.
85
111
pub fn set_up_mappings < I , D > (
86
112
kernel_bytes : & [ u8 ] ,
87
113
frame_allocator : & mut LegacyFrameAllocator < I , D > ,
@@ -201,17 +227,31 @@ where
201
227
}
202
228
}
203
229
230
+ /// Contains the addresses of all memory mappings set up by [`set_up_mappings`].
204
231
pub struct Mappings {
232
+ /// The entry point address of the kernel.
205
233
pub entry_point : VirtAddr ,
234
+ /// The stack end page of the kernel.
206
235
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.
207
238
pub used_entries : UsedLevel4Entries ,
239
+ /// The start address of the framebuffer, if any.
208
240
pub framebuffer : Option < VirtAddr > ,
241
+ /// The start address of the physical memory mapping, if enabled.
209
242
pub physical_memory_offset : Option < VirtAddr > ,
243
+ /// The level 4 page table index of the recursive mapping, if enabled.
210
244
pub recursive_index : Option < PageTableIndex > ,
245
+ /// The thread local storage template of the kernel executable, if it contains one.
211
246
pub tls_template : Option < TlsTemplate > ,
212
247
}
213
248
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`.
215
255
pub fn create_boot_info < I , D > (
216
256
mut frame_allocator : LegacyFrameAllocator < I , D > ,
217
257
page_tables : & mut PageTables ,
@@ -325,15 +365,26 @@ pub fn switch_to_kernel(
325
365
}
326
366
}
327
367
368
+ /// Provides access to the page tables of the bootloader and kernel address space.
328
369
pub struct PageTables {
370
+ /// Provides access to the page tables of the bootloader address space.
329
371
pub bootloader : OffsetPageTable < ' static > ,
372
+ /// Provides access to the page tables of the kernel address space (not active).
330
373
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.
331
379
pub kernel_level_4_frame : PhysFrame ,
332
380
}
333
381
334
- /// Performs the actual context switch
382
+ /// Performs the actual context switch.
335
383
///
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.
337
388
unsafe fn context_switch (
338
389
addresses : Addresses ,
339
390
mut kernel_page_table : OffsetPageTable ,
@@ -367,18 +418,28 @@ unsafe fn context_switch(
367
418
unreachable ! ( ) ;
368
419
}
369
420
370
- pub struct Addresses {
421
+ /// Memory addresses required for the context switch.
422
+ struct Addresses {
371
423
page_table : PhysFrame ,
372
424
stack_top : VirtAddr ,
373
425
entry_point : VirtAddr ,
374
426
boot_info : & ' static mut crate :: boot_info:: BootInfo ,
375
427
}
376
428
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.
377
437
pub struct TwoFrames {
378
438
frames : [ Option < PhysFrame > ; 2 ] ,
379
439
}
380
440
381
441
impl TwoFrames {
442
+ /// Creates a new instance by allocating two physical frames from the given frame allocator.
382
443
pub fn new ( frame_allocator : & mut impl FrameAllocator < Size4KiB > ) -> Self {
383
444
TwoFrames {
384
445
frames : [
0 commit comments