Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vmsa: import vmsa module from sev library #32

Merged
merged 1 commit into from
Jun 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ sev = { git = "https://github.com/virtee/sev.git", branch = "main", features = [
serde = { version = "1.0", features = ["derive"] }
# serde_json is just for the example, not required in general
serde_json = "1.0"
serde-big-array = "0.4.1"
bincode = "1.3.3"
structopt = "0.3"
codicon = "3.0"
Expand Down
13 changes: 10 additions & 3 deletions src/vmsa/build.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// SPDX-License-Identifier: Apache-2.0

use crate::error::Contextual;
use crate::{BuildUpdateCmdArgs, Ovmf, UserspaceVmm, Vmsa};
use crate::error::{Context, Contextual};
use crate::{BuildUpdateCmdArgs, Ovmf, UserspaceVmm};

use sev::vmsa::*;

pub fn cmd(args: BuildUpdateCmdArgs) -> super::Result<()> {
let mut vmsa = Vmsa::default();
Expand Down Expand Up @@ -34,7 +36,12 @@ pub fn cmd(args: BuildUpdateCmdArgs) -> super::Result<()> {
}
}

vmsa.to_file(&args.filename)?;
if let VmsaRWResult::IoErr(e) = vmsa.to_file(&args.filename) {
return Err(Context::new(
"error writing the VMSA to a file",
Box::new(e),
));
}

Ok(())
}
275 changes: 0 additions & 275 deletions src/vmsa/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@ use std::fs;
use std::str::FromStr;
use std::string::{ParseError, String};

use serde::{Deserialize, Serialize};
use serde_big_array::BigArray;

use uuid::{uuid, Uuid};

#[derive(StructOpt)]
Expand Down Expand Up @@ -106,16 +103,6 @@ impl FromStr for UserspaceVmm {

const OVMF_SEV_INFO_BLOCK_GUID: Uuid = uuid!("00f771de-1a7e-4fcb-890e-68c77e2fb44e");

// Linux struct vmcb_seg (arch/x86/include/asm/svm.h)
#[repr(C, packed)]
#[derive(Default, Serialize, Deserialize, Clone, Copy)]
pub struct VmcbSegment {
selector: u16,
attrib: u16,
limit: u32,
base: u64,
}

#[derive(Default)]
pub struct Ovmf {
entries: HashMap<Uuid, Vec<u8>>,
Expand Down Expand Up @@ -214,265 +201,3 @@ impl Ovmf {
Ok(reset_addr)
}
}

const ATTR_G_SHIFT: usize = 23;
const ATTR_B_SHIFT: usize = 22;
const ATTR_L_SHIFT: usize = 21;
const ATTR_AVL_SHIFT: usize = 20;
const ATTR_P_SHIFT: usize = 15;
const ATTR_DPL_SHIFT: usize = 13;
const ATTR_S_SHIFT: usize = 12;
const ATTR_TYPE_SHIFT: usize = 8;
const ATTR_A_SHIFT: usize = 8;
const ATTR_CS_SHIFT: usize = 11;
const ATTR_C_SHIFT: usize = 10;
const ATTR_R_SHIFT: usize = 9;
const ATTR_E_SHIFT: usize = 10;
const ATTR_W_SHIFT: usize = 9;

const ATTR_G_MASK: usize = 1 << ATTR_G_SHIFT;
const ATTR_B_MASK: usize = 1 << ATTR_B_SHIFT;
const ATTR_L_MASK: usize = 1 << ATTR_L_SHIFT;
const ATTR_AVL_MASK: usize = 1 << ATTR_AVL_SHIFT;
const ATTR_P_MASK: u16 = 1 << ATTR_P_SHIFT;
const ATTR_DPL_MASK: u16 = 1 << ATTR_DPL_SHIFT;
const ATTR_S_MASK: u16 = 1 << ATTR_S_SHIFT;
const ATTR_TYPE_MASK: u16 = 1 << ATTR_TYPE_SHIFT;
const ATTR_A_MASK: u16 = 1 << ATTR_A_SHIFT;
const ATTR_CS_MASK: u16 = 1 << ATTR_CS_SHIFT;
const ATTR_C_MASK: u16 = 1 << ATTR_C_SHIFT;
const ATTR_R_MASK: u16 = 1 << ATTR_R_SHIFT;
const ATTR_E_MASK: u16 = 1 << ATTR_E_SHIFT;
const ATTR_W_MASK: u16 = 1 << ATTR_W_SHIFT;

// Linux struct vmcb_save_area (arch/x86/include/asm/svm.h)
// https://github.com/torvalds/linux/blob/eaea45fc0e7b6ae439526b4a41d91230c8517336/arch/x86/include/asm/svm.h#L274
#[repr(C, packed)]
#[derive(Serialize, Deserialize)]
pub struct Vmsa {
es: VmcbSegment,
cs: VmcbSegment,
ss: VmcbSegment,
ds: VmcbSegment,
fs: VmcbSegment,
gs: VmcbSegment,
gdtr: VmcbSegment,
ldtr: VmcbSegment,
idtr: VmcbSegment,
tr: VmcbSegment,
#[serde(with = "BigArray")]
reserved_1: [u8; 43],
cpl: u8,
reserved_2: [u8; 4],
efer: u64,
#[serde(with = "BigArray")]
reserved_3: [u8; 104],
xss: u64,
cr4: u64,
cr3: u64,
cr0: u64,
dr7: u64,
dr6: u64,
rflags: u64,
rip: u64,
#[serde(with = "BigArray")]
reserved_4: [u8; 88],
rsp: u64,
reserved_5: [u8; 24],
rax: u64,
star: u64,
lstar: u64,
cstar: u64,
sfmask: u64,
kernel_gs_base: u64,
sysenter_cs: u64,
sysenter_esp: u64,
sysenter_eip: u64,
cr2: u64,
reserved_6: [u8; 32],
g_pat: u64,
dbgctl: u64,
br_from: u64,
br_to: u64,
last_excp_from: u64,
last_excp_to: u64,
#[serde(with = "BigArray")]
reserved_7: [u8; 72],
spec_ctrl: u32,
reserved_7b: [u8; 4],
pkru: u32,
reserved_7a: [u8; 20],
reserved_8: u64,
rcx: u64,
rdx: u64,
rbx: u64,
reserved_9: u64,
rbp: u64,
rsi: u64,
rdi: u64,
r8: u64,
r9: u64,
r10: u64,
r11: u64,
r12: u64,
r13: u64,
r14: u64,
r15: u64,
reserved_10: [u8; 16],
sw_exit_code: u64,
sw_exit_info_1: u64,
sw_exit_info_2: u64,
sw_scratch: u64,
#[serde(with = "BigArray")]
reserved_11: [u8; 56],
xcr0: u64,
valid_bitmap: [u8; 16],
x87_state_gpa: u64,
}

impl Vmsa {
fn init_amd64(&mut self) {
self.cr0 = 1 << 4;
self.rip = 0xfff0;

self.cs.selector = 0xf000;
self.cs.base = 0xffff0000;
self.cs.limit = 0xffff;

self.ds.limit = 0xffff;

self.es.limit = 0xffff;
self.fs.limit = 0xffff;
self.gs.limit = 0xffff;
self.ss.limit = 0xffff;

self.gdtr.limit = 0xffff;
self.idtr.limit = 0xffff;

self.ldtr.limit = 0xffff;
self.tr.limit = 0xffff;

self.dr6 = 0xffff0ff0;
self.dr7 = 0x0400;
self.rflags = 0x2;
self.xcr0 = 0x1;
}

fn init_kvm(&mut self) {
// svm_set_cr4() sets guest X86_CR4_MCE bit if host
// has X86_CR4_MCE enabled
self.cr4 = 0x40;

// svm_set_efer sets guest EFER_SVME (Secure Virtual Machine enable)
self.efer = 0x1000;

// init_vmcb + init_sys_seg() sets
// SVM_SELECTOR_P_MASK | SEG_TYPE_LDT
self.ldtr.attrib = 0x0082;

// init_vmcb + init_sys_seg() sets
// SVM_SELECTOR_P_MASK | SEG_TYPE_BUSY_TSS16
self.tr.attrib = 0x0083;

// kvm_arch_vcpu_create() in arch/x86/kvm/x86.c
self.g_pat = 0x0007040600070406;
}

// Based on logic in setup_regs() (src/arch/src/x86_64/regs.rs)
fn init_krun(&mut self, cpu: u64) {
self.rsi = 0x7000;
self.rbp = 0x8ff0;
self.rsp = 0x8ff0;

// Doesn't match with configure_segments_and_sregs
self.cs.attrib =
(ATTR_P_MASK | ATTR_S_MASK | ATTR_CS_MASK | ATTR_R_MASK) >> ATTR_TYPE_SHIFT;
self.ds.attrib = (ATTR_P_MASK | ATTR_S_MASK | ATTR_W_MASK | ATTR_A_MASK) >> ATTR_TYPE_SHIFT;
self.es.attrib = (ATTR_P_MASK | ATTR_S_MASK | ATTR_W_MASK | ATTR_A_MASK) >> ATTR_TYPE_SHIFT;
self.ss.attrib = (ATTR_P_MASK | ATTR_S_MASK | ATTR_W_MASK) >> ATTR_TYPE_SHIFT;
self.fs.attrib = (ATTR_P_MASK | ATTR_S_MASK | ATTR_W_MASK | ATTR_A_MASK) >> ATTR_TYPE_SHIFT;
self.gs.attrib = (ATTR_P_MASK | ATTR_S_MASK | ATTR_W_MASK | ATTR_A_MASK) >> ATTR_TYPE_SHIFT;

if cpu > 0 {
self.rip = 0;
self.rsp = 0;
self.rbp = 0;
self.rsi = 0;

self.cs.selector = 0x9100;
self.cs.base = 0x91000;
}
}

// Based on logic in x86_cpu_reset() (target/i386/cpu.c)
fn init_qemu(&mut self, _cpu: u64) {
self.ldtr.attrib = (ATTR_P_MASK | (2 << ATTR_TYPE_SHIFT)) >> ATTR_TYPE_SHIFT;
self.tr.attrib = (ATTR_P_MASK | (11 << ATTR_TYPE_SHIFT)) >> ATTR_TYPE_SHIFT;
self.cs.attrib = (ATTR_P_MASK | ATTR_S_MASK | ATTR_CS_MASK | ATTR_R_MASK | ATTR_A_MASK)
>> ATTR_TYPE_SHIFT;
self.ds.attrib = (ATTR_P_MASK | ATTR_S_MASK | ATTR_W_MASK | ATTR_A_MASK) >> ATTR_TYPE_SHIFT;
self.es.attrib = (ATTR_P_MASK | ATTR_S_MASK | ATTR_W_MASK | ATTR_A_MASK) >> ATTR_TYPE_SHIFT;
self.ss.attrib = (ATTR_P_MASK | ATTR_S_MASK | ATTR_W_MASK | ATTR_A_MASK) >> ATTR_TYPE_SHIFT;
self.fs.attrib = (ATTR_P_MASK | ATTR_S_MASK | ATTR_W_MASK | ATTR_A_MASK) >> ATTR_TYPE_SHIFT;
self.gs.attrib = (ATTR_P_MASK | ATTR_S_MASK | ATTR_W_MASK | ATTR_A_MASK) >> ATTR_TYPE_SHIFT;

self.g_pat = 0x0007040600070406;
}

fn cpu_sku(&mut self, mut family: u64, mut model: u64, mut stepping: u64) {
stepping &= 0xf;
model &= 0xff;
family &= 0xfff;

self.rdx = stepping;

if family > 0xf {
self.rdx |= 0xf00 | ((family - 0x0f) << 20);
} else {
self.rdx |= family << 8;
}

self.rdx |= ((model & 0xf) << 4) | ((model >> 4) << 16);
}

fn reset_addr(&mut self, ra: u32) {
let reset_cs = ra & 0xffff0000;
let reset_ip = ra & 0x0000ffff;

self.rip = u64::from(reset_ip);
self.cs.base = u64::from(reset_cs);
}

fn from_file(filename: &str) -> Result<Vmsa> {
//! Read binary content from the passed filename and deserialize
//! it into a Vmsa

let data =
std::fs::read(filename).context(format!("Failed to read filename={}", filename))?;
let vmsa = bincode::deserialize(&data[..])
.context(format!("Failed to deserialize filename={}", filename))?;
Ok(vmsa)
}

fn to_file(&self, filename: &str) -> Result<()> {
//! Save binary Vmsa content to the passed filename

let vmsa_buf = bincode::serialize(self).context("Failed to serialize Vmsa")?;

// Pad to 4096 bytes
let buf: &mut [u8] = &mut [0; 4096];
buf[..std::mem::size_of::<Vmsa>()].copy_from_slice(&vmsa_buf[..]);

fs::write(filename, buf).context(format!(
"could not write VMSA buffer to filename={}",
filename
))?;
Ok(())
}
}

impl Default for Vmsa {
fn default() -> Self {
unsafe { std::mem::zeroed() }
}
}
13 changes: 11 additions & 2 deletions src/vmsa/show.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
// SPDX-License-Identifier: Apache-2.0

use crate::{Vmsa, VmsaShowCmdArgs};
use crate::error::Context;
use crate::VmsaShowCmdArgs;

use sev::vmsa::*;

pub fn cmd(args: VmsaShowCmdArgs) -> super::Result<()> {
let vmsa = Vmsa::from_file(&args.filename)?;
let vmsa = match Vmsa::from_file(&args.filename) {
VmsaRWResult::ReadSuccess(v) => v,
VmsaRWResult::IoErr(e) => {
return Err(Context::new("error reading VMSA from file", Box::new(e)))
}
_ => unreachable!(),
};

println!("{}", serde_json::to_string_pretty(&vmsa).unwrap());

Expand Down
Loading