Skip to content

Commit 03d72f9

Browse files
Merge pull request #45 from FrameworkComputer/freebsd
Add FreeBSD Support
2 parents 4ae1189 + 234c931 commit 03d72f9

12 files changed

Lines changed: 294 additions & 87 deletions

File tree

Cargo.lock

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

README.md

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ see the [Support Matrices](support-matrices.md).
1616
- [x] OS Tool (`framework_tool`)
1717
- [x] Tested on Linux
1818
- [x] Tested on Windows
19-
- [ ] Tested on FreeBSD
19+
- [x] Tested on FreeBSD
2020
- [x] UEFI Shell tool (`framework_uefi`)
2121

2222
###### Firmware Information
2323

2424
- [x] Show system information
25-
- [x] ESRT table (UEFI and Linux only) (`--esrt`)
25+
- [x] ESRT table (UEFI, Linux, FreeBSD only) (`--esrt`)
2626
- [x] SMBIOS
2727
- [x] Get firmware version from binary file
2828
- [x] Legacy EC (Intel 13th Gen and earlier) (`--ec-bin`)
@@ -299,3 +299,15 @@ Keyboard backlight: 0%
299299
[DEBUG] send_command(command=0x22, ver=0, data_len=0)
300300
Keyboard backlight: 0%
301301
```
302+
303+
## FreeBSD
304+
305+
```
306+
sudo pkg install hidapi
307+
308+
# Build the library and tool
309+
cargo build --no-default-features --features freebsd
310+
311+
# Running the tool
312+
cargo run --no-default-features --features freebsd
313+
```

framework_lib/Cargo.toml

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@ build = "build.rs"
88
[features]
99
default = ["linux"]
1010
# Linux/FreeBSD
11-
unix = ["std", "cros_ec_driver", "raw_pio", "smbios", "dep:nix"]
12-
linux = ["linux_pio", "unix"]
11+
unix = ["std", "raw_pio", "smbios", "dep:nix", "dep:libc"]
12+
linux = ["unix", "linux_pio", "cros_ec_driver"]
13+
freebsd = ["unix", "freebsd_pio"]
1314
# Windows does not have the cros_ec driver nor raw port I/O access to userspace
14-
windows = ["std", "smbios", "dep:windows", "win_driver"]
15+
windows = ["std", "smbios", "dep:windows", "win_driver", "raw_pio"]
1516
smbios = ["dep:smbios-lib"]
1617
std = ["dep:clap", "dep:clap-verbosity-flag", "dep:env_logger", "smbios-lib?/std", "dep:hidapi", "dep:rusb"]
1718
uefi = [
@@ -22,8 +23,10 @@ uefi = [
2223
"sha2/force-soft"
2324
]
2425

26+
# EC communication via Port I/O on FreeBSD
27+
freebsd_pio = ["redox_hwio/std"]
2528
# EC communication via Port I/O on Linux
26-
linux_pio = ["dep:libc"]
29+
linux_pio = ["dep:libc", "redox_hwio/std"]
2730
# EC communication via raw Port I/O (e.g. UEFI or other ring 0 code)
2831
raw_pio = []
2932
# EC communication via cros_ec driver on Linux
@@ -39,8 +42,8 @@ built = { version = "0.5", features = ["chrono", "git2"] }
3942
lazy_static = "1.4.0"
4043
sha2 = { version = "0.10.6", default_features = false, features = [ "force-soft" ] }
4144
regex = { version = "1.10.0", default-features = false }
42-
redox_hwio = { version = "0.1.5", default_features = false }
43-
libc = { version = "0.2.137", optional = true }
45+
redox_hwio = { git = "https://github.com/FrameworkComputer/rust-hwio", branch = "freebsd", default_features = false }
46+
libc = { version = "0.2.155", optional = true }
4447
clap = { version = "4.0", features = ["derive"], optional = true }
4548
clap-verbosity-flag = { version = "2.0.1", optional = true }
4649
nix = { version = "0.25.0", optional = true }

framework_lib/src/ccgx/binary.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ fn read_version(
150150
unsafe { std::ptr::read(data[0..version_len].as_ptr() as *const _) };
151151

152152
let base_version = BaseVersion::from(version_info.base_version);
153-
let app_version = AppVersion::try_from(version_info.app_version).ok()?;
153+
let app_version = AppVersion::from(version_info.app_version);
154154

155155
let fw_silicon_id = version_info.silicon_id;
156156
let fw_silicon_family = version_info.silicon_family;

framework_lib/src/ccgx/device.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use core::prelude::rust_2021::derive;
1111

1212
use crate::ccgx::{AppVersion, BaseVersion, ControllerVersion};
1313
use crate::chromium_ec::command::EcCommands;
14-
use crate::chromium_ec::{CrosEc, CrosEcDriver, EcError, EcResponseStatus, EcResult};
14+
use crate::chromium_ec::{CrosEc, CrosEcDriver, EcError, EcResult};
1515
use crate::util::{self, assert_win_len, Config, Platform};
1616
use std::mem::size_of;
1717

@@ -299,8 +299,7 @@ impl PdController {
299299
let data = self.ccgx_read(register, 8)?;
300300
Ok(ControllerVersion {
301301
base: BaseVersion::from(&data[..4]),
302-
app: AppVersion::try_from(&data[4..])
303-
.or(Err(EcError::Response(EcResponseStatus::InvalidResponse)))?,
302+
app: AppVersion::from(&data[4..]),
304303
})
305304
}
306305

framework_lib/src/ccgx/hid.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,9 +254,17 @@ pub fn find_devices(api: &HidApi, filter_devs: &[u16], sn: Option<&str>) -> Vec<
254254
let vid = dev_info.vendor_id();
255255
let pid = dev_info.product_id();
256256
let usage_page = dev_info.usage_page();
257+
258+
debug!("Found {:X}:{:X} Usage Page: {}", vid, pid, usage_page);
259+
let usage_page_filter = usage_page == CCG_USAGE_PAGE;
260+
// On FreeBSD it seems we don't get different usage pages
261+
// There's just one entry overall
262+
#[cfg(target_os = "freebsd")]
263+
let usage_page_filter = true;
264+
257265
if vid == FRAMEWORK_VID
258266
&& filter_devs.contains(&pid)
259-
&& usage_page == CCG_USAGE_PAGE
267+
&& usage_page_filter
260268
&& (sn.is_none() || sn == dev_info.serial_number())
261269
{
262270
Some(dev_info.clone())

framework_lib/src/chromium_ec/portio.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ use alloc::string::ToString;
44
use alloc::vec;
55
use alloc::vec::Vec;
66
use core::convert::TryInto;
7+
#[cfg(any(feature = "linux_pio", feature = "freebsd_pio", feature = "raw_pio"))]
78
use hwio::{Io, Pio};
8-
#[cfg(feature = "linux_pio")]
9+
#[cfg(all(feature = "linux_pio", target_os = "linux"))]
910
use libc::ioperm;
1011
use log::Level;
1112
#[cfg(feature = "linux_pio")]

framework_lib/src/commandline/mod.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ fn print_versions(ec: &CrosEc) {
293293
println!("UEFI BIOS");
294294
if let Some(smbios) = get_smbios() {
295295
let bios_entries = smbios.collect::<SMBiosInformation>();
296-
let bios = bios_entries.get(0).unwrap();
296+
let bios = bios_entries.first().unwrap();
297297
println!(" Version: {}", bios.version());
298298
println!(" Release Date: {}", bios.release_date());
299299
}
@@ -911,6 +911,14 @@ fn selftest(ec: &CrosEc) -> Option<()> {
911911
}
912912

913913
fn smbios_info() {
914+
println!("Summary");
915+
println!(" Is Framework: {}", is_framework());
916+
if let Some(platform) = smbios::get_platform() {
917+
println!(" Platform: {:?}", platform);
918+
} else {
919+
println!(" Platform: Unknown",);
920+
}
921+
914922
let smbios = get_smbios();
915923
if smbios.is_none() {
916924
error!("Failed to find SMBIOS");

framework_lib/src/esrt/mod.rs

Lines changed: 68 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ use core::prelude::v1::derive;
2020
#[cfg(not(feature = "uefi"))]
2121
use guid_macros::guid;
2222
#[cfg(feature = "uefi")]
23-
use std::slice;
24-
#[cfg(feature = "uefi")]
2523
use uefi::{guid, Guid};
2624

2725
#[cfg(feature = "linux")]
@@ -31,6 +29,15 @@ use std::io;
3129
#[cfg(feature = "linux")]
3230
use std::path::Path;
3331

32+
#[cfg(target_os = "freebsd")]
33+
use nix::ioctl_readwrite;
34+
#[cfg(target_os = "freebsd")]
35+
use std::fs::OpenOptions;
36+
#[cfg(target_os = "freebsd")]
37+
use std::os::fd::AsRawFd;
38+
#[cfg(target_os = "freebsd")]
39+
use std::os::unix::fs::OpenOptionsExt;
40+
3441
/// Decode from GUID string version
3542
///
3643
/// # Examples
@@ -316,7 +323,7 @@ fn esrt_from_sysfs(dir: &Path) -> io::Result<Esrt> {
316323
Ok(esrt_table)
317324
}
318325

319-
#[cfg(all(not(feature = "uefi"), feature = "linux"))]
326+
#[cfg(all(not(feature = "uefi"), feature = "linux", target_os = "linux"))]
320327
pub fn get_esrt() -> Option<Esrt> {
321328
let res = esrt_from_sysfs(Path::new("/sys/firmware/efi/esrt/entries")).ok();
322329
if res.is_none() {
@@ -332,11 +339,43 @@ pub fn get_esrt() -> Option<Esrt> {
332339
None
333340
}
334341

342+
#[cfg(target_os = "freebsd")]
343+
#[repr(C)]
344+
struct EfiGetTableIoc {
345+
buf: *mut u8,
346+
uuid: [u8; 16],
347+
table_len: usize,
348+
buf_len: usize,
349+
}
350+
#[cfg(target_os = "freebsd")]
351+
ioctl_readwrite!(efi_get_table, b'E', 1, EfiGetTableIoc);
352+
335353
#[cfg(all(not(feature = "uefi"), target_os = "freebsd"))]
336354
pub fn get_esrt() -> Option<Esrt> {
337-
// TODO: Implement
338-
println!("Reading ESRT is not implemented on FreeBSD yet.");
339-
None
355+
let file = OpenOptions::new()
356+
.read(true)
357+
.write(true)
358+
.custom_flags(libc::O_NONBLOCK)
359+
.open("/dev/efi")
360+
.unwrap();
361+
362+
let mut buf: Vec<u8> = Vec::new();
363+
let mut table = EfiGetTableIoc {
364+
buf: std::ptr::null_mut(),
365+
uuid: SYSTEM_RESOURCE_TABLE_GUID.to_bytes(),
366+
buf_len: 0,
367+
table_len: 0,
368+
};
369+
unsafe {
370+
let fd = file.as_raw_fd();
371+
let _res = efi_get_table(fd, &mut table).unwrap();
372+
buf.resize(table.table_len, 0);
373+
table.buf_len = table.table_len;
374+
table.buf = buf.as_mut_ptr();
375+
376+
let _res = efi_get_table(fd, &mut table).unwrap();
377+
esrt_from_buf(table.buf)
378+
}
340379
}
341380

342381
/// gEfiSystemResourceTableGuid from MdePkg/MdePkg.dec
@@ -353,26 +392,32 @@ pub fn get_esrt() -> Option<Esrt> {
353392
let table_guid: Guid = unsafe { std::mem::transmute(table.guid) };
354393
match table_guid {
355394
SYSTEM_RESOURCE_TABLE_GUID => unsafe {
356-
let raw_esrt = &*(table.address as *const _Esrt);
357-
let mut esrt = Esrt {
358-
resource_count: raw_esrt.resource_count,
359-
resource_count_max: raw_esrt.resource_count_max,
360-
resource_version: raw_esrt.resource_version,
361-
entries: vec![],
362-
};
363-
364-
// Make sure it's the version we expect
365-
debug_assert!(esrt.resource_version == ESRT_FIRMWARE_RESOURCE_VERSION);
366-
367-
let src_ptr = std::ptr::addr_of!(raw_esrt.entries) as *const EsrtResourceEntry;
368-
let slice_entries = slice::from_raw_parts(src_ptr, esrt.resource_count as usize);
369-
370-
esrt.entries = slice_entries.to_vec();
371-
372-
return Some(esrt);
395+
return esrt_from_buf(table.address as *const u8);
373396
},
374397
_ => {}
375398
}
376399
}
377400
None
378401
}
402+
403+
/// Parse the ESRT table buffer
404+
#[cfg(any(feature = "uefi", target_os = "freebsd"))]
405+
unsafe fn esrt_from_buf(ptr: *const u8) -> Option<Esrt> {
406+
let raw_esrt = &*(ptr as *const _Esrt);
407+
let mut esrt = Esrt {
408+
resource_count: raw_esrt.resource_count,
409+
resource_count_max: raw_esrt.resource_count_max,
410+
resource_version: raw_esrt.resource_version,
411+
entries: vec![],
412+
};
413+
414+
// Make sure it's the version we expect
415+
debug_assert!(esrt.resource_version == ESRT_FIRMWARE_RESOURCE_VERSION);
416+
417+
let src_ptr = core::ptr::addr_of!(raw_esrt.entries) as *const EsrtResourceEntry;
418+
let slice_entries = core::slice::from_raw_parts(src_ptr, esrt.resource_count as usize);
419+
420+
esrt.entries = slice_entries.to_vec();
421+
422+
Some(esrt)
423+
}

0 commit comments

Comments
 (0)