Skip to content

Commit 6fd13f2

Browse files
Merge pull request #32 from FrameworkComputer/version_check
Create version check function
2 parents fee9f43 + 69c97b0 commit 6fd13f2

File tree

11 files changed

+264
-12
lines changed

11 files changed

+264
-12
lines changed

README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,38 @@ own EC firmware and flash it.
272272
- [x] Basic unit tests
273273
- [x] Test parsing real binaries
274274

275+
## Version Check
276+
277+
Check if the firmware version is what you expect, returns exit code 0 on
278+
succcess, 1 on failure.
279+
280+
```
281+
# Check which devices it's available for
282+
> ./framework_system --device
283+
[possible values: bios, ec, pd0, pd1, rtm01, rtm23]
284+
285+
For more information try '--help'
286+
287+
# Successful compare
288+
> ./framework_system --device bios --compare-version 03.01
289+
Target Version "03.01"
290+
Comparing BIOS version "03.01"
291+
Compared version: 0
292+
> echo $?
293+
0
294+
295+
# Failed compare
296+
> ./framework_system --device bios --compare-version 03.00
297+
Finished dev [unoptimized + debuginfo] target(s) in 0.05s
298+
Target Version "03.00"
299+
Comparing BIOS version "03.01"
300+
Compared version: 1
301+
Error: "Fail"
302+
303+
> echo $?
304+
1
305+
```
306+
275307
## Debugging
276308

277309
To debug, increase the verbosity from the commandline with `-v`.

framework_lib/src/ccgx/mod.rs

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
//! Interact with Infineon (formerly Cypress) PD controllers (their firmware binaries) in the CCGx series
22
3+
use alloc::string::String;
4+
use alloc::string::ToString;
35
#[cfg(feature = "uefi")]
46
use core::prelude::rust_2021::derive;
57
use num_derive::FromPrimitive;
68
use std::fmt;
79

810
use crate::chromium_ec::{CrosEc, EcResult};
11+
use crate::smbios;
12+
use crate::util::Platform;
913

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

@@ -102,7 +106,7 @@ pub enum SiliconId {
102106
Ccg8 = 0x3580,
103107
}
104108

105-
#[derive(Debug, PartialEq)]
109+
#[derive(Debug, PartialEq, Copy, Clone)]
106110
pub struct BaseVersion {
107111
/// Major part of the version. X of X.Y.Z.BB
108112
pub major: u8,
@@ -138,15 +142,15 @@ impl From<u32> for BaseVersion {
138142
}
139143
}
140144

141-
#[derive(Debug, PartialEq)]
145+
#[derive(Debug, PartialEq, Copy, Clone)]
142146
pub enum Application {
143147
Notebook,
144148
Monitor,
145149
AA,
146150
Invalid,
147151
}
148152

149-
#[derive(Debug, PartialEq)]
153+
#[derive(Debug, PartialEq, Copy, Clone)]
150154
pub struct AppVersion {
151155
pub application: Application,
152156
/// Major part of the version. X of X.Y.Z
@@ -185,7 +189,7 @@ impl From<u32> for AppVersion {
185189
}
186190
}
187191

