Skip to content

Commit 63b214c

Browse files
committed
implement file system ops
Signed-off-by: Daniel Schaefer <dhs@frame.work>
1 parent 39fe084 commit 63b214c

File tree

12 files changed

+297
-338
lines changed

12 files changed

+297
-338
lines changed

Cargo.lock

Lines changed: 4 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,10 @@ default-members = [
1919
"framework_tool",
2020
]
2121

22+
# Need latest commit that hasn't been released yet
23+
[patch.crates-io]
24+
uefi = { git = "https://github.com/rust-osdev/uefi-rs", rev = "1fcf4d84d5ed10fe76055469b6df01318eb35af8" }
25+
uefi-raw = { git = "https://github.com/rust-osdev/uefi-rs", rev = "1fcf4d84d5ed10fe76055469b6df01318eb35af8" }
26+
2227
[profile.release]
2328
lto = true

framework_lib/src/chromium_ec/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@
99
//! - `windows` - It uses [DHowett's Windows driver](https://github.com/DHowett/FrameworkWindowsUtils)
1010
1111
use crate::ec_binary;
12+
#[cfg(feature = "uefi")]
13+
use crate::fw_uefi::shell_get_execution_break_flag;
1214
use crate::os_specific;
1315
use crate::power;
1416
use crate::smbios;
15-
#[cfg(feature = "uefi")]
16-
use crate::fw_uefi::shell_get_execution_break_flag;
1717
use crate::util::{self, Platform};
1818

1919
use no_std_compat::time::Duration;

framework_lib/src/commandline/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ use crate::chromium_ec::{EcError, EcResult};
4848
use crate::csme;
4949
use crate::ec_binary;
5050
use crate::esrt;
51+
#[cfg(feature = "uefi")]
52+
use crate::fw_uefi::enable_page_break;
5153
#[cfg(feature = "rusb")]
5254
use crate::inputmodule::check_inputmodule_version;
5355
#[cfg(target_os = "linux")]
@@ -62,8 +64,6 @@ use crate::smbios::{dmidecode_string_val, get_smbios, is_framework};
6264
use crate::touchpad::print_touchpad_fw_ver;
6365
#[cfg(feature = "hidapi")]
6466
use crate::touchscreen;
65-
#[cfg(feature = "uefi")]
66-
use crate::fw_uefi::enable_page_break;
6767
#[cfg(feature = "rusb")]
6868
use crate::usbhub::check_usbhub_version;
6969
use crate::util::{self, Config, Platform, PlatformFamily};

framework_lib/src/commandline/uefi.rs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@ use alloc::vec::Vec;
44

55
#[allow(unused_imports)]
66
use log::{debug, error, info, trace};
7-
use uefi::prelude::BootServices;
8-
use uefi::proto::shell_params::*;
9-
use uefi::Handle;
7+
use uefi::boot;
8+
use uefi::proto::shell_params::ShellParameters;
109

1110
use crate::chromium_ec::commands::SetGpuSerialMagic;
1211
use crate::chromium_ec::{CrosEcDriverType, HardwareDeviceType};
@@ -15,13 +14,19 @@ use crate::commandline::{Cli, LogLevel};
1514
use super::{ConsoleArg, FpBrightnessArg, InputDeckModeArg, RebootEcArg, TabletModeArg};
1615

