Add optional EC security state and documentation
This commit is contained in:
@@ -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 {
|
||||
|
@@ -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;
|
||||
|
@@ -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!()
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user