188-
#[derive(Debug, PartialEq)]
192+
#[derive(Debug, PartialEq, Copy, Clone)]
189193
pub struct ControllerVersion {
190194
pub base: BaseVersion,
191195
pub app: AppVersion,
@@ -199,6 +203,26 @@ pub struct ControllerFirmwares {
199203
pub main_fw: ControllerVersion,
200204
}
201205

206+
impl ControllerFirmwares {
207+
pub fn active_fw(&self) -> ControllerVersion {
208+
match self.active_fw {
209+
FwMode::MainFw => self.main_fw,
210+
FwMode::BackupFw => self.backup_fw,
211+
FwMode::BootLoader => self.bootloader,
212+
}
213+
}
214+
215+
pub fn active_fw_ver(&self) -> String {
216+
let active = self.active_fw();
217+
// On 11th Gen we modified base version instead of app version
218+
if let Some(Platform::IntelGen11) = smbios::get_platform() {
219+
active.base.to_string()
220+
} else {
221+
active.app.to_string()
222+
}
223+
}
224+
}
225+
202226
#[derive(Debug, PartialEq)]
203227
pub struct PdVersions {
204228
pub controller01: ControllerFirmwares,

framework_lib/src/chromium_ec/mod.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -864,6 +864,19 @@ pub enum CrosEcDriverType {
864864
Windows,
865865
}
866866

867+
#[cfg_attr(not(feature = "uefi"), derive(clap::ValueEnum))]
868+
#[derive(Clone, Debug, Copy, PartialEq)]
869+
pub enum HardwareDeviceType {
870+
BIOS,
871+
EC,
872+
PD0,
873+
PD1,
874+
RTM01,
875+
RTM23,
876+
AcLeft,
877+
AcRight,
878+
}
879+
867880
impl CrosEcDriver for CrosEc {
868881
fn read_memory(&self, offset: u16, length: u16) -> Option<Vec<u8>> {
869882
if !smbios::is_framework() {

framework_lib/src/commandline/clap_std.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
use clap::Parser;
55

66
use crate::chromium_ec::CrosEcDriverType;
7-
use crate::commandline::{Cli, ConsoleArg, FpBrightnessArg, InputDeckModeArg, RebootEcArg};
7+
use crate::commandline::{
8+
Cli, ConsoleArg, FpBrightnessArg, HardwareDeviceType, InputDeckModeArg, RebootEcArg,
9+
};
810

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

30+
// Device type to compare_version string with version string on device
31+
#[clap(value_enum)]
32+
#[arg(long)]
33+
device: Option<HardwareDeviceType>,
34+
35+
// version to compare with
36+
#[arg(long)]
37+
compare_version: Option<String>,
38+
2839
/// Show current power status of battery and AC (Add -vv for more details)
2940
#[arg(long)]
3041
power: bool,
@@ -198,6 +209,8 @@ pub fn parse(args: &[String]) -> Cli {
198209
versions: args.versions,
199210
version: args.version,
200211
esrt: args.esrt,
212+
device: args.device,
213+
compare_version: args.compare_version,
201214
power: args.power,
202215
thermal: args.thermal,
203216
sensors: args.sensors,

framework_lib/src/commandline/mod.rs

Lines changed: 124 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
//! Can be easily re-used from any OS or UEFI shell.
44
//! We have implemented both in the `framework_tool` and `framework_uefi` crates.
55
6+
use alloc::format;
67
use alloc::string::String;
78
use alloc::string::ToString;
89
use alloc::vec::Vec;
@@ -54,7 +55,7 @@ use sha2::{Digest, Sha256, Sha384, Sha512};
5455
//use smbioslib::*;
5556
use smbioslib::{DefinedStruct, SMBiosInformation};
5657

57-
use crate::chromium_ec::{CrosEc, CrosEcDriverType};
58+
use crate::chromium_ec::{CrosEc, CrosEcDriverType, HardwareDeviceType};
5859

5960
#[cfg(feature = "uefi")]
6061
use core::prelude::rust_2021::derive;
@@ -120,6 +121,8 @@ pub struct Cli {
120121
pub versions: bool,
121122
pub version: bool,
122123
pub esrt: bool,
124+
pub device: Option<HardwareDeviceType>,
125+
pub compare_version: Option<String>,
123126
pub power: bool,
124127
pub thermal: bool,
125128
pub sensors: bool,
@@ -506,6 +509,119 @@ fn dump_ec_flash(ec: &CrosEc, dump_path: &str) {
506509
}
507510
}
508511

512+
fn compare_version(device: Option<HardwareDeviceType>, version: String, ec: &CrosEc) -> i32 {
513+
println!("Target Version {:?}", version);
514+
515+
if let Some(smbios) = get_smbios() {
516+
let bios_entries = smbios.collect::<SMBiosInformation>();
517+
let bios = bios_entries.get(0).unwrap();
518+
519+
if device == Some(HardwareDeviceType::BIOS) {
520+
println!("Comparing BIOS version {:?}", bios.version().to_string());
521+
if version.to_uppercase() == bios.version().to_string().to_uppercase() {
522+
return 0;
523+
} else {
524+
return 1;
525+
}
526+
}
527+
}
528+
529+
match device {
530+
Some(HardwareDeviceType::EC) => {
531+
let ver = print_err(ec.version_info()).unwrap_or_else(|| "UNKNOWN".to_string());
532+
println!("Comparing EC version {:?}", ver);
533+
534+
if ver.contains(&version) {
535+
return 0;
536+
} else {
537+
return 1;
538+
}
539+
}
540+
Some(HardwareDeviceType::PD0) => {
541+
if let Ok(pd_versions) = ccgx::get_pd_controller_versions(ec) {
542+
let ver = pd_versions.controller01.active_fw_ver();
543+
println!("Comparing PD0 version {:?}", ver);
544+
545+
if ver.contains(&version) {
546+
return 0;
547+
} else {
548+
return 1;
549+
}
550+
}
551+
}
552+
Some(HardwareDeviceType::PD1) => {
553+
if let Ok(pd_versions) = ccgx::get_pd_controller_versions(ec) {
554+
let ver = pd_versions.controller23.active_fw_ver();
555+
println!("Comparing PD1 version {:?}", ver);
556+
557+
if ver.contains(&version) {
558+
return 0;
559+
} else {
560+
return 1;
561+
}
562+
}
563+
}
564+
Some(HardwareDeviceType::AcLeft) => {
565+
if let Ok((_right, left)) = power::is_charging(ec) {
566+
let ver = format!("{}", left as i32);
567+
println!("Comparing AcLeft {:?}", ver);
568+
if ver == version {
569+
return 0;
570+
} else {
571+
return 1;
572+
}
573+
} else {
574+
error!("Failed to get charging information");
575+
// Not charging is the safe default
576+
return 1;
577+
}
578+
}
579+
Some(HardwareDeviceType::AcRight) => {
580+
if let Ok((right, _left)) = power::is_charging(ec) {
581+
let ver = format!("{}", right as i32);
582+
println!("Comparing AcRight {:?}", ver);
583+
if ver == version {
584+
return 0;
585+
} else {
586+
return 1;
587+
}
588+
} else {
589+
error!("Failed to get charging information");
590+
// Not charging is the safe default
591+
return 1;
592+
}
593+
}
594+
_ => {}
595+
}
596+
597+
if let Some(esrt) = esrt::get_esrt() {
598+
for entry in &esrt.entries {
599+
match entry.fw_class {
600+
esrt::TGL_RETIMER01_GUID | esrt::ADL_RETIMER01_GUID | esrt::RPL_RETIMER01_GUID => {
601+
if device == Some(HardwareDeviceType::RTM01) {
602+
println!("Comparing RTM01 version {:?}", entry.fw_version.to_string());
603+
604+
if entry.fw_version.to_string().contains(&version) {
605+
return 0;
606+
}
607+
}
608+
}
609+
esrt::TGL_RETIMER23_GUID | esrt::ADL_RETIMER23_GUID | esrt::RPL_RETIMER23_GUID => {
610+
if device == Some(HardwareDeviceType::RTM23) {
611+
println!("Comparing RTM23 version {:?}", entry.fw_version.to_string());
612+
if entry.fw_version.to_string().contains(&version) {
613+
return 0;
614+
}
615+
}
616+
}
617+
_ => {}
618+
}
619+
}
620+
}
621+
622+
1
623+
}
624+
509625
pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 {
510626
#[cfg(feature = "uefi")]
511627
{
@@ -563,6 +679,10 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 {
563679
print_tool_version();
564680
} else if args.esrt {
565681
print_esrt();
682+
} else if let Some(compare_version_ver) = &args.compare_version {
683+
let compare_ret = compare_version(args.device, compare_version_ver.to_string(), &ec);
684+
println!("Comparison Result: {}", compare_ret);
685+
return compare_ret;
566686
} else if args.intrusion {
567687
println!("Chassis status:");
568688
if let Some(status) = print_err(ec.get_intrusion_status()) {
@@ -653,7 +773,7 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 {
653773
return 1;
654774
}
655775
} else if args.power {
656-
power::get_and_print_power_info(&ec);
776+
return power::get_and_print_power_info(&ec);
657777
} else if args.thermal {
658778
power::print_thermal(&ec);
659779
} else if args.sensors {
@@ -835,6 +955,8 @@ Options:
835955
--versions List current firmware versions
836956
--version Show tool version information (Add -vv for more detailed information)
837957
--esrt Display the UEFI ESRT table
958+
--device <DEVICE> Device used to compare firmware version [possible values: bios, ec, pd0, pd1, rtm01, rtm23]
959+
--compare-version Version string used to match firmware version (use with --device)
838960
--power Show current power status (battery and AC)
839961
--thermal Print thermal information (Temperatures and Fan speed)
840962
--sensors Print sensor information (ALS, G-Sensor)

0 commit comments

Comments
 (0)