Skip to content

Commit 9b9b9ad

Browse files
committed
Implement ramdisk for uefi
1 parent 06c224c commit 9b9b9ad

File tree

2 files changed

+113
-122
lines changed

2 files changed

+113
-122
lines changed

bios/stage-4/src/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,9 @@ pub extern "C" fn _start(info: &mut BiosInfo) -> ! {
123123
rsdp_addr: detect_rsdp(),
124124
ramdisk_addr: match info.ramdisk.len {
125125
0 => None,
126-
_ => Some(info.ramdisk.start)
126+
_ => Some(info.ramdisk.start),
127127
},
128-
ramdisk_len: info.ramdisk.len
128+
ramdisk_len: info.ramdisk.len,
129129
};
130130

131131
load_and_switch_to_kernel(kernel, frame_allocator, page_tables, system_info);

uefi/src/main.rs

Lines changed: 111 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ use uefi::{
1313
prelude::{entry, Boot, Handle, Status, SystemTable},
1414
proto::{
1515
console::gop::{GraphicsOutput, PixelFormat},
16-
device_path::{self, DevicePath},
17-
loaded_image::{self, LoadedImage},
16+
device_path::DevicePath,
17+
loaded_image::LoadedImage,
1818
media::{
1919
file::{File, FileAttribute, FileInfo, FileMode},
2020
fs::SimpleFileSystem,
@@ -23,9 +23,11 @@ use uefi::{
2323
pxe::{BaseCode, DhcpV4Packet},
2424
IpAddress,
2525
},
26+
ProtocolPointer,
2627
},
2728
table::boot::{
2829
AllocateType, MemoryDescriptor, MemoryType, OpenProtocolAttributes, OpenProtocolParams,
30+
ScopedProtocol,
2931
},
3032
CStr16, CStr8,
3133
};
@@ -37,8 +39,8 @@ use x86_64::{
3739
mod memory_descriptor;
3840

3941
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";
4244

4345
struct RacyCell<T>(UnsafeCell<T>);
4446

@@ -98,7 +100,7 @@ fn main_inner(image: Handle, mut st: SystemTable<Boot>) -> Status {
98100
let ptr = st
99101
.boot_services()
100102
.allocate_pool(MemoryType::LOADER_DATA, max_mmap_size)
101-
.expect("Failed to allocate memory for memory map");
103+
.expect("Failed to allocate memory for mmap storage");
102104
unsafe { slice::from_raw_parts_mut(ptr, max_mmap_size) }
103105
};
104106

@@ -111,7 +113,12 @@ fn main_inner(image: Handle, mut st: SystemTable<Boot>) -> Status {
111113
LegacyFrameAllocator::new(memory_map.copied().map(UefiMemoryDescriptor));
112114

113115
let page_tables = create_page_tables(&mut frame_allocator);
114-
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+
}
115122
let system_info = SystemInfo {
116123
framebuffer,
117124
rsdp_addr: {
@@ -124,14 +131,11 @@ fn main_inner(image: Handle, mut st: SystemTable<Boot>) -> Status {
124131
.or_else(|| config_entries.find(|entry| matches!(entry.guid, cfg::ACPI_GUID)));
125132
rsdp.map(|entry| PhysAddr::new(entry.address as u64))
126133
},
127-
ramdisk_addr: match ramdisk {
128-
Some(rd) => Some(rd as *const _ as u64),
129-
None => None,
130-
},
131-
ramdisk_len: match ramdisk {
132-
Some(rd) => rd.len() as u64,
133-
None => 0u64,
134+
ramdisk_addr: match ramdisk_addr {
135+
0 => None,
136+
v => Some(v),
134137
},
138+
ramdisk_len: ramdisk_len,
135139
};
136140

137141
bootloader_x86_64_common::load_and_switch_to_kernel(
@@ -142,100 +146,125 @@ fn main_inner(image: Handle, mut st: SystemTable<Boot>) -> Status {
142146
);
143147
}
144148

145-
fn load_ramdisk(image: Handle, st: &SystemTable<Boot>) -> Option<&'static [u8]> {
149+
fn load_ramdisk(image: Handle, st: &SystemTable<Boot>) -> Option<&'static mut [u8]> {
146150
load_file_from_disk(RAMDISK_FILENAME, image, st)
151+
.or_else(|| load_file_from_tftp_boot_server(RAMDISK_FILENAME, image, st))
147152
}
148153

149154
fn load_kernel(image: Handle, st: &SystemTable<Boot>) -> Kernel<'static> {
150155
let kernel_slice = load_file_from_disk(KERNEL_FILENAME, image, st)
151-
.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))
152157
.expect("couldn't find kernel");
153158
Kernel::parse(kernel_slice)
154159
}
155160

