mirror of
https://github.com/ZeroOSProject/ZeroOS.git
synced 2026-09-13 00:24:41 +08:00
180 lines
4.5 KiB
Rust
180 lines
4.5 KiB
Rust
use core::ffi::c_void;
|
|
|
|
use crate::efi::{
|
|
EFI_LOADED_IMAGE_PROTOCOL_GUID, EFI_NOT_FOUND, EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID,
|
|
EFI_SUCCESS, EfiBootServices, EfiGuid, EfiHandle, EfiLoadedImageProtocol, EfiStatus,
|
|
};
|
|
use crate::memory::{PAGE_SIZE, PhysicalMemoryManager};
|
|
|
|
pub const BASH_PATH: &[u16] = &[
|
|
'\\' as u16,
|
|
'b' as u16,
|
|
'i' as u16,
|
|
'n' as u16,
|
|
'\\' as u16,
|
|
'b' as u16,
|
|
'a' as u16,
|
|
's' as u16,
|
|
'h' as u16,
|
|
0,
|
|
];
|
|
|
|
pub const SH_PATH: &[u16] = &[
|
|
'\\' as u16,
|
|
'b' as u16,
|
|
'i' as u16,
|
|
'n' as u16,
|
|
'\\' as u16,
|
|
's' as u16,
|
|
'h' as u16,
|
|
0,
|
|
];
|
|
|
|
const EFI_FILE_MODE_READ: u64 = 1;
|
|
const EFI_FILE_INFO_GUID: EfiGuid = EfiGuid::new(
|
|
0x09576e92,
|
|
0x6d3f,
|
|
0x11d2,
|
|
[0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b],
|
|
);
|
|
|
|
pub struct LoadedFile {
|
|
pub ptr: *const u8,
|
|
pub len: usize,
|
|
}
|
|
|
|
#[repr(C)]
|
|
struct EfiSimpleFileSystemProtocol {
|
|
revision: u64,
|
|
open_volume: extern "efiapi" fn(
|
|
this: *mut EfiSimpleFileSystemProtocol,
|
|
root: *mut *mut EfiFileProtocol,
|
|
) -> EfiStatus,
|
|
}
|
|
|
|
#[repr(C)]
|
|
struct EfiFileProtocol {
|
|
revision: u64,
|
|
open: extern "efiapi" fn(
|
|
this: *mut EfiFileProtocol,
|
|
new_handle: *mut *mut EfiFileProtocol,
|
|
file_name: *const u16,
|
|
open_mode: u64,
|
|
attributes: u64,
|
|
) -> EfiStatus,
|
|
close: extern "efiapi" fn(this: *mut EfiFileProtocol) -> EfiStatus,
|
|
delete: usize,
|
|
read: extern "efiapi" fn(
|
|
this: *mut EfiFileProtocol,
|
|
buffer_size: *mut usize,
|
|
buffer: *mut c_void,
|
|
) -> EfiStatus,
|
|
write: usize,
|
|
get_position: usize,
|
|
set_position: usize,
|
|
get_info: extern "efiapi" fn(
|
|
this: *mut EfiFileProtocol,
|
|
information_type: *const EfiGuid,
|
|
buffer_size: *mut usize,
|
|
buffer: *mut c_void,
|
|
) -> EfiStatus,
|
|
}
|
|
|
|
#[repr(C)]
|
|
struct EfiFileInfoPrefix {
|
|
size: u64,
|
|
file_size: u64,
|
|
physical_size: u64,
|
|
}
|
|
|
|
pub unsafe fn load_file(
|
|
image_handle: EfiHandle,
|
|
boot_services: *mut EfiBootServices,
|
|
memory: &mut PhysicalMemoryManager,
|
|
path: &[u16],
|
|
) -> Option<LoadedFile> {
|
|
let mut loaded_image = core::ptr::null_mut();
|
|
let status = unsafe {
|
|
((*boot_services).handle_protocol)(
|
|
image_handle,
|
|
&EFI_LOADED_IMAGE_PROTOCOL_GUID,
|
|
&mut loaded_image,
|
|
)
|
|
};
|
|
if status != EFI_SUCCESS || loaded_image.is_null() {
|
|
return None;
|
|
}
|
|
|
|
let loaded_image = loaded_image as *mut EfiLoadedImageProtocol;
|
|
let mut fs = core::ptr::null_mut();
|
|
let status = unsafe {
|
|
((*boot_services).handle_protocol)(
|
|
(*loaded_image).device_handle,
|
|
&EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID,
|
|
&mut fs,
|
|
)
|
|
};
|
|
if status != EFI_SUCCESS || fs.is_null() {
|
|
return None;
|
|
}
|
|
|
|
let fs = fs as *mut EfiSimpleFileSystemProtocol;
|
|
let mut root = core::ptr::null_mut();
|
|
let status = unsafe { ((*fs).open_volume)(fs, &mut root) };
|
|
if status != EFI_SUCCESS || root.is_null() {
|
|
return None;
|
|
}
|
|
|
|
let mut file = core::ptr::null_mut();
|
|
let status = unsafe { ((*root).open)(root, &mut file, path.as_ptr(), EFI_FILE_MODE_READ, 0) };
|
|
unsafe {
|
|
((*root).close)(root);
|
|
}
|
|
if status == EFI_NOT_FOUND || status != EFI_SUCCESS || file.is_null() {
|
|
return None;
|
|
}
|
|
|
|
let size = unsafe { file_size(file)? };
|
|
let pages = size.div_ceil(PAGE_SIZE).max(1);
|
|
let buffer = memory.alloc_pages(pages)?;
|
|
let mut read_len = size;
|
|
let status = unsafe { ((*file).read)(file, &mut read_len, buffer.cast::<c_void>()) };
|
|
unsafe {
|
|
((*file).close)(file);
|
|
}
|
|
|
|
if status != EFI_SUCCESS || read_len == 0 {
|
|
unsafe {
|
|
memory.free_pages(buffer, pages);
|
|
}
|
|
return None;
|
|
}
|
|
|
|
Some(LoadedFile {
|
|
ptr: buffer as *const u8,
|
|
len: read_len,
|
|
})
|
|
}
|
|
|
|
unsafe fn file_size(file: *mut EfiFileProtocol) -> Option<usize> {
|
|
let mut info_buffer = [0u8; 1024];
|
|
let mut info_size = info_buffer.len();
|
|
let status = unsafe {
|
|
((*file).get_info)(
|
|
file,
|
|
&EFI_FILE_INFO_GUID,
|
|
&mut info_size,
|
|
info_buffer.as_mut_ptr().cast::<c_void>(),
|
|
)
|
|
};
|
|
if status != EFI_SUCCESS {
|
|
return None;
|
|
}
|
|
if info_size < core::mem::size_of::<EfiFileInfoPrefix>() {
|
|
return None;
|
|
}
|
|
|
|
let info = unsafe { &*(info_buffer.as_ptr() as *const EfiFileInfoPrefix) };
|
|
usize::try_from(info.file_size).ok()
|
|
}
|