use super::super::{Error, Indeterminate, Version};
use super::{Build, Identifier, State, Status, TcbStatus, TcbVersion};
use iocuddle::{Group, Ioctl, WriteRead};
use std::fs::{File, OpenOptions};
use std::marker::PhantomData;
use std::os::unix::io::{AsRawFd, RawFd};
impl_const_id! {
pub Id => u32;
GetId<'_> = 8,
SnpPlatformStatus = 9,
}
const SEV: Group = Group::new(b'S');
const GET_ID: Ioctl<WriteRead, &Command<'_, GetId<'_>>> = unsafe { SEV.write_read(0) };
const SNP_PLATFORM_STATUS: Ioctl<WriteRead, &Command<'_, SnpPlatformStatus>> =
unsafe { SEV.write_read(0) };
#[repr(C, packed)]
struct GetId<'a> {
id_addr: u64,
id_len: u32,
_phantom: PhantomData<&'a ()>,
}
impl<'a> GetId<'a> {
pub fn new(id: &'a mut [u8; 64]) -> Self {
Self {
id_addr: id.as_mut_ptr() as _,
id_len: id.len() as _,
_phantom: PhantomData,
}
}
pub fn as_slice(&self) -> &[u8] {
unsafe { std::slice::from_raw_parts(self.id_addr as *const u8, self.id_len as _) }
}
}
#[derive(Default)]
#[repr(C)]
struct SnpPlatformStatus {
pub version: Version,
pub state: u8,
pub is_rmp_init: u8,
pub build_id: u32,
pub mask_chip_id: u32,
pub guest_count: u32,
pub platform_tcb_version: TcbVersion,
pub reported_tcb_version: TcbVersion,
}
#[repr(C, packed)]
pub struct Command<'a, T: Id> {
code: u32,
data: u64,
error: u32,
_phantom: PhantomData<&'a T>,
}
impl<'a, T: Id> Command<'a, T> {
pub fn from_mut(subcmd: &'a mut T) -> Self {
Command {
code: T::ID,
data: subcmd as *mut T as u64,
error: 0,
_phantom: PhantomData,
}
}
}
pub struct Firmware(File);
impl Firmware {
pub fn open() -> std::io::Result<Firmware> {
Ok(Firmware(
OpenOptions::new().read(true).write(true).open("/dev/sev")?,
))
}
pub fn platform_status(&mut self) -> Result<Status, Indeterminate<Error>> {
let mut info: SnpPlatformStatus = Default::default();
SNP_PLATFORM_STATUS.ioctl(&mut self.0, &mut Command::from_mut(&mut info))?;
Ok(Status {
build: Build {
version: Version {
major: info.version.major,
minor: info.version.minor,
},
build: info.build_id,
},
guests: info.guest_count,
tcb: TcbStatus {
platform_version: info.platform_tcb_version,
reported_version: info.reported_tcb_version,
},
is_rmp_init: info.is_rmp_init == 1,
mask_chip_id: info.mask_chip_id == 1,
state: match info.state {
0 => State::Uninitialized,
1 => State::Initialized,
_ => return Err(Indeterminate::Unknown),
},
})
}
pub fn identifier(&mut self) -> Result<Identifier, Indeterminate<Error>> {
let mut bytes = [0u8; 64];
let mut id = GetId::new(&mut bytes);
GET_ID.ioctl(&mut self.0, &mut Command::from_mut(&mut id))?;
Ok(Identifier(id.as_slice().to_vec()))
}
}
impl AsRawFd for Firmware {
fn as_raw_fd(&self) -> RawFd {
self.0.as_raw_fd()
}
}