Skip to content

Commit 675a00f

Browse files
committed
Implement ramdisk for uefi
1 parent da5a52d commit 675a00f

File tree

1 file changed

+112
-117
lines changed

1 file changed

+112
-117
lines changed

uefi/src/main.rs

+112-117
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

@@ -97,7 +99,8 @@ fn main_inner(image: Handle, mut st: SystemTable<Boot>) -> Status {
9799
st.boot_services().memory_map_size().map_size + 8 * mem::size_of::<MemoryDescriptor>();
98100
let ptr = st
99101
.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");
101104
unsafe { slice::from_raw_parts_mut(ptr, max_mmap_size) }
102105
};
103106

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

112115
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+
}
114122
let system_info = SystemInfo {
115123
framebuffer,
116124
rsdp_addr: {
@@ -123,14 +131,11 @@ fn main_inner(image: Handle, mut st: SystemTable<Boot>) -> Status {
123131
.or_else(|| config_entries.find(|entry| matches!(entry.guid, cfg::ACPI_GUID)));
124132
rsdp.map(|entry| PhysAddr::new(entry.address as u64))
125133
},
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)
133137
},
138+
ramdisk_len: ramdisk_len
134139
};
135140

136141
bootloader_x86_64_common::load_and_switch_to_kernel(
@@ -141,100 +146,124 @@ fn main_inner(image: Handle, mut st: SystemTable<Boot>) -> Status {
141146
);
142147
}
143148

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]> {
145150
load_file_from_disk(RAMDISK_FILENAME, image, st)
151+
.or_else(|| load_file_from_tftp_boot_server(RAMDISK_FILENAME, image, st))
146152
}
147153

148154
fn load_kernel(image: Handle, st: &SystemTable<Boot>) -> Kernel<'static> {
149155
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))
151157
.expect("couldn't find kernel");
152158
Kernel::parse(kernel_slice)
153159
}
154160

155-
fn load_file_from_disk(
156-
name: &str,
161+
fn open_device_path_protocol(
157162
image: Handle,
158163
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>(
163168
OpenProtocolParams {
164169
handle: image,
165170
agent: image,
166171
controller: None,
167172
},
168173
OpenProtocolAttributes::Exclusive,
169-
);
174+
)
175+
};
170176

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() };
177183

178-
let device_handle = loaded_image.device();
184+
let device_handle = loaded_image.device();
179185

180-
let device_path = this.open_protocol::<DevicePath>(
186+
let device_path = unsafe {
187+
this.open_protocol::<DevicePath>(
181188
OpenProtocolParams {
182189
handle: device_handle,
183190
agent: image,
184191
controller: None,
185192
},
186193
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+
}
194202

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+
}
200221

201-
let fs_handle = fs_handle.unwrap();
222+
let fs_handle = fs_handle.unwrap();
202223

203-
let opened_handle = this.open_protocol::<SimpleFileSystem>(
224+
let opened_handle = unsafe {
225+
this.open_protocol::<P>(
204226
OpenProtocolParams {
205227
handle: fs_handle,
206228
agent: image,
207229
controller: None,
208230
},
209231
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+
)
217233
};
218234

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+
219249
if file_system_raw.is_none() {
220-
return None();
250+
return None;
221251
}
222252
let file_system_raw = file_system_raw.unwrap();
223253
let file_system = unsafe { &mut *file_system_raw.interface.get() };
224254

225255
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());
232261

233-
if kernel_file_handle_result.is_err() {
262+
if file_handle_result.is_err() {
234263
return None;
235264
}
236265

237-
let file_handle = kernel_file_handle_result.unwrap();
266+
let file_handle = file_handle_result.unwrap();
238267

239268
let mut file = match file_handle.into_type().unwrap() {
240269
uefi::proto::media::file::FileType::Regular(f) => f,
@@ -261,87 +290,52 @@ fn load_file_from_disk(
261290
}
262291

263292
/// 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(
265294
name: &str,
266295
image: Handle,
267296
st: &SystemTable<Boot>,
268297
) -> 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();
311304
let base_code = unsafe { &mut *base_code_raw.interface.get() };
312305

313306
// Find the TFTP boot server.
314307
let mode = base_code.mode();
315308
assert!(mode.dhcp_ack_received);
316309
let dhcpv4: &DhcpV4Packet = mode.dhcp_ack.as_ref();
317310
let server_ip = IpAddress::new_v4(dhcpv4.bootp_si_addr);
311+
let mut buf = [0u8; 256];
312+
assert!(name.len() < 256);
318313

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();
320315

321316
// Determine the kernel file size.
322317
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");
327321

328322
// Allocate some memory for the kernel file.
329-
let kernel_ptr = st
323+
let ptr = st
330324
.boot_services()
331325
.allocate_pages(
332326
AllocateType::AnyPages,
333327
MemoryType::LOADER_DATA,
334328
((kernel_size - 1) / 4096) + 1,
335329
)
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) };
338332

339333
// Load the kernel file.
340334
base_code
341-
.tftp_read_file(&server_ip, filename, Some(kernel_slice))
335+
.tftp_read_file(&server_ip, &filename, Some(slice))
342336
.expect("Failed to read kernel file from the TFTP boot server");
343337

344-
Some(kernel_slice)
338+
Some(slice)
345339
}
346340

347341
/// Creates page table abstraction types for both the bootloader and kernel page tables.
@@ -411,10 +405,11 @@ fn create_page_tables(
411405
}
412406

413407
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+
};
418413
let gop = unsafe { &mut *gop.get() };
419414

420415
let mode = {

0 commit comments

Comments
 (0)