Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create version check function #32

Merged
merged 5 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,38 @@ own EC firmware and flash it.
- [x] Basic unit tests
- [x] Test parsing real binaries

## Version Check

Check if the firmware version is what you expect, returns exit code 0 on
succcess, 1 on failure.

```
# Check which devices it's available for
> ./framework_system --device
[possible values: bios, ec, pd0, pd1, rtm01, rtm23]
For more information try '--help'
# Successful compare
> ./framework_system --device bios --compare-version 03.01
Target Version "03.01"
Comparing BIOS version "03.01"
Compared version: 0
> echo $?
0
# Failed compare
> ./framework_system --device bios --compare-version 03.00
Finished dev [unoptimized + debuginfo] target(s) in 0.05s
Target Version "03.00"
Comparing BIOS version "03.01"
Compared version: 1
Error: "Fail"
> echo $?
1
```

## Debugging

To debug, increase the verbosity from the commandline with `-v`.
Expand Down
32 changes: 28 additions & 4 deletions framework_lib/src/ccgx/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
//! Interact with Infineon (formerly Cypress) PD controllers (their firmware binaries) in the CCGx series

use alloc::string::String;
use alloc::string::ToString;
#[cfg(feature = "uefi")]
use core::prelude::rust_2021::derive;
use num_derive::FromPrimitive;
use std::fmt;

use crate::chromium_ec::{CrosEc, EcResult};
use crate::smbios;
use crate::util::Platform;

use self::device::{FwMode, PdController, PdPort};

Expand Down Expand Up @@ -102,7 +106,7 @@ pub enum SiliconId {
Ccg8 = 0x3580,
}

#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Copy, Clone)]
pub struct BaseVersion {
/// Major part of the version. X of X.Y.Z.BB
pub major: u8,
Expand Down Expand Up @@ -138,15 +142,15 @@ impl From<u32> for BaseVersion {
}
}

#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum Application {
Notebook,
Monitor,
AA,
Invalid,
}

#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Copy, Clone)]
pub struct AppVersion {
pub application: Application,
/// Major part of the version. X of X.Y.Z
Expand Down Expand Up @@ -185,7 +189,7 @@ impl From<u32> for AppVersion {
}
}

