From 17efc8eeb9c57f481ec05d87f1aca151b4e56fa6 Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Mon, 18 Dec 2023 17:02:17 +0000 Subject: [PATCH 01/10] efi: Refactor device path protocol parsing Convert the EFI device path protocol structure into a Rust structure in order to be able to handle different device path types (e.g. memory backed) in the future. Signed-off-by: Rob Bradford --- src/efi/mod.rs | 133 +++++++++++++++++++++++++++---------------------- 1 file changed, 73 insertions(+), 60 deletions(-) diff --git a/src/efi/mod.rs b/src/efi/mod.rs index c4cf434a..aa34c8dd 100644 --- a/src/efi/mod.rs +++ b/src/efi/mod.rs @@ -653,54 +653,57 @@ pub extern "efiapi" fn load_image( ) -> Status { use crate::fat::Read; - let mut path = [0_u8; 256]; let device_path = unsafe { &*device_path }; - extract_path(device_path, &mut path); - let path = crate::common::ascii_strip(&path); - - let li = parent_image_handle as *const LoadedImageWrapper; - let dh = unsafe { (*li).proto.device_handle }; - let wrapped_fs_ref = unsafe { &*(dh as *const file::FileSystemWrapper) }; - let mut file = match wrapped_fs_ref.fs.open(path) { - Ok(file) => file, - Err(_) => return Status::DEVICE_ERROR, - }; - - let file_size = (file.get_size() as u64 + PAGE_SIZE - 1) / PAGE_SIZE; - // Get free pages address - let load_addr = - match ALLOCATOR - .borrow_mut() - .find_free_pages(efi::ALLOCATE_ANY_PAGES, file_size, 0) - { - Some(a) => a, - None => return Status::OUT_OF_RESOURCES, - }; - - let mut l = crate::pe::Loader::new(&mut file); - let (entry_addr, load_addr, load_size) = match l.load(load_addr) { - Ok(load_info) => load_info, - Err(_) => return Status::DEVICE_ERROR, - }; - ALLOCATOR.borrow_mut().allocate_pages( - efi::ALLOCATE_ADDRESS, - efi::LOADER_CODE, - file_size, - load_addr, - ); - - let image = new_image_handle( - path, - parent_image_handle, - wrapped_fs_ref as *const _ as Handle, - load_addr, - load_size, - entry_addr, - ); - - unsafe { *image_handle = image as *mut _ as *mut c_void }; - - Status::SUCCESS + match DevicePath::parse(device_path) { + DevicePath::File(path) => { + let path = crate::common::ascii_strip(&path); + + let li = parent_image_handle as *const LoadedImageWrapper; + let dh = unsafe { (*li).proto.device_handle }; + let wrapped_fs_ref = unsafe { &*(dh as *const file::FileSystemWrapper) }; + let mut file = match wrapped_fs_ref.fs.open(path) { + Ok(file) => file, + Err(_) => return Status::DEVICE_ERROR, + }; + + let file_size = (file.get_size() as u64 + PAGE_SIZE - 1) / PAGE_SIZE; + // Get free pages address + let load_addr = + match ALLOCATOR + .borrow_mut() + .find_free_pages(efi::ALLOCATE_ANY_PAGES, file_size, 0) + { + Some(a) => a, + None => return Status::OUT_OF_RESOURCES, + }; + + let mut l = crate::pe::Loader::new(&mut file); + let (entry_addr, load_addr, load_size) = match l.load(load_addr) { + Ok(load_info) => load_info, + Err(_) => return Status::DEVICE_ERROR, + }; + ALLOCATOR.borrow_mut().allocate_pages( + efi::ALLOCATE_ADDRESS, + efi::LOADER_CODE, + file_size, + load_addr, + ); + + let image = new_image_handle( + path, + parent_image_handle, + wrapped_fs_ref as *const _ as Handle, + load_addr, + load_size, + entry_addr, + ); + + unsafe { *image_handle = image as *mut _ as *mut c_void }; + + Status::SUCCESS + } + _ => Status::UNSUPPORTED, + } } pub extern "efiapi" fn start_image( @@ -934,20 +937,30 @@ extern "efiapi" fn image_unload(_: Handle) -> Status { efi::Status::UNSUPPORTED } -fn extract_path(device_path: &DevicePathProtocol, path: &mut [u8]) { - let mut dp = device_path; - loop { - if dp.r#type == r_efi::protocols::device_path::TYPE_MEDIA && dp.sub_type == 0x04 { - let ptr = - (dp as *const _ as u64 + size_of::() as u64) as *const u16; - crate::common::ucs2_to_ascii(ptr, path); - return; - } - if dp.r#type == r_efi::protocols::device_path::TYPE_END && dp.sub_type == 0xff { - panic!("Failed to extract path"); +#[allow(clippy::large_enum_variant)] +enum DevicePath { + File([u8; 256]), + Unsupported, +} + +impl DevicePath { + fn parse(dpp: &DevicePathProtocol) -> DevicePath { + let mut dpp = dpp; + loop { + if dpp.r#type == r_efi::protocols::device_path::TYPE_MEDIA && dpp.sub_type == 0x04 { + let ptr = (dpp as *const _ as usize + offset_of!(FileDevicePathProtocol, filename)) + as *const u16; + let mut path = [0u8; 256]; + crate::common::ucs2_to_ascii(ptr, &mut path); + return DevicePath::File(path); + } + if dpp.r#type == r_efi::protocols::device_path::TYPE_END && dpp.sub_type == 0xff { + log!("Unexpected end of device path"); + return DevicePath::Unsupported; + } + let len = unsafe { core::mem::transmute::<[u8; 2], u16>(dpp.length) }; + dpp = unsafe { &*((dpp as *const _ as u64 + len as u64) as *const _) }; } - let len = unsafe { core::mem::transmute::<[u8; 2], u16>(dp.length) }; - dp = unsafe { &*((dp as *const _ as u64 + len as u64) as *const _) }; } } From ffc77a2e1d26473e4982c271d62e453a615bab2f Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Mon, 18 Dec 2023 17:13:24 +0000 Subject: [PATCH 02/10] efi: Refactor construction of file based device path Rather than construct the device path when creating the image handle do so earlier so that ultimately a NULL path could be provided in the case of loading from memory. Signed-off-by: Rob Bradford --- src/efi/mod.rs | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/efi/mod.rs b/src/efi/mod.rs index aa34c8dd..8f2d915b 100644 --- a/src/efi/mod.rs +++ b/src/efi/mod.rs @@ -690,7 +690,7 @@ pub extern "efiapi" fn load_image( ); let image = new_image_handle( - path, + file_device_path(path), parent_image_handle, wrapped_fs_ref as *const _ as Handle, load_addr, @@ -1046,14 +1046,7 @@ struct LoadedImageWrapper { type DevicePaths = [file::FileDevicePathProtocol; 2]; -fn new_image_handle( - path: &str, - parent_handle: Handle, - device_handle: Handle, - load_addr: u64, - load_size: u64, - entry_addr: u64, -) -> *mut LoadedImageWrapper { +fn file_device_path(path: &str) -> *mut r_efi::protocols::device_path::Protocol { let mut file_paths = null_mut(); let status = allocate_pool( efi::LOADER_DATA, @@ -1083,8 +1076,19 @@ fn new_image_handle( crate::common::ascii_to_ucs2(path, &mut file_paths[0].filename); + &mut file_paths[0].device_path // Pointer to first path entry +} + +fn new_image_handle( + file_path: *mut r_efi::protocols::device_path::Protocol, + parent_handle: Handle, + device_handle: Handle, + load_addr: u64, + load_size: u64, + entry_addr: u64, +) -> *mut LoadedImageWrapper { let mut image = null_mut(); - allocate_pool( + let status = allocate_pool( efi::LOADER_DATA, size_of::(), &mut image as *mut *mut c_void, @@ -1100,7 +1104,7 @@ fn new_image_handle( parent_handle, system_table: unsafe { &mut ST }, device_handle, - file_path: &mut file_paths[0].device_path, // Pointer to first path entry + file_path, load_options_size: 0, load_options: null_mut(), image_base: load_addr as *mut _, @@ -1196,7 +1200,7 @@ pub fn efi_exec( let wrapped_fs = file::FileSystemWrapper::new(fs, efi_part_id); let image = new_image_handle( - crate::efi::EFI_BOOT_PATH, + file_device_path(crate::efi::EFI_BOOT_PATH), 0 as Handle, &wrapped_fs as *const _ as Handle, loaded_address, From a20c2341af62d509ef15cc2a37641accb94ba824 Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Mon, 18 Dec 2023 17:29:46 +0000 Subject: [PATCH 03/10] efi: Refactor EFI device path generatation for loaded image Add a DevicePath::generate() method to generate the device path from the parsed device path. Signed-off-by: Rob Bradford --- src/efi/mod.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/efi/mod.rs b/src/efi/mod.rs index 8f2d915b..92894c67 100644 --- a/src/efi/mod.rs +++ b/src/efi/mod.rs @@ -654,9 +654,9 @@ pub extern "efiapi" fn load_image( use crate::fat::Read; let device_path = unsafe { &*device_path }; - match DevicePath::parse(device_path) { - DevicePath::File(path) => { - let path = crate::common::ascii_strip(&path); + match &DevicePath::parse(device_path) { + dp @ DevicePath::File(path) => { + let path = crate::common::ascii_strip(path); let li = parent_image_handle as *const LoadedImageWrapper; let dh = unsafe { (*li).proto.device_handle }; @@ -690,7 +690,7 @@ pub extern "efiapi" fn load_image( ); let image = new_image_handle( - file_device_path(path), + dp.generate(), parent_image_handle, wrapped_fs_ref as *const _ as Handle, load_addr, @@ -962,6 +962,13 @@ impl DevicePath { dpp = unsafe { &*((dpp as *const _ as u64 + len as u64) as *const _) }; } } + + fn generate(&self) -> *mut r_efi::protocols::device_path::Protocol { + match self { + Self::File(path) => file_device_path(crate::common::ascii_strip(path)), + Self::Unsupported => panic!("Cannot generate from unsupported Device Path type"), + } + } } const PAGE_SIZE: u64 = 4096; From 151643ba866ac7e1a50eabac117a162b9a556274 Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Mon, 18 Dec 2023 17:37:07 +0000 Subject: [PATCH 04/10] efi: Use DevicePath::generate() for executing the main EFI binary Signed-off-by: Rob Bradford --- src/efi/mod.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/efi/mod.rs b/src/efi/mod.rs index 92894c67..4f22181d 100644 --- a/src/efi/mod.rs +++ b/src/efi/mod.rs @@ -1206,8 +1206,12 @@ pub fn efi_exec( let wrapped_fs = file::FileSystemWrapper::new(fs, efi_part_id); + let mut path = [0u8; 256]; + path[0..crate::efi::EFI_BOOT_PATH.as_bytes().len()] + .copy_from_slice(crate::efi::EFI_BOOT_PATH.as_bytes()); + let device_path = DevicePath::File(path); let image = new_image_handle( - file_device_path(crate::efi::EFI_BOOT_PATH), + device_path.generate(), 0 as Handle, &wrapped_fs as *const _ as Handle, loaded_address, From f6ebfc3df54859dc41417fc90d6cb9d3f5215eb2 Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Tue, 19 Dec 2023 14:32:54 +0000 Subject: [PATCH 05/10] efi: Move FileDevicePathProtocol struct to where it is used Signed-off-by: Rob Bradford --- src/efi/file.rs | 9 +-------- src/efi/mod.rs | 12 +++++++++--- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/efi/file.rs b/src/efi/file.rs index ce2b6a42..19634536 100644 --- a/src/efi/file.rs +++ b/src/efi/file.rs @@ -6,19 +6,12 @@ use core::ffi::c_void; use r_efi::{ efi::{self, Char16, Guid, Status}, protocols::{ - device_path::Protocol as DevicePathProtocol, file::Protocol as FileProtocol, - simple_file_system::Protocol as SimpleFileSystemProtocol, + file::Protocol as FileProtocol, simple_file_system::Protocol as SimpleFileSystemProtocol, }, }; use crate::block::SectorBuf; -#[repr(C)] -pub struct FileDevicePathProtocol { - pub device_path: DevicePathProtocol, - pub filename: [u16; 64], -} - pub extern "efiapi" fn filesystem_open_volume( fs_proto: *mut SimpleFileSystemProtocol, file: *mut *mut FileProtocol, diff --git a/src/efi/mod.rs b/src/efi/mod.rs index 4f22181d..5fde4a41 100644 --- a/src/efi/mod.rs +++ b/src/efi/mod.rs @@ -1051,7 +1051,13 @@ struct LoadedImageWrapper { entry_point: u64, } -type DevicePaths = [file::FileDevicePathProtocol; 2]; +#[repr(C)] +struct FileDevicePathProtocol { + pub device_path: DevicePathProtocol, + pub filename: [u16; 64], +} + +type DevicePaths = [FileDevicePathProtocol; 2]; fn file_device_path(path: &str) -> *mut r_efi::protocols::device_path::Protocol { let mut file_paths = null_mut(); @@ -1063,7 +1069,7 @@ fn file_device_path(path: &str) -> *mut r_efi::protocols::device_path::Protocol assert!(status == Status::SUCCESS); let file_paths = unsafe { &mut *(file_paths as *mut DevicePaths) }; *file_paths = [ - file::FileDevicePathProtocol { + FileDevicePathProtocol { device_path: DevicePathProtocol { r#type: r_efi::protocols::device_path::TYPE_MEDIA, sub_type: 4, // Media Path type file @@ -1071,7 +1077,7 @@ fn file_device_path(path: &str) -> *mut r_efi::protocols::device_path::Protocol }, filename: [0; 64], }, - file::FileDevicePathProtocol { + FileDevicePathProtocol { device_path: DevicePathProtocol { r#type: r_efi::protocols::device_path::TYPE_END, sub_type: 0xff, // End of full path From 67aaef6a94cec04e289dcdaa7c3a3f4cc569fb79 Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Tue, 19 Dec 2023 14:15:30 +0000 Subject: [PATCH 06/10] efi: Consistently support filenames up to 256 characters Previously the path in the FileDevicePathProtocol was limited to 128 ascii characters. Signed-off-by: Rob Bradford --- src/efi/mod.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/efi/mod.rs b/src/efi/mod.rs index 5fde4a41..0f3d1a40 100644 --- a/src/efi/mod.rs +++ b/src/efi/mod.rs @@ -1054,7 +1054,7 @@ struct LoadedImageWrapper { #[repr(C)] struct FileDevicePathProtocol { pub device_path: DevicePathProtocol, - pub filename: [u16; 64], + pub filename: [u16; 256], } type DevicePaths = [FileDevicePathProtocol; 2]; @@ -1073,17 +1073,17 @@ fn file_device_path(path: &str) -> *mut r_efi::protocols::device_path::Protocol device_path: DevicePathProtocol { r#type: r_efi::protocols::device_path::TYPE_MEDIA, sub_type: 4, // Media Path type file - length: [132, 0], + length: (size_of::() as u16).to_le_bytes(), }, - filename: [0; 64], + filename: [0; 256], }, FileDevicePathProtocol { device_path: DevicePathProtocol { r#type: r_efi::protocols::device_path::TYPE_END, - sub_type: 0xff, // End of full path - length: [4, 0], + sub_type: r_efi::protocols::device_path::End::SUBTYPE_ENTIRE, + length: (size_of::() as u16).to_le_bytes(), }, - filename: [0; 64], + filename: [0; 256], }, ]; From 527de2aaf54d61929d541d11338e052950251101 Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Tue, 19 Dec 2023 14:56:23 +0000 Subject: [PATCH 07/10] efi: Clarify naming of type for two FileDevicePathProtocol This will prevent it clashing when generating other types of device paths. Signed-off-by: Rob Bradford --- src/efi/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/efi/mod.rs b/src/efi/mod.rs index 0f3d1a40..71e466d2 100644 --- a/src/efi/mod.rs +++ b/src/efi/mod.rs @@ -1057,17 +1057,17 @@ struct FileDevicePathProtocol { pub filename: [u16; 256], } -type DevicePaths = [FileDevicePathProtocol; 2]; +type FileDevicePaths = [FileDevicePathProtocol; 2]; fn file_device_path(path: &str) -> *mut r_efi::protocols::device_path::Protocol { let mut file_paths = null_mut(); let status = allocate_pool( efi::LOADER_DATA, - size_of::(), + size_of::(), &mut file_paths as *mut *mut c_void, ); assert!(status == Status::SUCCESS); - let file_paths = unsafe { &mut *(file_paths as *mut DevicePaths) }; + let file_paths = unsafe { &mut *(file_paths as *mut FileDevicePaths) }; *file_paths = [ FileDevicePathProtocol { device_path: DevicePathProtocol { From 7e6857c9dc426e50cf665d68f715f9b6790f7bdb Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Tue, 19 Dec 2023 15:08:48 +0000 Subject: [PATCH 08/10] efi: Add support for memory mapped device path Signed-off-by: Rob Bradford --- src/efi/mod.rs | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/src/efi/mod.rs b/src/efi/mod.rs index 71e466d2..ddad1249 100644 --- a/src/efi/mod.rs +++ b/src/efi/mod.rs @@ -940,6 +940,7 @@ extern "efiapi" fn image_unload(_: Handle) -> Status { #[allow(clippy::large_enum_variant)] enum DevicePath { File([u8; 256]), + Memory(MemoryType, u64, u64), Unsupported, } @@ -954,6 +955,24 @@ impl DevicePath { crate::common::ucs2_to_ascii(ptr, &mut path); return DevicePath::File(path); } + if dpp.r#type == r_efi::protocols::device_path::TYPE_HARDWARE + && dpp.sub_type == r_efi::protocols::device_path::Hardware::SUBTYPE_MMAP + { + let memory_type_ptr = (dpp as *const _ as usize + + offset_of!(MemoryDevicePathProtocol, memory_type)) + as *const MemoryType; + let start_ptr = (dpp as *const _ as usize + + offset_of!(MemoryDevicePathProtocol, start)) + as *const u64; + let end_ptr = (dpp as *const _ as usize + offset_of!(MemoryDevicePathProtocol, end)) + as *const u64; + return DevicePath::Memory( + unsafe { *memory_type_ptr }, + unsafe { *start_ptr }, + unsafe { *end_ptr }, + ); + } + if dpp.r#type == r_efi::protocols::device_path::TYPE_END && dpp.sub_type == 0xff { log!("Unexpected end of device path"); return DevicePath::Unsupported; @@ -966,6 +985,7 @@ impl DevicePath { fn generate(&self) -> *mut r_efi::protocols::device_path::Protocol { match self { Self::File(path) => file_device_path(crate::common::ascii_strip(path)), + Self::Memory(memory_type, start, end) => memory_device_path(*memory_type, *start, *end), Self::Unsupported => panic!("Cannot generate from unsupported Device Path type"), } } @@ -1092,6 +1112,55 @@ fn file_device_path(path: &str) -> *mut r_efi::protocols::device_path::Protocol &mut file_paths[0].device_path // Pointer to first path entry } +#[repr(C)] +struct MemoryDevicePathProtocol { + pub device_path: DevicePathProtocol, + pub memory_type: u32, + pub start: u64, + pub end: u64, +} + +type MemoryDevicePaths = [MemoryDevicePathProtocol; 2]; + +fn memory_device_path( + memory_type: MemoryType, + start: u64, + end: u64, +) -> *mut r_efi::protocols::device_path::Protocol { + let mut memory_paths = null_mut(); + let status = allocate_pool( + efi::LOADER_DATA, + size_of::(), + &mut memory_paths as *mut *mut c_void, + ); + assert!(status == Status::SUCCESS); + let memory_paths = unsafe { &mut *(memory_paths as *mut MemoryDevicePaths) }; + *memory_paths = [ + MemoryDevicePathProtocol { + device_path: DevicePathProtocol { + r#type: r_efi::protocols::device_path::TYPE_HARDWARE, + sub_type: r_efi::protocols::device_path::Hardware::SUBTYPE_MMAP, + length: (size_of::() as u16).to_le_bytes(), + }, + memory_type, + start, + end, + }, + MemoryDevicePathProtocol { + device_path: DevicePathProtocol { + r#type: r_efi::protocols::device_path::TYPE_END, + sub_type: r_efi::protocols::device_path::End::SUBTYPE_ENTIRE, + length: (size_of::() as u16).to_le_bytes(), + }, + memory_type: 0, + start: 0, + end: 0, + }, + ]; + + &mut memory_paths[0].device_path // Pointer to first path entry +} + fn new_image_handle( file_path: *mut r_efi::protocols::device_path::Protocol, parent_handle: Handle, From ca865389f06780ddaf050fac3717c11450c8604c Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Tue, 19 Dec 2023 16:33:25 +0000 Subject: [PATCH 09/10] efi: Add support for booting from a memory mapped device path Grub will load the kernel into memory and ask the firmware to parse that as a PE binary. In order to reuse the existing infrastructure the memory range provided is turned into a struct that implements the fat::Read trait. Signed-off-by: Rob Bradford --- src/efi/mod.rs | 108 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 106 insertions(+), 2 deletions(-) diff --git a/src/efi/mod.rs b/src/efi/mod.rs index ddad1249..14feece7 100644 --- a/src/efi/mod.rs +++ b/src/efi/mod.rs @@ -8,6 +8,7 @@ use core::{ ffi::c_void, mem::{size_of, transmute}, ptr::null_mut, + slice::from_raw_parts, }; use atomic_refcell::AtomicRefCell; @@ -28,9 +29,9 @@ use r_efi::{ #[cfg(target_arch = "riscv64")] use r_efi::{eficall, eficall_abi}; -use crate::bootinfo; -use crate::layout; use crate::rtc; +use crate::{block::SectorBuf, layout}; +use crate::{bootinfo, fat}; mod alloc; mod block; @@ -643,6 +644,71 @@ pub extern "efiapi" fn install_configuration_table(guid: *mut Guid, table: *mut Status::OUT_OF_RESOURCES } +struct MemoryFile { + address: u64, + size: u32, + position: u32, +} + +impl MemoryFile { + fn new(address: u64, size: u32) -> Self { + MemoryFile { + address, + size, + position: 0, + } + } +} + +impl fat::Read for MemoryFile { + fn get_size(&self) -> u32 { + self.size + } + + fn read(&mut self, data: &mut [u8]) -> Result { + let sector_size = SectorBuf::len() as u32; + assert_eq!(data.len(), SectorBuf::len()); + + if (self.position + sector_size) > self.size { + let bytes_read = self.size - self.position; + let memory = unsafe { + from_raw_parts( + (self.address + self.position as u64) as *const u8, + bytes_read as usize, + ) + }; + data[0..bytes_read as usize].copy_from_slice(memory); + self.position = self.size; + Ok(bytes_read) + } else { + let memory = unsafe { + from_raw_parts( + (self.address + self.position as u64) as *const u8, + sector_size as usize, + ) + }; + data[0..sector_size as usize].copy_from_slice(memory); + self.position += sector_size; + Ok(sector_size) + } + } + + fn seek(&mut self, position: u32) -> Result<(), fat::Error> { + let sector_size = SectorBuf::len() as u32; + if position % sector_size != 0 { + return Err(fat::Error::InvalidOffset); + } + + if position >= self.size { + return Err(fat::Error::EndOfFile); + } + + self.position = position; + + Ok(()) + } +} + pub extern "efiapi" fn load_image( _boot_policy: Boolean, parent_image_handle: Handle, @@ -702,6 +768,44 @@ pub extern "efiapi" fn load_image( Status::SUCCESS } + dp @ DevicePath::Memory(_memory_type, start, end) => { + let mut file = MemoryFile::new(*start, (*end - *start) as u32); + let file_size = (file.get_size() as u64 + PAGE_SIZE - 1) / PAGE_SIZE; + // Get free pages address + let load_addr = + match ALLOCATOR + .borrow_mut() + .find_free_pages(efi::ALLOCATE_ANY_PAGES, file_size, 0) + { + Some(a) => a, + None => return Status::OUT_OF_RESOURCES, + }; + + let mut l = crate::pe::Loader::new(&mut file); + let (entry_addr, load_addr, load_size) = match l.load(load_addr) { + Ok(load_info) => load_info, + Err(_) => return Status::DEVICE_ERROR, + }; + ALLOCATOR.borrow_mut().allocate_pages( + efi::ALLOCATE_ADDRESS, + efi::LOADER_CODE, + file_size, + load_addr, + ); + + let image = new_image_handle( + dp.generate(), + parent_image_handle, + null_mut(), + load_addr, + load_size, + entry_addr, + ); + + unsafe { *image_handle = image as *mut _ as *mut c_void }; + + Status::SUCCESS + } _ => Status::UNSUPPORTED, } } From 70e286b18ae8484c16bdf319c011714cd319e5be Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Tue, 19 Dec 2023 18:03:02 +0000 Subject: [PATCH 10/10] efi: Refactor code for loading image Remove some duplicated code for loading an image by extracting it out to its own function. Signed-off-by: Rob Bradford --- src/efi/mod.rs | 124 +++++++++++++++++++++---------------------------- 1 file changed, 53 insertions(+), 71 deletions(-) diff --git a/src/efi/mod.rs b/src/efi/mod.rs index 14feece7..91e3ed33 100644 --- a/src/efi/mod.rs +++ b/src/efi/mod.rs @@ -717,8 +717,6 @@ pub extern "efiapi" fn load_image( _source_size: usize, image_handle: *mut Handle, ) -> Status { - use crate::fat::Read; - let device_path = unsafe { &*device_path }; match &DevicePath::parse(device_path) { dp @ DevicePath::File(path) => { @@ -727,89 +725,73 @@ pub extern "efiapi" fn load_image( let li = parent_image_handle as *const LoadedImageWrapper; let dh = unsafe { (*li).proto.device_handle }; let wrapped_fs_ref = unsafe { &*(dh as *const file::FileSystemWrapper) }; + let device_handle = wrapped_fs_ref as *const _ as Handle; + let mut file = match wrapped_fs_ref.fs.open(path) { Ok(file) => file, Err(_) => return Status::DEVICE_ERROR, }; - let file_size = (file.get_size() as u64 + PAGE_SIZE - 1) / PAGE_SIZE; - // Get free pages address - let load_addr = - match ALLOCATOR - .borrow_mut() - .find_free_pages(efi::ALLOCATE_ANY_PAGES, file_size, 0) - { - Some(a) => a, - None => return Status::OUT_OF_RESOURCES, - }; - - let mut l = crate::pe::Loader::new(&mut file); - let (entry_addr, load_addr, load_size) = match l.load(load_addr) { - Ok(load_info) => load_info, - Err(_) => return Status::DEVICE_ERROR, - }; - ALLOCATOR.borrow_mut().allocate_pages( - efi::ALLOCATE_ADDRESS, - efi::LOADER_CODE, - file_size, - load_addr, - ); - - let image = new_image_handle( - dp.generate(), + load_from_file( + &mut file, + dp, parent_image_handle, - wrapped_fs_ref as *const _ as Handle, - load_addr, - load_size, - entry_addr, - ); - - unsafe { *image_handle = image as *mut _ as *mut c_void }; - - Status::SUCCESS + device_handle, + image_handle, + ) } dp @ DevicePath::Memory(_memory_type, start, end) => { let mut file = MemoryFile::new(*start, (*end - *start) as u32); - let file_size = (file.get_size() as u64 + PAGE_SIZE - 1) / PAGE_SIZE; - // Get free pages address - let load_addr = - match ALLOCATOR - .borrow_mut() - .find_free_pages(efi::ALLOCATE_ANY_PAGES, file_size, 0) - { - Some(a) => a, - None => return Status::OUT_OF_RESOURCES, - }; - - let mut l = crate::pe::Loader::new(&mut file); - let (entry_addr, load_addr, load_size) = match l.load(load_addr) { - Ok(load_info) => load_info, - Err(_) => return Status::DEVICE_ERROR, - }; - ALLOCATOR.borrow_mut().allocate_pages( - efi::ALLOCATE_ADDRESS, - efi::LOADER_CODE, - file_size, - load_addr, - ); - - let image = new_image_handle( - dp.generate(), - parent_image_handle, - null_mut(), - load_addr, - load_size, - entry_addr, - ); - - unsafe { *image_handle = image as *mut _ as *mut c_void }; - - Status::SUCCESS + load_from_file(&mut file, dp, parent_image_handle, null_mut(), image_handle) } _ => Status::UNSUPPORTED, } } +fn load_from_file( + file: &mut dyn fat::Read, + dp: &DevicePath, + parent_image_handle: *mut c_void, + device_handle: *mut c_void, + image_handle: *mut *mut c_void, +) -> Status { + let file_size = (file.get_size() as u64 + PAGE_SIZE - 1) / PAGE_SIZE; + // Get free pages address + let load_addr = + match ALLOCATOR + .borrow_mut() + .find_free_pages(efi::ALLOCATE_ANY_PAGES, file_size, 0) + { + Some(a) => a, + None => return Status::OUT_OF_RESOURCES, + }; + + let mut l = crate::pe::Loader::new(file); + let (entry_addr, load_addr, load_size) = match l.load(load_addr) { + Ok(load_info) => load_info, + Err(_) => return Status::DEVICE_ERROR, + }; + ALLOCATOR.borrow_mut().allocate_pages( + efi::ALLOCATE_ADDRESS, + efi::LOADER_CODE, + file_size, + load_addr, + ); + + let image = new_image_handle( + dp.generate(), + parent_image_handle, + device_handle, + load_addr, + load_size, + entry_addr, + ); + + unsafe { *image_handle = image as *mut c_void }; + + Status::SUCCESS +} + pub extern "efiapi" fn start_image( image_handle: Handle, _: *mut usize,