#[cfg(target_os = "linux")]
pub mod linux;
#[cfg(target_os = "linux")]
use linux::*;
use super::Version;
use std::io::Result;
use std::marker::PhantomData;
use std::os::unix::io::AsRawFd;
use bitflags::bitflags;
pub struct New;
pub struct Started;
pub struct Launcher<T, U: AsRawFd, V: AsRawFd> {
vm_fd: U,
sev: V,
state: PhantomData<T>,
}
impl<T, U: AsRawFd, V: AsRawFd> AsRef<U> for Launcher<T, U, V> {
fn as_ref(&self) -> &U {
&self.vm_fd
}
}
impl<T, U: AsRawFd, V: AsRawFd> AsMut<U> for Launcher<T, U, V> {
fn as_mut(&mut self) -> &mut U {
&mut self.vm_fd
}
}
impl<U: AsRawFd, V: AsRawFd> Launcher<New, U, V> {
pub fn new(vm_fd: U, sev: V) -> Result<Self> {
let mut launcher = Launcher {
vm_fd,
sev,
state: PhantomData::default(),
};
let init = Init::default();
let mut cmd = Command::from(&mut launcher.sev, &init);
SNP_INIT
.ioctl(&mut launcher.vm_fd, &mut cmd)
.map_err(|e| cmd.encapsulate(e))?;
Ok(launcher)
}
pub fn start(mut self, start: Start) -> Result<Launcher<Started, U, V>> {
let mut launch_start = LaunchStart::from(start);
let mut cmd = Command::from_mut(&mut self.sev, &mut launch_start);
SNP_LAUNCH_START
.ioctl(&mut self.vm_fd, &mut cmd)
.map_err(|e| cmd.encapsulate(e))?;
let launcher = Launcher {
vm_fd: self.vm_fd,
sev: self.sev,
state: PhantomData::default(),
};
Ok(launcher)
}
}
impl<U: AsRawFd, V: AsRawFd> Launcher<Started, U, V> {
pub fn update_data(&mut self, update: Update) -> Result<()> {
let launch_update_data = LaunchUpdate::from(update);
let mut cmd = Command::from(&mut self.sev, &launch_update_data);
KvmEncRegion::new(update.uaddr).register(&mut self.vm_fd)?;
SNP_LAUNCH_UPDATE
.ioctl(&mut self.vm_fd, &mut cmd)
.map_err(|e| cmd.encapsulate(e))?;
Ok(())
}
pub fn finish(mut self, finish: Finish) -> Result<(U, V)> {
let launch_finish = LaunchFinish::from(finish);
let mut cmd = Command::from(&mut self.sev, &launch_finish);
SNP_LAUNCH_FINISH
.ioctl(&mut self.vm_fd, &mut cmd)
.map_err(|e| cmd.encapsulate(e))?;
Ok((self.vm_fd, self.sev))
}
}
bitflags! {
#[derive(Default)]
pub struct PolicyFlags: u16 {
const SMT = 1;
const MIGRATE_MA = 1 << 2;
const DEBUG = 1 << 3;
}
}
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub struct Policy {
pub flags: PolicyFlags,
pub minfw: Version,
}
impl From<Policy> for u64 {
fn from(policy: Policy) -> u64 {
let mut val: u64 = 0;
let minor_version = u64::from(policy.minfw.minor);
let mut major_version = u64::from(policy.minfw.major);
let flags = policy.flags.bits | 0b10;
let mut flags_64 = u64::from(flags);
major_version <<= 8;
flags_64 <<= 16;
val |= minor_version;
val |= major_version;
val |= flags_64;
val &= 0x00FFFFFF;
val
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct Start<'a> {
pub(crate) ma_uaddr: Option<&'a [u8]>,
pub(crate) policy: Policy,
pub(crate) imi_en: bool,
pub(crate) gosvw: [u8; 16],
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Update<'a> {
pub(crate) start_gfn: u64,
pub(crate) uaddr: &'a [u8],
pub(crate) imi_page: bool,
pub(crate) page_type: PageType,
pub(crate) vmpl3_perms: VmplPerms,
pub(crate) vmpl2_perms: VmplPerms,
pub(crate) vmpl1_perms: VmplPerms,
}
impl<'a> Update<'a> {
pub fn new(
start_gfn: u64,
uaddr: &'a [u8],
imi_page: bool,
page_type: PageType,
perms: (VmplPerms, VmplPerms, VmplPerms),
) -> Self {
Self {
start_gfn,
uaddr,
imi_page,
page_type,
vmpl3_perms: perms.2,
vmpl2_perms: perms.1,
vmpl1_perms: perms.0,
}
}
}
bitflags! {
#[derive(Default)]
pub struct VmplPerms: u8 {
const READ = 1;
const WRITE = 1 << 1;
const EXECUTE_USER = 1 << 2;
const EXECUTE_SUPERVISOR = 1 << 3;
}
}
#[allow(dead_code)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(C)]
#[non_exhaustive]
pub enum PageType {
Normal = 0x1,
Vmsa = 0x2,
Zero = 0x3,
Unmeasured = 0x4,
Secrets = 0x5,
Cpuid = 0x6,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Finish<'a, 'b> {
pub(crate) id_block: Option<&'a [u8]>,
pub(crate) id_auth: Option<&'b [u8]>,
pub(crate) host_data: [u8; KVM_SEV_SNP_FINISH_DATA_SIZE],
}
impl<'a, 'b> Finish<'a, 'b> {
pub fn new(
id_block: Option<&'a [u8]>,
id_auth: Option<&'b [u8]>,
host_data: [u8; KVM_SEV_SNP_FINISH_DATA_SIZE],
) -> Self {
Self {
id_block,
id_auth,
host_data,
}
}
}