@@ -13,8 +13,8 @@ use uefi::{
13
13
prelude::{entry, Boot, Handle, Status, SystemTable},
14
14
proto::{
15
15
console::gop::{GraphicsOutput, PixelFormat},
16
- device_path::{self, DevicePath},
17
- loaded_image::{self, LoadedImage},
16
+ device_path::{DevicePath},
17
+ loaded_image::{LoadedImage},
18
18
media::{
19
19
file::{File, FileAttribute, FileInfo, FileMode},
20
20
fs::SimpleFileSystem,
@@ -23,9 +23,11 @@ use uefi::{
23
23
pxe::{BaseCode, DhcpV4Packet},
24
24
IpAddress,
25
25
},
26
+ ProtocolPointer,
26
27
},
27
28
table::boot::{
28
29
AllocateType, MemoryDescriptor, MemoryType, OpenProtocolAttributes, OpenProtocolParams,
30
+ ScopedProtocol,
29
31
},
30
32
CStr16, CStr8,
31
33
};
@@ -37,8 +39,8 @@ use x86_64::{
37
39
mod memory_descriptor;
38
40
39
41
static SYSTEM_TABLE: RacyCell<Option<SystemTable<Boot>>> = RacyCell::new(None);
40
- const KERNEL_FILENAME: &str = "kernel-x86_64";
41
- const RAMDISK_FILENAME: &str = "ramdisk-x86_64";
42
+ static KERNEL_FILENAME: &str = "kernel-x86_64\0 ";
43
+ static RAMDISK_FILENAME: &str = "ramdisk-x86_64\0 ";
42
44
43
45
struct RacyCell<T>(UnsafeCell<T>);
44
46
@@ -97,7 +99,8 @@ fn main_inner(image: Handle, mut st: SystemTable<Boot>) -> Status {
97
99
st.boot_services().memory_map_size().map_size + 8 * mem::size_of::<MemoryDescriptor>();
98
100
let ptr = st
99
101
.boot_services()
100
- .allocate_pool(MemoryType::LOADER_DATA, max_mmap_size)?;
102
+ .allocate_pool(MemoryType::LOADER_DATA, max_mmap_size)
103
+ .expect("Failed to allocate memory for mmap storage");
101
104
unsafe { slice::from_raw_parts_mut(ptr, max_mmap_size) }
102
105
};
103
106
@@ -110,7 +113,12 @@ fn main_inner(image: Handle, mut st: SystemTable<Boot>) -> Status {
110
113
LegacyFrameAllocator::new(memory_map.copied().map(UefiMemoryDescriptor));
111
114
112
115
let page_tables = create_page_tables(&mut frame_allocator);
113
-
116
+ let mut ramdisk_addr = 0u64;
117
+ let mut ramdisk_len = 0u64;
118
+ if let Some(rd) = ramdisk {
119
+ ramdisk_len = rd.len() as u64;
120
+ ramdisk_addr = rd.as_ptr() as usize as u64;
121
+ }
114
122
let system_info = SystemInfo {
115
123
framebuffer,
116
124
rsdp_addr: {
@@ -123,14 +131,11 @@ fn main_inner(image: Handle, mut st: SystemTable<Boot>) -> Status {
123
131
.or_else(|| config_entries.find(|entry| matches!(entry.guid, cfg::ACPI_GUID)));
124
132
rsdp.map(|entry| PhysAddr::new(entry.address as u64))
125
133
},
126
- ramdisk_addr: match ramdisk {
127
- Some(rd) => Some(rd as *const _ as u64),
128
- None => None,
129
- },
130
- ramdisk_len: match ramdisk {
131
- Some(rd) => rd.len() as u64,
132
- None => 0u64,
134
+ ramdisk_addr: match ramdisk_addr {
135
+ 0 => None,
136
+ v => Some(v)
133
137
},
138
+ ramdisk_len: ramdisk_len
134
139
};
135
140
136
141
bootloader_x86_64_common::load_and_switch_to_kernel(
@@ -141,100 +146,124 @@ fn main_inner(image: Handle, mut st: SystemTable<Boot>) -> Status {
141
146
);
142
147
}
143
148
144
- fn load_ramdisk(image: Handle, st: &SystemTable<Boot>) -> Option<&'static [u8]> {
149
+ fn load_ramdisk(image: Handle, st: &SystemTable<Boot>) -> Option<&'static mut [u8]> {
145
150
load_file_from_disk(RAMDISK_FILENAME, image, st)
151
+ .or_else(|| load_file_from_tftp_boot_server(RAMDISK_FILENAME, image, st))
146
152
}
147
153
148
154
fn load_kernel(image: Handle, st: &SystemTable<Boot>) -> Kernel<'static> {
149
155
let kernel_slice = load_file_from_disk(KERNEL_FILENAME, image, st)
150
- .or_else(|| load_kernel_file_from_tftp_boot_server (KERNEL_FILENAME, image, st))
156
+ .or_else(|| load_file_from_tftp_boot_server (KERNEL_FILENAME, image, st))
151
157
.expect("couldn't find kernel");
152
158
Kernel::parse(kernel_slice)
153
159
}
154
160
155
- fn load_file_from_disk(
156
- name: &str,
161
+ fn open_device_path_protocol(
157
162
image: Handle,
158
163
st: &SystemTable<Boot>,
159
- ) -> Option<&'static mut [u8] > {
160
- let file_system_raw = {
161
- let this = st.boot_services();
162
- let loaded_image = this.open_protocol::<LoadedImage>(
164
+ ) -> Option<ScopedProtocol<DevicePath> > {
165
+ let this = st.boot_services();
166
+ let loaded_image = unsafe {
167
+ this.open_protocol::<LoadedImage>(
163
168
OpenProtocolParams {
164
169
handle: image,
165
170
agent: image,
166
171
controller: None,
167
172
},
168
173
OpenProtocolAttributes::Exclusive,
169
- );
174
+ )
175
+ };
170
176
171
- if loaded_image.is_err() {
172
- log::error!("Failed to open protocol SimpleFileSystem while attempting to load {name} ");
173
- return None;
174
- }
175
- let loaded_image = loaded_image.unwrap();
176
- let loaded_image = unsafe { &*loaded_image.interface.get() };
177
+ if loaded_image.is_err() {
178
+ log::error!("Failed to open protocol LoadedImage ");
179
+ return None;
180
+ }
181
+ let loaded_image = loaded_image.unwrap();
182
+ let loaded_image = unsafe { &*loaded_image.interface.get() };
177
183
178
- let device_handle = loaded_image.device();
184
+ let device_handle = loaded_image.device();
179
185
180
- let device_path = this.open_protocol::<DevicePath>(
186
+ let device_path = unsafe {
187
+ this.open_protocol::<DevicePath>(
181
188
OpenProtocolParams {
182
189
handle: device_handle,
183
190
agent: image,
184
191
controller: None,
185
192
},
186
193
OpenProtocolAttributes::Exclusive,
187
- );
188
- if device_path.is_err() {
189
- log::error!("Failed to open protocol DevicePath while attempting to load {name}");
190
- return None;
191
- }
192
- let device_path = device_path.unwrap();
193
- let mut device_path = unsafe { &*device_path.interface.get() };
194
+ )
195
+ };
196
+ if device_path.is_err() {
197
+ log::error!("Failed to open protocol DevicePath");
198
+ return None;
199
+ }
200
+ Some(device_path.unwrap())
201
+ }
194
202
195
- let fs_handle = this.locate_device_path::<SimpleFileSystem>(&mut device_path);
196
- if fs_handle.is_err() {
197
- log::error!("Failed to open device path while attempting to load {name}");
198
- return None;
199
- }
203
+ fn locate_and_open_protocol<P: ProtocolPointer>(
204
+ image: Handle,
205
+ st: &SystemTable<Boot>,
206
+ ) -> Option<ScopedProtocol<P>> {
207
+ let this = st.boot_services();
208
+ let device_path = open_device_path_protocol(image, st);
209
+ if device_path.is_none() {
210
+ log::error!("Unable to open device path protocol from boot services");
211
+ return None;
212
+ }
213
+ let device_path = device_path.unwrap();
214
+ let mut device_path = unsafe { &*device_path.interface.get() };
215
+
216
+ let fs_handle = this.locate_device_path::<P>(&mut device_path);
217
+ if fs_handle.is_err() {
218
+ log::error!("Failed to open device path");
219
+ return None;
220
+ }
200
221
201
- let fs_handle = fs_handle.unwrap();
222
+ let fs_handle = fs_handle.unwrap();
202
223
203
- let opened_handle = this.open_protocol::<SimpleFileSystem>(
224
+ let opened_handle = unsafe {
225
+ this.open_protocol::<P>(
204
226
OpenProtocolParams {
205
227
handle: fs_handle,
206
228
agent: image,
207
229
controller: None,
208
230
},
209
231
OpenProtocolAttributes::Exclusive,
210
- );
211
-
212
- if opened_handle.is_err() {
213
- log::error!("Failed to open file system while attempting to load {name}");
214
- return None;
215
- }
216
- Some(opened_handle.unwrap())
232
+ )
217
233
};
218
234
235
+ if opened_handle.is_err() {
236
+ log::error!("Failed to open protocol {}", core::any::type_name::<P>());
237
+ return None;
238
+ }
239
+ Some(opened_handle.unwrap())
240
+ }
241
+
242
+ fn load_file_from_disk(
243
+ name: &str,
244
+ image: Handle,
245
+ st: &SystemTable<Boot>,
246
+ ) -> Option<&'static mut [u8]> {
247
+ let file_system_raw = locate_and_open_protocol::<SimpleFileSystem>(image, st);
248
+
219
249
if file_system_raw.is_none() {
220
- return None() ;
250
+ return None;
221
251
}
222
252
let file_system_raw = file_system_raw.unwrap();
223
253
let file_system = unsafe { &mut *file_system_raw.interface.get() };
224
254
225
255
let mut root = file_system.open_volume().unwrap();
226
- if (name.len() > 255) {
227
- panic!("File name {}, exceeds maximum length!", name);
228
- }
229
- let mut buf = [0; 512];
230
- let filename = CStr16::from_str_with_buf(name, &mut buf).unwrap();
231
- let kernel_file_handle_result = root.open(filename, FileMode::Read, FileAttribute::empty());
256
+ let mut buf = [0u16; 256];
257
+ assert!(name.len() < 256);
258
+ let filename = CStr16::from_str_with_buf(name.trim_end_matches('\0'), &mut buf).expect("Failed to convert string to utf16");
259
+
260
+ let file_handle_result = root.open(filename, FileMode::Read, FileAttribute::empty());
232
261
233
- if kernel_file_handle_result .is_err() {
262
+ if file_handle_result .is_err() {
234
263
return None;
235
264
}
236
265
237
- let file_handle = kernel_file_handle_result .unwrap();
266
+ let file_handle = file_handle_result .unwrap();
238
267
239
268
let mut file = match file_handle.into_type().unwrap() {
240
269
uefi::proto::media::file::FileType::Regular(f) => f,
@@ -261,87 +290,52 @@ fn load_file_from_disk(
261
290
}
262
291
263
292
/// Try to load a kernel from a TFTP boot server.
264
- fn load_kernel_file_from_tftp_boot_server (
293
+ fn load_file_from_tftp_boot_server (
265
294
name: &str,
266
295
image: Handle,
267
296
st: &SystemTable<Boot>,
268
297
) -> Option<&'static mut [u8]> {
269
- let this = st.boot_services();
270
-
271
- // Try to locate a `BaseCode` protocol on the boot device.
272
-
273
- let loaded_image = this
274
- .open_protocol::<LoadedImage>(
275
- OpenProtocolParams {
276
- handle: image,
277
- agent: image,
278
- controller: None,
279
- },
280
- OpenProtocolAttributes::Exclusive,
281
- )
282
- .expect("Failed to retrieve `LoadedImage` protocol from handle");
283
- let loaded_image = unsafe { &*loaded_image.interface.get() };
284
-
285
- let device_handle = loaded_image.device();
286
-
287
- let device_path = this
288
- .open_protocol::<DevicePath>(
289
- OpenProtocolParams {
290
- handle: device_handle,
291
- agent: image,
292
- controller: None,
293
- },
294
- OpenProtocolAttributes::Exclusive,
295
- )
296
- .expect("Failed to retrieve `DevicePath` protocol from image's device handle");
297
- let mut device_path = unsafe { &*device_path.interface.get() };
298
-
299
- let base_code_handle = this.locate_device_path::<BaseCode>(&mut device_path).ok()?;
300
-
301
- let base_code_raw = this
302
- .open_protocol::<BaseCode>(
303
- OpenProtocolParams {
304
- handle: base_code_handle,
305
- agent: image,
306
- controller: None,
307
- },
308
- OpenProtocolAttributes::Exclusive,
309
- )
310
- .unwrap();
298
+ let base_code_raw = locate_and_open_protocol::<BaseCode>(image, st);
299
+ if base_code_raw.is_none() {
300
+ // The previous code will log errors along the way, we do not need to.
301
+ return None;
302
+ }
303
+ let base_code_raw = base_code_raw.unwrap();
311
304
let base_code = unsafe { &mut *base_code_raw.interface.get() };
312
305
313
306
// Find the TFTP boot server.
314
307
let mode = base_code.mode();
315
308
assert!(mode.dhcp_ack_received);
316
309
let dhcpv4: &DhcpV4Packet = mode.dhcp_ack.as_ref();
317
310
let server_ip = IpAddress::new_v4(dhcpv4.bootp_si_addr);
311
+ let mut buf = [0u8; 256];
312
+ assert!(name.len() < 256);
318
313
319
- let filename = CStr8::from_bytes_with_nul(b"kernel-x86_64\0" ).unwrap();
314
+ let filename = CStr8::from_bytes_with_nul(name.as_bytes() ).unwrap();
320
315
321
316
// Determine the kernel file size.
322
317
let file_size = base_code
323
- .tftp_get_file_size(&server_ip, filename)
324
- .expect("Failed to query the kernel file size");
325
- let kernel_size =
326
- usize::try_from(file_size).expect("The kernel file size should fit into usize");
318
+ .tftp_get_file_size(&server_ip, &filename)
319
+ .expect("Failed to query the file size");
320
+ let kernel_size = usize::try_from(file_size).expect("The file size should fit into usize");
327
321
328
322
// Allocate some memory for the kernel file.
329
- let kernel_ptr = st
323
+ let ptr = st
330
324
.boot_services()
331
325
.allocate_pages(
332
326
AllocateType::AnyPages,
333
327
MemoryType::LOADER_DATA,
334
328
((kernel_size - 1) / 4096) + 1,
335
329
)
336
- .expect("Failed to allocate memory for the kernel file") as *mut u8;
337
- let kernel_slice = unsafe { slice::from_raw_parts_mut(kernel_ptr , kernel_size) };
330
+ .expect("Failed to allocate memory for the file") as *mut u8;
331
+ let slice = unsafe { slice::from_raw_parts_mut(ptr , kernel_size) };
338
332
339
333
// Load the kernel file.
340
334
base_code
341
- .tftp_read_file(&server_ip, filename, Some(kernel_slice ))
335
+ .tftp_read_file(&server_ip, & filename, Some(slice ))
342
336
.expect("Failed to read kernel file from the TFTP boot server");
343
337
344
- Some(kernel_slice )
338
+ Some(slice )
345
339
}
346
340
347
341
/// Creates page table abstraction types for both the bootloader and kernel page tables.
@@ -411,10 +405,11 @@ fn create_page_tables(
411
405
}
412
406
413
407
fn init_logger(st: &SystemTable<Boot>, config: BootloaderConfig) -> Option<RawFrameBufferInfo> {
414
- let gop = st
415
- .boot_services()
416
- .locate_protocol::<GraphicsOutput>()
417
- .ok()?;
408
+ let gop = unsafe {
409
+ st.boot_services()
410
+ .locate_protocol::<GraphicsOutput>()
411
+ .ok()?
412
+ };
418
413
let gop = unsafe { &mut *gop.get() };
419
414
420
415
let mode = {
0 commit comments