Add optional EC security state and documentation

This commit is contained in:
Jeremy Soller
2023-03-06 13:14:38 -07:00
parent 4567f99015
commit 4a1e0a5aa8
10 changed files with 243 additions and 4 deletions

View File

@@ -5,6 +5,7 @@ use alloc::{
boxed::Box,
vec,
};
use core::convert::TryFrom;
use crate::{
Access,
@@ -36,6 +37,8 @@ enum Cmd {
MatrixGet = 17,
LedSave = 18,
SetNoInput = 19,
SecurityGet = 20,
SecuritySet = 21,
}
const CMD_SPI_FLAG_READ: u8 = 1 << 0;
@@ -43,6 +46,33 @@ const CMD_SPI_FLAG_DISABLE: u8 = 1 << 1;
const CMD_SPI_FLAG_SCRATCH: u8 = 1 << 2;
const CMD_SPI_FLAG_BACKUP: u8 = 1 << 3;
#[derive(Clone, Copy, Debug)]
#[repr(u8)]
pub enum SecurityState {
// Default value, flashing is prevented, cannot be set with security_set
Lock = 0,
// Flashing is allowed, cannot be set with security_set
Unlock = 1,
// Flashing will be prevented on the next reboot
PrepareLock = 2,
// Flashing will be allowed on the next reboot
PrepareUnlock = 3,
}
impl TryFrom<u8> for SecurityState {
type Error = Error;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0 => Ok(Self::Lock),
1 => Ok(Self::Unlock),
2 => Ok(Self::PrepareLock),
3 => Ok(Self::PrepareUnlock),
_ => Err(Error::Verify),
}
}
}
/// Run EC commands using a provided access method
pub struct Ec<A: Access> {
access: A,
@@ -284,6 +314,19 @@ impl<A: Access> Ec<A> {
self.command(Cmd::SetNoInput, &mut [no_input as u8])
}
/// Get security state
pub unsafe fn security_get(&mut self) -> Result<SecurityState, Error> {
let mut data = [0];
self.command(Cmd::SecurityGet, &mut data)?;
SecurityState::try_from(data[0])
}
/// Set security state
pub unsafe fn security_set(&mut self, state: SecurityState) -> Result<(), Error> {
let mut data = [state as u8];
self.command(Cmd::SecuritySet, &mut data)
}
pub fn into_dyn(self) -> Ec<Box<dyn Access>>
where A: 'static {
Ec {

View File

@@ -25,7 +25,7 @@ extern crate alloc;
pub use self::access::*;
mod access;
pub use self::ec::Ec;
pub use self::ec::{Ec, SecurityState};
mod ec;
pub use self::error::Error;

View File

@@ -9,6 +9,7 @@ use ectool::{
Ec,
Error,
Firmware,
SecurityState,
StdTimeout,
Spi,
SpiRom,
@@ -276,6 +277,19 @@ unsafe fn keymap_set(ec: &mut Ec<Box<dyn Access>>, layer: u8, output: u8, input:
ec.keymap_set(layer, output, input, value)
}
unsafe fn security_get(ec: &mut Ec<Box<dyn Access>>) -> Result<(), Error> {
println!("{:?}", ec.security_get()?);
Ok(())
}
unsafe fn security_set(ec: &mut Ec<Box<dyn Access>>, state: SecurityState) -> Result<(), Error> {
ec.security_set(state)?;
println!("Shut down the system for the security state to take effect");
Ok(())
}
fn parse_color(s: &str) -> Result<(u8, u8, u8), String> {
let r = u8::from_str_radix(&s[0..2], 16);
let g = u8::from_str_radix(&s[2..4], 16);
@@ -375,6 +389,11 @@ fn main() {
.required(true)
)
)
.subcommand(SubCommand::with_name("security")
.arg(Arg::with_name("state")
.possible_values(&["lock", "unlock"])
)
)
.get_matches();
let get_ec = || -> Result<_, Error> {
@@ -609,7 +628,35 @@ fn main() {
process::exit(1);
}
}
}
},
Some(("security", sub_m)) => {
match sub_m.value_of("state") {
Some(value) => {
let state = match value {
"lock" => SecurityState::PrepareLock,
"unlock" => SecurityState::PrepareUnlock,
_ => {
eprintln!("invalid security state '{}': must be 'lock' or 'unlock'", value);
process::exit(1);
}
};
match unsafe { security_set(&mut ec, state) } {
Ok(()) => (),
Err(err) => {
eprintln!("failed to set security state to '{}': {:X?}", value, err);
process::exit(1);
},
}
},
None => match unsafe { security_get(&mut ec) } {
Ok(()) => (),
Err(err) => {
eprintln!("failed to get security state: {:X?}", err);
process::exit(1);
},
},
}
},
_ => unreachable!()
}
}