4
4
#![ feature( maybe_uninit_extra) ]
5
5
#![ deny( unsafe_op_in_unsafe_fn) ]
6
6
7
- #[ repr( align( 4096 ) ) ]
8
- struct PageAligned < T > ( T ) ;
9
-
10
7
use bootloader:: binary:: { legacy_memory_region:: LegacyFrameAllocator , Kernel , SystemInfo } ;
11
8
use bootloader_api:: { info:: FrameBufferInfo , BootloaderConfig } ;
12
- use core:: { arch:: asm, mem, panic:: PanicInfo , ptr, slice} ;
9
+ use core:: { arch:: asm, cell :: UnsafeCell , fmt :: Write , mem, panic:: PanicInfo , ptr, slice} ;
13
10
use uefi:: {
14
11
prelude:: { entry, Boot , Handle , ResultExt , Status , SystemTable } ,
15
12
proto:: {
@@ -22,46 +19,125 @@ use uefi::{
22
19
} ,
23
20
} ,
24
21
table:: boot:: { AllocateType , MemoryDescriptor , MemoryType } ,
25
- CStr16 , Completion ,
22
+ Completion ,
26
23
} ;
27
24
use x86_64:: {
28
25
structures:: paging:: { FrameAllocator , OffsetPageTable , PageTable , PhysFrame , Size4KiB } ,
29
26
PhysAddr , VirtAddr ,
30
27
} ;
31
28
use xmas_elf:: ElfFile ;
32
29
30
+ static SYSTEM_TABLE : VeryUnsafeCell < Option < SystemTable < Boot > > > = VeryUnsafeCell :: new ( None ) ;
31
+
32
+ struct VeryUnsafeCell < T > ( UnsafeCell < T > ) ;
33
+
34
+ impl < T > VeryUnsafeCell < T > {
35
+ const fn new ( v : T ) -> Self {
36
+ Self ( UnsafeCell :: new ( v) )
37
+ }
38
+ }
39
+
40
+ unsafe impl < T > Sync for VeryUnsafeCell < T > { }
41
+
42
+ impl < T > core:: ops:: Deref for VeryUnsafeCell < T > {
43
+ type Target = UnsafeCell < T > ;
44
+
45
+ fn deref ( & self ) -> & Self :: Target {
46
+ & self . 0
47
+ }
48
+ }
49
+
33
50
#[ entry]
34
51
fn efi_main ( image : Handle , st : SystemTable < Boot > ) -> Status {
35
52
main_inner ( image, st)
36
53
}
37
54
38
55
fn main_inner ( image : Handle , mut st : SystemTable < Boot > ) -> Status {
39
- let mut buf = [ 0 ; 100 ] ;
40
- st. stdout ( )
41
- . output_string (
42
- CStr16 :: from_str_with_buf ( "UEFI bootloader started; trying to load kernel" , & mut buf)
43
- . unwrap ( ) ,
44
- )
45
- . unwrap ( )
46
- . unwrap ( ) ;
56
+ // temporarily clone the system table for printing panics
57
+ unsafe {
58
+ * SYSTEM_TABLE . get ( ) = Some ( st. unsafe_clone ( ) ) ;
59
+ }
60
+
61
+ st. stdout ( ) . clear ( ) . unwrap ( ) . unwrap ( ) ;
62
+ writeln ! (
63
+ st. stdout( ) ,
64
+ "UEFI bootloader started; trying to load kernel"
65
+ )
66
+ . unwrap ( ) ;
67
+
68
+ let kernel = load_kernel ( image, & st) ;
69
+
70
+ let ( framebuffer_addr, framebuffer_info) = init_logger ( & st, kernel. config ) ;
71
+
72
+ // we no longer need the system table for printing panics
73
+ unsafe {
74
+ * SYSTEM_TABLE . get ( ) = None ;
75
+ }
76
+
77
+ log:: info!( "UEFI bootloader started" ) ;
78
+ log:: info!( "Reading kernel and configuration from disk was successful" ) ;
79
+ log:: info!( "Using framebuffer at {:#x}" , framebuffer_addr) ;
80
+
81
+ let mmap_storage = {
82
+ let max_mmap_size =
83
+ st. boot_services ( ) . memory_map_size ( ) + 8 * mem:: size_of :: < MemoryDescriptor > ( ) ;
84
+ let ptr = st
85
+ . boot_services ( )
86
+ . allocate_pool ( MemoryType :: LOADER_DATA , max_mmap_size) ?
87
+ . log ( ) ;
88
+ unsafe { slice:: from_raw_parts_mut ( ptr, max_mmap_size) }
89
+ } ;
90
+
91
+ log:: trace!( "exiting boot services" ) ;
92
+ let ( system_table, memory_map) = st
93
+ . exit_boot_services ( image, mmap_storage)
94
+ . expect_success ( "Failed to exit boot services" ) ;
95
+
96
+ let mut frame_allocator = LegacyFrameAllocator :: new ( memory_map. copied ( ) ) ;
97
+
98
+ let page_tables = create_page_tables ( & mut frame_allocator) ;
99
+
100
+ let system_info = SystemInfo {
101
+ framebuffer_addr,
102
+ framebuffer_info,
103
+ rsdp_addr : {
104
+ use uefi:: table:: cfg;
105
+ let mut config_entries = system_table. config_table ( ) . iter ( ) ;
106
+ // look for an ACPI2 RSDP first
107
+ let acpi2_rsdp = config_entries. find ( |entry| matches ! ( entry. guid, cfg:: ACPI2_GUID ) ) ;
108
+ // if no ACPI2 RSDP is found, look for a ACPI1 RSDP
109
+ let rsdp = acpi2_rsdp
110
+ . or_else ( || config_entries. find ( |entry| matches ! ( entry. guid, cfg:: ACPI_GUID ) ) ) ;
111
+ rsdp. map ( |entry| PhysAddr :: new ( entry. address as u64 ) )
112
+ } ,
113
+ } ;
47
114
115
+ bootloader:: binary:: load_and_switch_to_kernel (
116
+ kernel,
117
+ frame_allocator,
118
+ page_tables,
119
+ system_info,
120
+ ) ;
121
+ }
122
+
123
+ fn load_kernel ( image : Handle , st : & SystemTable < Boot > ) -> Kernel < ' static > {
48
124
let file_system_raw = {
49
125
let ref this = st. boot_services ( ) ;
50
126
let loaded_image = this
51
- . handle_protocol :: < LoadedImage > ( image) ?
52
- . expect ( "Failed to retrieve `LoadedImage` protocol from handle" ) ;
127
+ . handle_protocol :: < LoadedImage > ( image)
128
+ . expect_success ( "Failed to retrieve `LoadedImage` protocol from handle" ) ;
53
129
let loaded_image = unsafe { & * loaded_image. get ( ) } ;
54
130
55
131
let device_handle = loaded_image. device ( ) ;
56
132
57
133
let device_path = this
58
- . handle_protocol :: < DevicePath > ( device_handle) ?
59
- . expect ( "Failed to retrieve `DevicePath` protocol from image's device handle" ) ;
134
+ . handle_protocol :: < DevicePath > ( device_handle)
135
+ . expect_success ( "Failed to retrieve `DevicePath` protocol from image's device handle" ) ;
60
136
let mut device_path = unsafe { & * device_path. get ( ) } ;
61
137
62
138
let device_handle = this
63
- . locate_device_path :: < SimpleFileSystem > ( & mut device_path) ?
64
- . expect ( "Failed to locate `SimpleFileSystem` protocol on device path" ) ;
139
+ . locate_device_path :: < SimpleFileSystem > ( & mut device_path)
140
+ . expect_success ( "Failed to locate `SimpleFileSystem` protocol on device path" ) ;
65
141
66
142
this. handle_protocol :: < SimpleFileSystem > ( device_handle)
67
143
}
@@ -72,14 +148,14 @@ fn main_inner(image: Handle, mut st: SystemTable<Boot>) -> Status {
72
148
let mut root = file_system. open_volume ( ) . unwrap ( ) . unwrap ( ) ;
73
149
let kernel_file_handle = root
74
150
. open ( "kernel-x86_64" , FileMode :: Read , FileAttribute :: empty ( ) )
75
- . unwrap ( )
151
+ . expect ( "Failed to load kernel (expected file named `kernel-x86_64`)" )
76
152
. unwrap ( ) ;
77
153
let mut kernel_file = match kernel_file_handle. into_type ( ) . unwrap ( ) . unwrap ( ) {
78
154
uefi:: proto:: media:: file:: FileType :: Regular ( f) => f,
79
155
uefi:: proto:: media:: file:: FileType :: Dir ( _) => panic ! ( ) ,
80
156
} ;
81
157
82
- let mut buf = [ 0 ; 100 ] ;
158
+ let mut buf = [ 0 ; 500 ] ;
83
159
let kernel_info: & mut FileInfo = kernel_file. get_info ( & mut buf) . unwrap ( ) . unwrap ( ) ;
84
160
let kernel_size = usize:: try_from ( kernel_info. file_size ( ) ) . unwrap ( ) ;
85
161
@@ -106,56 +182,10 @@ fn main_inner(image: Handle, mut st: SystemTable<Boot>) -> Status {
106
182
BootloaderConfig :: deserialize ( raw) . unwrap ( )
107
183
} ;
108
184
109
- let kernel = Kernel {
185
+ Kernel {
110
186
elf : kernel_elf,
111
187
config,
112
- } ;
113
-
114
- let ( framebuffer_addr, framebuffer_info) = init_logger ( & st, config) ;
115
- log:: info!( "UEFI bootloader started" ) ;
116
- log:: info!( "Reading kernel and configuration from disk was successful" ) ;
117
- log:: info!( "Using framebuffer at {:#x}" , framebuffer_addr) ;
118
-
119
- let mmap_storage = {
120
- let max_mmap_size =
121
- st. boot_services ( ) . memory_map_size ( ) + 8 * mem:: size_of :: < MemoryDescriptor > ( ) ;
122
- let ptr = st
123
- . boot_services ( )
124
- . allocate_pool ( MemoryType :: LOADER_DATA , max_mmap_size) ?
125
- . log ( ) ;
126
- unsafe { slice:: from_raw_parts_mut ( ptr, max_mmap_size) }
127
- } ;
128
-
129
- log:: trace!( "exiting boot services" ) ;
130
- let ( system_table, memory_map) = st
131
- . exit_boot_services ( image, mmap_storage)
132
- . expect_success ( "Failed to exit boot services" ) ;
133
-
134
- let mut frame_allocator = LegacyFrameAllocator :: new ( memory_map. copied ( ) ) ;
135
-
136
- let page_tables = create_page_tables ( & mut frame_allocator) ;
137
-
138
- let system_info = SystemInfo {
139
- framebuffer_addr,
140
- framebuffer_info,
141
- rsdp_addr : {
142
- use uefi:: table:: cfg;
143
- let mut config_entries = system_table. config_table ( ) . iter ( ) ;
144
- // look for an ACPI2 RSDP first
145
- let acpi2_rsdp = config_entries. find ( |entry| matches ! ( entry. guid, cfg:: ACPI2_GUID ) ) ;
146
- // if no ACPI2 RSDP is found, look for a ACPI1 RSDP
147
- let rsdp = acpi2_rsdp
148
- . or_else ( || config_entries. find ( |entry| matches ! ( entry. guid, cfg:: ACPI_GUID ) ) ) ;
149
- rsdp. map ( |entry| PhysAddr :: new ( entry. address as u64 ) )
150
- } ,
151
- } ;
152
-
153
- bootloader:: binary:: load_and_switch_to_kernel (
154
- kernel,
155
- frame_allocator,
156
- page_tables,
157
- system_info,
158
- ) ;
188
+ }
159
189
}
160
190
161
191
/// Creates page table abstraction types for both the bootloader and kernel page tables.
@@ -286,12 +316,17 @@ fn init_logger(st: &SystemTable<Boot>, config: BootloaderConfig) -> (PhysAddr, F
286
316
287
317
#[ panic_handler]
288
318
fn panic ( info : & PanicInfo ) -> ! {
319
+ if let Some ( st) = unsafe { & mut * SYSTEM_TABLE . get ( ) } {
320
+ let _ = writeln ! ( st. stdout( ) , "{}" , info) ;
321
+ }
322
+
289
323
unsafe {
290
324
bootloader:: binary:: logger:: LOGGER
291
325
. get ( )
292
326
. map ( |l| l. force_unlock ( ) )
293
327
} ;
294
328
log:: error!( "{}" , info) ;
329
+
295
330
loop {
296
331
unsafe { asm ! ( "cli; hlt" ) } ;
297
332
}
0 commit comments