Skip to content

Commit 9ad012f

Browse files
Merge pull request #98 from FrameworkComputer/fw16.dgpu_config
add commands to read/write gpu serial Examples ``` framework_tool.efi --flash_gpu_descriptor GPU FRAKMQCP41500ASSY1 framework_tool.efi --flash_gpu_descriptor 13 FRAKMQCP41500ASSY1 framework_tool.efi --flash_gpu_descriptor 0x0D FRAKMQCP41500ASSY1 ```
2 parents 6f8da8f + 87f2132 commit 9ad012f

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,
@@ -208,31 +211,71 @@ struct ClapCli {
208211

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

213268
let pd_addrs = match args.pd_addrs.len() {
214269
2 => Some((args.pd_addrs[0], args.pd_addrs[1])),
215270
0 => None,
216-
_ => {
217-
// Actually unreachable, checked by clap
218-
println!(
219-
"Must provide exactly to PD Addresses. Provided: {:?}",
220-
args.pd_addrs
221-
);
222-
std::process::exit(1);
223-
}
271+
// Checked by clap
272+
_ => unreachable!(),
224273
};
225274
let pd_ports = match args.pd_ports.len() {
226275
2 => Some((args.pd_ports[0], args.pd_ports[1])),
227276
0 => None,
228-
_ => {
229-
// Actually unreachable, checked by clap
230-
println!(
231-
"Must provide exactly to PD Ports. Provided: {:?}",
232-
args.pd_ports
233-
);
234-
std::process::exit(1);
235-
}
277+
// Checked by clap
278+
_ => unreachable!(),
236279
};
237280

238281
Cli {
@@ -305,6 +348,7 @@ pub fn parse(args: &[String]) -> Cli {
305348
// UEFI only - every command needs to implement a parameter to enable the pager
306349
paginate: false,
307350
info: args.info,
351+
flash_gpu_descriptor,
308352
raw_command: vec![],
309353
}
310354
}

framework_lib/src/commandline/mod.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ pub struct Cli {
184184
pub has_mec: Option<bool>,
185185
pub help: bool,
186186
pub info: bool,
187+
pub flash_gpu_descriptor: Option<(u8, String)>,
187188
// UEFI only
188189
pub allupdate: bool,
189190
pub paginate: bool,
@@ -1015,6 +1016,13 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 {
10151016
println!(" Size: {:>20} KB", data.len() / 1024);
10161017
hash(&data);
10171018
}
1019+
} else if let Some(gpu_descriptor) = &args.flash_gpu_descriptor {
1020+
let res = ec.set_gpu_serial(gpu_descriptor.0, gpu_descriptor.1.to_ascii_uppercase());
1021+
match res {
1022+
Ok(1) => println!("GPU Descriptor successfully written"),
1023+
Ok(x) => println!("GPU Descriptor write failed with status code: {}", x),
1024+
Err(err) => println!("GPU Descriptor write failed with error: {:?}", err),
1025+
}
10181026
}
10191027

10201028
0
@@ -1064,6 +1072,7 @@ Options:
10641072
--kblight [<KBLIGHT>] Set keyboard backlight percentage or get, if no value provided
10651073
--console <CONSOLE> Get EC console, choose whether recent or to follow the output [possible values: recent, follow]
10661074
--hash <HASH> Hash a file of arbitrary data
1075+
--flash-gpu-descriptor <MAGIC> <18 DIGIT SN> Overwrite the GPU bay descriptor SN and type.
10671076
-t, --test Run self-test to check if interaction with EC is possible
10681077
-h, --help Print help information
10691078
-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

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

0 commit comments

Comments
 (0)