Skip to content

add commands to read/write gpu serial #98

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

Merged
merged 1 commit into from
Apr 14, 2025
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
2 changes: 1 addition & 1 deletion framework_lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ sha2 = { version = "0.10.8", default-features = false, features = [ "force-soft"
regex = { version = "1.11.1", default-features = false }
redox_hwio = { git = "https://github.com/FrameworkComputer/rust-hwio", branch = "freebsd", default-features = false }
libc = { version = "0.2.155", optional = true }
clap = { version = "4.5", features = ["derive"], optional = true }
clap = { version = "4.5", features = ["derive", "cargo"], optional = true }
clap-num = { version = "1.2.0", optional = true }
clap-verbosity-flag = { version = "2.2.1", optional = true }
nix = { version = "0.29.0", features = ["ioctl", "user"], optional = true }
Expand Down
4 changes: 4 additions & 0 deletions framework_lib/src/chromium_ec/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ pub enum EcCommands {
ExpansionBayStatus = 0x3E1B,
/// Get hardware diagnostics
GetHwDiag = 0x3E1C,
/// Get gpu bay serial
GetGpuSerial = 0x3E1D,
/// Set gpu bay serial and program structure
ProgramGpuEeprom = 0x3E1F,
}

pub trait EcRequest<R> {
Expand Down
46 changes: 46 additions & 0 deletions framework_lib/src/chromium_ec/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -931,3 +931,49 @@ impl EcRequest<EcResponseFpLedLevelControlV1> for EcRequestFpLedLevelControlV1 {
1
}
}

#[repr(C, packed)]
pub struct EcRequestGetGpuSerial {
pub idx: u8,
}

#[repr(C, packed)]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct EcResponseGetGpuSerial {
pub idx: u8,
pub valid: u8,
pub serial: [u8; 20],
}

impl EcRequest<EcResponseGetGpuSerial> for EcRequestGetGpuSerial {
fn command_id() -> EcCommands {
EcCommands::GetGpuSerial
}
}

#[repr(u8)]
pub enum SetGpuSerialMagic {
/// 7700S config magic value
WriteGPUConfig = 0x0D,
/// SSD config magic value
WriteSSDConfig = 0x55,
}

#[repr(C, packed)]
pub struct EcRequestSetGpuSerial {
pub magic: u8,
pub idx: u8,
pub serial: [u8; 20],
}

#[repr(C, packed)]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct EcResponseSetGpuSerial {
pub valid: u8,
}

impl EcRequest<EcResponseSetGpuSerial> for EcRequestSetGpuSerial {
fn command_id() -> EcCommands {
EcCommands::ProgramGpuEeprom
}
}
31 changes: 31 additions & 0 deletions framework_lib/src/chromium_ec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ use alloc::string::String;
use alloc::string::ToString;
use alloc::vec;
use alloc::vec::Vec;

#[cfg(feature = "uefi")]
use core::prelude::rust_2021::derive;
use num_traits::FromPrimitive;
Expand Down Expand Up @@ -789,6 +790,36 @@ impl CrosEc {
res
}

/// Get the GPU Serial
///
pub fn get_gpu_serial(&self) -> EcResult<String> {
let gpuserial: EcResponseGetGpuSerial =
EcRequestGetGpuSerial { idx: 0 }.send_command(self)?;
let serial: String = String::from_utf8(gpuserial.serial.to_vec()).unwrap();

if gpuserial.valid == 0 {
return Err(EcError::DeviceError("No valid GPU serial".to_string()));
}

Ok(serial)
}

/// Set the GPU Serial
///
/// # Arguments
/// `newserial` - a string that is 18 characters long
pub fn set_gpu_serial(&self, magic: u8, newserial: String) -> EcResult<u8> {
let mut array_tmp: [u8; 20] = [0; 20];
array_tmp[..18].copy_from_slice(newserial.as_bytes());
let result = EcRequestSetGpuSerial {
magic,
idx: 0,
serial: array_tmp,
}
.send_command(self)?;
Ok(result.valid)
}

