Skip to content

Commit

Permalink
Merge pull request #45 from FrameworkComputer/freebsd
Browse files Browse the repository at this point in the history
Add FreeBSD Support
  • Loading branch information
JohnAZoidberg authored Jul 10, 2024
2 parents 4ae1189 + 234c931 commit 03d72f9
Show file tree
Hide file tree
Showing 12 changed files with 294 additions and 87 deletions.
11 changes: 7 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ see the [Support Matrices](support-matrices.md).
- [x] OS Tool (`framework_tool`)
- [x] Tested on Linux
- [x] Tested on Windows
- [ ] Tested on FreeBSD
- [x] Tested on FreeBSD
- [x] UEFI Shell tool (`framework_uefi`)

###### Firmware Information

- [x] Show system information
- [x] ESRT table (UEFI and Linux only) (`--esrt`)
- [x] ESRT table (UEFI, Linux, FreeBSD only) (`--esrt`)
- [x] SMBIOS
- [x] Get firmware version from binary file
- [x] Legacy EC (Intel 13th Gen and earlier) (`--ec-bin`)
Expand Down Expand Up @@ -299,3 +299,15 @@ Keyboard backlight: 0%
[DEBUG] send_command(command=0x22, ver=0, data_len=0)
Keyboard backlight: 0%
```

## FreeBSD

```
sudo pkg install hidapi
# Build the library and tool
cargo build --no-default-features --features freebsd
# Running the tool
cargo run --no-default-features --features freebsd
```
15 changes: 9 additions & 6 deletions framework_lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ build = "build.rs"
[features]
default = ["linux"]
# Linux/FreeBSD
unix = ["std", "cros_ec_driver", "raw_pio", "smbios", "dep:nix"]
linux = ["linux_pio", "unix"]
unix = ["std", "raw_pio", "smbios", "dep:nix", "dep:libc"]
linux = ["unix", "linux_pio", "cros_ec_driver"]
freebsd = ["unix", "freebsd_pio"]
# Windows does not have the cros_ec driver nor raw port I/O access to userspace
windows = ["std", "smbios", "dep:windows", "win_driver"]
windows = ["std", "smbios", "dep:windows", "win_driver", "raw_pio"]
smbios = ["dep:smbios-lib"]
std = ["dep:clap", "dep:clap-verbosity-flag", "dep:env_logger", "smbios-lib?/std", "dep:hidapi", "dep:rusb"]
uefi = [
Expand All @@ -22,8 +23,10 @@ uefi = [
"sha2/force-soft"
]

# EC communication via Port I/O on FreeBSD
freebsd_pio = ["redox_hwio/std"]
# EC communication via Port I/O on Linux
linux_pio = ["dep:libc"]
linux_pio = ["dep:libc", "redox_hwio/std"]
# EC communication via raw Port I/O (e.g. UEFI or other ring 0 code)
raw_pio = []
# EC communication via cros_ec driver on Linux
Expand All @@ -39,8 +42,8 @@ built = { version = "0.5", features = ["chrono", "git2"] }
lazy_static = "1.4.0"
sha2 = { version = "0.10.6", default_features = false, features = [ "force-soft" ] }
regex = { version = "1.10.0", default-features = false }
redox_hwio = { version = "0.1.5", default_features = false }
libc = { version = "0.2.137", optional = true }
redox_hwio = { git = "https://github.com/FrameworkComputer/rust-hwio", branch = "freebsd", default_features = false }
libc = { version = "0.2.155", optional = true }
clap = { version = "4.0", features = ["derive"], optional = true }
clap-verbosity-flag = { version = "2.0.1", optional = true }
nix = { version = "0.25.0", optional = true }
Expand Down
2 changes: 1 addition & 1 deletion framework_lib/src/ccgx/binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ fn read_version(
unsafe { std::ptr::read(data[0..version_len].as_ptr() as *const _) };

let base_version = BaseVersion::from(version_info.base_version);
let app_version = AppVersion::try_from(version_info.app_version).ok()?;
let app_version = AppVersion::from(version_info.app_version);

let fw_silicon_id = version_info.silicon_id;
let fw_silicon_family = version_info.silicon_family;
Expand Down
5 changes: 2 additions & 3 deletions framework_lib/src/ccgx/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use core::prelude::rust_2021::derive;

use crate::ccgx::{AppVersion, BaseVersion, ControllerVersion};
use crate::chromium_ec::command::EcCommands;
use crate::chromium_ec::{CrosEc, CrosEcDriver, EcError, EcResponseStatus, EcResult};
use crate::chromium_ec::{CrosEc, CrosEcDriver, EcError, EcResult};
use crate::util::{self, assert_win_len, Config, Platform};
use std::mem::size_of;

Expand Down Expand Up @@ -299,8 +299,7 @@ impl PdController {
let data = self.ccgx_read(register, 8)?;
Ok(ControllerVersion {
base: BaseVersion::from(&data[..4]),
app: AppVersion::try_from(&data[4..])
.or(Err(EcError::Response(EcResponseStatus::InvalidResponse)))?,
app: AppVersion::from(&data[4..]),
})
}

Expand Down
10 changes: 9 additions & 1 deletion framework_lib/src/ccgx/hid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,9 +254,17 @@ pub fn find_devices(api: &HidApi, filter_devs: &[u16], sn: Option<&str>) -> Vec<
let vid = dev_info.vendor_id();
let pid = dev_info.product_id();
let usage_page = dev_info.usage_page();

debug!("Found {:X}:{:X} Usage Page: {}", vid, pid, usage_page);
let usage_page_filter = usage_page == CCG_USAGE_PAGE;
// On FreeBSD it seems we don't get different usage pages
// There's just one entry overall
#[cfg(target_os = "freebsd")]
let usage_page_filter = true;

if vid == FRAMEWORK_VID
&& filter_devs.contains(&pid)
&& usage_page == CCG_USAGE_PAGE
&& usage_page_filter
&& (sn.is_none() || sn == dev_info.serial_number())
{
Some(dev_info.clone())
Expand Down
3 changes: 2 additions & 1 deletion framework_lib/src/chromium_ec/portio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ use alloc::string::ToString;
use alloc::vec;
use alloc::vec::Vec;
use core::convert::TryInto;
#[cfg(any(feature = "linux_pio", feature = "freebsd_pio", feature = "raw_pio"))]
use hwio::{Io, Pio};
#[cfg(feature = "linux_pio")]
#[cfg(all(feature = "linux_pio", target_os = "linux"))]
use libc::ioperm;
use log::Level;
#[cfg(feature = "linux_pio")]
Expand Down
10 changes: 9 additions & 1 deletion framework_lib/src/commandline/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ fn print_versions(ec: &CrosEc) {
println!("UEFI BIOS");
if let Some(smbios) = get_smbios() {
let bios_entries = smbios.collect::<SMBiosInformation>();
let bios = bios_entries.get(0).unwrap();
let bios = bios_entries.first().unwrap();
println!(" Version: {}", bios.version());
println!(" Release Date: {}", bios.release_date());
}
Expand Down Expand Up @@ -911,6 +911,14 @@ fn selftest(ec: &CrosEc) -> Option<()> {
}

fn smbios_info() {
println!("Summary");
println!(" Is Framework: {}", is_framework());
if let Some(platform) = smbios::get_platform() {
println!(" Platform: {:?}", platform);
} else {
println!(" Platform: Unknown",);
}

let smbios = get_smbios();
if smbios.is_none() {
error!("Failed to find SMBIOS");
Expand Down
91 changes: 68 additions & 23 deletions framework_lib/src/esrt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ use core::prelude::v1::derive;
#[cfg(not(feature = "uefi"))]
use guid_macros::guid;
#[cfg(feature = "uefi")]
use std::slice;
#[cfg(feature = "uefi")]
use uefi::{guid, Guid};

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

#[cfg(target_os = "freebsd")]
use nix::ioctl_readwrite;
#[cfg(target_os = "freebsd")]
use std::fs::OpenOptions;
#[cfg(target_os = "freebsd")]
use std::os::fd::AsRawFd;
#[cfg(target_os = "freebsd")]
use std::os::unix::fs::OpenOptionsExt;

/// Decode from GUID string version
///
/// # Examples
Expand Down Expand Up @@ -316,7 +323,7 @@ fn esrt_from_sysfs(dir: &Path) -> io::Result<Esrt> {
Ok(esrt_table)
}

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

#[cfg(target_os = "freebsd")]
#[repr(C)]
struct EfiGetTableIoc {
buf: *mut u8,
uuid: [u8; 16],
table_len: usize,
buf_len: usize,
}
#[cfg(target_os = "freebsd")]
ioctl_readwrite!(efi_get_table, b'E', 1, EfiGetTableIoc);

#[cfg(all(not(feature = "uefi"), target_os = "freebsd"))]
pub fn get_esrt() -> Option<Esrt> {
// TODO: Implement
println!("Reading ESRT is not implemented on FreeBSD yet.");
None
let file = OpenOptions::new()
.read(true)
.write(true)
.custom_flags(libc::O_NONBLOCK)
.open("/dev/efi")
.unwrap();

let mut buf: Vec<u8> = Vec::new();
let mut table = EfiGetTableIoc {
buf: std::ptr::null_mut(),
uuid: SYSTEM_RESOURCE_TABLE_GUID.to_bytes(),
buf_len: 0,
table_len: 0,
};
unsafe {
let fd = file.as_raw_fd();
let _res = efi_get_table(fd, &mut table).unwrap();
buf.resize(table.table_len, 0);
table.buf_len = table.table_len;
table.buf = buf.as_mut_ptr();

let _res = efi_get_table(fd, &mut table).unwrap();
esrt_from_buf(table.buf)
}
}

/// gEfiSystemResourceTableGuid from MdePkg/MdePkg.dec
Expand All @@ -353,26 +392,32 @@ pub fn get_esrt() -> Option<Esrt> {
let table_guid: Guid = unsafe { std::mem::transmute(table.guid) };
match table_guid {
SYSTEM_RESOURCE_TABLE_GUID => unsafe {
let raw_esrt = &*(table.address as *const _Esrt);
let mut esrt = Esrt {
resource_count: raw_esrt.resource_count,
resource_count_max: raw_esrt.resource_count_max,
resource_version: raw_esrt.resource_version,
entries: vec![],
};

// Make sure it's the version we expect
debug_assert!(esrt.resource_version == ESRT_FIRMWARE_RESOURCE_VERSION);

let src_ptr = std::ptr::addr_of!(raw_esrt.entries) as *const EsrtResourceEntry;
let slice_entries = slice::from_raw_parts(src_ptr, esrt.resource_count as usize);

esrt.entries = slice_entries.to_vec();

return Some(esrt);
return esrt_from_buf(table.address as *const u8);
},
_ => {}
}
}
None
}

/// Parse the ESRT table buffer
#[cfg(any(feature = "uefi", target_os = "freebsd"))]
unsafe fn esrt_from_buf(ptr: *const u8) -> Option<Esrt> {
let raw_esrt = &*(ptr as *const _Esrt);
let mut esrt = Esrt {
resource_count: raw_esrt.resource_count,
resource_count_max: raw_esrt.resource_count_max,
resource_version: raw_esrt.resource_version,
entries: vec![],
};

// Make sure it's the version we expect
debug_assert!(esrt.resource_version == ESRT_FIRMWARE_RESOURCE_VERSION);

let src_ptr = core::ptr::addr_of!(raw_esrt.entries) as *const EsrtResourceEntry;
let slice_entries = core::slice::from_raw_parts(src_ptr, esrt.resource_count as usize);

esrt.entries = slice_entries.to_vec();

Some(esrt)
}
Loading

0 comments on commit 03d72f9

Please sign in to comment.