use core::{ffi::c_void, mem::size_of, slice::from_raw_parts};
use alloc::boxed::Box;
use patina::{boot_services::BootServices, component::component, pi::error_codes::EFI_NOT_AVAILABLE_YET};
use r_efi::efi;
use crate::{allocator::EFI_RUNTIME_SERVICES_DATA_ALLOCATOR, tpl_mutex};
pub static SYSTEM_TABLE: tpl_mutex::TplMutex<Option<EfiSystemTable>> =
tpl_mutex::TplMutex::new(efi::TPL_NOTIFY, None, "StLock");
pub struct EfiRuntimeServicesTable {
runtime_services: *mut efi::RuntimeServices,
}
impl EfiRuntimeServicesTable {
pub fn allocate_new_table() -> Self {
let rt = Self::default_runtime_services_table();
let (runtime_services, _alloc) =
Box::into_raw_with_allocator(Box::new_in(rt, &EFI_RUNTIME_SERVICES_DATA_ALLOCATOR));
let mut table = Self { runtime_services };
table.checksum();
table
}
pub unsafe fn from_raw_pointer(ptr: *mut efi::RuntimeServices) -> Self {
Self { runtime_services: ptr }
}
fn checksum(&mut self) {
let mut table_copy = unsafe { self.runtime_services.read() };
table_copy.hdr.crc32 = 0;
let tbl_slice =
unsafe { from_raw_parts(&table_copy as *const _ as *const u8, size_of::<efi::RuntimeServices>()) };
table_copy.hdr.crc32 = crc32fast::hash(tbl_slice);
unsafe { self.runtime_services.write(table_copy) }
}
#[allow(dead_code)]
pub fn get(&self) -> efi::RuntimeServices {
unsafe { self.runtime_services.read() }
}
#[allow(dead_code)]
pub fn set(&mut self, new_table: efi::RuntimeServices) {
unsafe {
self.runtime_services.write(new_table);
}
self.checksum();
}
pub fn as_mut_ptr(&self) -> *mut efi::RuntimeServices {
self.runtime_services
}
fn default_runtime_services_table() -> efi::RuntimeServices {
#[coverage(off)]
extern "efiapi" fn get_time_unimplemented(_: *mut efi::Time, _: *mut efi::TimeCapabilities) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn set_time_unimplemented(_: *mut efi::Time) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn get_wakeup_time_unimplemented(
_: *mut efi::Boolean,
_: *mut efi::Boolean,
_: *mut efi::Time,
) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn set_wakeup_time_unimplemented(_: efi::Boolean, _: *mut efi::Time) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn set_virtual_address_map_unimplemented(
_: usize,
_: usize,
_: u32,
_: *mut efi::MemoryDescriptor,
) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn convert_pointer_unimplemented(_: usize, _: *mut *mut c_void) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn get_variable_unimplemented(
_: *mut efi::Char16,
_: *mut efi::Guid,
_: *mut u32,
_: *mut usize,
_: *mut c_void,
) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn get_next_variable_name_unimplemented(
_: *mut usize,
_: *mut efi::Char16,
_: *mut efi::Guid,
) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn set_variable_unimplemented(
_: *mut efi::Char16,
_: *mut efi::Guid,
_: u32,
_: usize,
_: *mut c_void,
) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn get_next_high_mono_count_unimplemented(_: *mut u32) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn reset_system_unimplemented(_: efi::ResetType, _: efi::Status, _: usize, _: *mut c_void) {}
#[coverage(off)]
extern "efiapi" fn update_capsule_unimplemented(
_: *mut *mut efi::CapsuleHeader,
_: usize,
_: efi::PhysicalAddress,
) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn query_capsule_capabilities_unimplemented(
_: *mut *mut efi::CapsuleHeader,
_: usize,
_: *mut u64,
_: *mut efi::ResetType,
) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn query_variable_info_unimplemented(
_: u32,
_: *mut u64,
_: *mut u64,
_: *mut u64,
) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
efi::RuntimeServices {
hdr: efi::TableHeader {
signature: efi::RUNTIME_SERVICES_SIGNATURE,
revision: efi::RUNTIME_SERVICES_REVISION,
header_size: size_of::<efi::RuntimeServices>() as u32,
crc32: 0,
reserved: 0,
},
get_time: get_time_unimplemented,
set_time: set_time_unimplemented,
get_wakeup_time: get_wakeup_time_unimplemented,
set_wakeup_time: set_wakeup_time_unimplemented,
set_virtual_address_map: set_virtual_address_map_unimplemented,
convert_pointer: convert_pointer_unimplemented,
get_variable: get_variable_unimplemented,
get_next_variable_name: get_next_variable_name_unimplemented,
set_variable: set_variable_unimplemented,
get_next_high_mono_count: get_next_high_mono_count_unimplemented,
reset_system: reset_system_unimplemented,
update_capsule: update_capsule_unimplemented,
query_capsule_capabilities: query_capsule_capabilities_unimplemented,
query_variable_info: query_variable_info_unimplemented,
}
}
}
pub struct EfiBootServicesTable {
boot_services: *mut efi::BootServices,
}
impl EfiBootServicesTable {
pub fn allocate_new_table() -> Self {
let bs = Self::default_boot_services_table();
let boot_services = Box::into_raw(Box::new(bs));
let mut table = Self { boot_services };
table.checksum();
table
}
pub unsafe fn from_raw_pointer(ptr: *mut efi::BootServices) -> Self {
Self { boot_services: ptr }
}
fn checksum(&mut self) {
let mut table_copy = unsafe { self.boot_services.read() };
table_copy.hdr.crc32 = 0;
let tbl_slice = unsafe { from_raw_parts(&table_copy as *const _ as *const u8, size_of::<efi::BootServices>()) };
table_copy.hdr.crc32 = crc32fast::hash(tbl_slice);
unsafe { self.boot_services.write(table_copy) }
}
pub fn get(&self) -> efi::BootServices {
unsafe { self.boot_services.read() }
}
pub fn set(&mut self, new_table: efi::BootServices) {
unsafe {
self.boot_services.write(new_table);
}
self.checksum();
}
pub fn as_mut_ptr(&self) -> *mut efi::BootServices {
self.boot_services
}
fn default_boot_services_table() -> efi::BootServices {
#[coverage(off)]
extern "efiapi" fn raise_tpl_unimplemented(_: efi::Tpl) -> efi::Tpl {
efi::TPL_APPLICATION
}
#[coverage(off)]
extern "efiapi" fn restore_tpl_unimplemented(_: efi::Tpl) {}
#[coverage(off)]
extern "efiapi" fn allocate_pages_unimplemented(
_: efi::AllocateType,
_: efi::MemoryType,
_: usize,
_: *mut efi::PhysicalAddress,
) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn free_pages_unimplemented(_: efi::PhysicalAddress, _: usize) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn get_memory_map_unimplemented(
_: *mut usize,
_: *mut efi::MemoryDescriptor,
_: *mut usize,
_: *mut usize,
_: *mut u32,
) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn allocate_pool_unimplemented(
_: efi::MemoryType,
_: usize,
_: *mut *mut c_void,
) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn free_pool_unimplemented(_: *mut c_void) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn create_event_unimplemented(
_: u32,
_: efi::Tpl,
_: Option<efi::EventNotify>,
_: *mut c_void,
_: *mut efi::Event,
) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn set_timer_unimplemented(_: efi::Event, _: efi::TimerDelay, _: u64) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn wait_for_event_unimplemented(_: usize, _: *mut efi::Event, _: *mut usize) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn signal_event_unimplemented(_: efi::Event) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn close_event_unimplemented(_: efi::Event) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn check_event_unimplemented(_: efi::Event) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn install_protocol_interface_unimplemented(
_: *mut efi::Handle,
_: *mut efi::Guid,
_: efi::InterfaceType,
_: *mut c_void,
) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn reinstall_protocol_interface_unimplemented(
_: efi::Handle,
_: *mut efi::Guid,
_: *mut c_void,
_: *mut c_void,
) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn uninstall_protocol_interface_unimplemented(
_: efi::Handle,
_: *mut efi::Guid,
_: *mut c_void,
) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn handle_protocol_unimplemented(
_: efi::Handle,
_: *mut efi::Guid,
_: *mut *mut c_void,
) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn register_protocol_notify_unimplemented(
_: *mut efi::Guid,
_: efi::Event,
_: *mut *mut c_void,
) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn locate_handle_unimplemented(
_: efi::LocateSearchType,
_: *mut efi::Guid,
_: *mut c_void,
_: *mut usize,
_: *mut efi::Handle,
) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn locate_device_path_unimplemented(
_: *mut efi::Guid,
_: *mut *mut efi::protocols::device_path::Protocol,
_: *mut efi::Handle,
) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn install_configuration_table_unimplemented(_: *mut efi::Guid, _: *mut c_void) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn load_image_unimplemented(
_: efi::Boolean,
_: efi::Handle,
_: *mut efi::protocols::device_path::Protocol,
_: *mut c_void,
_: usize,
_: *mut efi::Handle,
) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn start_image_unimplemented(
_: efi::Handle,
_: *mut usize,
_: *mut *mut efi::Char16,
) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn exit_unimplemented(
_: efi::Handle,
_: efi::Status,
_: usize,
_: *mut efi::Char16,
) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn unload_image_unimplemented(_: efi::Handle) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn exit_boot_services_unimplemented(_: efi::Handle, _: usize) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn get_next_monotonic_count_unimplemented(_: *mut u64) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn stall_unimplemented(_: usize) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn set_watchdog_timer_unimplemented(
_: usize,
_: u64,
_: usize,
_: *mut efi::Char16,
) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn connect_controller_unimplemented(
_: efi::Handle,
_: *mut efi::Handle,
_: *mut efi::protocols::device_path::Protocol,
_: efi::Boolean,
) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn disconnect_controller_unimplemented(
_: efi::Handle,
_: efi::Handle,
_: efi::Handle,
) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn open_protocol_unimplemented(
_: efi::Handle,
_: *mut efi::Guid,
_: *mut *mut c_void,
_: efi::Handle,
_: efi::Handle,
_: u32,
) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn close_protocol_unimplemented(
_: efi::Handle,
_: *mut efi::Guid,
_: efi::Handle,
_: efi::Handle,
) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn open_protocol_information_unimplemented(
_: efi::Handle,
_: *mut efi::Guid,
_: *mut *mut efi::OpenProtocolInformationEntry,
_: *mut usize,
) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn protocols_per_handle_unimplemented(
_: efi::Handle,
_: *mut *mut *mut efi::Guid,
_: *mut usize,
) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn locate_handle_buffer_unimplemented(
_: efi::LocateSearchType,
_: *mut efi::Guid,
_: *mut c_void,
_: *mut usize,
_: *mut *mut efi::Handle,
) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn locate_protocol_unimplemented(
_: *mut efi::Guid,
_: *mut c_void,
_: *mut *mut c_void,
) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn install_multiple_protocol_interfaces_unimplemented(
_: *mut efi::Handle,
_: *mut c_void,
_: *mut c_void,
) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn uninstall_multiple_protocol_interfaces_unimplemented(
_: efi::Handle,
_: *mut c_void,
_: *mut c_void,
) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn calculate_crc32_unimplemented(_: *mut c_void, _: usize, _: *mut u32) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
#[coverage(off)]
extern "efiapi" fn copy_mem_unimplemented(_: *mut c_void, _: *mut c_void, _: usize) {}
#[coverage(off)]
extern "efiapi" fn set_mem_unimplemented(_: *mut c_void, _: usize, _: u8) {}
#[coverage(off)]
extern "efiapi" fn create_event_ex_unimplemented(
_: u32,
_: efi::Tpl,
_: Option<efi::EventNotify>,
_: *const c_void,
_: *const efi::Guid,
_: *mut efi::Event,
) -> efi::Status {
efi::Status::from_usize(EFI_NOT_AVAILABLE_YET)
}
efi::BootServices {
hdr: efi::TableHeader {
signature: efi::BOOT_SERVICES_SIGNATURE,
revision: efi::BOOT_SERVICES_REVISION,
header_size: size_of::<efi::BootServices>() as u32,
crc32: 0,
reserved: 0,
},
raise_tpl: raise_tpl_unimplemented,
restore_tpl: restore_tpl_unimplemented,
allocate_pages: allocate_pages_unimplemented,
free_pages: free_pages_unimplemented,
get_memory_map: get_memory_map_unimplemented,
allocate_pool: allocate_pool_unimplemented,
free_pool: free_pool_unimplemented,
create_event: create_event_unimplemented,
set_timer: set_timer_unimplemented,
wait_for_event: wait_for_event_unimplemented,
signal_event: signal_event_unimplemented,
close_event: close_event_unimplemented,
check_event: check_event_unimplemented,
install_protocol_interface: install_protocol_interface_unimplemented,
reinstall_protocol_interface: reinstall_protocol_interface_unimplemented,
uninstall_protocol_interface: uninstall_protocol_interface_unimplemented,
handle_protocol: handle_protocol_unimplemented,
reserved: core::ptr::null_mut(),
register_protocol_notify: register_protocol_notify_unimplemented,
locate_handle: locate_handle_unimplemented,
locate_device_path: locate_device_path_unimplemented,
install_configuration_table: install_configuration_table_unimplemented,
load_image: load_image_unimplemented,
start_image: start_image_unimplemented,
exit: exit_unimplemented,
unload_image: unload_image_unimplemented,
exit_boot_services: exit_boot_services_unimplemented,
get_next_monotonic_count: get_next_monotonic_count_unimplemented,
stall: stall_unimplemented,
set_watchdog_timer: set_watchdog_timer_unimplemented,
connect_controller: connect_controller_unimplemented,
disconnect_controller: disconnect_controller_unimplemented,
open_protocol: open_protocol_unimplemented,
close_protocol: close_protocol_unimplemented,
open_protocol_information: open_protocol_information_unimplemented,
protocols_per_handle: protocols_per_handle_unimplemented,
locate_handle_buffer: locate_handle_buffer_unimplemented,
locate_protocol: locate_protocol_unimplemented,
install_multiple_protocol_interfaces: install_multiple_protocol_interfaces_unimplemented,
uninstall_multiple_protocol_interfaces: uninstall_multiple_protocol_interfaces_unimplemented,
calculate_crc32: calculate_crc32_unimplemented,
copy_mem: copy_mem_unimplemented,
set_mem: set_mem_unimplemented,
create_event_ex: create_event_ex_unimplemented,
}
}
}
pub struct EfiSystemTable {
system_table: *mut efi::SystemTable,
}
unsafe impl Send for EfiSystemTable {}
impl EfiSystemTable {
pub fn allocate_new_table() -> Self {
let mut st = Self::default_system_table();
st.runtime_services = EfiRuntimeServicesTable::allocate_new_table().as_mut_ptr();
st.boot_services = EfiBootServicesTable::allocate_new_table().as_mut_ptr();
let (system_table, _alloc) =
Box::into_raw_with_allocator(Box::new_in(st, &EFI_RUNTIME_SERVICES_DATA_ALLOCATOR));
let mut table = Self { system_table };
table.checksum();
table
}
#[allow(dead_code)]
pub unsafe fn from_raw_pointer(ptr: *mut efi::SystemTable) -> Self {
unsafe {
if ptr.is_null() {
panic!("Attempted to create EfiSystemTable with null System Table pointer");
}
if (*ptr).boot_services.is_null() {
panic!("Attempted to create EfiSystemTable with null Boot Services pointer");
}
if (*ptr).runtime_services.is_null() {
panic!("Attempted to create EfiSystemTable with null Runtime Services pointer");
}
}
Self { system_table: ptr }
}
fn checksum(&mut self) {
let mut table_copy = unsafe { self.system_table.read() };
table_copy.hdr.crc32 = 0;
let st_slice = unsafe { from_raw_parts(&table_copy as *const _ as *const u8, size_of::<efi::SystemTable>()) };
table_copy.hdr.crc32 = crc32fast::hash(st_slice);
unsafe { self.system_table.write(table_copy) }
}
pub fn get(&self) -> efi::SystemTable {
unsafe { self.system_table.read() }
}
pub fn set(&mut self, new_table: efi::SystemTable) {
if new_table.boot_services.is_null() {
panic!("Attempted to set System Table with null Boot Services pointer");
}
if new_table.runtime_services.is_null() {
panic!("Attempted to set System Table with null Runtime Services pointer");
}
unsafe {
self.system_table.write(new_table);
}
self.checksum();
}
pub unsafe fn set_unchecked(&mut self, new_table: efi::SystemTable) {
unsafe {
self.system_table.write(new_table);
}
self.checksum();
}
pub fn as_mut_ptr(&self) -> *mut efi::SystemTable {
self.system_table
}
pub fn runtime_services(&self) -> EfiRuntimeServicesTable {
unsafe {
let st = self.system_table.read();
if st.runtime_services.is_null() {
panic!("RuntimeServices pointer is null");
}
EfiRuntimeServicesTable::from_raw_pointer(st.runtime_services)
}
}
pub fn boot_services(&self) -> EfiBootServicesTable {
unsafe {
let st = self.system_table.read();
if st.boot_services.is_null() {
panic!("BootServices pointer is null");
}
EfiBootServicesTable::from_raw_pointer(st.boot_services)
}
}
pub unsafe fn clear_boot_time_services(&mut self) {
let mut st = self.get();
st.boot_services = core::ptr::null_mut();
st.con_in = core::ptr::null_mut();
st.console_in_handle = core::ptr::null_mut();
st.con_out = core::ptr::null_mut();
st.console_out_handle = core::ptr::null_mut();
st.std_err = core::ptr::null_mut();
st.standard_error_handle = core::ptr::null_mut();
unsafe {
self.set_unchecked(st);
}
}
pub fn checksum_all(&mut self) {
let mut rt = self.runtime_services();
rt.checksum();
let mut bs = self.boot_services();
bs.checksum();
self.checksum();
}
fn default_system_table() -> efi::SystemTable {
efi::SystemTable {
hdr: efi::TableHeader {
signature: efi::SYSTEM_TABLE_SIGNATURE,
revision: efi::SYSTEM_TABLE_REVISION,
header_size: size_of::<efi::SystemTable>() as u32,
crc32: 0,
reserved: 0,
},
firmware_vendor: core::ptr::null_mut(),
firmware_revision: 0,
console_in_handle: core::ptr::null_mut(),
con_in: core::ptr::null_mut(),
console_out_handle: core::ptr::null_mut(),
con_out: core::ptr::null_mut(),
standard_error_handle: core::ptr::null_mut(),
std_err: core::ptr::null_mut(),
runtime_services: core::ptr::null_mut(),
boot_services: core::ptr::null_mut(),
number_of_table_entries: 0,
configuration_table: core::ptr::null_mut(),
}
}
}
pub fn init_system_table() {
*SYSTEM_TABLE.lock() = Some(EfiSystemTable::allocate_new_table());
}
#[derive(Default)]
pub(crate) struct SystemTableChecksumInstaller;
#[component]
impl SystemTableChecksumInstaller {
fn entry_point(self, bs: patina::boot_services::StandardBootServices) -> patina::error::Result<()> {
extern "efiapi" fn callback(_event: efi::Event, _: *mut c_void) {
SYSTEM_TABLE.lock().as_mut().expect("System Table is initialized").checksum_all();
}
const GUIDS: [efi::Guid; 16] = [
efi::Guid::from_bytes(&uuid::uuid!("1DA97072-BDDC-4B30-99F1-72A0B56FFF2A").to_bytes_le()), efi::Guid::from_bytes(&uuid::uuid!("1E5668E2-8481-11D4-BCF1-0080C73C8881").to_bytes_le()), efi::Guid::from_bytes(&uuid::uuid!("26BACCB1-6F42-11D4-BC7E-0080C73C8881").to_bytes_le()), efi::Guid::from_bytes(&uuid::uuid!("26BACCB2-6F42-11D4-BCE7-0080C73C8881").to_bytes_le()), efi::Guid::from_bytes(&uuid::uuid!("26BACCB3-6F42-11D4-BCE7-0080C73C8881").to_bytes_le()), efi::Guid::from_bytes(&uuid::uuid!("27CFAC87-46CC-11D4-9A38-0090273FC14D").to_bytes_le()), efi::Guid::from_bytes(&uuid::uuid!("27CFAC88-46CC-11D4-9A38-0090273FC14D").to_bytes_le()), efi::Guid::from_bytes(&uuid::uuid!("5053697E-2CBC-4819-90D9-0580DEEE5754").to_bytes_le()), efi::Guid::from_bytes(&uuid::uuid!("55198405-26c0-4765-8b7d-be1df5f99712").to_bytes_le()), efi::Guid::from_bytes(&uuid::uuid!("6441F818-6362-4E44-B570-7DBA31DD2453").to_bytes_le()), efi::Guid::from_bytes(&uuid::uuid!("665E3FF5-46CC-11D4-9A38-0090273FC14D").to_bytes_le()), efi::Guid::from_bytes(&uuid::uuid!("665E3FF6-46CC-11D4-9A38-0090273FC14D").to_bytes_le()), efi::Guid::from_bytes(&uuid::uuid!("94AB2F58-1438-4EF1-9152-18941894A3A0").to_bytes_le()), efi::Guid::from_bytes(&uuid::uuid!("A46423E3-4617-49F1-B9FF-D1BFA9115839").to_bytes_le()), efi::Guid::from_bytes(&uuid::uuid!("B7DFB4E1-052F-449F-87BE-9818FC91B733").to_bytes_le()), efi::Guid::from_bytes(&uuid::uuid!("F4CCBFB7-F6E0-47FD-9DD4-10A8F150C191").to_bytes_le()), ];
for guid in &GUIDS {
let event = bs.create_event(
patina::boot_services::event::EventType::NOTIFY_SIGNAL,
patina::boot_services::tpl::Tpl::CALLBACK,
Some(callback),
core::ptr::null_mut(),
)?;
bs.register_protocol_notify(guid, event)?;
}
Ok(())
}
}
#[cfg(test)]
#[coverage(off)]
mod tests {
use super::*;
use crate::test_support;
fn with_locked_state<F: Fn() + std::panic::RefUnwindSafe>(f: F) {
test_support::with_global_lock(|| {
test_support::init_test_logger();
unsafe { test_support::init_test_gcd(Some(0x4000000)) };
f();
})
.unwrap();
}
#[test]
fn test_checksum_changes_on_edit() {
with_locked_state(|| {
let mut table = EfiSystemTable::allocate_new_table();
table.checksum();
let system_table_crc32 = table.get().hdr.crc32;
let boot_services_crc32 = table.boot_services().get().hdr.crc32;
let runtime_services_crc32 = table.runtime_services().get().hdr.crc32;
extern "efiapi" fn raise_tpl(_: efi::Tpl) -> efi::Tpl {
efi::TPL_APPLICATION
}
let mut bs = table.boot_services().get();
bs.raise_tpl = raise_tpl;
table.boot_services().set(bs);
extern "efiapi" fn get_variable(
_: *mut efi::Char16,
_: *mut efi::Guid,
_: *mut u32,
_: *mut usize,
_: *mut c_void,
) -> efi::Status {
efi::Status::SUCCESS
}
let mut rt = table.runtime_services().get();
rt.get_variable = get_variable;
table.runtime_services().set(rt);
let mut st = table.get();
st.hdr.revision = 0x100;
table.set(st);
let new_system_table_crc32 = table.get().hdr.crc32;
let new_boot_services_crc32 = table.boot_services().get().hdr.crc32;
let new_runtime_services_crc32 = table.runtime_services().get().hdr.crc32;
assert_ne!(system_table_crc32, new_system_table_crc32);
assert_ne!(boot_services_crc32, new_boot_services_crc32);
assert_ne!(runtime_services_crc32, new_runtime_services_crc32);
unsafe {
table.clear_boot_time_services();
assert_eq!((*table.system_table).boot_services, core::ptr::null_mut());
};
})
}
}