/// Requests recent console output from EC and constantly asks for more
/// Prints the output and returns it when an error is encountered
pub fn console_read(&self) -> EcResult<String> {
Expand Down
78 changes: 61 additions & 17 deletions framework_lib/src/commandline/clap_std.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
//! Module to factor out commandline interaction
//! This way we can use it in the regular OS commandline tool on Linux and Windows,
//! as well as on the UEFI shell tool.
use clap::error::ErrorKind;
use clap::Parser;
use clap::{arg, command, Arg, Args, FromArgMatches};
use clap_num::maybe_hex;

use crate::chromium_ec::commands::SetGpuSerialMagic;
use crate::chromium_ec::CrosEcDriverType;
use crate::commandline::{
Cli, ConsoleArg, FpBrightnessArg, HardwareDeviceType, InputDeckModeArg, RebootEcArg,
Expand Down Expand Up @@ -203,31 +206,71 @@ struct ClapCli {

/// Parse a list of commandline arguments and return the struct
pub fn parse(args: &[String]) -> Cli {
let args = ClapCli::parse_from(args);
// Step 1 - Define args that can't be derived
let cli = command!()
.arg(Arg::new("fgd").long("flash-gpu-descriptor").num_args(2))
.disable_version_flag(true);
// Step 2 - Define args from derived struct
let mut cli = ClapCli::augment_args(cli);

// Step 3 - Parse args that can't be derived
let matches = cli.clone().get_matches_from(args);
let fgd = matches
.get_many::<String>("fgd")
.unwrap_or_default()
.map(|v| v.as_str())
.collect::<Vec<_>>();
let flash_gpu_descriptor = if !fgd.is_empty() {
let hex_magic = if let Some(hex_magic) = fgd[0].strip_prefix("0x") {
u8::from_str_radix(hex_magic, 16)
} else {
// Force parse error
u8::from_str_radix("", 16)
};

let magic = if let Ok(magic) = fgd[0].parse::<u8>() {
magic
} else if let Ok(hex_magic) = hex_magic {
hex_magic
} else if fgd[0].to_uppercase() == "GPU" {
SetGpuSerialMagic::WriteGPUConfig as u8
} else if fgd[0].to_uppercase() == "SSD" {
SetGpuSerialMagic::WriteSSDConfig as u8
} else {
cli.error(
ErrorKind::InvalidValue,
"First argument of --flash-gpu-descriptor must be an integer or one of: 'GPU', 'SSD'",
)
.exit();
};
if fgd[1].len() != 18 {
cli.error(
ErrorKind::InvalidValue,
"Second argument of --flash-gpu-descriptor must be an 18 digit serial number",
)
.exit();
}
Some((magic, fgd[1].to_string()))
} else {
None
};

// Step 4 - Parse from derived struct
let args = ClapCli::from_arg_matches(&matches)
.map_err(|err| err.exit())
.unwrap();

let pd_addrs = match args.pd_addrs.len() {
2 => Some((args.pd_addrs[0], args.pd_addrs[1])),
0 => None,
_ => {
// Actually unreachable, checked by clap
println!(
"Must provide exactly to PD Addresses. Provided: {:?}",
args.pd_addrs
);
std::process::exit(1);
}
// Checked by clap
_ => unreachable!(),
};
let pd_ports = match args.pd_ports.len() {
2 => Some((args.pd_ports[0], args.pd_ports[1])),
0 => None,
_ => {
// Actually unreachable, checked by clap
println!(
"Must provide exactly to PD Ports. Provided: {:?}",
args.pd_ports
);
std::process::exit(1);
}
// Checked by clap
_ => unreachable!(),
};

Cli {
Expand Down Expand Up @@ -299,6 +342,7 @@ pub fn parse(args: &[String]) -> Cli {
// UEFI only - every command needs to implement a parameter to enable the pager
paginate: false,
info: args.info,
flash_gpu_descriptor,
raw_command: vec![],
}
}
9 changes: 9 additions & 0 deletions framework_lib/src/commandline/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ pub struct Cli {
pub has_mec: Option<bool>,
pub help: bool,
pub info: bool,
pub flash_gpu_descriptor: Option<(u8, String)>,
// UEFI only
pub allupdate: bool,
pub paginate: bool,
Expand Down Expand Up @@ -1004,6 +1005,13 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 {
println!(" Size: {:>20} KB", data.len() / 1024);
hash(&data);
}
} else if let Some(gpu_descriptor) = &args.flash_gpu_descriptor {
let res = ec.set_gpu_serial(gpu_descriptor.0, gpu_descriptor.1.to_ascii_uppercase());
match res {
Ok(1) => println!("GPU Descriptor successfully written"),
Ok(x) => println!("GPU Descriptor write failed with status code: {}", x),
Err(err) => println!("GPU Descriptor write failed with error: {:?}", err),
}
}

0
Expand Down Expand Up @@ -1053,6 +1061,7 @@ Options:
--kblight [<KBLIGHT>] Set keyboard backlight percentage or get, if no value provided
--console <CONSOLE> Get EC console, choose whether recent or to follow the output [possible values: recent, follow]
--hash <HASH> Hash a file of arbitrary data
--flash-gpu-descriptor <MAGIC> <18 DIGIT SN> Overwrite the GPU bay descriptor SN and type.
-t, --test Run self-test to check if interaction with EC is possible
-h, --help Print help information
-b Print output one screen at a time
Expand Down
37 changes: 36 additions & 1 deletion framework_lib/src/commandline/uefi.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use alloc::string::String;
use alloc::string::{String, ToString};
use alloc::vec;
use alloc::vec::Vec;

Expand All @@ -9,6 +9,7 @@ use uefi::proto::shell_params::*;
use uefi::table::boot::{OpenProtocolAttributes, OpenProtocolParams, SearchType};
use uefi::Identify;

use crate::chromium_ec::commands::SetGpuSerialMagic;
use crate::chromium_ec::{CrosEcDriverType, HardwareDeviceType};
use crate::commandline::Cli;

Expand Down Expand Up @@ -99,6 +100,7 @@ pub fn parse(args: &[String]) -> Cli {
has_mec: None,
test: false,
help: false,
flash_gpu_descriptor: None,
allupdate: false,
info: false,
raw_command: vec![],
Expand Down Expand Up @@ -513,6 +515,39 @@ pub fn parse(args: &[String]) -> Cli {
println!("Need to provide a value for --console. Possible values: bios, ec, pd0, pd1, rtm01, rtm23, ac-left, ac-right");
None
};
} else if arg == "--flash-gpu-descriptor" {
cli.flash_gpu_descriptor = if args.len() > i + 2 {
let sn = args[i + 2].to_string();
let magic = &args[i + 1];

let hex_magic = if let Some(hex_magic) = magic.strip_prefix("0x") {
u8::from_str_radix(hex_magic, 16)
} else {
// Force parse error
u8::from_str_radix("", 16)
};

if let Ok(magic) = magic.parse::<u8>() {
Some((magic, sn))
} else if let Ok(hex_magic) = hex_magic {
Some((hex_magic, sn))
} else if magic.to_uppercase() == "GPU" {
Some((SetGpuSerialMagic::WriteGPUConfig as u8, sn))
} else if magic.to_uppercase() == "SSD" {
Some((SetGpuSerialMagic::WriteSSDConfig as u8, sn))
} else {
println!(
"Invalid values for --flash_gpu_descriptor: '{} {}'. Must be u8, 18 character string.",
args[i + 1],
args[i + 2]
);
None
}
} else {
println!("Need to provide a value for --flash_gpu_descriptor. TYPE_MAGIC SERIAL");
None
};
found_an_option = true;
}
}

Expand Down
Loading