156-
fn load_file_from_disk(
157-
name: &str,
161+
fn open_device_path_protocol(
158162
image: Handle,
159163
st: &SystemTable<Boot>,
160-
) -> Option<&'static mut [u8]> {
161-
let file_system_raw = {
162-
let this = st.boot_services();
163-
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>(
164168
OpenProtocolParams {
165169
handle: image,
166170
agent: image,
167171
controller: None,
168172
},
169173
OpenProtocolAttributes::Exclusive,
170-
);
174+
)
175+
};
171176

172-
if loaded_image.is_err() {
173-
log::error!("Failed to open protocol SimpleFileSystem while attempting to load {name}");
174-
return None;
175-
}
176-
let loaded_image = loaded_image.unwrap();
177-
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() };
178183

179-
let device_handle = loaded_image.device();
184+
let device_handle = loaded_image.device();
180185

181-
let device_path = this.open_protocol::<DevicePath>(
186+
let device_path = unsafe {
187+
this.open_protocol::<DevicePath>(
182188
OpenProtocolParams {
183189
handle: device_handle,
184190
agent: image,
185191
controller: None,
186192
},
187193
OpenProtocolAttributes::Exclusive,
188-
);
189-
if device_path.is_err() {
190-
log::error!("Failed to open protocol DevicePath while attempting to load {name}");
191-
return None;
192-
}
193-
let device_path = device_path.unwrap();
194-
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+
}
195202

196-
let fs_handle = this.locate_device_path::<SimpleFileSystem>(&mut device_path);
197-
if fs_handle.is_err() {
198-
log::error!("Failed to open device path while attempting to load {name}");
199-
return None;
200-
}
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() };
201215

202-
let fs_handle = fs_handle.unwrap();
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+
}
203221

204-
let opened_handle = this.open_protocol::<SimpleFileSystem>(
222+
let fs_handle = fs_handle.unwrap();
223+
224+
let opened_handle = unsafe {
225+
this.open_protocol::<P>(
205226
OpenProtocolParams {
206227
handle: fs_handle,
207228
agent: image,
208229
controller: None,
209230
},
210231
OpenProtocolAttributes::Exclusive,
211-
);
212-
213-
if opened_handle.is_err() {
214-
log::error!("Failed to open file system while attempting to load {name}");
215-
return None;
216-
}
217-
Some(opened_handle.unwrap())
232+
)
218233
};
219234

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+
220249
if file_system_raw.is_none() {
221-
return None();
250+
return None;
222251
}
223252
let file_system_raw = file_system_raw.unwrap();
224253
let file_system = unsafe { &mut *file_system_raw.interface.get() };
225254

226255
let mut root = file_system.open_volume().unwrap();
227-
if (name.len() > 255) {
228-
panic!("File name {}, exceeds maximum length!", name);
229-
}
230-
let mut buf = [0; 512];
231-
let filename = CStr16::from_str_with_buf(name, &mut buf).unwrap();
232-
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)
259+
.expect("Failed to convert string to utf16");
260+
261+
let file_handle_result = root.open(filename, FileMode::Read, FileAttribute::empty());
233262

