igvmfilegen/vp_context_builder/
vbs.rs1use crate::file_loader::DEFAULT_COMPATIBILITY_MASK;
7use crate::vp_context_builder::VpContextBuilder;
8use crate::vp_context_builder::VpContextState;
9use hvdef::Vtl;
10use igvm::FileDataSerializer;
11use igvm::IgvmDirectiveHeader;
12use igvm_defs::PAGE_SIZE_4K;
13use loader::importer::Aarch64Register;
14use loader::importer::X86Register;
15use std::fmt::Debug;
16use std::mem::discriminant;
17
18pub trait VbsRegister: Sized {
22    fn into_igvm_header(vtl: Vtl, list: &[Self]) -> IgvmDirectiveHeader;
25}
26
27impl VbsRegister for X86Register {
28    fn into_igvm_header(vtl: Vtl, list: &[Self]) -> IgvmDirectiveHeader {
29        IgvmDirectiveHeader::X64VbsVpContext {
30            registers: list
31                .iter()
32                .map(|®| reg.into())
33                .collect::<Vec<igvm::registers::X86Register>>(),
34            vtl: (vtl as u8).try_into().expect("vtl should be valid"),
35            compatibility_mask: DEFAULT_COMPATIBILITY_MASK,
36        }
37    }
38}
39
40impl VbsRegister for Aarch64Register {
41    fn into_igvm_header(vtl: Vtl, list: &[Self]) -> IgvmDirectiveHeader {
42        IgvmDirectiveHeader::AArch64VbsVpContext {
43            registers: list
44                .iter()
45                .map(|®| reg.into())
46                .collect::<Vec<igvm::registers::AArch64Register>>(),
47            vtl: (vtl as u8).try_into().expect("vtl should be valid"),
48            compatibility_mask: DEFAULT_COMPATIBILITY_MASK,
49        }
50    }
51}
52
53#[derive(Debug, Clone)]
54pub struct VbsVpContext<R: VbsRegister> {
55    registers: Vec<R>,
57    vtl: Vtl,
59}
60
61impl<R: VbsRegister> VbsVpContext<R> {
62    pub fn new(vtl: Vtl) -> Self {
63        Self {
64            registers: Vec::new(),
65            vtl,
66        }
67    }
68
69    pub fn as_page(&self) -> Vec<u8> {
72        let header = R::into_igvm_header(self.vtl, &self.registers);
73        let mut variable_header = Vec::new();
75        let mut file_data = FileDataSerializer::new(0);
76        header
77            .write_binary_header(&mut variable_header, &mut file_data)
78            .expect("registers should be valid");
79
80        let file_data = file_data.take();
81
82        assert!(file_data.len() <= PAGE_SIZE_4K as usize);
83
84        file_data
85    }
86}
87
88impl<R: VbsRegister> VpContextBuilder for VbsVpContext<R> {
89    type Register = R;
90
91    fn import_vp_register(&mut self, register: R) {
92        assert!(
94            !self
95                .registers
96                .iter()
97                .any(|reg| discriminant(reg) == discriminant(®ister)),
98            "duplicate register import"
99        );
100
101        self.registers.push(register);
102    }
103
104    fn set_vp_context_memory(&mut self, _page_base: u64) {
105        unimplemented!("not supported for VBS");
106    }
107
108    fn finalize(&mut self, state: &mut Vec<VpContextState>) {
109        if self.registers.is_empty() {
110            return;
111        }
112        state.push(VpContextState::Directive(R::into_igvm_header(
114            self.vtl,
115            &self.registers,
116        )));
117    }
118}