Skip to content

Commit 87f2132

Browse files
kiram9JohnAZoidberg
andcommitted
Add commands to read/write GPU serial
TEST=Tested on platform to overwrite the serial And I can see the serial updates to the new value after rebooting the EC. Signed-off-by: Kieran Levin <[email protected]> Co-Authored-By: Daniel Schaefer <[email protected]>
1 parent 84a79f9 commit 87f2132

File tree

7 files changed

+188
-19
lines changed

7 files changed

+188
-19
lines changed

framework_lib/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ sha2 = { version = "0.10.8", default-features = false, features = [ "force-soft"
5050
regex = { version = "1.11.1", default-features = false }
5151
redox_hwio = { git = "https://github.com/FrameworkComputer/rust-hwio", branch = "freebsd", default-features = false }
5252
libc = { version = "0.2.155", optional = true }
53-
clap = { version = "4.5", features = ["derive"], optional = true }
53+
clap = { version = "4.5", features = ["derive", "cargo"], optional = true }
5454
clap-num = { version = "1.2.0", optional = true }
5555
clap-verbosity-flag = { version = "2.2.1", optional = true }
5656
nix = { version = "0.29.0", features = ["ioctl", "user"], optional = true }

framework_lib/src/chromium_ec/command.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ pub enum EcCommands {
8888
ExpansionBayStatus = 0x3E1B,
8989
/// Get hardware diagnostics
9090
GetHwDiag = 0x3E1C,
91+
/// Get gpu bay serial
92+
GetGpuSerial = 0x3E1D,
93+
/// Set gpu bay serial and program structure
94+
ProgramGpuEeprom = 0x3E1F,
9195
}
9296

9397
pub trait EcRequest<R> {

framework_lib/src/chromium_ec/commands.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -931,3 +931,49 @@ impl EcRequest<EcResponseFpLedLevelControlV1> for EcRequestFpLedLevelControlV1 {
931931
1
932932
}
933933
}
934+
935+
#[repr(C, packed)]
936+
pub struct EcRequestGetGpuSerial {
937+
pub idx: u8,
938+
}
939+
940+
#[repr(C, packed)]
941+
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
942+
pub struct EcResponseGetGpuSerial {
943+
pub idx: u8,
944+
pub valid: u8,
945+
pub serial: [u8; 20],
946+
}
947+
948+
impl EcRequest<EcResponseGetGpuSerial> for EcRequestGetGpuSerial {
949+
fn command_id() -> EcCommands {
950+
EcCommands::GetGpuSerial
951+
}
952+
}
953+
954+
#[repr(u8)]
955+
pub enum SetGpuSerialMagic {
956+
/// 7700S config magic value
957+
WriteGPUConfig = 0x0D,
958+
/// SSD config magic value
959+
WriteSSDConfig = 0x55,
960+
}
961+
962+
#[repr(C, packed)]
963+
pub struct EcRequestSetGpuSerial {
964+
pub magic: u8,
965+
pub idx: u8,
966+
pub serial: [u8; 20],
967+
}
968+
969+
#[repr(C, packed)]
970+
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
971+
pub struct EcResponseSetGpuSerial {
972+
pub valid: u8,
973+
}
974+
975+
impl EcRequest<EcResponseSetGpuSerial> for EcRequestSetGpuSerial {
976+
fn command_id() -> EcCommands {
977+
EcCommands::ProgramGpuEeprom
978+
}
979+
}

framework_lib/src/chromium_ec/mod.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ use alloc::string::String;
3333
use alloc::string::ToString;
3434
use alloc::vec;
3535
use alloc::vec::Vec;
36+
3637
#[cfg(feature = "uefi")]
3738
use core::prelude::rust_2021::derive;
3839
use num_traits::FromPrimitive;
@@ -789,6 +790,36 @@ impl CrosEc {
789790
res
790791
}
791792

793+
/// Get the GPU Serial
794+
///
795+
pub fn get_gpu_serial(&self) -> EcResult<String> {
796+
let gpuserial: EcResponseGetGpuSerial =
797+
EcRequestGetGpuSerial { idx: 0 }.send_command(self)?;
798+
let serial: String = String::from_utf8(gpuserial.serial.to_vec()).unwrap();
799+
800+
if gpuserial.valid == 0 {
801+
return Err(EcError::DeviceError("No valid GPU serial".to_string()));
802+
}
803+
804+
Ok(serial)
805+
}
806+
807+
/// Set the GPU Serial
808+
///
809+
/// # Arguments
810+
/// `newserial` - a string that is 18 characters long
811+
pub fn set_gpu_serial(&self, magic: u8, newserial: String) -> EcResult<u8> {
812+
let mut array_tmp: [u8; 20] = [0; 20];
813+
array_tmp[..18].copy_from_slice(newserial.as_bytes());
814+
let result = EcRequestSetGpuSerial {
815+
magic,
816+
idx: 0,
817+
serial: array_tmp,
818+
}
819+
.send_command(self)?;
820+
Ok(result.valid)
821+
}
822+
792823
/// Requests recent console output from EC and constantly asks for more
793824
/// Prints the output and returns it when an error is encountered
794825
pub fn console_read(&self) -> EcResult<String> {

framework_lib/src/commandline/clap_std.rs

Lines changed: 61 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
//! Module to factor out commandline interaction
22
//! This way we can use it in the regular OS commandline tool on Linux and Windows,
33
//! as well as on the UEFI shell tool.
4+
use clap::error::ErrorKind;
45
use clap::Parser;
6+
use clap::{arg, command, Arg, Args, FromArgMatches};
57
use clap_num::maybe_hex;
68

9+
use crate::chromium_ec::commands::SetGpuSerialMagic;
710
use crate::chromium_ec::CrosEcDriverType;
811
use crate::commandline::{
912
Cli, ConsoleArg, FpBrightnessArg, HardwareDeviceType, InputDeckModeArg, RebootEcArg,
@@ -203,31 +206,71 @@ struct ClapCli {
203206

204207
/// Parse a list of commandline arguments and return the struct
205208
pub fn parse(args: &[String]) -> Cli {
206-
let args = ClapCli::parse_from(args);
209+
// Step 1 - Define args that can't be derived
210+
let cli = command!()
211+
.arg(Arg::new("fgd").long("flash-gpu-descriptor").num_args(2))
212+
.disable_version_flag(true);
213+
// Step 2 - Define args from derived struct
214+
let mut cli = ClapCli::augment_args(cli);
215+
216+
// Step 3 - Parse args that can't be derived
217+
let matches = cli.clone().get_matches_from(args);
218+
let fgd = matches
219+
.get_many::<String>("fgd")
220+
.unwrap_or_default()
221+
.map(|v| v.as_str())
222+
.collect::<Vec<_>>();
223+
let flash_gpu_descriptor = if !fgd.is_empty() {
224+
let hex_magic = if let Some(hex_magic) = fgd[0].strip_prefix("0x") {
225+
u8::from_str_radix(hex_magic, 16)
226+
} else {
227+
// Force parse error
228+
u8::from_str_radix("", 16)
229+
};
230+
231+
let magic = if let Ok(magic) = fgd[0].parse::<u8>() {
232+
magic
233+
} else if let Ok(hex_magic) = hex_magic {
234+
hex_magic
235+
} else if fgd[0].to_uppercase() == "GPU" {
236+
SetGpuSerialMagic::WriteGPUConfig as u8
237+
} else if fgd[0].to_uppercase() == "SSD" {
238+
SetGpuSerialMagic::WriteSSDConfig as u8
239+
} else {
240+
cli.error(
241+
ErrorKind::InvalidValue,
242+
"First argument of --flash-gpu-descriptor must be an integer or one of: 'GPU', 'SSD'",
243+
)
244+
.exit();
245+
};
246+
if fgd[1].len() != 18 {
247+
cli.error(
248+
ErrorKind::InvalidValue,
249+
"Second argument of --flash-gpu-descriptor must be an 18 digit serial number",
250+
)
251+
.exit();
252+
}
253+
Some((magic, fgd[1].to_string()))
254+
} else {
255+
None
256+
};
257+
258+
// Step 4 - Parse from derived struct
259+
let args = ClapCli::from_arg_matches(&matches)
260+
.map_err(|err| err.exit())
261+
.unwrap();
207262

208263
let pd_addrs = match args.pd_addrs.len() {
209264
2 => Some((args.pd_addrs[0], args.pd_addrs[1])),
210265
0 => None,
211-
_ => {
212-
// Actually unreachable, checked by clap
213-
println!(
214-
"Must provide exactly to PD Addresses. Provided: {:?}",
215-
args.pd_addrs
216-
);
217-
std::process::exit(1);
218-
}
266+
// Checked by clap
267+
_ => unreachable!(),
219268
};
220269
let pd_ports = match args.pd_ports.len() {
221270
2 => Some((args.pd_ports[0], args.pd_ports[1])),
222271
0 => None,
223-
_ => {
224-
// Actually unreachable, checked by clap
225-
println!(
226-
"Must provide exactly to PD Ports. Provided: {:?}",
227-
args.pd_ports
228-
);
229-
std::process::exit(1);
230-
}
272+
// Checked by clap
273+
_ => unreachable!(),
231274
};
232275

233276
Cli {
@@ -299,6 +342,7 @@ pub fn parse(args: &[String]) -> Cli {
299342
// UEFI only - every command needs to implement a parameter to enable the pager
300343
paginate: false,
301344
info: args.info,
345+
flash_gpu_descriptor,
302346
raw_command: vec![],
303347
}
304348
}

framework_lib/src/commandline/mod.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ pub struct Cli {
181181
pub has_mec: Option<bool>,
182182
pub help: bool,
183183
pub info: bool,
184+
pub flash_gpu_descriptor: Option<(u8, String)>,
184185
// UEFI only
185186
pub allupdate: bool,
186187
pub paginate: bool,
@@ -1004,6 +1005,13 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 {
10041005
println!(" Size: {:>20} KB", data.len() / 1024);
10051006
hash(&data);
10061007
}
1008+
} else if let Some(gpu_descriptor) = &args.flash_gpu_descriptor {
1009+
let res = ec.set_gpu_serial(gpu_descriptor.0, gpu_descriptor.1.to_ascii_uppercase());
1010+
match res {
1011+
Ok(1) => println!("GPU Descriptor successfully written"),
1012+
Ok(x) => println!("GPU Descriptor write failed with status code: {}", x),
1013+
Err(err) => println!("GPU Descriptor write failed with error: {:?}", err),
1014+
}
10071015
}
10081016

10091017
0
@@ -1053,6 +1061,7 @@ Options:
10531061
--kblight [<KBLIGHT>] Set keyboard backlight percentage or get, if no value provided
10541062
--console <CONSOLE> Get EC console, choose whether recent or to follow the output [possible values: recent, follow]
10551063
--hash <HASH> Hash a file of arbitrary data
1064+
--flash-gpu-descriptor <MAGIC> <18 DIGIT SN> Overwrite the GPU bay descriptor SN and type.
10561065
-t, --test Run self-test to check if interaction with EC is possible
10571066
-h, --help Print help information
10581067
-b Print output one screen at a time

framework_lib/src/commandline/uefi.rs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use alloc::string::String;
1+
use alloc::string::{String, ToString};
22
use alloc::vec;
33
use alloc::vec::Vec;
44

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

12+
use crate::chromium_ec::commands::SetGpuSerialMagic;
1213
use crate::chromium_ec::{CrosEcDriverType, HardwareDeviceType};
1314
use crate::commandline::Cli;
1415

@@ -99,6 +100,7 @@ pub fn parse(args: &[String]) -> Cli {
99100
has_mec: None,
100101
test: false,
101102
help: false,
103+
flash_gpu_descriptor: None,
102104
allupdate: false,
103105
info: false,
104106
raw_command: vec![],
@@ -513,6 +515,39 @@ pub fn parse(args: &[String]) -> Cli {
513515
println!("Need to provide a value for --console. Possible values: bios, ec, pd0, pd1, rtm01, rtm23, ac-left, ac-right");
514516
None
515517
};
518+
} else if arg == "--flash-gpu-descriptor" {
519+
cli.flash_gpu_descriptor = if args.len() > i + 2 {
520+
let sn = args[i + 2].to_string();
521+
let magic = &args[i + 1];
522+
523+
let hex_magic = if let Some(hex_magic) = magic.strip_prefix("0x") {
524+
u8::from_str_radix(hex_magic, 16)
525+
} else {
526+
// Force parse error
527+
u8::from_str_radix("", 16)
528+
};
529+
530+
if let Ok(magic) = magic.parse::<u8>() {
531+
Some((magic, sn))
532+
} else if let Ok(hex_magic) = hex_magic {
533+
Some((hex_magic, sn))
534+
} else if magic.to_uppercase() == "GPU" {
535+
Some((SetGpuSerialMagic::WriteGPUConfig as u8, sn))
536+
} else if magic.to_uppercase() == "SSD" {
537+
Some((SetGpuSerialMagic::WriteSSDConfig as u8, sn))
538+
} else {
539+
println!(
540+
"Invalid values for --flash_gpu_descriptor: '{} {}'. Must be u8, 18 character string.",
541+
args[i + 1],
542+
args[i + 2]
543+
);
544+
None
545+
}
546+
} else {
547+
println!("Need to provide a value for --flash_gpu_descriptor. TYPE_MAGIC SERIAL");
548+
None
549+
};
550+
found_an_option = true;
516551
}
517552
}
518553

0 commit comments

Comments
 (0)