234-
if kernel_file_handle_result.is_err() {
263+
if file_handle_result.is_err() {
235264
return None;
236265
}
237266

238-
let file_handle = kernel_file_handle_result.unwrap();
267+
let file_handle = file_handle_result.unwrap();
239268

240269
let mut file = match file_handle.into_type().unwrap() {
241270
uefi::proto::media::file::FileType::Regular(f) => f,
@@ -262,90 +291,52 @@ fn load_file_from_disk(
262291
}
263292

264293
/// Try to load a kernel from a TFTP boot server.
265-
fn load_kernel_file_from_tftp_boot_server(
294+
fn load_file_from_tftp_boot_server(
266295
name: &str,
267296
image: Handle,
268297
st: &SystemTable<Boot>,
269298
) -> Option<&'static mut [u8]> {
270-
let this = st.boot_services();
271-
272-
// Try to locate a `BaseCode` protocol on the boot device.
273-
274-
let loaded_image = unsafe { this
275-
.open_protocol::<LoadedImage>(
276-
OpenProtocolParams {
277-
handle: image,
278-
agent: image,
279-
controller: None,
280-
},
281-
OpenProtocolAttributes::Exclusive,
282-
)
283-
.expect("Failed to retrieve `LoadedImage` protocol from handle")
284-
};
285-
let loaded_image = unsafe { &*loaded_image.interface.get() };
286-
287-
let device_handle = loaded_image.device();
288-
289-
let device_path = unsafe { this
290-
.open_protocol::<DevicePath>(
291-
OpenProtocolParams {
292-
handle: device_handle,
293-
agent: image,
294-
controller: None,
295-
},
296-
OpenProtocolAttributes::Exclusive,
297-
)
298-
.expect("Failed to retrieve `DevicePath` protocol from image's device handle")
299-
};
300-
let mut device_path = unsafe { &*device_path.interface.get() };
301-
302-
let base_code_handle = this.locate_device_path::<BaseCode>(&mut device_path).ok()?;
303-
304-
let base_code_raw = unsafe { this
305-
.open_protocol::<BaseCode>(
306-
OpenProtocolParams {
307-
handle: base_code_handle,
308-
agent: image,
309-
controller: None,
310-
},
311-
OpenProtocolAttributes::Exclusive,
312-
)
313-
.unwrap()
314-
};
299+
let base_code_raw = locate_and_open_protocol::<BaseCode>(image, st);
300+
if base_code_raw.is_none() {
301+
// The previous code will log errors along the way, we do not need to.
302+
return None;
303+
}
304+
let base_code_raw = base_code_raw.unwrap();
315305
let base_code = unsafe { &mut *base_code_raw.interface.get() };
316306

317307
// Find the TFTP boot server.
318308
let mode = base_code.mode();
319309
assert!(mode.dhcp_ack_received);
320310
let dhcpv4: &DhcpV4Packet = mode.dhcp_ack.as_ref();
321311
let server_ip = IpAddress::new_v4(dhcpv4.bootp_si_addr);
312+
let mut buf = [0u8; 256];
313+
assert!(name.len() < 256);
322314

323-
let filename = CStr8::from_bytes_with_nul(b"kernel-x86_64\0").unwrap();
315+
let filename = CStr8::from_bytes_with_nul(name.as_bytes()).unwrap();
324316

325317
// Determine the kernel file size.
326318
let file_size = base_code
327-
.tftp_get_file_size(&server_ip, filename)
328-
.expect("Failed to query the kernel file size");
329-
let kernel_size =
330-
usize::try_from(file_size).expect("The kernel file size should fit into usize");
319+
.tftp_get_file_size(&server_ip, &filename)
320+
.expect("Failed to query the file size");
321+
let kernel_size = usize::try_from(file_size).expect("The file size should fit into usize");
331322

332323
// Allocate some memory for the kernel file.
333-
let kernel_ptr = st
324+
let ptr = st
334325
.boot_services()
335326
.allocate_pages(
336327
AllocateType::AnyPages,
337328
MemoryType::LOADER_DATA,
338329
((kernel_size - 1) / 4096) + 1,
339330
)
340-
.expect("Failed to allocate memory for the kernel file") as *mut u8;
341-
let kernel_slice = unsafe { slice::from_raw_parts_mut(kernel_ptr, kernel_size) };
331+
.expect("Failed to allocate memory for the file") as *mut u8;
332+
let slice = unsafe { slice::from_raw_parts_mut(ptr, kernel_size) };
342333

343334
// Load the kernel file.
344335
base_code
345-
.tftp_read_file(&server_ip, filename, Some(kernel_slice))
336+
.tftp_read_file(&server_ip, &filename, Some(slice))
346337
.expect("Failed to read kernel file from the TFTP boot server");
347338

348-
Some(kernel_slice)
339+
Some(slice)
349340
}
350341

351342
/// Creates page table abstraction types for both the bootloader and kernel page tables.
@@ -415,10 +406,10 @@ fn create_page_tables(
415406
}
416407

417408
fn init_logger(st: &SystemTable<Boot>, config: BootloaderConfig) -> Option<RawFrameBufferInfo> {
418-
let gop = unsafe { st
419-
.boot_services()
420-
.locate_protocol::<GraphicsOutput>()
421-
.ok()?
409+
let gop = unsafe {
410+
st.boot_services()
411+
.locate_protocol::<GraphicsOutput>()
412+
.ok()?
422413
};
423414
let gop = unsafe { &mut *gop.get() };
424415

0 commit comments

Comments
 (0)