morpheus_bootloader/uefi/file_system/
operations.rsuse super::{FileProtocol, LoadedImageProtocol, EFI_FILE_MODE_READ, LOADED_IMAGE_PROTOCOL_GUID};
use crate::BootServices;
pub fn ascii_to_utf16(ascii: &str, buf: &mut [u16]) -> usize {
let mut i = 0;
for (idx, byte) in ascii.bytes().enumerate() {
if idx >= buf.len() - 1 {
break;
}
buf[idx] = byte as u16;
i = idx + 1;
}
buf[i] = 0; i + 1
}
pub unsafe fn get_loaded_image(
bs: &BootServices,
image_handle: *mut (),
) -> Result<*mut LoadedImageProtocol, ()> {
let mut loaded_image: *mut () = core::ptr::null_mut();
let status = (bs.handle_protocol)(image_handle, &LOADED_IMAGE_PROTOCOL_GUID, &mut loaded_image);
if status != 0 {
return Err(());
}
Ok(loaded_image as *mut LoadedImageProtocol)
}
pub unsafe fn get_pe_file_size(image_base: *const u8) -> Result<usize, ()> {
let dos_signature = u16::from_le_bytes([*image_base, *image_base.offset(1)]);
if dos_signature != 0x5A4D {
return Err(());
}
let pe_offset = u32::from_le_bytes([
*image_base.offset(0x3C),
*image_base.offset(0x3D),
*image_base.offset(0x3E),
*image_base.offset(0x3F),
]) as isize;
let pe_sig = u32::from_le_bytes([
*image_base.offset(pe_offset),
*image_base.offset(pe_offset + 1),
*image_base.offset(pe_offset + 2),
*image_base.offset(pe_offset + 3),
]);
if pe_sig != 0x00004550 {
return Err(());
}
let coff_header = pe_offset + 4;
let num_sections = u16::from_le_bytes([
*image_base.offset(coff_header + 0x02),
*image_base.offset(coff_header + 0x03),
]) as usize;
let opt_header_size = u16::from_le_bytes([
*image_base.offset(coff_header + 0x10),
*image_base.offset(coff_header + 0x11),
]) as isize;
let section_table = pe_offset + 4 + 20 + opt_header_size;
let mut max_file_offset = 0usize;
for i in 0..num_sections {
let section_header = section_table + (i as isize * 40);
let size_of_raw_data = u32::from_le_bytes([
*image_base.offset(section_header + 0x10),
*image_base.offset(section_header + 0x11),
*image_base.offset(section_header + 0x12),
*image_base.offset(section_header + 0x13),
]) as usize;
let pointer_to_raw_data = u32::from_le_bytes([
*image_base.offset(section_header + 0x14),
*image_base.offset(section_header + 0x15),
*image_base.offset(section_header + 0x16),
*image_base.offset(section_header + 0x17),
]) as usize;
if size_of_raw_data > 0 && pointer_to_raw_data > 0 {
let section_end = pointer_to_raw_data + size_of_raw_data;
if section_end > max_file_offset {
max_file_offset = section_end;
}
}
}
if max_file_offset == 0 {
return Err(());
}
Ok(max_file_offset)
}
pub fn restore_pe_image_base(pe_data: &mut [u8]) -> Result<(), ()> {
if pe_data.len() < 0x40 {
return Err(());
}
let dos_sig = u16::from_le_bytes([pe_data[0], pe_data[1]]);
if dos_sig != 0x5A4D {
return Err(());
}
let pe_offset =
u32::from_le_bytes([pe_data[0x3C], pe_data[0x3D], pe_data[0x3E], pe_data[0x3F]]) as usize;
if pe_offset + 0xB8 > pe_data.len() {
return Err(());
}
let pe_sig = u32::from_le_bytes([
pe_data[pe_offset],
pe_data[pe_offset + 1],
pe_data[pe_offset + 2],
pe_data[pe_offset + 3],
]);
if pe_sig != 0x00004550 {
return Err(());
}
let image_base_offset = pe_offset + 4 + 20 + 0x18;
let original_image_base = 0x0000000000400000u64;
pe_data[image_base_offset..image_base_offset + 8]
.copy_from_slice(&original_image_base.to_le_bytes());
Ok(())
}
pub unsafe fn open_file_read(
root: *mut FileProtocol,
path: &[u16],
) -> Result<*mut FileProtocol, usize> {
let mut file: *mut FileProtocol = core::ptr::null_mut();
let status = ((*root).open)(root, &mut file, path.as_ptr(), EFI_FILE_MODE_READ, 0);
if status != 0 {
return Err(status);
}
Ok(file)
}