diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 92f5299d..3f8dc7d1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -74,12 +74,21 @@ jobs: name: framework.efi path: framework_uefi/build/x86_64-unknown-uefi/boot.efi - - name: Install mtools to build ESP (Linux) - run: sudo apt-get install -y mtools + - name: Install mtools to build ESP and ISO (Linux) + run: sudo apt-get install -y mtools genisoimage - name: Build ESP (Linux) run: make -C framework_uefi + - name: Build ISO (Linux) + run: make -C framework_uefi iso + + - name: Upload UEFI App ISO + uses: actions/upload-artifact@v4 + with: + name: UEFI-Shell-fwk.iso + path: framework_uefi/build/x86_64-unknown-uefi/UEFI-Shell-fwk.iso + build-windows: name: Build Windows runs-on: windows-2022 diff --git a/Cargo.lock b/Cargo.lock index 0f0b1984..2f9f5c9a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -408,14 +408,14 @@ dependencies = [ [[package]] name = "framework_lib" -version = "0.4.1" +version = "0.4.2" dependencies = [ "built", "clap", "clap-num", "clap-verbosity-flag", "env_logger", - "guid_macros", + "guid-create", "hidapi", "lazy_static", "libc", @@ -440,7 +440,7 @@ dependencies = [ [[package]] name = "framework_tool" -version = "0.4.1" +version = "0.4.2" dependencies = [ "embed-resource", "framework_lib", @@ -451,7 +451,7 @@ dependencies = [ [[package]] name = "framework_uefi" -version = "0.4.1" +version = "0.4.2" dependencies = [ "framework_lib", "log", @@ -581,12 +581,11 @@ dependencies = [ ] [[package]] -name = "guid_macros" -version = "0.11.0" +name = "guid-create" +version = "0.4.1" +source = "git+https://github.com/FrameworkComputer/guid-create?branch=no-rand#84c3ad2e8b64a12beebb460804a65da55434cfd9" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.98", + "winapi", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 41f48e81..d8108e1b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,9 +11,6 @@ members = [ "framework_uefi", # Catchall library that we'll probably want to split up further "framework_lib", - # Fork of https://github.com/rust-osdev/uefi-rs/blob/main/uefi-macros - # To avoid pulling in UEFI dependencies when building for an OS - "guid_macros", ] # Don't build UEFI by default. Needs special cargo invocation diff --git a/EXAMPLES.md b/EXAMPLES.md index 7b915984..f688c635 100644 --- a/EXAMPLES.md +++ b/EXAMPLES.md @@ -15,17 +15,11 @@ UEFI BIOS Version: 03.00 Release Date: 03/10/2025 EC Firmware - Build version: "lilac-3.0.0-1541dc6 2025-05-05 11:31:24 zoid@localhost" - RO Version: "lilac-3.0.0-1541dc6" - RW Version: "lilac-3.0.0-1541dc6" + Build version: lilac-3.0.0-1541dc6 2025-05-05 11:31:24 zoid@localhost Current image: RO PD Controllers - Right (01) - Main: 0.0.0E (Active) - Backup: 0.0.0E - Left (23) - Main: 0.0.0E (Active) - Backup: 0.0.0E + Right (01): 0.0.0E (MainFw) + Left (23): 0.0.0E (MainFw) [...] ``` @@ -56,8 +50,7 @@ Laptop Webcam Module (2nd Gen) [...] Touchscreen Firmware Version: v7.0.0.5.0.0.0.0 - USI Protocol: false - MPP Protocol: true + Protocols: USI ``` ### Stylus (Framework 12) @@ -79,7 +72,6 @@ Stylus > framework_tool --versions [...] Touchpad - IC Type: 0239 Firmware Version: v0E07 ``` @@ -114,6 +106,35 @@ LED Matrix [...] ``` +### DisplayPort or HDMI Expansion Card + +``` +> framework_tool --dp-hdmi-info +DisplayPort Expansion Card + Serial Number: 11AD1D0030123F17142C0B00 + Active Firmware: 101 (3.0.11.065) + Inactive Firmware: 008 (3.0.11.008) + Operating Mode: MainFw (#2) + +# Or +> framework_tool --versions +[...] +DisplayPort Expansion Card + Active Firmware: 101 (3.0.11.065) + Inactive Firmware: 008 (3.0.11.008) + Operating Mode: MainFw (#2) +``` + +### CSME Version (Linux on Intel systems) + +``` +> framework_tool --versions +[...] +CSME + Firmware Version: 0:16.1.32.2473 +[...] +``` + ## Check input deck status ### On Framework 12 @@ -173,13 +194,13 @@ ALS: 76 Lux ``` ### Accelerometer (Framework 12) + ``` > sudo framework_tool --sensors -ALS: 0 Lux Accelerometers: - Lid Angle: 122 Deg - Sensor 1: X=+0.00G Y=+0.84G, Z=+0.52G - Sensor 2: X=-0.03G Y=+0.00G, Z=+1.01G + Lid Angle: 118 Deg + Lid Sensor: X=+0.00G Y=+0.86G, Z=+0.53G + Base Sensor: X=-0.03G Y=-0.07G, Z=+1.02G ``` ## Set custom fan duty/RPM @@ -225,6 +246,8 @@ Expansion Bay Door closed: true Board: DualInterposer Serial Number: FRAXXXXXXXXXXXXXXX + Config: Pcie4x2 + Vendor: SsdHolder ``` ## Check charger and battery status (Framework 12/13/16) @@ -380,3 +403,39 @@ sudo framework_tool --rgbkbd 2 0xFF0000 > sudo framework_tool --stylus-battery Stylus Battery Strength: 77% ``` + +## Remap keyboard + +Note that the keyboard matrix on Framework 12 and Framework 13 are +different. +The scancodes are the same. + +- Left-Ctrl 0x0014 +- Left-Alt 0x0014 +- Tab 0x0058 + +### Framework 12 + +``` +# Remap capslock key as left-ctrl +> framework_tool --remap-key 6 15 0x0014 + +# Swap left-ctrl and alt +> framework_tool --remap-key 1 14 0x0011 +> framework_tool --remap-key 6 13 0x0014 +``` + +### Framework 13 + +``` +# Remap capslock key as left-ctrl +> framework_tool --remap-key 4 4 0x0014 + +# Swap left-ctrl and alt +> framework_tool --remap-key 1 12 0x0011 +> framework_tool --remap-key 1 3 0x0014 +``` + +### Framework 16 + +It's not controlled by the EC, use https://keyboard.frame.work. diff --git a/README.md b/README.md index 7c41c4ca..7fbcea32 100644 --- a/README.md +++ b/README.md @@ -126,14 +126,12 @@ make -C framework_uefi ls -l framework_uefi/build/x86_64-unknown-uefi/boot.efi ``` -Building on Windows or in general with fewer features: +## Install local package -```ps1 -# Build the library and tool -cargo build - -# Running the tool -cargo run +``` +> cargo install --path framework_tool +> which framework_tool +/home/zoid/.cargo/bin/framework_tool ``` ## Running @@ -171,8 +169,8 @@ Options: --expansion-bay Show status of the expansion bay (Framework 16 only) --charge-limit [] Get or set max charge limit - --get-gpio - Get GPIO value by name + --get-gpio [] + Get GPIO value by name or all, if no name provided --fp-led-level [] Get or set fingerprint LED brightness level [possible values: high, medium, low, ultra-low, auto] --fp-brightness [] diff --git a/framework_lib/Cargo.toml b/framework_lib/Cargo.toml index f0477678..8d362370 100644 --- a/framework_lib/Cargo.toml +++ b/framework_lib/Cargo.toml @@ -1,6 +1,11 @@ [package] name = "framework_lib" -version = "0.4.1" +version = "0.4.2" +description = "Library to control Framework Computer systems" +homepage = "https://github.com/FrameworkComputer/framework-system" +repository = "https://github.com/FrameworkComputer/framework-system" +readme = "README.md" +license = "BSD-3-Clause" edition = "2021" # Minimum Supported Rust Version # Ubuntu 24.04 LTS ships 1.75 @@ -26,9 +31,9 @@ num-traits = { version = "0.2", default-features = false } log = { version = "0.4", default-features = true } spin = { version = "0.9.8" } no-std-compat = { version = "0.4.1", features = [ "alloc" ] } -guid_macros = { path = "../guid_macros" } hidapi = { version = "2.6.3", features = [ "windows-native" ], optional = true } 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"] } diff --git a/framework_lib/src/capsule.rs b/framework_lib/src/capsule.rs index 971db631..e2dff320 100644 --- a/framework_lib/src/capsule.rs +++ b/framework_lib/src/capsule.rs @@ -11,16 +11,12 @@ use std::prelude::v1::*; use core::prelude::rust_2021::derive; +use guid_create::Guid; #[cfg(not(feature = "uefi"))] use std::fs::File; #[cfg(not(feature = "uefi"))] use std::io::prelude::*; -#[cfg(not(feature = "uefi"))] -use crate::guid::Guid; -#[cfg(feature = "uefi")] -use uefi::Guid; - #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[repr(C)] pub struct EfiCapsuleHeader { @@ -209,14 +205,14 @@ mod tests { let data = fs::read(capsule_path).unwrap(); let cap = parse_capsule_header(&data).unwrap(); let expected_header = EfiCapsuleHeader { - capsule_guid: esrt::WINUX_GUID, + capsule_guid: Guid::from(esrt::WINUX_GUID), header_size: 28, flags: 65536, capsule_image_size: 676898, }; assert_eq!(cap, expected_header); - assert_eq!(cap.capsule_guid, esrt::WINUX_GUID); + assert_eq!(cap.capsule_guid, Guid::from(esrt::WINUX_GUID)); let ux_header = parse_ux_header(&data); assert_eq!( ux_header, diff --git a/framework_lib/src/ccgx/hid.rs b/framework_lib/src/ccgx/hid.rs index 64dcc748..c36aeebb 100644 --- a/framework_lib/src/ccgx/hid.rs +++ b/framework_lib/src/ccgx/hid.rs @@ -132,10 +132,10 @@ fn get_fw_info(device: &HidDevice) -> HidFirmwareInfo { decode_fw_info(&buf) } -pub fn check_ccg_fw_version(device: &HidDevice) { +pub fn check_ccg_fw_version(device: &HidDevice, verbose: bool) { magic_unlock(device); let info = get_fw_info(device); - print_fw_info(&info); + print_fw_info(&info, verbose); } fn decode_fw_info(buf: &[u8]) -> HidFirmwareInfo { @@ -152,13 +152,13 @@ fn decode_fw_info(buf: &[u8]) -> HidFirmwareInfo { info } -fn print_fw_info(info: &HidFirmwareInfo) { +fn print_fw_info(info: &HidFirmwareInfo, verbose: bool) { assert_eq!(info.report_id, ReportIdCmd::E0Read as u8); info!(" Signature: {:X?}", info.signature); // Something's totally off if the signature is invalid if info.signature != [b'C', b'Y'] { - println!("Firmware Signature is invalid."); + error!("Firmware Signature is invalid."); return; } @@ -219,23 +219,33 @@ fn print_fw_info(info: &HidFirmwareInfo) { FwMode::BackupFw => (base_version_1, image_1_valid, base_version_2, image_2_valid), }; - println!( - " Active Firmware: {:03} ({}){}", - active_ver.build_number, - active_ver, - if active_valid { "" } else { " - INVALID!" } - ); - println!( - " Inactive Firmware: {:03} ({}){}", - inactive_ver.build_number, - inactive_ver, - if inactive_valid { "" } else { " - INVALID!" } - ); - println!( - " Operating Mode: {:?} (#{})", - FwMode::try_from(info.operating_mode).unwrap(), - info.operating_mode - ); + if verbose || active_ver != inactive_ver { + println!( + " Active Firmware: {:03} ({}){}", + active_ver.build_number, + active_ver, + if active_valid { "" } else { " - INVALID!" } + ); + println!( + " Inactive Firmware: {:03} ({}){}", + inactive_ver.build_number, + inactive_ver, + if inactive_valid { "" } else { " - INVALID!" } + ); + println!( + " Operating Mode: {:?} (#{})", + FwMode::try_from(info.operating_mode).unwrap(), + info.operating_mode + ); + } else { + println!( + " Active Firmware: {:03} ({}, {:?}){}", + active_ver.build_number, + active_ver, + FwMode::try_from(info.operating_mode).unwrap(), + if active_valid { "" } else { " - INVALID!" } + ); + } } /// Turn CCG3 Expansion Card VID/PID into their name @@ -332,7 +342,7 @@ pub fn flash_firmware(fw_binary: &[u8]) { magic_unlock(&device); let info = get_fw_info(&device); println!("Before Updating"); - print_fw_info(&info); + print_fw_info(&info, true); println!("Updating..."); match info.operating_mode { @@ -369,7 +379,7 @@ pub fn flash_firmware(fw_binary: &[u8]) { wait_to_reappear(&mut api, &filter_devs, sn).expect("Device did not reappear"); println!("After Updating"); - print_fw_info(&info); + print_fw_info(&info, true); } } diff --git a/framework_lib/src/chromium_ec/command.rs b/framework_lib/src/chromium_ec/command.rs index 54b8db52..e009a9ec 100644 --- a/framework_lib/src/chromium_ec/command.rs +++ b/framework_lib/src/chromium_ec/command.rs @@ -33,6 +33,7 @@ pub enum EcCommands { PwmSetKeyboardBacklight = 0x0023, PwmSetFanDuty = 0x0024, PwmSetDuty = 0x0025, + MotionSense = 0x002B, PwmGetDuty = 0x0026, SetTabletMode = 0x0031, AutoFanCtrl = 0x0052, @@ -60,6 +61,8 @@ pub enum EcCommands { FlashNotified = 0x3E01, /// Change charge limit ChargeLimitControl = 0x3E03, + DisablePs2Emulation = 0x3E08, + UpdateKeyboardMatrix = 0x3E0C, /// Get/Set Fingerprint LED brightness FpLedLevelControl = 0x3E0E, /// Get information about the current chassis open/close status @@ -96,6 +99,7 @@ pub enum EcCommands { GetHwDiag = 0x3E1C, /// Get gpu bay serial GetGpuSerial = 0x3E1D, + GetGpuPcie = 0x3E1E, /// Set gpu bay serial and program structure ProgramGpuEeprom = 0x3E1F, } diff --git a/framework_lib/src/chromium_ec/commands.rs b/framework_lib/src/chromium_ec/commands.rs index 38cafeb6..4a8fd2bf 100644 --- a/framework_lib/src/chromium_ec/commands.rs +++ b/framework_lib/src/chromium_ec/commands.rs @@ -282,6 +282,134 @@ impl EcRequest for EcRequestPwmGetDuty { } } +#[repr(u8)] +pub enum MotionSenseCmd { + Dump = 0, + Info = 1, +} + +#[repr(C, packed)] +pub struct EcRequestMotionSenseDump { + /// MotionSenseCmd::Dump + pub cmd: u8, + /// Maximal number of sensor the host is expecting. + /// 0 means the host is only interested in the number + /// of sensors controlled by the EC. + pub max_sensor_count: u8, +} + +#[repr(C, packed)] +pub struct EcResponseMotionSenseDump { + /// Flags representing the motion sensor module + pub module_flags: u8, + + /// Number of sensors managed directly by the EC + pub sensor_count: u8, + + /// Sensor data is truncated if response_max is too small + /// for holding all the data. + pub sensor: [u8; 0], +} + +impl EcRequest for EcRequestMotionSenseDump { + fn command_id() -> EcCommands { + EcCommands::MotionSense + } + fn command_version() -> u8 { + 1 + } +} + +#[derive(Debug, FromPrimitive, PartialEq)] +pub enum MotionSenseType { + Accel = 0, + Gyro = 1, + Mag = 2, + Prox = 3, + Light = 4, + Activity = 5, + Baro = 6, + Sync = 7, + LightRgb = 8, +} + +#[derive(Debug, FromPrimitive)] +pub enum MotionSenseLocation { + Base = 0, + Lid = 1, + Camera = 2, +} + +#[derive(Debug, FromPrimitive)] +pub enum MotionSenseChip { + Kxcj9 = 0, + Lsm6ds0 = 1, + Bmi160 = 2, + Si1141 = 3, + Si1142 = 4, + Si1143 = 5, + Kx022 = 6, + L3gd20h = 7, + Bma255 = 8, + Bmp280 = 9, + Opt3001 = 10, + Bh1730 = 11, + Gpio = 12, + Lis2dh = 13, + Lsm6dsm = 14, + Lis2de = 15, + Lis2mdl = 16, + Lsm6ds3 = 17, + Lsm6dso = 18, + Lng2dm = 19, + Tcs3400 = 20, + Lis2dw12 = 21, + Lis2dwl = 22, + Lis2ds = 23, + Bmi260 = 24, + Icm426xx = 25, + Icm42607 = 26, + Bma422 = 27, + Bmi323 = 28, + Bmi220 = 29, + Cm32183 = 30, + Veml3328 = 31, +} + +#[repr(C, packed)] +pub struct EcRequestMotionSenseInfo { + /// MotionSenseCmd::Info + pub cmd: u8, + /// Sensor index + pub sensor_num: u8, +} + +#[repr(C)] +pub struct EcResponseMotionSenseInfo { + /// See enum MotionSenseInfo + pub sensor_type: u8, + /// See enum MotionSenseLocation + pub location: u8, + /// See enum MotionSenseChip + pub chip: u8, +} + +#[derive(Debug)] +pub struct MotionSenseInfo { + pub sensor_type: MotionSenseType, + pub location: MotionSenseLocation, + pub chip: MotionSenseChip, +} + +impl EcRequest for EcRequestMotionSenseInfo { + fn command_id() -> EcCommands { + EcCommands::MotionSense + } + fn command_version() -> u8 { + 1 + } +} + pub enum TabletModeOverride { Default = 0, ForceTablet = 1, @@ -343,6 +471,61 @@ impl EcRequest for EcRequestGpioGetV0 { } } +pub enum GpioGetSubCommand { + ByName = 0, + Count = 1, + Info = 2, +} + +#[repr(C, packed)] +pub struct EcRequestGpioGetV1Count { + pub subcmd: u8, +} + +#[repr(C, packed)] +pub struct EcRequestGpioGetV1ByName { + pub subcmd: u8, + pub name: [u8; 32], +} + +#[repr(C, packed)] +pub struct EcRequestGpioGetV1Info { + pub subcmd: u8, + pub index: u8, +} + +#[repr(C)] +pub struct EcResponseGpioGetV1Info { + pub val: u8, + pub name: [u8; 32], + pub flags: u32, +} + +impl EcRequest for EcRequestGpioGetV1Count { + fn command_id() -> EcCommands { + EcCommands::GpioGet + } + fn command_version() -> u8 { + 1 + } +} +impl EcRequest for EcRequestGpioGetV1ByName { + fn command_id() -> EcCommands { + EcCommands::GpioGet + } + fn command_version() -> u8 { + 1 + } +} +impl EcRequest for EcRequestGpioGetV1Info { + fn command_id() -> EcCommands { + EcCommands::GpioGet + } + fn command_version() -> u8 { + 1 + } +} + #[repr(C, packed)] pub struct EcRequestReboot {} @@ -744,6 +927,31 @@ impl EcRequest for EcRequestFlashNotify { } } +#[repr(C, packed)] +pub struct KeyboardMatrixMap { + pub row: u8, + pub col: u8, + pub scanset: u16, +} +#[repr(C, packed)] +pub struct EcRequestUpdateKeyboardMatrix { + pub num_items: u32, + pub write: u32, + pub scan_update: [KeyboardMatrixMap; 1], +} +#[repr(C, packed)] +pub struct EcResponseUpdateKeyboardMatrix { + pub num_items: u32, + pub write: u32, + pub scan_update: [KeyboardMatrixMap; 32], +} + +impl EcRequest for EcRequestUpdateKeyboardMatrix { + fn command_id() -> EcCommands { + EcCommands::UpdateKeyboardMatrix + } +} + #[repr(C, packed)] pub struct EcRequestChassisOpenCheck {} @@ -1048,6 +1256,17 @@ impl EcRequest for EcRequestChargeLimitControl { /// TODO: Use this pub const EC_CHARGE_LIMIT_RESTORE: u8 = 0x7F; +#[repr(C, packed)] +pub struct EcRequestDisablePs2Emulation { + pub disable: u8, +} + +impl EcRequest<()> for EcRequestDisablePs2Emulation { + fn command_id() -> EcCommands { + EcCommands::DisablePs2Emulation + } +} + #[repr(u8)] #[derive(Debug, FromPrimitive)] pub enum FpLedBrightnessLevel { @@ -1129,6 +1348,43 @@ impl EcRequest for EcRequestGetGpuSerial { } } +#[repr(C, packed)] +pub struct EcRequestGetGpuPcie {} + +#[repr(u8)] +#[derive(Debug, FromPrimitive)] +pub enum GpuPcieConfig { + /// PCIe 8x1 + Pcie8x1 = 0, + /// PCIe 4x1 + Pcie4x1 = 1, + /// PCIe 4x2 + Pcie4x2 = 2, +} + +#[repr(u8)] +#[derive(Debug, FromPrimitive)] +pub enum GpuVendor { + Initializing = 0x00, + FanOnly = 0x01, + GpuAmdR23M = 0x02, + SsdHolder = 0x03, + PcieAccessory = 0x4, +} + +#[repr(C, packed)] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub struct EcResponseGetGpuPcie { + pub gpu_pcie_config: u8, + pub gpu_vendor: u8, +} + +impl EcRequest for EcRequestGetGpuPcie { + fn command_id() -> EcCommands { + EcCommands::GetGpuPcie + } +} + #[repr(u8)] pub enum SetGpuSerialMagic { /// 7700S config magic value diff --git a/framework_lib/src/chromium_ec/mod.rs b/framework_lib/src/chromium_ec/mod.rs index afdaef0c..9bd367a0 100644 --- a/framework_lib/src/chromium_ec/mod.rs +++ b/framework_lib/src/chromium_ec/mod.rs @@ -353,6 +353,57 @@ impl CrosEc { )) } + pub fn motionsense_sensor_count(&self) -> EcResult { + EcRequestMotionSenseDump { + cmd: MotionSenseCmd::Dump as u8, + max_sensor_count: 0, + } + .send_command(self) + .map(|res| res.sensor_count) + } + + pub fn motionsense_sensor_info(&self) -> EcResult> { + let count = self.motionsense_sensor_count()?; + + let mut sensors = vec![]; + for sensor_num in 0..count { + let info = EcRequestMotionSenseInfo { + cmd: MotionSenseCmd::Info as u8, + sensor_num, + } + .send_command(self)?; + sensors.push(MotionSenseInfo { + sensor_type: FromPrimitive::from_u8(info.sensor_type).unwrap(), + location: FromPrimitive::from_u8(info.location).unwrap(), + chip: FromPrimitive::from_u8(info.chip).unwrap(), + }); + } + Ok(sensors) + } + + pub fn motionsense_sensor_list(&self) -> EcResult { + EcRequestMotionSenseDump { + cmd: MotionSenseCmd::Dump as u8, + max_sensor_count: 0, + } + .send_command(self) + .map(|res| res.sensor_count) + } + + pub fn remap_caps_to_ctrl(&self) -> EcResult<()> { + self.remap_key(6, 15, 0x0014) + } + + pub fn remap_key(&self, row: u8, col: u8, scanset: u16) -> EcResult<()> { + let _current_matrix = EcRequestUpdateKeyboardMatrix { + num_items: 1, + write: 1, + scan_update: [KeyboardMatrixMap { row, col, scanset }], + } + .send_command(self)?; + Ok(()) + } + /// Get current status of Framework Laptop's microphone and camera privacy switches /// [true = device enabled/connected, false = device disabled] pub fn get_privacy_info(&self) -> EcResult<(bool, bool)> { @@ -596,6 +647,13 @@ impl CrosEc { Ok((kblight.duty / (PWM_MAX_DUTY / 100)) as u8) } + pub fn ps2_emulation_enable(&self, enable: bool) -> EcResult<()> { + EcRequestDisablePs2Emulation { + disable: !enable as u8, + } + .send_command(self) + } + pub fn fan_set_rpm(&self, fan: Option, rpm: u32) -> EcResult<()> { if let Some(fan_idx) = fan { EcRequestPwmSetFanTargetRpmV1 { rpm, fan_idx }.send_command(self) @@ -1000,6 +1058,20 @@ impl CrosEc { println!(" Serial Number: Unknown"); } + let res = EcRequestGetGpuPcie {}.send_command(self)?; + let config: Option = FromPrimitive::from_u8(res.gpu_pcie_config); + let vendor: Option = FromPrimitive::from_u8(res.gpu_vendor); + if let Some(config) = config { + println!(" Config: {:?}", config); + } else { + println!(" Config: Unknown ({})", res.gpu_pcie_config); + } + if let Some(vendor) = vendor { + println!(" Vendor: {:?}", vendor); + } else { + println!(" Vendor: Unknown ({})", res.gpu_vendor); + } + Ok(()) } @@ -1228,6 +1300,41 @@ impl CrosEc { Ok(res.val == 1) } + pub fn get_all_gpios(&self) -> EcResult { + let res = EcRequestGpioGetV1Count { + subcmd: GpioGetSubCommand::Count as u8, + } + .send_command(self)?; + let gpio_count = res.val; + + debug!("Found {} GPIOs", gpio_count); + + for index in 0..res.val { + let res = EcRequestGpioGetV1Info { + subcmd: GpioGetSubCommand::Info as u8, + index, + } + .send_command(self)?; + + let name = std::str::from_utf8(&res.name) + .map_err(|utf8_err| { + EcError::DeviceError(format!("Failed to decode GPIO name: {:?}", utf8_err)) + })? + .trim_end_matches(char::from(0)) + .to_string(); + + if log_enabled!(Level::Info) { + // Same output as ectool + println!("{:>32}: {:>2} 0x{:04X}", res.val, name, { res.flags }); + } else { + // Simple output, just name and level high/low + println!("{:<32} {}", name, res.val); + } + } + + Ok(gpio_count) + } + pub fn adc_read(&self, adc_channel: u8) -> EcResult { let res = EcRequestAdcRead { adc_channel }.send_command(self)?; Ok(res.adc_value) diff --git a/framework_lib/src/commandline/clap_std.rs b/framework_lib/src/commandline/clap_std.rs index 76784a5f..aabd5468 100644 --- a/framework_lib/src/commandline/clap_std.rs +++ b/framework_lib/src/commandline/clap_std.rs @@ -165,9 +165,9 @@ struct ClapCli { #[clap(num_args = ..=2)] charge_rate_limit: Vec, - /// Get GPIO value by name + /// Get GPIO value by name or all, if no name provided #[arg(long)] - get_gpio: Option, + get_gpio: Option>, /// Get or set fingerprint LED brightness level #[arg(long)] @@ -181,6 +181,11 @@ struct ClapCli { #[arg(long)] kblight: Option>, + /// Set keyboard backlight percentage or get, if no value provided + #[arg(long, value_parser=maybe_hex::)] + #[clap(num_args = 3)] + remap_key: Vec, + /// Set the color of to . Multiple colors for adjacent keys can be set at once. /// [ ...] /// Example: 0 0xFF000 0x00FF00 0x0000FF @@ -188,6 +193,11 @@ struct ClapCli { #[arg(long, value_parser=maybe_hex::)] rgbkbd: Vec, + /// Control PS2 touchpad emulation (DEBUG COMMAND, if touchpad not working, reboot system) + #[clap(value_enum, hide(true))] + #[arg(long)] + ps2_enable: Option, + /// Set tablet mode override #[clap(value_enum)] #[arg(long)] @@ -333,6 +343,14 @@ pub fn parse(args: &[String]) -> Cli { 1 => Some((args.charge_rate_limit[0], None)), _ => None, }; + let remap_key = match args.remap_key.len() { + 3 => Some(( + args.remap_key[0] as u8, + args.remap_key[1] as u8, + args.remap_key[2], + )), + _ => None, + }; Cli { verbosity: args.verbosity.log_level_filter(), @@ -392,7 +410,9 @@ pub fn parse(args: &[String]) -> Cli { fp_led_level: args.fp_led_level, fp_brightness: args.fp_brightness, kblight: args.kblight, + remap_key, rgbkbd: args.rgbkbd, + ps2_enable: args.ps2_enable, tablet_mode: args.tablet_mode, touchscreen_enable: args.touchscreen_enable, stylus_battery: args.stylus_battery, diff --git a/framework_lib/src/commandline/mod.rs b/framework_lib/src/commandline/mod.rs index b2a324f1..7f11c87f 100644 --- a/framework_lib/src/commandline/mod.rs +++ b/framework_lib/src/commandline/mod.rs @@ -7,6 +7,7 @@ use alloc::format; use alloc::string::String; use alloc::string::ToString; use alloc::vec::Vec; +use guid_create::{Guid, GUID}; use log::Level; use num_traits::FromPrimitive; @@ -177,11 +178,13 @@ pub struct Cli { pub charge_limit: Option>, pub charge_current_limit: Option<(u32, Option)>, pub charge_rate_limit: Option<(f32, Option)>, - pub get_gpio: Option, + pub get_gpio: Option>, pub fp_led_level: Option>, pub fp_brightness: Option>, pub kblight: Option>, + pub remap_key: Option<(u8, u8, u16)>, pub rgbkbd: Vec, + pub ps2_enable: Option, pub tablet_mode: Option, pub touchscreen_enable: Option, pub stylus_battery: bool, @@ -246,7 +249,7 @@ fn print_audio_card_details() { } #[cfg(feature = "hidapi")] -fn print_dp_hdmi_details() { +fn print_dp_hdmi_details(verbose: bool) { match HidApi::new() { Ok(api) => { for dev_info in find_devices(&api, &[HDMI_CARD_PID, DP_CARD_PID], None) { @@ -264,11 +267,11 @@ fn print_dp_hdmi_details() { dev_info.product_string().unwrap_or(NOT_SET) ); - println!( + debug!( " Serial Number: {}", dev_info.serial_number().unwrap_or(NOT_SET) ); - check_ccg_fw_version(&device); + check_ccg_fw_version(&device, verbose); } } Err(e) => { @@ -373,11 +376,13 @@ fn print_versions(ec: &CrosEc) { println!("EC Firmware"); let ver = print_err(ec.version_info()).unwrap_or_else(|| "UNKNOWN".to_string()); - println!(" Build version: {:?}", ver); + println!(" Build version: {}", ver); if let Some((ro, rw, curr)) = ec.flash_version() { - println!(" RO Version: {:?}", ro); - println!(" RW Version: {:?}", rw); + if ro != rw || log_enabled!(Level::Info) { + println!(" RO Version: {}", ro); + println!(" RW Version: {}", rw); + } print!(" Current image: "); if curr == chromium_ec::EcCurrentImage::RO { println!("RO"); @@ -397,53 +402,78 @@ fn print_versions(ec: &CrosEc) { if let Ok(pd_versions) = ccgx::get_pd_controller_versions(ec) { let right = &pd_versions.controller01; let left = &pd_versions.controller23; - println!(" Right (01)"); // let active_mode = if let Some(Platform::IntelGen11) = smbios::get_platform() { + if right.main_fw.base != right.backup_fw.base { + println!(" Right (01)"); + println!( + " Main: {}{}", + right.main_fw.base, + active_mode(&right.active_fw, FwMode::MainFw) + ); + println!( + " Backup: {}{}", + right.backup_fw.base, + active_mode(&right.active_fw, FwMode::BackupFw) + ); + } else { + println!( + " Right (01): {} ({:?})", + right.main_fw.base, right.active_fw + ); + } + } else if right.main_fw.app != right.backup_fw.app { println!( - " Main: {}{}", - right.main_fw.base, + " Main: {}{}", + right.main_fw.app, active_mode(&right.active_fw, FwMode::MainFw) ); println!( - " Backup: {}{}", - right.backup_fw.base, + " Backup: {}{}", + right.backup_fw.app, active_mode(&right.active_fw, FwMode::BackupFw) ); } else { println!( - " Main: {}{}", - right.main_fw.app, - active_mode(&right.active_fw, FwMode::MainFw) - ); - println!( - " Backup: {}{}", - right.backup_fw.app, - active_mode(&right.active_fw, FwMode::BackupFw) + " Right (01): {} ({:?})", + right.main_fw.app, right.active_fw ); } - println!(" Left (23)"); if let Some(Platform::IntelGen11) = smbios::get_platform() { + if left.main_fw.base != left.backup_fw.base { + println!(" Left (23)"); + println!( + " Main: {}{}", + left.main_fw.base, + active_mode(&left.active_fw, FwMode::MainFw) + ); + println!( + " Backup: {}{}", + left.backup_fw.base, + active_mode(&left.active_fw, FwMode::BackupFw) + ); + } else { + println!( + " Left (23): {} ({:?})", + left.main_fw.base, left.active_fw + ); + } + } else if left.main_fw.app != left.backup_fw.app { + println!(" Left (23)"); println!( - " Main: {}{}", - left.main_fw.base, + " Main: {}{}", + left.main_fw.app, active_mode(&left.active_fw, FwMode::MainFw) ); println!( - " Backup: {}{}", - left.backup_fw.base, + " Backup: {}{}", + left.backup_fw.app, active_mode(&left.active_fw, FwMode::BackupFw) ); } else { println!( - " Main: {}{}", - left.main_fw.app, - active_mode(&left.active_fw, FwMode::MainFw) - ); - println!( - " Backup: {}{}", - left.backup_fw.app, - active_mode(&left.active_fw, FwMode::BackupFw) + " Left (23): {} ({:?})", + left.main_fw.app, left.active_fw ); } } else if let Ok(pd_versions) = power::read_pd_version(ec) { @@ -465,7 +495,7 @@ fn print_versions(ec: &CrosEc) { let mut right_retimer: Option = None; if let Some(esrt) = esrt::get_esrt() { for entry in &esrt.entries { - match entry.fw_class { + match GUID::from(entry.fw_class) { esrt::TGL_RETIMER01_GUID | esrt::ADL_RETIMER01_GUID | esrt::RPL_RETIMER01_GUID @@ -500,10 +530,12 @@ fn print_versions(ec: &CrosEc) { { println!("CSME"); if let Ok(csme) = csme::csme_from_sysfs() { - println!(" Enabled: {}", csme.enabled); - println!(" Version: {}", csme.main_ver); - println!(" Recovery Ver: {}", csme.recovery_ver); - println!(" Original Ver: {}", csme.fitc_ver); + info!(" Enabled: {}", csme.enabled); + println!(" Firmware Version: {}", csme.main_ver); + if csme.main_ver != csme.recovery_ver || csme.main_ver != csme.fitc_ver { + println!(" Recovery Ver: {}", csme.recovery_ver); + println!(" Original Ver: {}", csme.fitc_ver); + } } else { println!(" Unknown"); } @@ -521,6 +553,8 @@ fn print_versions(ec: &CrosEc) { if let Some(Platform::Framework12IntelGen13) = smbios::get_platform() { let _ignore_err = touchscreen::print_fw_ver(); } + #[cfg(feature = "hidapi")] + print_dp_hdmi_details(false); } fn print_esrt() { @@ -536,19 +570,14 @@ fn flash_ec(ec: &CrosEc, ec_bin_path: &str, flash_type: EcFlashType) { let data = crate::uefi::fs::shell_read_file(ec_bin_path); #[cfg(not(feature = "uefi"))] let data: Option> = { - let _data = match fs::read(ec_bin_path) { + match fs::read(ec_bin_path) { Ok(data) => Some(data), // TODO: Perhaps a more user-friendly error Err(e) => { println!("Error {:?}", e); None } - }; - - // EC communication from OS is not stable enough yet, - // it can't be trusted to reliably flash the EC without risk of damage. - println!("Sorry, flashing EC from the OS is not supported yet."); - None + } }; if let Some(data) = data { @@ -667,7 +696,7 @@ fn compare_version(device: Option, version: String, ec: &Cro if let Some(esrt) = esrt::get_esrt() { for entry in &esrt.entries { - match entry.fw_class { + match GUID::from(entry.fw_class) { esrt::TGL_RETIMER01_GUID | esrt::ADL_RETIMER01_GUID | esrt::RPL_RETIMER01_GUID => { if device == Some(HardwareDeviceType::RTM01) { println!("Comparing RTM01 version {:?}", entry.fw_version.to_string()); @@ -791,11 +820,15 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 { } else if let Some((limit, soc)) = args.charge_rate_limit { print_err(ec.set_charge_rate_limit(limit, soc)); } else if let Some(gpio_name) = &args.get_gpio { - print!("Getting GPIO value {}: ", gpio_name); - if let Ok(value) = ec.get_gpio(gpio_name) { - println!("{:?}", value); + if let Some(gpio_name) = gpio_name { + print!("GPIO {}: ", gpio_name); + if let Ok(value) = ec.get_gpio(gpio_name) { + println!("{:?}", value); + } else { + println!("Not found"); + } } else { - println!("Not found"); + print_err(ec.get_all_gpios()); } } else if let Some(maybe_led_level) = &args.fp_led_level { print_err(handle_fp_led_level(&ec, *maybe_led_level)); @@ -804,6 +837,15 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 { } else if let Some(Some(kblight)) = args.kblight { assert!(kblight <= 100); ec.set_keyboard_backlight(kblight); + } else if let Some(None) = args.kblight { + print!("Keyboard backlight: "); + if let Some(percentage) = print_err(ec.get_keyboard_backlight()) { + println!("{}%", percentage); + } else { + println!("Unable to tell"); + } + } else if let Some((row, col, scanset)) = args.remap_key { + print_err(ec.remap_key(row, col, scanset)); } else if !args.rgbkbd.is_empty() { if args.rgbkbd.len() < 2 { println!( @@ -819,13 +861,8 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 { }); ec.rgbkbd_set_color(start_key, colors.collect()).unwrap(); } - } else if let Some(None) = args.kblight { - print!("Keyboard backlight: "); - if let Some(percentage) = print_err(ec.get_keyboard_backlight()) { - println!("{}%", percentage); - } else { - println!("Unable to tell"); - } + } else if let Some(enable) = args.ps2_enable { + print_err(ec.ps2_emulation_enable(enable)); } else if let Some(tablet_arg) = &args.tablet_mode { let mode = match tablet_arg { TabletModeArg::Auto => TabletModeOverride::Default, @@ -909,7 +946,7 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 { print_pd_details(&ec); } else if args.dp_hdmi_info { #[cfg(feature = "hidapi")] - print_dp_hdmi_details(); + print_dp_hdmi_details(true); } else if let Some(pd_bin_path) = &args.dp_hdmi_update { #[cfg(feature = "hidapi")] flash_dp_hdmi_card(pd_bin_path); @@ -991,7 +1028,7 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 { println!(" Size: {:>20} B", data.len()); println!(" Size: {:>20} KB", data.len() / 1024); if let Some(header) = analyze_capsule(&data) { - if header.capsule_guid == esrt::WINUX_GUID { + if header.capsule_guid == Guid::from(esrt::WINUX_GUID) { let ux_header = capsule::parse_ux_header(&data); if let Some(dump_path) = &args.dump { // TODO: Better error handling, rather than just panicking @@ -1120,7 +1157,7 @@ Options: --expansion-bay Show status of the expansion bay (Framework 16 only) --charge-limit [] Get or set battery charge limit (Percentage number as arg, e.g. '100') --charge-current-limit [] Get or set battery current charge limit (Percentage number as arg, e.g. '100') - --get-gpio Get GPIO value by name + --get-gpio Get GPIO value by name or all, if no name provided --fp-led-level [] Get or set fingerprint LED brightness level [possible values: high, medium, low] --fp-brightness []Get or set fingerprint LED brightness percentage --kblight [] Set keyboard backlight percentage or get, if no value provided @@ -1393,7 +1430,7 @@ pub fn analyze_capsule(data: &[u8]) -> Option { let header = capsule::parse_capsule_header(data)?; capsule::print_capsule_header(&header); - match header.capsule_guid { + match GUID::from(header.capsule_guid) { esrt::TGL_BIOS_GUID => { println!(" Type: Framework TGL Insyde BIOS"); } diff --git a/framework_lib/src/commandline/uefi.rs b/framework_lib/src/commandline/uefi.rs index 1fd9e5d8..097c006f 100644 --- a/framework_lib/src/commandline/uefi.rs +++ b/framework_lib/src/commandline/uefi.rs @@ -94,7 +94,9 @@ pub fn parse(args: &[String]) -> Cli { fp_led_level: None, fp_brightness: None, kblight: None, + remap_key: None, rgbkbd: vec![], + ps2_enable: None, tablet_mode: None, touchscreen_enable: None, stylus_battery: false, @@ -329,9 +331,9 @@ pub fn parse(args: &[String]) -> Cli { found_an_option = true; } else if arg == "--get-gpio" { cli.get_gpio = if args.len() > i + 1 { - Some(args[i + 1].clone()) + Some(Some(args[i + 1].clone())) } else { - None + Some(None) }; found_an_option = true; } else if arg == "--kblight" { @@ -361,6 +363,26 @@ pub fn parse(args: &[String]) -> Cli { println!("--rgbkbd requires at least 2 arguments, the start key and an RGB value"); vec![] } + } else if arg == "--ps2-enable" { + cli.ps2_enable = if args.len() > i + 1 { + let enable_arg = &args[i + 1]; + if enable_arg == "true" { + Some(true) + } else if enable_arg == "false" { + Some(false) + } else { + println!( + "Need to provide a value for --ps2-enable: '{}'. {}", + args[i + 1], + "Must be `true` or `false`", + ); + None + } + } else { + println!("Need to provide a value for --tablet-mode. One of: `auto`, `tablet` or `laptop`"); + None + }; + found_an_option = true; } else if arg == "--tablet-mode" { cli.tablet_mode = if args.len() > i + 1 { let tablet_mode_arg = &args[i + 1]; diff --git a/framework_lib/src/esrt/mod.rs b/framework_lib/src/esrt/mod.rs index 16770df5..15daea4c 100644 --- a/framework_lib/src/esrt/mod.rs +++ b/framework_lib/src/esrt/mod.rs @@ -14,13 +14,8 @@ use log::{debug, error, info, trace}; use std::prelude::v1::*; -#[cfg(not(feature = "uefi"))] -use crate::guid::Guid; use core::prelude::v1::derive; -#[cfg(not(feature = "uefi"))] -use guid_macros::guid; -#[cfg(feature = "uefi")] -use uefi::{guid, Guid}; +use guid_create::{Guid, GUID}; #[cfg(target_os = "linux")] use std::fs; @@ -38,66 +33,133 @@ use std::os::fd::AsRawFd; #[cfg(target_os = "freebsd")] use std::os::unix::fs::OpenOptionsExt; -/// Decode from GUID string version -/// -/// # Examples -/// ``` -/// use framework_lib::esrt::*; -/// use framework_lib::guid::*; -/// -/// let valid_guid = Guid::from_values(0xA9C91B0C, 0xC0B8, 0x463D, 0xA7DA, 0xA5D6EC646333); -/// // Works with lower-case -/// let guid = guid_from_str("a9c91b0c-c0b8-463d-a7da-a5d6ec646333"); -/// assert_eq!(guid, Some(valid_guid)); -/// // And upper-case -/// let guid = guid_from_str("A9C91B0C-C0B8-463D-A7DA-A5D6EC646333"); -/// assert_eq!(guid, Some(valid_guid)); -/// -/// let guid = guid_from_str("invalid-guid"); -/// assert_eq!(guid, None); -/// ``` -pub fn guid_from_str(string: &str) -> Option { - let string = string.strip_suffix('\n').unwrap_or(string); - let sections: Vec<&str> = string.split('-').collect(); - let time_low = u32::from_str_radix(sections[0], 16).ok()?; - let time_mid = u16::from_str_radix(sections[1], 16).ok()?; - let time_high_and_version = u16::from_str_radix(sections[2], 16).ok()?; - let clock_seq_and_variant = u16::from_str_radix(sections[3], 16).ok()?; - let node = u64::from_str_radix(sections[4], 16).ok()?; - - Some(Guid::from_values( - time_low, - time_mid, - time_high_and_version, - clock_seq_and_variant, - node, - )) -} - -pub const TGL_BIOS_GUID: Guid = guid!("b3bdb2e4-c5cb-5c1b-bdc3-e6fc132462ff"); -pub const ADL_BIOS_GUID: Guid = guid!("a30a8cf3-847f-5e59-bd59-f9ec145c1a8c"); -pub const RPL_BIOS_GUID: Guid = guid!("13fd4ed2-cba9-50ba-bb91-aece0acb4cc3"); -pub const MTL_BIOS_GUID: Guid = guid!("72cecb9b-2b37-5ec2-a9ff-c739aabaadf3"); - -pub const TGL_RETIMER01_GUID: Guid = guid!("832af090-2ef9-7c47-8f6d-b405c8c7f156"); -pub const TGL_RETIMER23_GUID: Guid = guid!("20ef4108-6c64-d049-b6de-11ee35980b8f"); -pub const ADL_RETIMER01_GUID: Guid = guid!("a9c91b0c-c0b8-463d-a7da-a5d6ec646333"); -pub const ADL_RETIMER23_GUID: Guid = guid!("ba2e4e6e-3b0c-4f25-8a59-4c553fc86ea2"); -pub const RPL_RETIMER01_GUID: Guid = guid!("0c42b824-818f-428f-8687-5efcaf059bea"); -pub const RPL_RETIMER23_GUID: Guid = guid!("268ccbde-e087-420b-bf82-2212bd3f9bfc"); -pub const MTL_RETIMER01_GUID: Guid = guid!("c57fd615-2ac9-4154-bf34-4dc715344408"); -pub const MTL_RETIMER23_GUID: Guid = guid!("bdffce36-809c-4fa6-aecc-54536922f0e0"); - -pub const FL16_BIOS_GUID: Guid = guid!("6ae76af1-c002-5d64-8e18-658d205acf34"); -pub const AMD13_BIOS_GUID: Guid = guid!("b5f7dcc1-568c-50f8-a4dd-e39d1f93fda1"); -pub const RPL_CSME_GUID: Guid = guid!("865d322c-6ac7-4734-b43e-55db5a557d63"); -pub const MTL_CSME_GUID: Guid = guid!("32d8d677-eebc-4947-8f8a-0693a45240e5"); +pub const TGL_BIOS_GUID: GUID = GUID::build_from_components( + 0xb3bdb2e4, + 0xc5cb, + 0x5c1b, + &[0xbd, 0xc3, 0xe6, 0xfc, 0x13, 0x24, 0x62, 0xff], +); +pub const ADL_BIOS_GUID: GUID = GUID::build_from_components( + 0xa30a8cf3, + 0x847f, + 0x5e59, + &[0xbd, 0x59, 0xf9, 0xec, 0x14, 0x5c, 0x1a, 0x8c], +); +pub const RPL_BIOS_GUID: GUID = GUID::build_from_components( + 0x13fd4ed2, + 0xcba9, + 0x50ba, + &[0xbb, 0x91, 0xae, 0xce, 0x0a, 0xcb, 0x4c, 0xc3], +); +pub const MTL_BIOS_GUID: GUID = GUID::build_from_components( + 0x72cecb9b, + 0x2b37, + 0x5ec2, + &[0xa9, 0xff, 0xc7, 0x39, 0xaa, 0xba, 0xad, 0xf3], +); +pub const FW12_RPL_BIOS_GUID: GUID = GUID::build_from_components( + 0x6bc0986c, + 0xd281, + 0x5ba3, + &[0x96, 0x5c, 0x2f, 0x8d, 0x13, 0xe1, 0xee, 0xe8], +); + +pub const TGL_RETIMER01_GUID: GUID = GUID::build_from_components( + 0x832af090, + 0x2ef9, + 0x7c47, + &[0x8f, 0x6d, 0xb4, 0x05, 0xc8, 0xc7, 0xf1, 0x56], +); +pub const TGL_RETIMER23_GUID: GUID = GUID::build_from_components( + 0x20ef4108, + 0x6c64, + 0xd049, + &[0xb6, 0xde, 0x11, 0xee, 0x35, 0x98, 0x0b, 0x8f], +); +pub const ADL_RETIMER01_GUID: GUID = GUID::build_from_components( + 0xa9c91b0c, + 0xc0b8, + 0x463d, + &[0xa7, 0xda, 0xa5, 0xd6, 0xec, 0x64, 0x63, 0x33], +); +pub const ADL_RETIMER23_GUID: GUID = GUID::build_from_components( + 0xba2e4e6e, + 0x3b0c, + 0x4f25, + &[0x8a, 0x59, 0x4c, 0x55, 0x3f, 0xc8, 0x6e, 0xa2], +); +pub const RPL_RETIMER01_GUID: GUID = GUID::build_from_components( + 0x0c42b824, + 0x818f, + 0x428f, + &[0x86, 0x87, 0x5e, 0xfc, 0xaf, 0x05, 0x9b, 0xea], +); +pub const RPL_RETIMER23_GUID: GUID = GUID::build_from_components( + 0x268ccbde, + 0xe087, + 0x420b, + &[0xbf, 0x82, 0x22, 0x12, 0xbd, 0x3f, 0x9b, 0xfc], +); +pub const MTL_RETIMER01_GUID: GUID = GUID::build_from_components( + 0xc57fd615, + 0x2ac9, + 0x4154, + &[0xbf, 0x34, 0x4d, 0xc7, 0x15, 0x34, 0x44, 0x08], +); +pub const MTL_RETIMER23_GUID: GUID = GUID::build_from_components( + 0xbdffce36, + 0x809c, + 0x4fa6, + &[0xae, 0xcc, 0x54, 0x53, 0x69, 0x22, 0xf0, 0xe0], +); + +pub const FL16_BIOS_GUID: GUID = GUID::build_from_components( + 0x6ae76af1, + 0xc002, + 0x5d64, + &[0x8e, 0x18, 0x65, 0x8d, 0x20, 0x5a, 0xcf, 0x34], +); +pub const AMD13_RYZEN7040_BIOS_GUID: GUID = GUID::build_from_components( + 0xb5f7dcc1, + 0x568c, + 0x50f8, + &[0xa4, 0xdd, 0xe3, 0x9d, 0x1f, 0x93, 0xfd, 0xa1], +); +pub const AMD13_AI300_BIOS_GUID: GUID = GUID::build_from_components( + 0x9c13b7f1, + 0xd618, + 0x5d68, + &[0xbe, 0x61, 0x6b, 0x17, 0x88, 0x10, 0x14, 0xa7], +); +pub const RPL_CSME_GUID: GUID = GUID::build_from_components( + 0x865d322c, + 0x6ac7, + 0x4734, + &[0xb4, 0x3e, 0x55, 0xdb, 0x5a, 0x55, 0x7d, 0x63], +); +pub const RPL_U_CSME_GUID: GUID = GUID::build_from_components( + 0x0f74c56d, + 0xd5ba, + 0x4942, + &[0x96, 0xfa, 0xd3, 0x75, 0x60, 0xf4, 0x05, 0x54], +); +pub const MTL_CSME_GUID: GUID = GUID::build_from_components( + 0x32d8d677, + 0xeebc, + 0x4947, + &[0x8f, 0x8a, 0x06, 0x93, 0xa4, 0x52, 0x40, 0xe5], +); // In EDK2 // Handled by MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c // Defined by MdePkg/Include/IndustryStandard/WindowsUxCapsule.h /// gWindowsUxCapsuleGuid from MdePkg/MdePkg.dec -pub const WINUX_GUID: Guid = guid!("3b8c8162-188c-46a4-aec9-be43f1d65697"); +pub const WINUX_GUID: GUID = GUID::build_from_components( + 0x3b8c8162, + 0x188c, + 0x46a4, + &[0xae, 0xc9, 0xbe, 0x43, 0xf1, 0xd6, 0x56, 0x97], +); #[derive(Debug)] pub enum FrameworkGuidKind { @@ -105,6 +167,7 @@ pub enum FrameworkGuidKind { AdlBios, RplBios, MtlBios, + Fw12RplBios, TglRetimer01, TglRetimer23, AdlRetimer01, @@ -114,21 +177,25 @@ pub enum FrameworkGuidKind { MtlRetimer01, MtlRetimer23, RplCsme, + RplUCsme, MtlCsme, Fl16Bios, - Amd13Bios, + Amd13Ryzen7040Bios, + Amd13Ai300Bios, WinUx, Unknown, } pub fn match_guid_kind(guid: &Guid) -> FrameworkGuidKind { - match *guid { + match GUID::from(*guid) { TGL_BIOS_GUID => FrameworkGuidKind::TglBios, ADL_BIOS_GUID => FrameworkGuidKind::AdlBios, RPL_BIOS_GUID => FrameworkGuidKind::RplBios, MTL_BIOS_GUID => FrameworkGuidKind::MtlBios, + FW12_RPL_BIOS_GUID => FrameworkGuidKind::Fw12RplBios, FL16_BIOS_GUID => FrameworkGuidKind::Fl16Bios, - AMD13_BIOS_GUID => FrameworkGuidKind::Amd13Bios, + AMD13_RYZEN7040_BIOS_GUID => FrameworkGuidKind::Amd13Ryzen7040Bios, + AMD13_AI300_BIOS_GUID => FrameworkGuidKind::Amd13Ai300Bios, TGL_RETIMER01_GUID => FrameworkGuidKind::TglRetimer01, TGL_RETIMER23_GUID => FrameworkGuidKind::TglRetimer23, ADL_RETIMER01_GUID => FrameworkGuidKind::AdlRetimer01, @@ -138,6 +205,7 @@ pub fn match_guid_kind(guid: &Guid) -> FrameworkGuidKind { MTL_RETIMER01_GUID => FrameworkGuidKind::MtlRetimer01, MTL_RETIMER23_GUID => FrameworkGuidKind::MtlRetimer23, RPL_CSME_GUID => FrameworkGuidKind::RplCsme, + RPL_U_CSME_GUID => FrameworkGuidKind::RplUCsme, MTL_CSME_GUID => FrameworkGuidKind::MtlCsme, WINUX_GUID => FrameworkGuidKind::WinUx, _ => FrameworkGuidKind::Unknown, @@ -288,8 +356,9 @@ fn esrt_from_sysfs(dir: &Path) -> io::Result { let last_attempt_version = fs::read_to_string(path.join("last_attempt_version"))?; let last_attempt_status = fs::read_to_string(path.join("last_attempt_status"))?; let esrt = EsrtResourceEntry { - // TODO: Parse GUID - fw_class: guid_from_str(&fw_class).expect("Kernel provided wrong value"), + fw_class: Guid::from( + GUID::parse(fw_class.trim()).expect("Kernel provided wrong value"), + ), fw_type: fw_type .trim() .parse::() @@ -358,8 +427,8 @@ pub fn get_esrt() -> Option { let guid_str = caps.get(1).unwrap().as_str().to_string(); let ver_str = caps.get(2).unwrap().as_str().to_string(); - let guid = guid_from_str(&guid_str).unwrap(); - let guid_kind = match_guid_kind(&guid); + let guid = GUID::parse(guid_str.trim()).expect("Kernel provided wrong value"); + let guid_kind = match_guid_kind(&Guid::from(guid)); let ver = u32::from_str_radix(&ver_str, 16).unwrap(); debug!("ESRT Entry {}", i); debug!(" Name: {:?}", guid_kind); @@ -379,7 +448,7 @@ pub fn get_esrt() -> Option { // TODO: The missing fields are present in Device Manager // So there must be a way to get at them let esrt = EsrtResourceEntry { - fw_class: guid, + fw_class: Guid::from(guid), fw_type, fw_version: ver, // TODO: Not exposed by windows @@ -428,7 +497,7 @@ pub fn get_esrt() -> Option { let mut buf: Vec = Vec::new(); let mut table = EfiGetTableIoc { buf: std::ptr::null_mut(), - uuid: SYSTEM_RESOURCE_TABLE_GUID.to_bytes(), + uuid: SYSTEM_RESOURCE_TABLE_GUID_BYTES, buf_len: 0, table_len: 0, }; @@ -448,7 +517,15 @@ pub fn get_esrt() -> Option { } /// gEfiSystemResourceTableGuid from MdePkg/MdePkg.dec -pub const SYSTEM_RESOURCE_TABLE_GUID: Guid = guid!("b122a263-3661-4f68-9929-78f8b0d62180"); +pub const SYSTEM_RESOURCE_TABLE_GUID: GUID = GUID::build_from_components( + 0xb122a263, + 0x3661, + 0x4f68, + &[0x99, 0x29, 0x78, 0xf8, 0xb0, 0xd6, 0x21, 0x80], +); +pub const SYSTEM_RESOURCE_TABLE_GUID_BYTES: [u8; 16] = [ + 0xb1, 0x22, 0xa2, 0x63, 0x36, 0x61, 0x4f, 0x68, 0x99, 0x29, 0x78, 0xf8, 0xb0, 0xd6, 0x21, 0x80, +]; #[cfg(feature = "uefi")] pub fn get_esrt() -> Option { @@ -459,6 +536,7 @@ pub fn get_esrt() -> Option { // 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); diff --git a/framework_lib/src/guid.rs b/framework_lib/src/guid.rs deleted file mode 100644 index 2de63088..00000000 --- a/framework_lib/src/guid.rs +++ /dev/null @@ -1,173 +0,0 @@ -// Taken from https://github.com/rust-osdev/uefi-rs/blob/main/uefi/src/data_types/guid.rs -use core::fmt; - -/// A globally unique identifier -/// -/// GUIDs are used by UEFI to identify protocols and other objects. They are -/// mostly like variant 2 UUIDs as specified by RFC 4122, but differ from them -/// in that the first 3 fields are little endian instead of big endian. -/// -/// The `Display` formatter prints GUIDs in the canonical format defined by -/// RFC 4122, which is also used by UEFI. -#[derive(Debug, Default, Copy, Clone, Eq, Ord, PartialEq, PartialOrd)] -#[repr(C)] -pub struct Guid { - /// The low field of the timestamp. - a: u32, - /// The middle field of the timestamp. - b: u16, - /// The high field of the timestamp multiplexed with the version number. - c: u16, - /// Contains, in this order: - /// - The high field of the clock sequence multiplexed with the variant. - /// - The low field of the clock sequence. - /// - The spatially unique node identifier. - d: [u8; 8], -} - -impl Guid { - /// Creates a new GUID from its canonical representation - #[must_use] - pub const fn from_values( - time_low: u32, - time_mid: u16, - time_high_and_version: u16, - clock_seq_and_variant: u16, - node: u64, - ) -> Self { - assert!(node.leading_zeros() >= 16, "node must be a 48-bit integer"); - // intentional shadowing - let node = node.to_be_bytes(); - - Guid { - a: time_low, - b: time_mid, - c: time_high_and_version, - d: [ - (clock_seq_and_variant / 0x100) as u8, - (clock_seq_and_variant % 0x100) as u8, - // first two elements of node are ignored, we only want the low 48 bits - node[2], - node[3], - node[4], - node[5], - node[6], - node[7], - ], - } - } - - /// Create a GUID from a 16-byte array. No changes to byte order are made. - #[must_use] - pub const fn from_bytes(bytes: [u8; 16]) -> Self { - let a = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]); - let b = u16::from_le_bytes([bytes[4], bytes[5]]); - let c = u16::from_le_bytes([bytes[6], bytes[7]]); - let d = [ - bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15], - ]; - - Self { a, b, c, d } - } - - /// Convert to a 16-byte array. - #[must_use] - #[rustfmt::skip] - pub const fn to_bytes(self) -> [u8; 16] { - let a = self.a.to_le_bytes(); - let b = self.b.to_le_bytes(); - let c = self.c.to_le_bytes(); - let d = self.d; - - [ - a[0], a[1], a[2], a[3], - b[0], b[1], c[0], c[1], - d[0], d[1], d[2], d[3], - d[4], d[5], d[6], d[7], - ] - } -} - -impl fmt::Display for Guid { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let a = self.a; - let b = self.b; - let c = self.c; - - let d = { - let mut buf = [0u8; 2]; - buf[..].copy_from_slice(&self.d[0..2]); - u16::from_be_bytes(buf) - }; - - let e = { - let mut buf = [0u8; 8]; - // first two elements of node are ignored, we only want the low 48 bits - buf[2..].copy_from_slice(&self.d[2..8]); - u64::from_be_bytes(buf) - }; - - write!(fmt, "{a:08x}-{b:04x}-{c:04x}-{d:04x}-{e:012x}",) - } -} - -/// Several entities in the UEFI specification can be referred to by their GUID, -/// this trait is a building block to interface them in uefi-rs. -/// -/// You should never need to use the `Identify` trait directly, but instead go -/// for more specific traits such as `Protocol` or `FileProtocolInfo`, which -/// indicate in which circumstances an `Identify`-tagged type should be used. -/// -/// For the common case of implementing this trait for a protocol, use -/// the `unsafe_protocol` macro. -/// -/// # Safety -/// -/// Implementing `Identify` is unsafe because attaching an incorrect GUID to a -/// type can lead to type unsafety on both the Rust and UEFI side. -pub unsafe trait Identify { - /// Unique protocol identifier. - const GUID: Guid; -} - -#[cfg(test)] -mod tests { - use super::*; - use guid_macros::guid; - - #[test] - fn test_guid_display() { - assert_eq!( - alloc::format!( - "{}", - Guid::from_values(0x12345678, 0x9abc, 0xdef0, 0x1234, 0x56789abcdef0) - ), - "12345678-9abc-def0-1234-56789abcdef0" - ); - } - - #[test] - fn test_guid_macro() { - assert_eq!( - guid!("12345678-9abc-def0-1234-56789abcdef0"), - Guid::from_values(0x12345678, 0x9abc, 0xdef0, 0x1234, 0x56789abcdef0) - ); - } - - #[test] - fn test_to_from_bytes() { - #[rustfmt::skip] - let bytes = [ - 0x78, 0x56, 0x34, 0x12, - 0xbc, 0x9a, - 0xf0, 0xde, - 0x12, 0x34, - 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, - ]; - assert_eq!( - Guid::from_bytes(bytes), - Guid::from_values(0x12345678, 0x9abc, 0xdef0, 0x1234, 0x56789abcdef0) - ); - assert_eq!(Guid::from_bytes(bytes).to_bytes(), bytes); - } -} diff --git a/framework_lib/src/lib.rs b/framework_lib/src/lib.rs index 661f9e14..93d91e2b 100644 --- a/framework_lib/src/lib.rs +++ b/framework_lib/src/lib.rs @@ -37,8 +37,6 @@ pub mod commandline; pub mod csme; pub mod ec_binary; pub mod esrt; -#[cfg(not(feature = "uefi"))] -pub mod guid; mod os_specific; pub mod power; pub mod smbios; diff --git a/framework_lib/src/power.rs b/framework_lib/src/power.rs index f365d57a..ba89af1d 100644 --- a/framework_lib/src/power.rs +++ b/framework_lib/src/power.rs @@ -1,5 +1,6 @@ //! Get information about system power (battery, AC, PD ports) +use alloc::format; use alloc::string::String; use alloc::vec; use alloc::vec::Vec; @@ -10,11 +11,11 @@ use log::Level; use crate::ccgx::{AppVersion, Application, BaseVersion, ControllerVersion, MainPdVersions}; use crate::chromium_ec::command::EcRequestRaw; -use crate::chromium_ec::commands::{EcRequestReadPdVersion, EcRequestUsbPdPowerInfo}; -use crate::chromium_ec::{print_err_ref, CrosEc, CrosEcDriver, EcResult}; +use crate::chromium_ec::commands::*; +use crate::chromium_ec::*; use crate::smbios; use crate::smbios::get_platform; -use crate::util::Platform; +use crate::util::{Platform, PlatformFamily}; /// Maximum length of strings in memmap const EC_MEMMAP_TEXT_MAX: u16 = 8; @@ -245,9 +246,15 @@ pub fn print_memmap_version_info(ec: &CrosEc) { } /// Not supported on TGL EC -pub fn get_als_reading(ec: &CrosEc) -> Option { +pub fn get_als_reading(ec: &CrosEc, index: usize) -> Option { let als = ec.read_memory(EC_MEMMAP_ALS, 0x04)?; - Some(u32::from_le_bytes([als[0], als[1], als[2], als[3]])) + let offset = index + 4 * index; + Some(u32::from_le_bytes([ + als[offset], + als[1 + offset], + als[2 + offset], + als[3 + offset], + ])) } pub fn get_accel_data(ec: &CrosEc) -> (AccelData, AccelData, LidAngle) { @@ -274,8 +281,40 @@ pub fn get_accel_data(ec: &CrosEc) -> (AccelData, AccelData, LidAngle) { } pub fn print_sensors(ec: &CrosEc) { - let als_int = get_als_reading(ec).unwrap(); - println!("ALS: {:>4} Lux", als_int); + let mut has_als = false; + let mut accel_locations = vec![]; + + match ec.motionsense_sensor_info() { + Ok(sensors) => { + info!("Sensors: {}", sensors.len()); + for sensor in sensors { + info!(" Type: {:?}", sensor.sensor_type); + info!(" Location: {:?}", sensor.location); + info!(" Chip: {:?}", sensor.chip); + if sensor.sensor_type == MotionSenseType::Light { + has_als = true; + } + if sensor.sensor_type == MotionSenseType::Accel { + accel_locations.push(sensor.location); + } + } + } + Err(EcError::Response(EcResponseStatus::InvalidCommand)) => { + debug!("Motionsense commands not supported") + } + err => _ = print_err(err), + } + + // If we can't detect it based on motionsense + let als_family = matches!( + smbios::get_family(), + Some(PlatformFamily::Framework13) | Some(PlatformFamily::Framework16) + ); + + if has_als || als_family { + let als_int = get_als_reading(ec, 0).unwrap(); + println!("ALS: {:>4} Lux", als_int); + } // bit 4 = busy // bit 7 = present @@ -294,18 +333,22 @@ pub fn print_sensors(ec: &CrosEc) { debug!(" Status Bit: {} 0x{:X}", acc_status, acc_status); debug!(" Present: {}", present); debug!(" Busy: {}", (acc_status & 0x8) > 0); - print!(" Lid Angle: "); + print!(" Lid Angle: "); if lid_angle == LID_ANGLE_UNRELIABLE { println!("Unreliable"); } else { println!("{} Deg", lid_angle); } - println!(" Sensor 1: {}", AccelData::from(accel_1)); - println!(" Sensor 2: {}", AccelData::from(accel_2)); - // Accelerometers - // Lid Angle: 26 Deg - // Sensor 1: 00.00 X 00.00 Y 00.00 Z - // Sensor 2: 00.00 X 00.00 Y 00.00 Z + println!( + " {:<12} {}", + format!("{:?} Sensor:", accel_locations[0]), + AccelData::from(accel_1) + ); + println!( + " {:<12} {}", + format!("{:?} Sensor:", accel_locations[1]), + AccelData::from(accel_2) + ); } } diff --git a/framework_lib/src/smbios.rs b/framework_lib/src/smbios.rs index c5cfef29..935f0dc7 100644 --- a/framework_lib/src/smbios.rs +++ b/framework_lib/src/smbios.rs @@ -6,7 +6,7 @@ use std::prelude::v1::*; use std::io::ErrorKind; use crate::util::Config; -pub use crate::util::Platform; +pub use crate::util::{Platform, PlatformFamily}; use num_derive::FromPrimitive; use num_traits::FromPrimitive; use smbioslib::*; @@ -271,6 +271,10 @@ pub fn get_baseboard_version() -> Option { }) } +pub fn get_family() -> Option { + get_platform().and_then(Platform::which_family) +} + pub fn get_platform() -> Option { #[cfg(feature = "uefi")] let mut cached_platform = CACHED_PLATFORM.lock(); diff --git a/framework_lib/src/touchpad.rs b/framework_lib/src/touchpad.rs index e767c7e6..35c4fc55 100644 --- a/framework_lib/src/touchpad.rs +++ b/framework_lib/src/touchpad.rs @@ -59,7 +59,7 @@ pub fn print_touchpad_fw_ver() -> Result<(), HidError> { let device = dev_info.open_device(&api).unwrap(); println!("Touchpad"); - println!(" IC Type: {:04X}", pid); + info!(" IC Type: {:04X}", pid); let ver = match pid { 0x0239 => format!("{:04X}", read_239_ver(&device)?), diff --git a/framework_lib/src/touchscreen.rs b/framework_lib/src/touchscreen.rs index 256df139..de74c9f9 100644 --- a/framework_lib/src/touchscreen.rs +++ b/framework_lib/src/touchscreen.rs @@ -207,8 +207,14 @@ pub trait TouchScreen { println!(" Firmware Version: v{}", ver); let res = self.send_message(0x20, 16, vec![0])?; - println!(" USI Protocol: {:?}", (res[15] & USI_BITMAP) > 0); - println!(" MPP Protocol: {:?}", (res[15] & MPP_BITMAP) > 0); + let mut protocols = vec![]; + if (res[15] & USI_BITMAP) > 0 { + protocols.push("USI"); + } + if (res[15] & MPP_BITMAP) > 0 { + protocols.push("MPP"); + } + println!(" Protocols: {}", protocols.join(", ")); Some(()) } diff --git a/framework_tool/Cargo.toml b/framework_tool/Cargo.toml index 7cdfd1f6..8da6a35c 100644 --- a/framework_tool/Cargo.toml +++ b/framework_tool/Cargo.toml @@ -1,8 +1,17 @@ [package] name = "framework_tool" -version = "0.4.1" +version = "0.4.2" +description = "Tool to control Framework Computer systems" +homepage = "https://github.com/FrameworkComputer/framework-system" +repository = "https://github.com/FrameworkComputer/framework-system" +readme = "README.md" +license = "BSD-3-Clause" edition = "2021" +[[bin]] +name = "framework_tool" +path = "src/main.rs" + [dependencies.framework_lib] path = "../framework_lib" diff --git a/framework_uefi/Cargo.toml b/framework_uefi/Cargo.toml index d0ad0cc4..852fa7ec 100644 --- a/framework_uefi/Cargo.toml +++ b/framework_uefi/Cargo.toml @@ -1,6 +1,11 @@ [package] name = "framework_uefi" -version = "0.4.1" +version = "0.4.2" +description = "UEFI Tool to control Framework Computer systems" +homepage = "https://github.com/FrameworkComputer/framework-system" +repository = "https://github.com/FrameworkComputer/framework-system" +readme = "README.md" +license = "BSD-3-Clause" edition = "2021" # Minimum Supported Rust Version rust-version = "1.74" diff --git a/framework_uefi/Makefile b/framework_uefi/Makefile index 6963d8f2..a571ba17 100644 --- a/framework_uefi/Makefile +++ b/framework_uefi/Makefile @@ -15,6 +15,8 @@ QEMU_FLAGS=\ all: $(BUILD)/boot.img +iso: $(BUILD)/UEFI-Shell-fwk.iso + clean: rm -r $(BUILD) @@ -39,6 +41,19 @@ $(BUILD)/efi.img: $(BUILD)/boot.efi mcopy -i $@.tmp $< ::efi/boot/bootx64.efi mv $@.tmp $@ +$(BUILD)/shellx64.efi: + wget https://github.com/pbatard/UEFI-Shell/releases/download/24H2/shellx64.efi -O $@ + +$(BUILD)/UEFI-Shell-fwk.iso: $(BUILD)/boot.efi $(BUILD)/shellx64.efi + mkdir -p $(BUILD)/$@.tmp/efi/boot + cp $(BUILD)/boot.efi $(BUILD)/$@.tmp/efi/boot/fwk.efi + cp $(BUILD)/shellx64.efi $(BUILD)/$@.tmp/efi/boot/bootx64.efi + genisoimage -v \ + -V "UEFI SHELL with fwk.efi" \ + -JR \ + -o "$(BUILD)/UEFI-Shell-fwk.iso" \ + $(BUILD)/$@.tmp + $(BUILD)/boot.efi: ../Cargo.lock $(SRC_DIR)/Cargo.toml $(SRC_DIR)/src/* mkdir -p $(BUILD) cargo rustc \ diff --git a/guid_macros/Cargo.toml b/guid_macros/Cargo.toml deleted file mode 100644 index d1680814..00000000 --- a/guid_macros/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -name = "guid_macros" -version = "0.11.0" -authors = ["The Rust OSDev team"] -readme = "README.md" -edition = "2021" -description = "Procedural macros for the `uefi` crate." -repository = "https://github.com/rust-osdev/uefi-rs" -keywords = ["uefi", "efi"] -categories = ["embedded", "no-std", "api-bindings"] -license = "MPL-2.0" - -[lib] -proc-macro = true - -[dependencies] -proc-macro2 = "1.0.28" -quote = "1.0.9" -syn = { version = "2.0.4", features = ["full"] } - -#[dev-dependencies] -#trybuild = "1.0.61" -#uefi = { version = "0.20.0", default-features = false } diff --git a/guid_macros/src/lib.rs b/guid_macros/src/lib.rs deleted file mode 100644 index 7556a5d5..00000000 --- a/guid_macros/src/lib.rs +++ /dev/null @@ -1,101 +0,0 @@ -// Taken from - -use proc_macro::TokenStream; - -use proc_macro2::{TokenStream as TokenStream2, TokenTree}; -use quote::{quote, ToTokens}; -use syn::spanned::Spanned; -use syn::{parse_macro_input, Error, LitStr}; - -macro_rules! err { - ($span:expr, $message:expr $(,)?) => { - Error::new($span.span(), $message).to_compile_error() - }; - ($span:expr, $message:expr, $($args:expr),*) => { - Error::new($span.span(), format!($message, $($args),*)).to_compile_error() - }; -} - -/// Create a `Guid` at compile time. -/// -/// # Example -/// -/// ``` -/// use uefi::{guid, Guid}; -/// const EXAMPLE_GUID: Guid = guid!("12345678-9abc-def0-1234-56789abcdef0"); -/// ``` -#[proc_macro] -pub fn guid(args: TokenStream) -> TokenStream { - let (time_low, time_mid, time_high_and_version, clock_seq_and_variant, node) = - match parse_guid(parse_macro_input!(args as LitStr)) { - Ok(data) => data, - Err(tokens) => return tokens.into(), - }; - - quote!({ - const g: crate::guid::Guid = crate::guid::Guid::from_values( - #time_low, - #time_mid, - #time_high_and_version, - #clock_seq_and_variant, - #node, - ); - g - }) - .into() -} - -fn parse_guid(guid_lit: LitStr) -> Result<(u32, u16, u16, u16, u64), TokenStream2> { - let guid_str = guid_lit.value(); - - // We expect a canonical GUID string, such as "12345678-9abc-def0-fedc-ba9876543210" - if guid_str.len() != 36 { - return Err(err!( - guid_lit, - "\"{}\" is not a canonical GUID string (expected 36 bytes, found {})", - guid_str, - guid_str.len() - )); - } - let mut offset = 1; // 1 is for the starting quote - let mut guid_hex_iter = guid_str.split('-'); - let mut next_guid_int = |len: usize| -> Result { - let guid_hex_component = guid_hex_iter.next().unwrap(); - - // convert syn::LitStr to proc_macro2::Literal.. - let lit = match guid_lit.to_token_stream().into_iter().next().unwrap() { - TokenTree::Literal(lit) => lit, - _ => unreachable!(), - }; - // ..so that we can call subspan and nightly users (us) will get the fancy span - let span = lit - .subspan(offset..offset + guid_hex_component.len()) - .unwrap_or_else(|| lit.span()); - - if guid_hex_component.len() != len * 2 { - return Err(err!( - span, - "GUID component \"{}\" is not a {}-bit hexadecimal string", - guid_hex_component, - len * 8 - )); - } - offset += guid_hex_component.len() + 1; // + 1 for the dash - u64::from_str_radix(guid_hex_component, 16).map_err(|_| { - err!( - span, - "GUID component \"{}\" is not a hexadecimal number", - guid_hex_component - ) - }) - }; - - // The GUID string is composed of a 32-bit integer, three 16-bit ones, and a 48-bit one - Ok(( - next_guid_int(4)? as u32, - next_guid_int(2)? as u16, - next_guid_int(2)? as u16, - next_guid_int(2)? as u16, - next_guid_int(6)?, - )) -} pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy