mirror of
https://github.com/ZeroOSProject/ZeroOS.git
synced 2026-09-13 01:14:43 +08:00
vi and busybox
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
[package]
|
||||
name = "zeroos-loader"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
@@ -0,0 +1,352 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use core::mem::size_of;
|
||||
use core::panic::PanicInfo;
|
||||
use core::ptr::{copy_nonoverlapping, null_mut};
|
||||
|
||||
type EfiHandle = *mut core::ffi::c_void;
|
||||
type EfiStatus = usize;
|
||||
|
||||
const EFI_SUCCESS: EfiStatus = 0;
|
||||
const EFI_LOAD_ERROR: EfiStatus = 1;
|
||||
const EFI_BUFFER_TOO_SMALL: EfiStatus = 5;
|
||||
|
||||
const EFI_LOADED_IMAGE_PROTOCOL_GUID: EfiGuid = EfiGuid::new(
|
||||
0x5b1b31a1,
|
||||
0x9562,
|
||||
0x11d2,
|
||||
[0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b],
|
||||
);
|
||||
|
||||
const EFI_DEVICE_PATH_PROTOCOL_GUID: EfiGuid = EfiGuid::new(
|
||||
0x09576e91,
|
||||
0x6d3f,
|
||||
0x11d2,
|
||||
[0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b],
|
||||
);
|
||||
|
||||
const MEDIA_DEVICE_PATH: u8 = 0x04;
|
||||
const MEDIA_FILEPATH_DP: u8 = 0x04;
|
||||
const END_DEVICE_PATH_TYPE: u8 = 0x7f;
|
||||
const END_ENTIRE_DEVICE_PATH_SUBTYPE: u8 = 0xff;
|
||||
|
||||
static ZEROOS_PATH: [u16; 23] = [
|
||||
'\\' as u16,
|
||||
'E' as u16,
|
||||
'F' as u16,
|
||||
'I' as u16,
|
||||
'\\' as u16,
|
||||
'Z' as u16,
|
||||
'e' as u16,
|
||||
'r' as u16,
|
||||
'o' as u16,
|
||||
'O' as u16,
|
||||
'S' as u16,
|
||||
'\\' as u16,
|
||||
'Z' as u16,
|
||||
'e' as u16,
|
||||
'r' as u16,
|
||||
'o' as u16,
|
||||
'O' as u16,
|
||||
'S' as u16,
|
||||
'.' as u16,
|
||||
'E' as u16,
|
||||
'F' as u16,
|
||||
'I' as u16,
|
||||
0,
|
||||
];
|
||||
|
||||
static LOADING: [u16; 22] = [
|
||||
'L' as u16,
|
||||
'o' as u16,
|
||||
'a' as u16,
|
||||
'd' as u16,
|
||||
'i' as u16,
|
||||
'n' as u16,
|
||||
'g' as u16,
|
||||
' ' as u16,
|
||||
'Z' as u16,
|
||||
'e' as u16,
|
||||
'r' as u16,
|
||||
'o' as u16,
|
||||
'O' as u16,
|
||||
'S' as u16,
|
||||
'.' as u16,
|
||||
'.' as u16,
|
||||
'.' as u16,
|
||||
'\r' as u16,
|
||||
'\n' as u16,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
];
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
struct EfiGuid {
|
||||
data1: u32,
|
||||
data2: u16,
|
||||
data3: u16,
|
||||
data4: [u8; 8],
|
||||
}
|
||||
|
||||
impl EfiGuid {
|
||||
const fn new(data1: u32, data2: u16, data3: u16, data4: [u8; 8]) -> Self {
|
||||
Self {
|
||||
data1,
|
||||
data2,
|
||||
data3,
|
||||
data4,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct EfiTableHeader {
|
||||
signature: u64,
|
||||
revision: u32,
|
||||
header_size: u32,
|
||||
crc32: u32,
|
||||
reserved: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct EfiSystemTable {
|
||||
hdr: EfiTableHeader,
|
||||
firmware_vendor: *mut u16,
|
||||
firmware_revision: u32,
|
||||
console_in_handle: EfiHandle,
|
||||
con_in: *mut core::ffi::c_void,
|
||||
console_out_handle: EfiHandle,
|
||||
con_out: *mut EfiSimpleTextOutputProtocol,
|
||||
standard_error_handle: EfiHandle,
|
||||
std_err: *mut EfiSimpleTextOutputProtocol,
|
||||
runtime_services: *mut core::ffi::c_void,
|
||||
boot_services: *mut EfiBootServices,
|
||||
number_of_table_entries: usize,
|
||||
configuration_table: *mut core::ffi::c_void,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct EfiSimpleTextOutputProtocol {
|
||||
reset: usize,
|
||||
output_string:
|
||||
extern "efiapi" fn(this: *mut EfiSimpleTextOutputProtocol, string: *const u16) -> EfiStatus,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct EfiBootServices {
|
||||
hdr: EfiTableHeader,
|
||||
raise_tpl: usize,
|
||||
restore_tpl: usize,
|
||||
allocate_pages: usize,
|
||||
free_pages: usize,
|
||||
get_memory_map: usize,
|
||||
allocate_pool: usize,
|
||||
free_pool: usize,
|
||||
create_event: usize,
|
||||
set_timer: usize,
|
||||
wait_for_event: usize,
|
||||
signal_event: usize,
|
||||
close_event: usize,
|
||||
check_event: usize,
|
||||
install_protocol_interface: usize,
|
||||
reinstall_protocol_interface: usize,
|
||||
uninstall_protocol_interface: usize,
|
||||
handle_protocol: extern "efiapi" fn(
|
||||
handle: EfiHandle,
|
||||
protocol: *const EfiGuid,
|
||||
interface: *mut *mut core::ffi::c_void,
|
||||
) -> EfiStatus,
|
||||
reserved: usize,
|
||||
register_protocol_notify: usize,
|
||||
locate_handle: usize,
|
||||
locate_device_path: usize,
|
||||
install_configuration_table: usize,
|
||||
load_image: extern "efiapi" fn(
|
||||
boot_policy: u8,
|
||||
parent_image_handle: EfiHandle,
|
||||
device_path: *const EfiDevicePathProtocol,
|
||||
source_buffer: *mut core::ffi::c_void,
|
||||
source_size: usize,
|
||||
image_handle: *mut EfiHandle,
|
||||
) -> EfiStatus,
|
||||
start_image: extern "efiapi" fn(
|
||||
image_handle: EfiHandle,
|
||||
exit_data_size: *mut usize,
|
||||
exit_data: *mut *mut u16,
|
||||
) -> EfiStatus,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct EfiLoadedImageProtocol {
|
||||
revision: u32,
|
||||
parent_handle: EfiHandle,
|
||||
system_table: *mut EfiSystemTable,
|
||||
device_handle: EfiHandle,
|
||||
file_path: *mut EfiDevicePathProtocol,
|
||||
reserved: *mut core::ffi::c_void,
|
||||
load_options_size: u32,
|
||||
load_options: *mut core::ffi::c_void,
|
||||
image_base: *mut core::ffi::c_void,
|
||||
image_size: u64,
|
||||
image_code_type: u32,
|
||||
image_data_type: u32,
|
||||
unload: usize,
|
||||
}
|
||||
|
||||
#[repr(C, packed)]
|
||||
struct EfiDevicePathProtocol {
|
||||
ty: u8,
|
||||
sub_type: u8,
|
||||
length: [u8; 2],
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
extern "efiapi" fn efi_main(
|
||||
image_handle: EfiHandle,
|
||||
system_table: *mut EfiSystemTable,
|
||||
) -> EfiStatus {
|
||||
unsafe {
|
||||
if system_table.is_null() || (*system_table).boot_services.is_null() {
|
||||
return EFI_LOAD_ERROR;
|
||||
}
|
||||
|
||||
write(system_table, LOADING.as_ptr());
|
||||
|
||||
let boot_services = (*system_table).boot_services;
|
||||
let mut loaded_image = null_mut();
|
||||
let status = ((*boot_services).handle_protocol)(
|
||||
image_handle,
|
||||
&EFI_LOADED_IMAGE_PROTOCOL_GUID,
|
||||
&mut loaded_image,
|
||||
);
|
||||
if status != EFI_SUCCESS {
|
||||
return status;
|
||||
}
|
||||
|
||||
let loaded_image = loaded_image as *mut EfiLoadedImageProtocol;
|
||||
let mut partition_device_path = null_mut();
|
||||
let status = ((*boot_services).handle_protocol)(
|
||||
(*loaded_image).device_handle,
|
||||
&EFI_DEVICE_PATH_PROTOCOL_GUID,
|
||||
&mut partition_device_path,
|
||||
);
|
||||
if status != EFI_SUCCESS {
|
||||
return status;
|
||||
}
|
||||
|
||||
let mut device_path_buffer = [0u8; 1024];
|
||||
let device_path = match build_zeroos_device_path(
|
||||
partition_device_path as *const EfiDevicePathProtocol,
|
||||
&mut device_path_buffer,
|
||||
) {
|
||||
Ok(path) => path,
|
||||
Err(status) => return status,
|
||||
};
|
||||
|
||||
let mut zeroos_image = null_mut();
|
||||
let status = ((*boot_services).load_image)(
|
||||
0,
|
||||
image_handle,
|
||||
device_path,
|
||||
null_mut(),
|
||||
0,
|
||||
&mut zeroos_image,
|
||||
);
|
||||
if status != EFI_SUCCESS {
|
||||
return status;
|
||||
}
|
||||
|
||||
((*boot_services).start_image)(zeroos_image, null_mut(), null_mut())
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn build_zeroos_device_path<'a>(
|
||||
partition_path: *const EfiDevicePathProtocol,
|
||||
buffer: &'a mut [u8],
|
||||
) -> Result<*const EfiDevicePathProtocol, EfiStatus> {
|
||||
if partition_path.is_null() {
|
||||
return Err(EFI_LOAD_ERROR);
|
||||
}
|
||||
|
||||
let partition_len = unsafe { device_path_len_without_end(partition_path)? };
|
||||
let file_path_node_len = 4 + ZEROOS_PATH.len() * size_of::<u16>();
|
||||
let total_len = partition_len + file_path_node_len + 4;
|
||||
|
||||
if total_len > buffer.len() || file_path_node_len > u16::MAX as usize {
|
||||
return Err(EFI_BUFFER_TOO_SMALL);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
copy_nonoverlapping(
|
||||
partition_path as *const u8,
|
||||
buffer.as_mut_ptr(),
|
||||
partition_len,
|
||||
);
|
||||
}
|
||||
|
||||
let file_node = &mut buffer[partition_len..partition_len + file_path_node_len];
|
||||
file_node[0] = MEDIA_DEVICE_PATH;
|
||||
file_node[1] = MEDIA_FILEPATH_DP;
|
||||
file_node[2] = (file_path_node_len & 0xff) as u8;
|
||||
file_node[3] = (file_path_node_len >> 8) as u8;
|
||||
|
||||
unsafe {
|
||||
copy_nonoverlapping(
|
||||
ZEROOS_PATH.as_ptr() as *const u8,
|
||||
file_node[4..].as_mut_ptr(),
|
||||
ZEROOS_PATH.len() * size_of::<u16>(),
|
||||
);
|
||||
}
|
||||
|
||||
let end_node = &mut buffer[partition_len + file_path_node_len..total_len];
|
||||
end_node[0] = END_DEVICE_PATH_TYPE;
|
||||
end_node[1] = END_ENTIRE_DEVICE_PATH_SUBTYPE;
|
||||
end_node[2] = 4;
|
||||
end_node[3] = 0;
|
||||
|
||||
Ok(buffer.as_ptr() as *const EfiDevicePathProtocol)
|
||||
}
|
||||
|
||||
unsafe fn device_path_len_without_end(
|
||||
mut node: *const EfiDevicePathProtocol,
|
||||
) -> Result<usize, EfiStatus> {
|
||||
let mut len = 0;
|
||||
|
||||
for _ in 0..256 {
|
||||
let node_len = unsafe { device_path_node_len(node) };
|
||||
if node_len < 4 {
|
||||
return Err(EFI_LOAD_ERROR);
|
||||
}
|
||||
|
||||
if unsafe {
|
||||
(*node).ty == END_DEVICE_PATH_TYPE && (*node).sub_type == END_ENTIRE_DEVICE_PATH_SUBTYPE
|
||||
} {
|
||||
return Ok(len);
|
||||
}
|
||||
|
||||
len += node_len;
|
||||
node = unsafe { (node as *const u8).add(node_len) as *const EfiDevicePathProtocol };
|
||||
}
|
||||
|
||||
Err(EFI_LOAD_ERROR)
|
||||
}
|
||||
|
||||
unsafe fn device_path_node_len(node: *const EfiDevicePathProtocol) -> usize {
|
||||
unsafe { ((*node).length[0] as usize) | ((*node).length[1] as usize) << 8 }
|
||||
}
|
||||
|
||||
unsafe fn write(system_table: *mut EfiSystemTable, text: *const u16) {
|
||||
unsafe {
|
||||
if !system_table.is_null() && !(*system_table).con_out.is_null() {
|
||||
((*(*system_table).con_out).output_string)((*system_table).con_out, text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[panic_handler]
|
||||
fn panic(_info: &PanicInfo) -> ! {
|
||||
loop {}
|
||||
}
|
||||
Reference in New Issue
Block a user