#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Copy, Clone)]
pub struct ControllerVersion {
pub base: BaseVersion,
pub app: AppVersion,
Expand All @@ -199,6 +203,26 @@ pub struct ControllerFirmwares {
pub main_fw: ControllerVersion,
}

impl ControllerFirmwares {
pub fn active_fw(&self) -> ControllerVersion {
match self.active_fw {
FwMode::MainFw => self.main_fw,
FwMode::BackupFw => self.backup_fw,
FwMode::BootLoader => self.bootloader,
}
}

pub fn active_fw_ver(&self) -> String {
let active = self.active_fw();
// On 11th Gen we modified base version instead of app version
if let Some(Platform::IntelGen11) = smbios::get_platform() {
active.base.to_string()
} else {
active.app.to_string()
}
}
}

#[derive(Debug, PartialEq)]
pub struct PdVersions {
pub controller01: ControllerFirmwares,
Expand Down
13 changes: 13 additions & 0 deletions framework_lib/src/chromium_ec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -864,6 +864,19 @@ pub enum CrosEcDriverType {
Windows,
}

#[cfg_attr(not(feature = "uefi"), derive(clap::ValueEnum))]
#[derive(Clone, Debug, Copy, PartialEq)]
pub enum HardwareDeviceType {
BIOS,
EC,
PD0,
PD1,
RTM01,
RTM23,
AcLeft,
AcRight,
}

impl CrosEcDriver for CrosEc {
fn read_memory(&self, offset: u16, length: u16) -> Option<Vec<u8>> {
if !smbios::is_framework() {
Expand Down
15 changes: 14 additions & 1 deletion framework_lib/src/commandline/clap_std.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
use clap::Parser;

use crate::chromium_ec::CrosEcDriverType;
use crate::commandline::{Cli, ConsoleArg, FpBrightnessArg, InputDeckModeArg, RebootEcArg};
use crate::commandline::{
Cli, ConsoleArg, FpBrightnessArg, HardwareDeviceType, InputDeckModeArg, RebootEcArg,
};

/// Swiss army knife for Framework laptops
#[derive(Parser)]
Expand All @@ -25,6 +27,15 @@ struct ClapCli {
#[arg(long)]
esrt: bool,

// Device type to compare_version string with version string on device
#[clap(value_enum)]
#[arg(long)]
device: Option<HardwareDeviceType>,

// version to compare with
#[arg(long)]
compare_version: Option<String>,

/// Show current power status of battery and AC (Add -vv for more details)
#[arg(long)]
power: bool,
Expand Down Expand Up @@ -198,6 +209,8 @@ pub fn parse(args: &[String]) -> Cli {
versions: args.versions,
version: args.version,
esrt: args.esrt,
device: args.device,
compare_version: args.compare_version,
power: args.power,
thermal: args.thermal,
sensors: args.sensors,
Expand Down
126 changes: 124 additions & 2 deletions framework_lib/src/commandline/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
//! Can be easily re-used from any OS or UEFI shell.
//! We have implemented both in the `framework_tool` and `framework_uefi` crates.

use alloc::format;
use alloc::string::String;
use alloc::string::ToString;
use alloc::vec::Vec;
Expand Down Expand Up @@ -54,7 +55,7 @@ use sha2::{Digest, Sha256, Sha384, Sha512};
//use smbioslib::*;
use smbioslib::{DefinedStruct, SMBiosInformation};

use crate::chromium_ec::{CrosEc, CrosEcDriverType};
use crate::chromium_ec::{CrosEc, CrosEcDriverType, HardwareDeviceType};

#[cfg(feature = "uefi")]
use core::prelude::rust_2021::derive;
Expand Down Expand Up @@ -120,6 +121,8 @@ pub struct Cli {
pub versions: bool,
pub version: bool,
pub esrt: bool,
pub device: Option<HardwareDeviceType>,
pub compare_version: Option<String>,
pub power: bool,
pub thermal: bool,
pub sensors: bool,
Expand Down Expand Up @@ -506,6 +509,119 @@ fn dump_ec_flash(ec: &CrosEc, dump_path: &str) {
}
}

fn compare_version(device: Option<HardwareDeviceType>, version: String, ec: &CrosEc) -> i32 {
println!("Target Version {:?}", version);

if let Some(smbios) = get_smbios() {
let bios_entries = smbios.collect::<SMBiosInformation>();
let bios = bios_entries.get(0).unwrap();

if device == Some(HardwareDeviceType::BIOS) {
println!("Comparing BIOS version {:?}", bios.version().to_string());
if version.to_uppercase() == bios.version().to_string().to_uppercase() {
return 0;
} else {
return 1;
}
}
}

match device {
Some(HardwareDeviceType::EC) => {
let ver = print_err(ec.version_info()).unwrap_or_else(|| "UNKNOWN".to_string());
println!("Comparing EC version {:?}", ver);

if ver.contains(&version) {
return 0;
} else {
return 1;
}
}
Some(HardwareDeviceType::PD0) => {
if let Ok(pd_versions) = ccgx::get_pd_controller_versions(ec) {
let ver = pd_versions.controller01.active_fw_ver();
println!("Comparing PD0 version {:?}", ver);

if ver.contains(&version) {
return 0;
} else {
return 1;
}
}
}
Some(HardwareDeviceType::PD1) => {
if let Ok(pd_versions) = ccgx::get_pd_controller_versions(ec) {
let ver = pd_versions.controller23.active_fw_ver();
println!("Comparing PD1 version {:?}", ver);

if ver.contains(&version) {
return 0;
} else {
return 1;
}
}
}
Some(HardwareDeviceType::AcLeft) => {
if let Ok((_right, left)) = power::is_charging(ec) {
let ver = format!("{}", left as i32);
println!("Comparing AcLeft {:?}", ver);
if ver == version {
return 0;
} else {
return 1;
}
} else {
error!("Failed to get charging information");
// Not charging is the safe default
return 1;
}
}
Some(HardwareDeviceType::AcRight) => {
if let Ok((right, _left)) = power::is_charging(ec) {
let ver = format!("{}", right as i32);
println!("Comparing AcRight {:?}", ver);
if ver == version {
return 0;
} else {
return 1;
}
} else {
error!("Failed to get charging information");
// Not charging is the safe default
return 1;
}
}
_ => {}
}

if let Some(esrt) = esrt::get_esrt() {
for entry in &esrt.entries {
match 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());

if entry.fw_version.to_string().contains(&version) {
return 0;
}
}
}
esrt::TGL_RETIMER23_GUID | esrt::ADL_RETIMER23_GUID | esrt::RPL_RETIMER23_GUID => {
if device == Some(HardwareDeviceType::RTM23) {
println!("Comparing RTM23 version {:?}", entry.fw_version.to_string());
if entry.fw_version.to_string().contains(&version) {
return 0;
}
}
}
_ => {}
}
}
}

1
}

pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 {
#[cfg(feature = "uefi")]
{
Expand Down Expand Up @@ -563,6 +679,10 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 {
print_tool_version();
} else if args.esrt {
print_esrt();
} else if let Some(compare_version_ver) = &args.compare_version {
let compare_ret = compare_version(args.device, compare_version_ver.to_string(), &ec);
println!("Comparison Result: {}", compare_ret);
return compare_ret;
} else if args.intrusion {
println!("Chassis status:");
if let Some(status) = print_err(ec.get_intrusion_status()) {
Expand Down Expand Up @@ -653,7 +773,7 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 {
return 1;
}
} else if args.power {
power::get_and_print_power_info(&ec);
return power::get_and_print_power_info(&ec);
} else if args.thermal {
power::print_thermal(&ec);
} else if args.sensors {
Expand Down Expand Up @@ -835,6 +955,8 @@ Options:
--versions List current firmware versions
--version Show tool version information (Add -vv for more detailed information)
--esrt Display the UEFI ESRT table
--device <DEVICE> Device used to compare firmware version [possible values: bios, ec, pd0, pd1, rtm01, rtm23]
--compare-version Version string used to match firmware version (use with --device)
--power Show current power status (battery and AC)
--thermal Print thermal information (Temperatures and Fan speed)
--sensors Print sensor information (ALS, G-Sensor)
Expand Down
Loading