#![allow(dead_code)]
use crate::parser::{Decoder, Encoder};
use super::{
util::{TypeLoad, TypeSave},
*,
};
use std::{fs, io, mem::size_of};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "serde")]
use serde_big_array::BigArray;
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;
#[repr(C, packed)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Default, Clone, Copy)]
pub struct VmcbSegment {
selector: u16,
attrib: u16,
limit: u32,
base: u64,
}
#[repr(C, packed)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Copy, Clone)]
pub struct Vmsa {
es: VmcbSegment,
cs: VmcbSegment,
ss: VmcbSegment,
ds: VmcbSegment,
fs: VmcbSegment,
gs: VmcbSegment,
gdtr: VmcbSegment,
ldtr: VmcbSegment,
idtr: VmcbSegment,
tr: VmcbSegment,
#[cfg_attr(feature = "serde", serde(with = "BigArray"))]
reserved_1: [u8; 43],
cpl: u8,
reserved_2: [u8; 4],
efer: u64,
#[cfg_attr(feature = "serde", serde(with = "BigArray"))]
reserved_3: [u8; 104],
xss: u64,
cr4: u64,
cr3: u64,
cr0: u64,
dr7: u64,
dr6: u64,
rflags: u64,
rip: u64,
#[cfg_attr(feature = "serde", 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,
#[cfg_attr(feature = "serde", 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,
#[cfg_attr(feature = "serde", serde(with = "BigArray"))]
reserved_11: [u8; 56],
xcr0: u64,
valid_bitmap: [u8; 16],
x87_state_gpa: u64,
}
impl Default for Vmsa {
fn default() -> Self {
Self {
es: Default::default(),
cs: Default::default(),
ss: Default::default(),
ds: Default::default(),
fs: Default::default(),
gs: Default::default(),
gdtr: Default::default(),
ldtr: Default::default(),
idtr: Default::default(),
tr: Default::default(),
reserved_1: [0u8; 43],
cpl: Default::default(),
reserved_2: Default::default(),
efer: Default::default(),
reserved_3: [0u8; 104],
xss: Default::default(),
cr4: Default::default(),
cr3: Default::default(),
cr0: Default::default(),
dr7: Default::default(),
dr6: Default::default(),
rflags: Default::default(),
rip: Default::default(),
reserved_4: [0u8; 88],
rsp: Default::default(),
reserved_5: Default::default(),
rax: Default::default(),
star: Default::default(),
lstar: Default::default(),
cstar: Default::default(),
sfmask: Default::default(),
kernel_gs_base: Default::default(),
sysenter_cs: Default::default(),
sysenter_esp: Default::default(),
sysenter_eip: Default::default(),
cr2: Default::default(),
reserved_6: Default::default(),
g_pat: Default::default(),
dbgctl: Default::default(),
br_from: Default::default(),
br_to: Default::default(),
last_excp_from: Default::default(),
last_excp_to: Default::default(),
reserved_7: [0u8; 72],
spec_ctrl: Default::default(),
reserved_7b: Default::default(),
pkru: Default::default(),
reserved_7a: Default::default(),
reserved_8: Default::default(),
rcx: Default::default(),
rdx: Default::default(),
rbx: Default::default(),
reserved_9: Default::default(),
rbp: Default::default(),
rsi: Default::default(),
rdi: Default::default(),
r8: Default::default(),
r9: Default::default(),
r10: Default::default(),
r11: Default::default(),
r12: Default::default(),
r13: Default::default(),
r14: Default::default(),
r15: Default::default(),
reserved_10: Default::default(),
sw_exit_code: Default::default(),
sw_exit_info_1: Default::default(),
sw_exit_info_2: Default::default(),
sw_scratch: Default::default(),
reserved_11: [0u8; 56],
xcr0: Default::default(),
valid_bitmap: Default::default(),
x87_state_gpa: Default::default(),
}
}
}
impl Decoder<()> for Vmsa {
fn decode(reader: &mut impl Read, _: ()) -> Result<Self, std::io::Error> {
reader.load()
}
}
impl Encoder<()> for Vmsa {
fn encode(&self, writer: &mut impl Write, _: ()) -> Result<(), std::io::Error> {
writer.save(self)
}
}
impl Vmsa {
pub 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;
}
pub fn init_kvm(&mut self) {
self.cr4 = 0x40;
self.efer = 0x1000;
self.ldtr.attrib = 0x0082;
self.tr.attrib = 0x0083;
self.g_pat = 0x0007040600070406;
}
pub fn init_krun(&mut self, cpu: u64) {
self.rsi = 0x7000;
self.rbp = 0x8ff0;
self.rsp = 0x8ff0;
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;
}
}
pub 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;
}
pub 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);
}
pub 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);
}
pub fn from_file(filename: &str) -> Result<Self, io::Error> {
let data = std::fs::read(filename)?;
if data.len() != 4096 {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("Expected VMSA length 4096, was {}", data.len()),
));
}
let vmsa = Vmsa::decode(&mut &data[..], ())?;
Ok(vmsa)
}
pub fn to_file(&self, filename: &str) -> Result<(), io::Error> {
let mut vmsa_buf = Vec::new();
self.encode(&mut vmsa_buf, ())?;
const SIZE: usize = size_of::<Vmsa>();
let buf: &mut [u8] = &mut [0; 4096];
buf[..SIZE].copy_from_slice(&vmsa_buf[..]);
fs::write(filename, buf)?;
Ok(())
}
}