1716
/// Get commandline arguments from UEFI environment
18-
pub fn get_args(bs: &BootServices, image_handle: Handle) -> Vec<String> {
19-
if let Ok(shell_params) = bs.open_protocol_exclusive::<ShellParameters>(image_handle) {
20-
shell_params.get_args()
21-
} else {
22-
// No protocol found if the application wasn't executed by the shell
23-
vec![]
24-
}
17+
pub fn get_args() -> Vec<String> {
18+
let shell_params = uefi::boot::open_protocol_exclusive::<ShellParameters>(boot::image_handle());
19+
let shell_params = match shell_params {
20+
Ok(s) => s,
21+
Err(e) => {
22+
error!("Failed to get ShellParameters protocol");
23+
// TODO: Return result
24+
// return e.status();
25+
return vec![];
26+
}
27+
};
28+
let args: Vec<String> = shell_params.args().map(|x| x.to_string()).collect();
29+
args
2530
}
2631

2732
pub fn parse(args: &[String]) -> Cli {

framework_lib/src/esrt/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -518,7 +518,7 @@ pub const SYSTEM_RESOURCE_TABLE_GUID_BYTES: [u8; 16] = [
518518
pub fn get_esrt() -> Option<Esrt> {
519519
with_config_table(|slice| {
520520
for i in slice {
521-
if i.guid == uefi::table::cfg::ESRT_GUID {
521+
if i.guid == ConfigTableEntry::ESRT_GUID {
522522
unsafe {
523523
return esrt_from_buf(i.address as *const u8);
524524
}

framework_lib/src/fw_uefi/fs.rs

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
use alloc::vec;
2+
use alloc::vec::Vec;
3+
use uefi::prelude::*;
4+
use uefi::proto::shell::{Shell, ShellProtocol};
5+
//use uefi::proto::shell::FileOpenMode;
6+
use core::ffi::c_void;
7+
use core::mem::MaybeUninit;
8+
use core::ptr::NonNull;
9+
use uefi::Result;
10+
11+
#[repr(transparent)]
12+
#[derive(Clone, Copy, Debug)]
13+
pub struct ShellFileHandle(NonNull<c_void>);
14+
15+
const FILE_MODE_READ: u64 = 0x0000000000000001;
16+
const FILE_MODE_WRITE: u64 = 0x0000000000000002;
17+
const FILE_MODE_CREATE: u64 = 0x8000000000000000;
18+
19+
pub fn wstr(string: &str) -> Vec<u16> {
20+
let mut wstring = vec![];
21+
22+
for c in string.chars() {
23+
wstring.push(c as u16);
24+
}
25+
wstring.push(0);
26+
27+
wstring
28+
}
29+
30+
pub fn shell_read_file(path: &str) -> Option<Vec<u8>> {
31+
let handle = boot::get_handle_for_protocol::<Shell>().expect("No Shell handles");
32+
let mut shell =
33+
boot::open_protocol_exclusive::<Shell>(handle).expect("Failed to open Shell protocol");
34+
let shell = unsafe {
35+
let proto: &ShellProtocol = std::mem::transmute(shell.get().unwrap());
36+
proto
37+
};
38+
39+
println!("Opened shell protocol");
40+
41+
debug_assert_eq!(shell.major_version, 2);
42+
debug_assert_eq!(shell.minor_version, 2);
43+
44+
println!(
45+
"Shell protocol ver: {}.{}",
46+
shell.major_version, shell.minor_version
47+
);
48+
49+
unsafe {
50+
let c_path = wstr(path);
51+
let mut mode = FILE_MODE_READ;
52+
let mut handle: MaybeUninit<*const c_void> = MaybeUninit::zeroed();
53+
(shell.open_file_by_name)(c_path.as_ptr(), handle.as_mut_ptr().cast(), mode);
54+
55+
println!("Opened file");
56+
57+
let file_handle = handle.assume_init();
58+
59+
let mut file_size = 0;
60+
println!("get_file_size");
61+
let res = (shell.get_file_size)(file_handle, &mut file_size);
62+
// let file_size = res.unwrap();
63+
64+
let mut buffer: Vec<u8> = vec![0; file_size as usize];
65+
let mut read_size = file_size as usize;
66+
println!("read_file {} bytes", file_size);
67+
(shell.read_file)(
68+
file_handle,
69+
&mut read_size,
70+
buffer.as_mut_ptr() as *mut c_void,
71+
);
72+
73+
println!("close_file");
74+
75+
// TODO: Make it auto-close using Rust destructors
76+
(shell.close_file)(file_handle);
77+
78+
println!("Done");
79+
80+
Some(buffer)
81+
}
82+
}
83+
84+
pub fn shell_write_file(path: &str, data: &[u8]) -> Result {
85+
let handle = boot::get_handle_for_protocol::<Shell>().expect("No Shell handles");
86+
let mut shell =
87+
boot::open_protocol_exclusive::<Shell>(handle).expect("Failed to open Shell protocol");
88+
let shell = unsafe {
89+
let proto: &ShellProtocol = std::mem::transmute(shell.get().unwrap());
90+
proto
91+
};
92+
93+
debug_assert_eq!(shell.major_version, 2);
94+
debug_assert_eq!(shell.minor_version, 2);
95+
96+
unsafe {
97+
// let mode = FileOpenMode::Read as u64 + FileOpenMode::Write as u64 + FileOpenMode::Create as u64;
98+
let mode = FILE_MODE_READ + FILE_MODE_WRITE + FILE_MODE_CREATE;
99+
let c_path = wstr(path);
100+
let mut handle: MaybeUninit<*const c_void> = MaybeUninit::zeroed();
101+
(shell.open_file_by_name)(c_path.as_ptr(), handle.as_mut_ptr().cast(), mode);
102+
let file_handle = handle.assume_init();
103+
104+
//// TODO: Free file_info buffer
105+
//let file_info = (shell.0.GetFileInfo)(file_handle);
106+
//if file_info.is_null() {
107+
// println!("Failed to get file info");
108+
// return ret;
109+
//}
110+
111+
//// Not sure if it's useful to set FileInfo
112+
////let mut file_info = unsafe {
113+
//// &mut *(file_info as *mut FileInfo)
114+
////};
115+
////println!("file_info.Size: {}", file_info.Size);
116+
117+
////if file_info.Size != 0 {
118+
//// file_info.Size = 0;
119+
//// let ret = (shell.0.SetFileInfo)(file_handle, file_info);
120+
//// if ret.0 != 0 {
121+
//// println!("Failed to set file info");
122+
//// return ret;
123+
//// }
124+
////}
125+
126+
//let mut buffer_size = data.len() as usize;
127+
//let ret = (shell.0.WriteFile)(file_handle, &mut buffer_size, data.as_ptr());
128+
//if ret.0 != 0 {
129+
// println!("Failed to write file");
130+
// return ret;
131+
//}
132+
//if buffer_size != data.len() {
133+
// println!(
134+
// "Failed to write whole buffer. Instead of {} wrote {} bytes.",
135+
// data.len(),
136+
// buffer_size
137+
// );
138+
// return Status(1);
139+
//}
140+
141+
let mut read_size = data.len();
142+
(shell.write_file)(file_handle, &mut read_size, data.as_ptr() as *mut c_void);
143+
144+
(shell.close_file)(file_handle);
145+
146+
Status::SUCCESS.to_result()
147+
}
148+
}

framework_lib/src/fw_uefi/mod.rs

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
use alloc::vec::Vec;
2+
use core::slice;
3+
use uefi::system::with_config_table;
4+
use uefi::table::cfg::ConfigTableEntry;
5+
6+
#[allow(unused_imports)]
7+
use log::{debug, error, info, trace};
8+
use uefi::boot;
9+
use uefi::proto::shell::{Shell, ShellProtocol};
10+
11+
pub mod fs;
12+
13+
/// Returns true when the execution break was requested, false otherwise
14+
pub fn shell_get_execution_break_flag() -> bool {
15+
let handle = boot::get_handle_for_protocol::<Shell>().expect("No Shell handles");
16+
let shell =
17+
boot::open_protocol_exclusive::<Shell>(handle).expect("Failed to open Shell protocol");
18+
unsafe {
19+
let proto: &ShellProtocol = std::mem::transmute(shell.get().unwrap());
20+
(proto.get_page_break)()
21+
}
22+
}
23+
24+
/// Enable pagination in UEFI shell
25+
///
26+
/// Pagination is handled by the UEFI shell environment automatically, whenever
27+
/// the application prints more than fits on the screen.
28+
pub fn enable_page_break() {
29+
let handle = boot::get_handle_for_protocol::<Shell>().expect("No Shell handles");
30+
let shell =
31+
boot::open_protocol_exclusive::<Shell>(handle).expect("Failed to open Shell protocol");
32+
unsafe {
33+
let proto: &ShellProtocol = std::mem::transmute(shell.get().unwrap());
34+
(proto.enable_page_break)()
35+
}
36+
}
37+
38+
#[repr(C, packed)]
39+
pub struct Smbios {
40+
pub anchor: [u8; 4],
41+
pub checksum: u8,
42+
pub length: u8,
43+
pub major_version: u8,
44+
pub minor_version: u8,
45+
pub max_structure_size: u16,
46+
pub revision: u8,
47+
pub formatted: [u8; 5],
48+
pub inter_anchor: [u8; 5],
49+
pub inter_checksum: u8,
50+
pub table_length: u16,
51+
pub table_address: u32,
52+
pub structure_count: u16,
53+
pub bcd_revision: u8,
54+
}
55+
56+
impl Smbios {
57+
pub fn checksum_valid(&self) -> bool {
58+
let mut sum: u8 = self.anchor.iter().sum::<u8>();
59+
sum += self.checksum;
60+
sum += self.length;
61+
sum += self.major_version;
62+
sum += self.minor_version;
63+
sum += self.max_structure_size as u8;
64+
sum += self.revision;
65+
sum += self.formatted.iter().sum::<u8>();
66+
sum == 0
67+
}
68+
}
69+
70+
pub struct Smbios3 {
71+
pub anchor: [u8; 5],
72+
pub checksum: u8,
73+
pub length: u8,
74+
pub major_version: u8,
75+
pub minor_version: u8,
76+
pub docrev: u8,
77+
pub revision: u8,
78+
_reserved: u8,
79+
pub table_length: u32,
80+
pub table_address: u64,
81+
}
82+
83+
pub fn smbios_data() -> Option<Vec<u8>> {
84+
with_config_table(|slice| {
85+
for i in slice {
86+
let table_data = match i.guid {
87+
ConfigTableEntry::SMBIOS3_GUID => unsafe {
88+
let smbios = &*(i.address as *const Smbios3);
89+
debug!("SMBIOS3 valid: {:?}", smbios.anchor == *b"_SM3_");
90+
Some(slice::from_raw_parts(
91+
smbios.table_address as *const u8,
92+
smbios.table_length as usize,
93+
))
94+
},
95+
ConfigTableEntry::SMBIOS_GUID => unsafe {
96+
let smbios = &*(i.address as *const Smbios);
97+
debug!("SMBIOS valid: {:?}", smbios.checksum_valid());
98+
Some(slice::from_raw_parts(
99+
smbios.table_address as *const u8,
100+
smbios.table_length as usize,
101+
))
102+
},
103+
_ => None,
104+
};
105+
106+
if let Some(data) = table_data {
107+
// Return directly here because there is only ever the old config
108+
// table or the new V3 config table. Never both.
109+
return Some(data.to_vec());
110+
}
111+
}
112+
113+
None
114+
})
115+
}

0 commit comments

Comments
 (0)