diff --git a/Cargo.lock b/Cargo.lock index f6c79ef6..740a0662 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -240,12 +240,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - [[package]] name = "core-foundation" version = "0.6.4" @@ -331,19 +325,6 @@ dependencies = [ "syn 2.0.98", ] -[[package]] -name = "derive_more" -version = "0.99.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version", - "syn 1.0.107", -] - [[package]] name = "digest" version = "0.10.7" @@ -433,7 +414,6 @@ dependencies = [ "smbios-lib", "spin 0.9.8", "uefi", - "uefi-services", "windows 0.59.0", "wmi", ] @@ -456,7 +436,6 @@ dependencies = [ "framework_lib", "log", "uefi", - "uefi-services", ] [[package]] @@ -965,22 +944,22 @@ dependencies = [ [[package]] name = "ptr_meta" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcada80daa06c42ed5f48c9a043865edea5dc44cbf9ac009fda3b89526e28607" +checksum = "fe9e76f66d3f9606f44e45598d155cb13ecf09f4a28199e48daf8c8fc937ea90" dependencies = [ "ptr_meta_derive", ] [[package]] name = "ptr_meta_derive" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bca9224df2e20e7c5548aeb5f110a0f3b77ef05f8585139b7148b59056168ed2" +checksum = "ca414edb151b4c8d125c12566ab0d74dc9cdba36fb80eb7b848c15f495fd32d1" dependencies = [ "proc-macro2", "quote", - "syn 1.0.107", + "syn 2.0.98", ] [[package]] @@ -1303,47 +1282,54 @@ checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" [[package]] name = "ucs2" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bad643914094137d475641b6bab89462505316ec2ce70907ad20102d28a79ab8" +checksum = "df79298e11f316400c57ec268f3c2c29ac3c4d4777687955cd3d4f3a35ce7eba" dependencies = [ "bit_field", ] [[package]] name = "uefi" -version = "0.20.0" -source = "git+https://github.com/FrameworkComputer/uefi-rs?branch=merged#76130a0f1c1585012e598b8c514526bac09c68e0" +version = "0.35.0" +source = "git+https://github.com/rust-osdev/uefi-rs?rev=1fcf4d84d5ed10fe76055469b6df01318eb35af8#1fcf4d84d5ed10fe76055469b6df01318eb35af8" dependencies = [ - "bitflags 1.3.2", - "derive_more", + "bitflags 2.6.0", + "cfg-if", "log", "ptr_meta", "ucs2", "uefi-macros", + "uefi-raw", + "uguid", ] [[package]] name = "uefi-macros" -version = "0.11.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0caeb0e7b31b9f1f347e541106be10aa8c66c76fa722a3298a4cd21433fabd4" +checksum = "b3dad47b3af8f99116c0f6d4d669c439487d9aaf1c8d9480d686cda6f3a8aa23" dependencies = [ "proc-macro2", "quote", - "syn 1.0.107", + "syn 2.0.98", ] [[package]] -name = "uefi-services" -version = "0.17.0" -source = "git+https://github.com/FrameworkComputer/uefi-rs?branch=merged#76130a0f1c1585012e598b8c514526bac09c68e0" +name = "uefi-raw" +version = "0.11.0" +source = "git+https://github.com/rust-osdev/uefi-rs?rev=1fcf4d84d5ed10fe76055469b6df01318eb35af8#1fcf4d84d5ed10fe76055469b6df01318eb35af8" dependencies = [ - "cfg-if", - "log", - "uefi", + "bitflags 2.6.0", + "uguid", ] +[[package]] +name = "uguid" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c8352f8c05e47892e7eaf13b34abd76a7f4aeaf817b716e88789381927f199c" + [[package]] name = "unicode-bidi" version = "0.3.13" diff --git a/Cargo.toml b/Cargo.toml index d8108e1b..f4dfcb51 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,9 +19,10 @@ default-members = [ "framework_tool", ] +# Need latest commit that hasn't been released yet [patch.crates-io] -uefi = { git = "https://github.com/FrameworkComputer/uefi-rs", branch = "merged" } -uefi-services = { git = "https://github.com/FrameworkComputer/uefi-rs", branch = "merged" } +uefi = { git = "https://github.com/rust-osdev/uefi-rs", rev = "1fcf4d84d5ed10fe76055469b6df01318eb35af8" } +uefi-raw = { git = "https://github.com/rust-osdev/uefi-rs", rev = "1fcf4d84d5ed10fe76055469b6df01318eb35af8" } [profile.release] lto = true diff --git a/framework_lib/Cargo.toml b/framework_lib/Cargo.toml index b3af9f25..9691c644 100644 --- a/framework_lib/Cargo.toml +++ b/framework_lib/Cargo.toml @@ -36,8 +36,7 @@ rusb = { version = "0.9.4", optional = true } guid-create = { git = "https://github.com/FrameworkComputer/guid-create", branch = "no-rand", default-features = false } [target.'cfg(target_os = "uefi")'.dependencies] -uefi = { version = "0.20", features = ["alloc"] } -uefi-services = "0.17" +uefi = { version = "0.35", features = ["alloc", "global_allocator", "panic_handler", "logger"] } plain = "0.2.3" redox_hwio = { git = "https://github.com/FrameworkComputer/rust-hwio", branch = "freebsd", default-features = false } smbios-lib = { git = "https://github.com/FrameworkComputer/smbios-lib.git", branch = "no-std", default-features = false } diff --git a/framework_lib/src/capsule.rs b/framework_lib/src/capsule.rs index e2dff320..eeacc8ed 100644 --- a/framework_lib/src/capsule.rs +++ b/framework_lib/src/capsule.rs @@ -183,7 +183,7 @@ pub fn dump_winux_image(data: &[u8], header: &DisplayCapsule, filename: &str) { } #[cfg(feature = "uefi")] { - let ret = crate::uefi::fs::shell_write_file(filename, image); + let ret = crate::fw_uefi::fs::shell_write_file(filename, image); if let Err(err) = ret { println!("Failed to dump winux image: {:?}", err); } diff --git a/framework_lib/src/chromium_ec/mod.rs b/framework_lib/src/chromium_ec/mod.rs index ed1210e6..f53fdb9a 100644 --- a/framework_lib/src/chromium_ec/mod.rs +++ b/framework_lib/src/chromium_ec/mod.rs @@ -9,11 +9,11 @@ //! - `windows` - It uses [DHowett's Windows driver](https://github.com/DHowett/FrameworkWindowsUtils) use crate::ec_binary; +#[cfg(feature = "uefi")] +use crate::fw_uefi::shell_get_execution_break_flag; use crate::os_specific; use crate::power; use crate::smbios; -#[cfg(feature = "uefi")] -use crate::uefi::shell_get_execution_break_flag; use crate::util::{self, Platform}; use log::Level; diff --git a/framework_lib/src/commandline/mod.rs b/framework_lib/src/commandline/mod.rs index 602ca09e..bc619684 100644 --- a/framework_lib/src/commandline/mod.rs +++ b/framework_lib/src/commandline/mod.rs @@ -47,6 +47,8 @@ use crate::chromium_ec::{EcError, EcResult}; use crate::csme; use crate::ec_binary; use crate::esrt; +#[cfg(feature = "uefi")] +use crate::fw_uefi::enable_page_break; #[cfg(feature = "rusb")] use crate::inputmodule::check_inputmodule_version; use crate::power; @@ -57,8 +59,6 @@ use crate::smbios::{dmidecode_string_val, get_smbios, is_framework}; use crate::touchpad::print_touchpad_fw_ver; #[cfg(feature = "hidapi")] use crate::touchscreen; -#[cfg(feature = "uefi")] -use crate::uefi::enable_page_break; use crate::util::{self, Config, Platform, PlatformFamily}; #[cfg(feature = "hidapi")] use hidapi::HidApi; @@ -639,7 +639,7 @@ fn print_esrt() { fn flash_ec(ec: &CrosEc, ec_bin_path: &str, flash_type: EcFlashType, dry_run: bool) { #[cfg(feature = "uefi")] - let data = crate::uefi::fs::shell_read_file(ec_bin_path); + let data = crate::fw_uefi::fs::shell_read_file(ec_bin_path); #[cfg(not(feature = "uefi"))] let data: Option> = { match fs::read(ec_bin_path) { @@ -674,7 +674,7 @@ fn dump_ec_flash(ec: &CrosEc, dump_path: &str) { } #[cfg(feature = "uefi")] { - let ret = crate::uefi::fs::shell_write_file(dump_path, &flash_bin); + let ret = crate::fw_uefi::fs::shell_write_file(dump_path, &flash_bin); if ret.is_err() { println!("Failed to dump EC FW image."); } @@ -691,7 +691,7 @@ fn dump_dgpu_eeprom(ec: &CrosEc, dump_path: &str) { } #[cfg(feature = "uefi")] { - let ret = crate::uefi::fs::shell_write_file(dump_path, &flash_bin); + let ret = crate::fw_uefi::fs::shell_write_file(dump_path, &flash_bin); if ret.is_err() { println!("Failed to dump EC FW image."); } @@ -1117,7 +1117,7 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 { // raw_command(&args[1..]); } else if let Some(pd_bin_path) = &args.pd_bin { #[cfg(feature = "uefi")] - let data: Option> = crate::uefi::fs::shell_read_file(pd_bin_path); + let data: Option> = crate::fw_uefi::fs::shell_read_file(pd_bin_path); #[cfg(not(feature = "uefi"))] let data = match fs::read(pd_bin_path) { Ok(data) => Some(data), @@ -1136,7 +1136,7 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 { } } else if let Some(ec_bin_path) = &args.ec_bin { #[cfg(feature = "uefi")] - let data: Option> = crate::uefi::fs::shell_read_file(ec_bin_path); + let data: Option> = crate::fw_uefi::fs::shell_read_file(ec_bin_path); #[cfg(not(feature = "uefi"))] let data = match fs::read(ec_bin_path) { Ok(data) => Some(data), @@ -1155,7 +1155,7 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 { } } else if let Some(capsule_path) = &args.capsule { #[cfg(feature = "uefi")] - let data: Option> = crate::uefi::fs::shell_read_file(capsule_path); + let data: Option> = crate::fw_uefi::fs::shell_read_file(capsule_path); #[cfg(not(feature = "uefi"))] let data = match fs::read(capsule_path) { Ok(data) => Some(data), @@ -1184,7 +1184,7 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 { } } else if let Some(capsule_path) = &args.h2o_capsule { #[cfg(feature = "uefi")] - let data = crate::uefi::fs::shell_read_file(capsule_path); + let data = crate::fw_uefi::fs::shell_read_file(capsule_path); #[cfg(not(feature = "uefi"))] let data = match fs::read(capsule_path) { Ok(data) => Some(data), @@ -1237,7 +1237,7 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 { } else if let Some(hash_file) = &args.hash { println!("Hashing file: {}", hash_file); #[cfg(feature = "uefi")] - let data = crate::uefi::fs::shell_read_file(hash_file); + let data = crate::fw_uefi::fs::shell_read_file(hash_file); #[cfg(not(feature = "uefi"))] let data = match fs::read(hash_file) { Ok(data) => Some(data), @@ -1266,7 +1266,7 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 { Some(PlatformFamily::Framework16) | None ) { #[cfg(feature = "uefi")] - let data: Option> = crate::uefi::fs::shell_read_file(gpu_descriptor_file); + let data: Option> = crate::fw_uefi::fs::shell_read_file(gpu_descriptor_file); #[cfg(not(feature = "uefi"))] let data = match fs::read(gpu_descriptor_file) { Ok(data) => Some(data), diff --git a/framework_lib/src/commandline/uefi.rs b/framework_lib/src/commandline/uefi.rs index 82d6c253..63fba0da 100644 --- a/framework_lib/src/commandline/uefi.rs +++ b/framework_lib/src/commandline/uefi.rs @@ -4,10 +4,8 @@ use alloc::vec::Vec; #[allow(unused_imports)] use log::{debug, error, info, trace}; -use uefi::prelude::BootServices; -use uefi::proto::shell_params::*; -use uefi::table::boot::{OpenProtocolAttributes, OpenProtocolParams, SearchType}; -use uefi::Identify; +use uefi::boot; +use uefi::proto::shell_params::ShellParameters; use crate::chromium_ec::commands::SetGpuSerialMagic; use crate::chromium_ec::{CrosEcDriverType, HardwareDeviceType}; @@ -16,40 +14,19 @@ use crate::commandline::Cli; use super::{ConsoleArg, FpBrightnessArg, InputDeckModeArg, RebootEcArg, TabletModeArg}; /// Get commandline arguments from UEFI environment -pub fn get_args(boot_services: &BootServices) -> Vec { - // TODO: I think i should open this from the ImageHandle? - let shell_params_h = - boot_services.locate_handle_buffer(SearchType::ByProtocol(&ShellParameters::GUID)); - let shell_params_h = if let Ok(shell_params_h) = shell_params_h { - shell_params_h - } else { - error!("ShellParameters protocol not found"); - return vec![]; - }; - - for handle in &*shell_params_h { - let params_handle = unsafe { - boot_services - .open_protocol::( - OpenProtocolParams { - handle: *handle, - agent: boot_services.image_handle(), - controller: None, - }, - OpenProtocolAttributes::GetProtocol, - ) - .expect("Failed to open ShellParameters handle") - }; - - // Ehm why are there two and one has no args? - // Maybe one is the shell itself? - if params_handle.argc == 0 { - continue; +pub fn get_args() -> Vec { + let shell_params = uefi::boot::open_protocol_exclusive::(boot::image_handle()); + let shell_params = match shell_params { + Ok(s) => s, + Err(e) => { + error!("Failed to get ShellParameters protocol"); + // TODO: Return result + // return e.status(); + return vec![]; } - - return params_handle.get_args(); - } - vec![] + }; + let args: Vec = shell_params.args().map(|x| x.to_string()).collect(); + args } pub fn parse(args: &[String]) -> Cli { diff --git a/framework_lib/src/esrt/mod.rs b/framework_lib/src/esrt/mod.rs index aa517bf4..2383ccea 100644 --- a/framework_lib/src/esrt/mod.rs +++ b/framework_lib/src/esrt/mod.rs @@ -33,6 +33,11 @@ use std::os::fd::AsRawFd; #[cfg(target_os = "freebsd")] use std::os::unix::fs::OpenOptionsExt; +#[cfg(feature = "uefi")] +use uefi::system::with_config_table; +#[cfg(feature = "uefi")] +use uefi::table::cfg::ConfigTableEntry; + pub const TGL_BIOS_GUID: GUID = GUID::build_from_components( 0xb3bdb2e4, 0xc5cb, @@ -537,22 +542,16 @@ pub const SYSTEM_RESOURCE_TABLE_GUID_BYTES: [u8; 16] = [ #[cfg(feature = "uefi")] pub fn get_esrt() -> Option { - let st = unsafe { uefi_services::system_table().as_ref() }; - let config_tables = st.config_table(); - - for table in config_tables { - // TODO: Why aren't they the same type? - //debug!("Table: {:?}", table); - let table_guid: Guid = unsafe { std::mem::transmute(table.guid) }; - let table_guid = GUID::from(table_guid); - match table_guid { - SYSTEM_RESOURCE_TABLE_GUID => unsafe { - return esrt_from_buf(table.address as *const u8); - }, - _ => {} + with_config_table(|slice| { + for i in slice { + if i.guid == ConfigTableEntry::ESRT_GUID { + unsafe { + return esrt_from_buf(i.address as *const u8); + } + } } - } - None + None + }) } /// Parse the ESRT table buffer diff --git a/framework_lib/src/fw_uefi/fs.rs b/framework_lib/src/fw_uefi/fs.rs new file mode 100644 index 00000000..e298fdcf --- /dev/null +++ b/framework_lib/src/fw_uefi/fs.rs @@ -0,0 +1,148 @@ +use alloc::vec; +use alloc::vec::Vec; +use uefi::prelude::*; +use uefi::proto::shell::{Shell, ShellProtocol}; +//use uefi::proto::shell::FileOpenMode; +use core::ffi::c_void; +use core::mem::MaybeUninit; +use core::ptr::NonNull; +use uefi::Result; + +#[repr(transparent)] +#[derive(Clone, Copy, Debug)] +pub struct ShellFileHandle(NonNull); + +const FILE_MODE_READ: u64 = 0x0000000000000001; +const FILE_MODE_WRITE: u64 = 0x0000000000000002; +const FILE_MODE_CREATE: u64 = 0x8000000000000000; + +pub fn wstr(string: &str) -> Vec { + let mut wstring = vec![]; + + for c in string.chars() { + wstring.push(c as u16); + } + wstring.push(0); + + wstring +} + +pub fn shell_read_file(path: &str) -> Option> { + let handle = boot::get_handle_for_protocol::().expect("No Shell handles"); + let mut shell = + boot::open_protocol_exclusive::(handle).expect("Failed to open Shell protocol"); + let shell = unsafe { + let proto: &ShellProtocol = std::mem::transmute(shell.get().unwrap()); + proto + }; + + println!("Opened shell protocol"); + + debug_assert_eq!(shell.major_version, 2); + debug_assert_eq!(shell.minor_version, 2); + + println!( + "Shell protocol ver: {}.{}", + shell.major_version, shell.minor_version + ); + + unsafe { + let c_path = wstr(path); + let mut mode = FILE_MODE_READ; + let mut handle: MaybeUninit<*const c_void> = MaybeUninit::zeroed(); + (shell.open_file_by_name)(c_path.as_ptr(), handle.as_mut_ptr().cast(), mode); + + println!("Opened file"); + + let file_handle = handle.assume_init(); + + let mut file_size = 0; + println!("get_file_size"); + let res = (shell.get_file_size)(file_handle, &mut file_size); + // let file_size = res.unwrap(); + + let mut buffer: Vec = vec![0; file_size as usize]; + let mut read_size = file_size as usize; + println!("read_file {} bytes", file_size); + (shell.read_file)( + file_handle, + &mut read_size, + buffer.as_mut_ptr() as *mut c_void, + ); + + println!("close_file"); + + // TODO: Make it auto-close using Rust destructors + (shell.close_file)(file_handle); + + println!("Done"); + + Some(buffer) + } +} + +pub fn shell_write_file(path: &str, data: &[u8]) -> Result { + let handle = boot::get_handle_for_protocol::().expect("No Shell handles"); + let mut shell = + boot::open_protocol_exclusive::(handle).expect("Failed to open Shell protocol"); + let shell = unsafe { + let proto: &ShellProtocol = std::mem::transmute(shell.get().unwrap()); + proto + }; + + debug_assert_eq!(shell.major_version, 2); + debug_assert_eq!(shell.minor_version, 2); + + unsafe { + // let mode = FileOpenMode::Read as u64 + FileOpenMode::Write as u64 + FileOpenMode::Create as u64; + let mode = FILE_MODE_READ + FILE_MODE_WRITE + FILE_MODE_CREATE; + let c_path = wstr(path); + let mut handle: MaybeUninit<*const c_void> = MaybeUninit::zeroed(); + (shell.open_file_by_name)(c_path.as_ptr(), handle.as_mut_ptr().cast(), mode); + let file_handle = handle.assume_init(); + + //// TODO: Free file_info buffer + //let file_info = (shell.0.GetFileInfo)(file_handle); + //if file_info.is_null() { + // println!("Failed to get file info"); + // return ret; + //} + + //// Not sure if it's useful to set FileInfo + ////let mut file_info = unsafe { + //// &mut *(file_info as *mut FileInfo) + ////}; + ////println!("file_info.Size: {}", file_info.Size); + + ////if file_info.Size != 0 { + //// file_info.Size = 0; + //// let ret = (shell.0.SetFileInfo)(file_handle, file_info); + //// if ret.0 != 0 { + //// println!("Failed to set file info"); + //// return ret; + //// } + ////} + + //let mut buffer_size = data.len() as usize; + //let ret = (shell.0.WriteFile)(file_handle, &mut buffer_size, data.as_ptr()); + //if ret.0 != 0 { + // println!("Failed to write file"); + // return ret; + //} + //if buffer_size != data.len() { + // println!( + // "Failed to write whole buffer. Instead of {} wrote {} bytes.", + // data.len(), + // buffer_size + // ); + // return Status(1); + //} + + let mut read_size = data.len(); + (shell.write_file)(file_handle, &mut read_size, data.as_ptr() as *mut c_void); + + (shell.close_file)(file_handle); + + Status::SUCCESS.to_result() + } +} diff --git a/framework_lib/src/fw_uefi/mod.rs b/framework_lib/src/fw_uefi/mod.rs new file mode 100644 index 00000000..e069a3b9 --- /dev/null +++ b/framework_lib/src/fw_uefi/mod.rs @@ -0,0 +1,115 @@ +use alloc::vec::Vec; +use core::slice; +use uefi::system::with_config_table; +use uefi::table::cfg::ConfigTableEntry; + +#[allow(unused_imports)] +use log::{debug, error, info, trace}; +use uefi::boot; +use uefi::proto::shell::{Shell, ShellProtocol}; + +pub mod fs; + +/// Returns true when the execution break was requested, false otherwise +pub fn shell_get_execution_break_flag() -> bool { + let handle = boot::get_handle_for_protocol::().expect("No Shell handles"); + let shell = + boot::open_protocol_exclusive::(handle).expect("Failed to open Shell protocol"); + unsafe { + let proto: &ShellProtocol = std::mem::transmute(shell.get().unwrap()); + (proto.get_page_break)() + } +} + +/// Enable pagination in UEFI shell +/// +/// Pagination is handled by the UEFI shell environment automatically, whenever +/// the application prints more than fits on the screen. +pub fn enable_page_break() { + let handle = boot::get_handle_for_protocol::().expect("No Shell handles"); + let shell = + boot::open_protocol_exclusive::(handle).expect("Failed to open Shell protocol"); + unsafe { + let proto: &ShellProtocol = std::mem::transmute(shell.get().unwrap()); + (proto.enable_page_break)() + } +} + +#[repr(C, packed)] +pub struct Smbios { + pub anchor: [u8; 4], + pub checksum: u8, + pub length: u8, + pub major_version: u8, + pub minor_version: u8, + pub max_structure_size: u16, + pub revision: u8, + pub formatted: [u8; 5], + pub inter_anchor: [u8; 5], + pub inter_checksum: u8, + pub table_length: u16, + pub table_address: u32, + pub structure_count: u16, + pub bcd_revision: u8, +} + +impl Smbios { + pub fn checksum_valid(&self) -> bool { + let mut sum: u8 = self.anchor.iter().sum::(); + sum += self.checksum; + sum += self.length; + sum += self.major_version; + sum += self.minor_version; + sum += self.max_structure_size as u8; + sum += self.revision; + sum += self.formatted.iter().sum::(); + sum == 0 + } +} + +pub struct Smbios3 { + pub anchor: [u8; 5], + pub checksum: u8, + pub length: u8, + pub major_version: u8, + pub minor_version: u8, + pub docrev: u8, + pub revision: u8, + _reserved: u8, + pub table_length: u32, + pub table_address: u64, +} + +pub fn smbios_data() -> Option> { + with_config_table(|slice| { + for i in slice { + let table_data = match i.guid { + ConfigTableEntry::SMBIOS3_GUID => unsafe { + let smbios = &*(i.address as *const Smbios3); + debug!("SMBIOS3 valid: {:?}", smbios.anchor == *b"_SM3_"); + Some(slice::from_raw_parts( + smbios.table_address as *const u8, + smbios.table_length as usize, + )) + }, + ConfigTableEntry::SMBIOS_GUID => unsafe { + let smbios = &*(i.address as *const Smbios); + debug!("SMBIOS valid: {:?}", smbios.checksum_valid()); + Some(slice::from_raw_parts( + smbios.table_address as *const u8, + smbios.table_length as usize, + )) + }, + _ => None, + }; + + if let Some(data) = table_data { + // Return directly here because there is only ever the old config + // table or the new V3 config table. Never both. + return Some(data.to_vec()); + } + } + + None + }) +} diff --git a/framework_lib/src/lib.rs b/framework_lib/src/lib.rs index 05adf8fb..82901fc1 100644 --- a/framework_lib/src/lib.rs +++ b/framework_lib/src/lib.rs @@ -28,7 +28,7 @@ pub mod touchscreen_win; #[cfg(feature = "uefi")] #[macro_use] -extern crate uefi_services; +extern crate uefi; pub mod capsule; pub mod capsule_content; @@ -38,11 +38,11 @@ pub mod commandline; pub mod csme; pub mod ec_binary; pub mod esrt; +#[cfg(feature = "uefi")] +pub mod fw_uefi; mod os_specific; pub mod power; pub mod smbios; -#[cfg(feature = "uefi")] -pub mod uefi; mod util; pub mod built_info { diff --git a/framework_lib/src/os_specific.rs b/framework_lib/src/os_specific.rs index 83ae2f37..1ad49e60 100644 --- a/framework_lib/src/os_specific.rs +++ b/framework_lib/src/os_specific.rs @@ -1,21 +1,20 @@ //! Helper functions that need OS/platform specific implementations +use core::time::Duration; #[cfg(not(feature = "uefi"))] -use std::{thread, time}; +use std::thread; /// Sleep a number of microseconds pub fn sleep(micros: u64) { + let duration = Duration::from_micros(micros); #[cfg(not(feature = "uefi"))] { - let duration = time::Duration::from_micros(micros); thread::sleep(duration); } #[cfg(feature = "uefi")] { // TODO: It's not recommended to use this for sleep more than 10ms // Should use a one-shot timer event - let st = unsafe { uefi_services::system_table().as_ref() }; - let bs = st.boot_services(); - bs.stall(micros as usize); + uefi::boot::stall(duration); } } diff --git a/framework_lib/src/smbios.rs b/framework_lib/src/smbios.rs index 144ad210..48657de8 100644 --- a/framework_lib/src/smbios.rs +++ b/framework_lib/src/smbios.rs @@ -193,7 +193,7 @@ pub fn get_smbios() -> Option { #[cfg(feature = "uefi")] pub fn get_smbios() -> Option { trace!("get_smbios() uefi entry"); - let data = crate::uefi::smbios_data().unwrap(); + let data = crate::fw_uefi::smbios_data().unwrap(); let version = None; // TODO: Maybe add the version here let smbios = SMBiosData::from_vec_and_version(data, version); Some(smbios) diff --git a/framework_lib/src/uefi/fs.rs b/framework_lib/src/uefi/fs.rs deleted file mode 100644 index a5e2ca96..00000000 --- a/framework_lib/src/uefi/fs.rs +++ /dev/null @@ -1,132 +0,0 @@ -use alloc::vec; -use alloc::vec::Vec; -use uefi::prelude::*; -use uefi::proto::shell::FileOpenMode; -use uefi::Result; - -use super::find_shell_handle; - -pub fn wstr(string: &str) -> Vec { - let mut wstring = vec![]; - - for c in string.chars() { - wstring.push(c as u16); - } - wstring.push(0); - - wstring -} - -pub fn shell_read_file(path: &str) -> Option> { - let shell = if let Some(shell) = find_shell_handle() { - shell - } else { - println!("Failed to open Shell Protocol"); - return None; - }; - - debug_assert_eq!(shell.major_version, 2); - debug_assert_eq!(shell.minor_version, 2); - - let c_path = wstr(path); - let handle = shell.open_file_by_name(c_path.as_slice(), FileOpenMode::Read as u64); - - let handle = if let Ok(handle) = handle { - handle - } else { - println!("Failed to open file: {:?}", handle); - return None; - }; - - let handle = if let Some(handle) = handle { - handle - } else { - println!("Failed to open file: {:?}", handle); - return None; - }; - let file_handle = handle; - - let res = shell.get_file_size(file_handle); - let file_size = res.unwrap(); - - let mut buffer: Vec = vec![0; file_size as usize]; - let res = shell.read_file(file_handle, &mut buffer); - res.unwrap(); - - // TODO: Make it auto-close using Rust destructors - shell.close_file(file_handle).unwrap(); - - Some(buffer) -} - -pub fn shell_write_file(path: &str, data: &[u8]) -> Result { - let shell = if let Some(shell) = find_shell_handle() { - shell - } else { - println!("Failed to open Shell Protocol"); - return Status::LOAD_ERROR.into(); - }; - - debug_assert_eq!(shell.major_version, 2); - debug_assert_eq!(shell.minor_version, 2); - - let mode = FileOpenMode::Read as u64 + FileOpenMode::Write as u64 + FileOpenMode::Create as u64; - let c_path = wstr(path); - let handle = shell.open_file_by_name(c_path.as_slice(), mode); - let handle = if let Ok(handle) = handle { - handle - } else { - println!("Failed to open file: {:?}", handle); - return Status::LOAD_ERROR.into(); - }; - let handle = if let Some(handle) = handle { - handle - } else { - println!("Failed to open file: {:?}", handle); - return Status::LOAD_ERROR.into(); - }; - let file_handle = handle; - - //// TODO: Free file_info buffer - //let file_info = (shell.0.GetFileInfo)(file_handle); - //if file_info.is_null() { - // println!("Failed to get file info"); - // return ret; - //} - - //// Not sure if it's useful to set FileInfo - ////let mut file_info = unsafe { - //// &mut *(file_info as *mut FileInfo) - ////}; - ////println!("file_info.Size: {}", file_info.Size); - - ////if file_info.Size != 0 { - //// file_info.Size = 0; - //// let ret = (shell.0.SetFileInfo)(file_handle, file_info); - //// if ret.0 != 0 { - //// println!("Failed to set file info"); - //// return ret; - //// } - ////} - - //let mut buffer_size = data.len() as usize; - //let ret = (shell.0.WriteFile)(file_handle, &mut buffer_size, data.as_ptr()); - //if ret.0 != 0 { - // println!("Failed to write file"); - // return ret; - //} - //if buffer_size != data.len() { - // println!( - // "Failed to write whole buffer. Instead of {} wrote {} bytes.", - // data.len(), - // buffer_size - // ); - // return Status(1); - //} - - shell.write_file(file_handle, data).unwrap(); - - shell.close_file(file_handle).unwrap(); - - Status::SUCCESS.into() -} diff --git a/framework_lib/src/uefi/mod.rs b/framework_lib/src/uefi/mod.rs deleted file mode 100644 index 71d85b44..00000000 --- a/framework_lib/src/uefi/mod.rs +++ /dev/null @@ -1,179 +0,0 @@ -use alloc::vec::Vec; -use core::slice; -use uefi::table::boot::{OpenProtocolAttributes, OpenProtocolParams, ScopedProtocol, SearchType}; - -#[allow(unused_imports)] -use log::{debug, error, info, trace}; -use uefi::proto::shell::Shell; -use uefi::table::cfg::{SMBIOS3_GUID, SMBIOS_GUID}; -use uefi::table::{Boot, SystemTable}; -use uefi::Identify; - -pub mod fs; - -pub fn get_system_table() -> &'static SystemTable { - unsafe { uefi_services::system_table().as_ref() } -} - -fn find_shell_handle() -> Option> { - let st = unsafe { uefi_services::system_table().as_ref() }; - let boot_services = st.boot_services(); - let shell_handles = boot_services.locate_handle_buffer(SearchType::ByProtocol(&Shell::GUID)); - if let Ok(sh_buf) = shell_handles { - for handle in &*sh_buf { - return Some(unsafe { - boot_services - .open_protocol::( - OpenProtocolParams { - handle: *handle, - agent: boot_services.image_handle(), - controller: None, - }, - OpenProtocolAttributes::GetProtocol, - ) - .expect("Failed to open Shell handle") - }); - } - } else { - panic!("No shell handle found!"); - } - None -} - -/// Returns true when the execution break was requested, false otherwise -pub fn shell_get_execution_break_flag() -> bool { - let st = unsafe { uefi_services::system_table().as_ref() }; - let boot_services = st.boot_services(); - let shell_handles = boot_services.locate_handle_buffer(SearchType::ByProtocol(&Shell::GUID)); - if let Ok(sh_buf) = shell_handles { - for handle in &*sh_buf { - let shell_handle = unsafe { - boot_services - .open_protocol::( - OpenProtocolParams { - handle: *handle, - agent: boot_services.image_handle(), - controller: None, - }, - OpenProtocolAttributes::GetProtocol, - ) - .expect("Failed to open Shell handle") - }; - - let event = unsafe { shell_handle.execution_break.unsafe_clone() }; - return boot_services.check_event(event).unwrap(); - } - return false; - } else { - panic!("No shell handle found!"); - } -} - -/// Enable pagination in UEFI shell -/// -/// Pagination is handled by the UEFI shell environment automatically, whenever -/// the application prints more than fits on the screen. -pub fn enable_page_break() { - let st = unsafe { uefi_services::system_table().as_ref() }; - let boot_services = st.boot_services(); - let shell_handles = boot_services.locate_handle_buffer(SearchType::ByProtocol(&Shell::GUID)); - if let Ok(sh_buf) = shell_handles { - for handle in &*sh_buf { - //trace!("Calling enable_page_break"); - let shell_handle = unsafe { - boot_services - .open_protocol::( - OpenProtocolParams { - handle: *handle, - agent: boot_services.image_handle(), - controller: None, - }, - OpenProtocolAttributes::GetProtocol, - ) - .expect("Failed to open Shell handle") - }; - shell_handle.enable_page_break(); - } - } else { - panic!("No shell handle found!"); - } -} - -#[repr(C, packed)] -pub struct Smbios { - pub anchor: [u8; 4], - pub checksum: u8, - pub length: u8, - pub major_version: u8, - pub minor_version: u8, - pub max_structure_size: u16, - pub revision: u8, - pub formatted: [u8; 5], - pub inter_anchor: [u8; 5], - pub inter_checksum: u8, - pub table_length: u16, - pub table_address: u32, - pub structure_count: u16, - pub bcd_revision: u8, -} - -impl Smbios { - pub fn checksum_valid(&self) -> bool { - let mut sum: u8 = self.anchor.iter().sum::(); - sum += self.checksum; - sum += self.length; - sum += self.major_version; - sum += self.minor_version; - sum += self.max_structure_size as u8; - sum += self.revision; - sum += self.formatted.iter().sum::(); - sum == 0 - } -} - -pub struct Smbios3 { - pub anchor: [u8; 5], - pub checksum: u8, - pub length: u8, - pub major_version: u8, - pub minor_version: u8, - pub docrev: u8, - pub revision: u8, - _reserved: u8, - pub table_length: u32, - pub table_address: u64, -} - -pub fn smbios_data() -> Option> { - let st = unsafe { uefi_services::system_table().as_ref() }; - let config_tables = st.config_table(); - - for table in config_tables { - let table_data = match table.guid { - SMBIOS3_GUID => unsafe { - let smbios = &*(table.address as *const Smbios3); - debug!("SMBIOS3 valid: {:?}", smbios.anchor == *b"_SM3_"); - Some(slice::from_raw_parts( - smbios.table_address as *const u8, - smbios.table_length as usize, - )) - }, - SMBIOS_GUID => unsafe { - let smbios = &*(table.address as *const Smbios); - debug!("SMBIOS valid: {:?}", smbios.checksum_valid()); - Some(slice::from_raw_parts( - smbios.table_address as *const u8, - smbios.table_length as usize, - )) - }, - _ => None, - }; - - if let Some(data) = table_data { - // Return directly here because there is only ever the old config - // table or the new V3 config table. Never both. - return Some(data.to_vec()); - } - } - None -} diff --git a/framework_uefi/Cargo.toml b/framework_uefi/Cargo.toml index adc8b14b..a3a225dc 100644 --- a/framework_uefi/Cargo.toml +++ b/framework_uefi/Cargo.toml @@ -15,8 +15,7 @@ name = "uefitool" path = "src/main.rs" [dependencies] -uefi = { version = "0.20", features = ["alloc"] } -uefi-services = "0.17" +uefi = { version = "0.35", features = ["alloc"] } log = { version = "0.4", default-features = true } [dependencies.framework_lib] diff --git a/framework_uefi/src/main.rs b/framework_uefi/src/main.rs index b81cbe63..a9e8f581 100644 --- a/framework_uefi/src/main.rs +++ b/framework_uefi/src/main.rs @@ -5,18 +5,17 @@ use log::{debug, error, info, trace}; use uefi::prelude::*; #[allow(unused_imports)] -use uefi_services::{print, println}; +use uefi::{print, println}; extern crate alloc; use framework_lib::commandline; #[entry] -fn main(_handle: Handle, mut system_table: SystemTable) -> Status { - uefi_services::init(&mut system_table).unwrap(); - let bs = system_table.boot_services(); +fn main() -> Status { + uefi::helpers::init().unwrap(); - let args = commandline::uefi::get_args(bs); + let args = commandline::uefi::get_args(); let args = commandline::parse(&args); if commandline::run_with_args(&args, false) == 0 { return Status::SUCCESS;