sev/vmsa/
mod.rs

1// SPDX-License-Identifier: Apache-2.0
2
3//! Types and abstractions regarding Virtual Machine Save Areas (VMSAs).
4
5#![allow(dead_code)]
6use crate::parser::{Decoder, Encoder};
7
8use super::{
9    util::{TypeLoad, TypeSave},
10    *,
11};
12
13use std::{fs, io, mem::size_of};
14
15#[cfg(feature = "serde")]
16use serde::{Deserialize, Serialize};
17#[cfg(feature = "serde")]
18use serde_big_array::BigArray;
19
20const ATTR_G_SHIFT: usize = 23;
21const ATTR_B_SHIFT: usize = 22;
22const ATTR_L_SHIFT: usize = 21;
23const ATTR_AVL_SHIFT: usize = 20;
24const ATTR_P_SHIFT: usize = 15;
25const ATTR_DPL_SHIFT: usize = 13;
26const ATTR_S_SHIFT: usize = 12;
27const ATTR_TYPE_SHIFT: usize = 8;
28const ATTR_A_SHIFT: usize = 8;
29const ATTR_CS_SHIFT: usize = 11;
30const ATTR_C_SHIFT: usize = 10;
31const ATTR_R_SHIFT: usize = 9;
32const ATTR_E_SHIFT: usize = 10;
33const ATTR_W_SHIFT: usize = 9;
34
35const ATTR_G_MASK: usize = 1 << ATTR_G_SHIFT;
36const ATTR_B_MASK: usize = 1 << ATTR_B_SHIFT;
37const ATTR_L_MASK: usize = 1 << ATTR_L_SHIFT;
38const ATTR_AVL_MASK: usize = 1 << ATTR_AVL_SHIFT;
39const ATTR_P_MASK: u16 = 1 << ATTR_P_SHIFT;
40const ATTR_DPL_MASK: u16 = 1 << ATTR_DPL_SHIFT;
41const ATTR_S_MASK: u16 = 1 << ATTR_S_SHIFT;
42const ATTR_TYPE_MASK: u16 = 1 << ATTR_TYPE_SHIFT;
43const ATTR_A_MASK: u16 = 1 << ATTR_A_SHIFT;
44const ATTR_CS_MASK: u16 = 1 << ATTR_CS_SHIFT;
45const ATTR_C_MASK: u16 = 1 << ATTR_C_SHIFT;
46const ATTR_R_MASK: u16 = 1 << ATTR_R_SHIFT;
47const ATTR_E_MASK: u16 = 1 << ATTR_E_SHIFT;
48const ATTR_W_MASK: u16 = 1 << ATTR_W_SHIFT;
49
50/// Virtual Machine Control Block
51/// The layout of a VMCB struct is documented in Table B-1 of the
52/// AMD64 Architecture Programmer’s Manual, Volume 2: System Programming
53#[repr(C, packed)]
54#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
55#[derive(Default, Clone, Copy)]
56pub struct VmcbSegment {
57    /// Segment selector: documented in Figure 4-3 of the
58    /// AMD64 Architecture Programmer’s Manual, Volume 2: System Programming
59    selector: u16,
60
61    /// Segment attributes.
62    attrib: u16,
63
64    /// Segment limit: used in comparisons with pointer offsets to prevent
65    /// segment limit violations.
66    limit: u32,
67
68    /// Segment base address.
69    base: u64,
70}
71
72/// Virtual Machine Save Area
73/// The layout of a VMCB struct is documented in Table B-4 of the
74/// AMD64 Architecture Programmer’s Manual, Volume 2: System Programming
75#[repr(C, packed)]
76#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
77#[derive(Copy, Clone)]
78pub struct Vmsa {
79    /// Extra segment.
80    es: VmcbSegment,
81
82    /// Code segment.
83    cs: VmcbSegment,
84
85    /// Stack segment.
86    ss: VmcbSegment,
87
88    /// Data segment.
89    ds: VmcbSegment,
90
91    /// Segment with no specific use defined by the hardware.
92    fs: VmcbSegment,
93
94    /// Segment with no specific use defined by the hardware.
95    gs: VmcbSegment,
96
97    /// Base address of the Global Descriptor Table.
98    gdtr: VmcbSegment,
99
100    /// Base address of the Local Descriptor Table.
101    ldtr: VmcbSegment,
102
103    /// Base address of the Interrupt Descriptor Table.
104    idtr: VmcbSegment,
105
106    /// Points to a valid TSS segment descriptor which resides in the GDT.
107    tr: VmcbSegment,
108
109    /// Reserved.
110    #[cfg_attr(feature = "serde", serde(with = "BigArray"))]
111    reserved_1: [u8; 43],
112
113    /// Current privilege level.
114    cpl: u8,
115
116    /// Reserved.
117    reserved_2: [u8; 4],
118
119    /// Extended features enable register.
120    efer: u64,
121
122    /// Reserved.
123    #[cfg_attr(feature = "serde", serde(with = "BigArray"))]
124    reserved_3: [u8; 104],
125
126    /// Bitmap of supervisor-level state components. System software sets bits
127    /// in the XSS register bitmap to enable management of corresponding state
128    /// component by the XSAVES/XRSTORS instructions.
129    xss: u64,
130
131    /// Control register 4.
132    cr4: u64,
133
134    /// Control register 3.
135    cr3: u64,
136
137    /// Control register 0.
138    cr0: u64,
139
140    /// Debug register 7.
141    dr7: u64,
142
143    /// Debug register 6.
144    dr6: u64,
145
146    /// RFLAGS register. Documented in Figure 3-7 of the
147    /// AMD64 Architecture Programmer’s Manual, Volume 2: System Programming
148    rflags: u64,
149
150    /// Instruction pointer.
151    rip: u64,
152
153    /// Reserved.
154    #[cfg_attr(feature = "serde", serde(with = "BigArray"))]
155    reserved_4: [u8; 88],
156
157    /// Stack pointer.
158    rsp: u64,
159
160    /// Reserved.
161    reserved_5: [u8; 24],
162
163    /// RAX register.
164    rax: u64,
165
166    /// STAR register. Documented in Figure 6-1 of the
167    /// AMD64 Architecture Programmer’s Manual, Volume 2: System Programming
168    star: u64,
169
170    /// Target RIP of the called procedure in long mode when the calling
171    /// software is in 64-bit mode.
172    lstar: u64,
173
174    /// Target RIP of the called procedure in long mode when the calling
175    /// software is in compatibility mode.
176    cstar: u64,
177
178    /// Used in long mode to specify how rFLAGS is handled by SYSCALL
179    /// instructions.
180    sfmask: u64,
181
182    /// This register is used by the SWAPGS instruction. This instruction
183    /// exchanges the value located in KernelGSbase with the value located in
184    /// "GS.base".
185    kernel_gs_base: u64,
186
187    /// CS linkage information for SYSENTER and SYSEXIT instructions.
188    sysenter_cs: u64,
189
190    /// ESP linkage information for SYSENTER and SYSEXIT instructions.
191    sysenter_esp: u64,
192
193    /// EIP linkage information for SYSENTER and SYSEXIT instructions.
194    sysenter_eip: u64,
195
196    /// Control register 2.
197    cr2: u64,
198
199    /// Reserved.
200    reserved_6: [u8; 32],
201
202    /// Register for holding guest PAT information.
203    g_pat: u64,
204
205    /// Holds the guest value of the DebugCTL MSR.
206    dbgctl: u64,
207
208    /// Holds the guest value of the LastBranchFromIP MSR.
209    br_from: u64,
210
211    /// Holds the guest value of the LastBranchToIP MSR.
212    br_to: u64,
213
214    /// Holds the guest value of the LastIntFromIP MSR.
215    last_excp_from: u64,
216
217    /// Holds the guest value of the LastIntToIPLastIntToIP MSR.
218    last_excp_to: u64,
219
220    /// Reserved.
221    #[cfg_attr(feature = "serde", serde(with = "BigArray"))]
222    reserved_7: [u8; 72],
223
224    /// Speculation Control of MSRs. Documented in Section 3.2.9 of the
225    /// AMD64 Architecture Programmer’s Manual, Volume 2: System Programming
226    spec_ctrl: u32,
227
228    /// Reserved.
229    reserved_7b: [u8; 4],
230
231    /// Memory Protection Key information. Documented in Section 5.6.7 of the
232    /// AMD64 Architecture Programmer’s Manual, Volume 2: System Programming
233    pkru: u32,
234
235    /// Reserved.
236    reserved_7a: [u8; 20],
237
238    /// Reserved.
239    reserved_8: u64,
240
241    /// RCX register.
242    rcx: u64,
243
244    /// RDX register.
245    rdx: u64,
246
247    /// RBX register.
248    rbx: u64,
249
250    /// Reserved.
251    reserved_9: u64,
252
253    /// RBP register.
254    rbp: u64,
255
256    /// RSI register.
257    rsi: u64,
258
259    /// RDI register.
260    rdi: u64,
261
262    /// R8 register.
263    r8: u64,
264
265    /// R9 register.
266    r9: u64,
267
268    /// R10 register.
269    r10: u64,
270
271    /// R11 register.
272    r11: u64,
273
274    /// R12 register.
275    r12: u64,
276
277    /// R13 register.
278    r13: u64,
279
280    /// R14 register.
281    r14: u64,
282
283    /// R15 register.
284    r15: u64,
285
286    /// Reserved.
287    reserved_10: [u8; 16],
288
289    /// Exit code.
290    sw_exit_code: u64,
291
292    /// Values written to the vAPIC ICRH and ICRL registers.
293    sw_exit_info_1: u64,
294
295    /// Information describing the specific reason for the IPI delivery
296    /// failure.
297    sw_exit_info_2: u64,
298
299    /// Scratch register.
300    sw_scratch: u64,
301
302    /// Reserved.
303    #[cfg_attr(feature = "serde", serde(with = "BigArray"))]
304    reserved_11: [u8; 56],
305
306    /// XCR0 register.
307    xcr0: u64,
308
309    /// Valid bitmap.
310    valid_bitmap: [u8; 16],
311
312    /// gPA of the x87 state.
313    x87_state_gpa: u64,
314}
315
316impl Default for Vmsa {
317    fn default() -> Self {
318        Self {
319            es: Default::default(),
320            cs: Default::default(),
321            ss: Default::default(),
322            ds: Default::default(),
323            fs: Default::default(),
324            gs: Default::default(),
325            gdtr: Default::default(),
326            ldtr: Default::default(),
327            idtr: Default::default(),
328            tr: Default::default(),
329            reserved_1: [0u8; 43],
330            cpl: Default::default(),
331            reserved_2: Default::default(),
332            efer: Default::default(),
333            reserved_3: [0u8; 104],
334            xss: Default::default(),
335            cr4: Default::default(),
336            cr3: Default::default(),
337            cr0: Default::default(),
338            dr7: Default::default(),
339            dr6: Default::default(),
340            rflags: Default::default(),
341            rip: Default::default(),
342            reserved_4: [0u8; 88],
343            rsp: Default::default(),
344            reserved_5: Default::default(),
345            rax: Default::default(),
346            star: Default::default(),
347            lstar: Default::default(),
348            cstar: Default::default(),
349            sfmask: Default::default(),
350            kernel_gs_base: Default::default(),
351            sysenter_cs: Default::default(),
352            sysenter_esp: Default::default(),
353            sysenter_eip: Default::default(),
354            cr2: Default::default(),
355            reserved_6: Default::default(),
356            g_pat: Default::default(),
357            dbgctl: Default::default(),
358            br_from: Default::default(),
359            br_to: Default::default(),
360            last_excp_from: Default::default(),
361            last_excp_to: Default::default(),
362            reserved_7: [0u8; 72],
363            spec_ctrl: Default::default(),
364            reserved_7b: Default::default(),
365            pkru: Default::default(),
366            reserved_7a: Default::default(),
367            reserved_8: Default::default(),
368            rcx: Default::default(),
369            rdx: Default::default(),
370            rbx: Default::default(),
371            reserved_9: Default::default(),
372            rbp: Default::default(),
373            rsi: Default::default(),
374            rdi: Default::default(),
375            r8: Default::default(),
376            r9: Default::default(),
377            r10: Default::default(),
378            r11: Default::default(),
379            r12: Default::default(),
380            r13: Default::default(),
381            r14: Default::default(),
382            r15: Default::default(),
383            reserved_10: Default::default(),
384            sw_exit_code: Default::default(),
385            sw_exit_info_1: Default::default(),
386            sw_exit_info_2: Default::default(),
387            sw_scratch: Default::default(),
388            reserved_11: [0u8; 56],
389            xcr0: Default::default(),
390            valid_bitmap: Default::default(),
391            x87_state_gpa: Default::default(),
392        }
393    }
394}
395
396impl Decoder<()> for Vmsa {
397    fn decode(reader: &mut impl Read, _: ()) -> Result<Self, std::io::Error> {
398        reader.load()
399    }
400}
401
402impl Encoder<()> for Vmsa {
403    fn encode(&self, writer: &mut impl Write, _: ()) -> Result<(), std::io::Error> {
404        writer.save(self)
405    }
406}
407
408impl Vmsa {
409    /// Set VMSA values to follow initialization for an amd64 CPU.
410    pub fn init_amd64(&mut self) {
411        self.cr0 = 1 << 4;
412        self.rip = 0xfff0;
413
414        self.cs.selector = 0xf000;
415        self.cs.base = 0xffff0000;
416        self.cs.limit = 0xffff;
417
418        self.ds.limit = 0xffff;
419
420        self.es.limit = 0xffff;
421        self.fs.limit = 0xffff;
422        self.gs.limit = 0xffff;
423        self.ss.limit = 0xffff;
424
425        self.gdtr.limit = 0xffff;
426        self.idtr.limit = 0xffff;
427
428        self.ldtr.limit = 0xffff;
429        self.tr.limit = 0xffff;
430
431        self.dr6 = 0xffff0ff0;
432        self.dr7 = 0x0400;
433        self.rflags = 0x2;
434        self.xcr0 = 0x1;
435    }
436
437    /// Set VMSA values to follow initialization for a VM running as a KVM guest.
438    pub fn init_kvm(&mut self) {
439        // svm_set_cr4() sets guest X86_CR4_MCE bit if host
440        // has X86_CR4_MCE enabled
441        self.cr4 = 0x40;
442
443        // svm_set_efer sets guest EFER_SVME (Secure Virtual Machine enable)
444        self.efer = 0x1000;
445
446        // init_vmcb + init_sys_seg() sets
447        // SVM_SELECTOR_P_MASK | SEG_TYPE_LDT
448        self.ldtr.attrib = 0x0082;
449
450        // init_vmcb + init_sys_seg() sets
451        // SVM_SELECTOR_P_MASK | SEG_TYPE_BUSY_TSS16
452        self.tr.attrib = 0x0083;
453
454        // kvm_arch_vcpu_create() in arch/x86/kvm/x86.c
455        self.g_pat = 0x0007040600070406;
456    }
457
458    // Based on logic in setup_regs() (src/arch/src/x86_64/regs.rs)
459    /// Set VMSA values to follow initialization for a VM running as a krun guest.
460    pub fn init_krun(&mut self, cpu: u64) {
461        self.rsi = 0x7000;
462        self.rbp = 0x8ff0;
463        self.rsp = 0x8ff0;
464
465        // Doesn't match with configure_segments_and_sregs
466        self.cs.attrib =
467            (ATTR_P_MASK | ATTR_S_MASK | ATTR_CS_MASK | ATTR_R_MASK) >> ATTR_TYPE_SHIFT;
468        self.ds.attrib = (ATTR_P_MASK | ATTR_S_MASK | ATTR_W_MASK | ATTR_A_MASK) >> ATTR_TYPE_SHIFT;
469        self.es.attrib = (ATTR_P_MASK | ATTR_S_MASK | ATTR_W_MASK | ATTR_A_MASK) >> ATTR_TYPE_SHIFT;
470        self.ss.attrib = (ATTR_P_MASK | ATTR_S_MASK | ATTR_W_MASK) >> ATTR_TYPE_SHIFT;
471        self.fs.attrib = (ATTR_P_MASK | ATTR_S_MASK | ATTR_W_MASK | ATTR_A_MASK) >> ATTR_TYPE_SHIFT;
472        self.gs.attrib = (ATTR_P_MASK | ATTR_S_MASK | ATTR_W_MASK | ATTR_A_MASK) >> ATTR_TYPE_SHIFT;
473
474        if cpu > 0 {
475            self.rip = 0;
476            self.rsp = 0;
477            self.rbp = 0;
478            self.rsi = 0;
479
480            self.cs.selector = 0x9100;
481            self.cs.base = 0x91000;
482        }
483    }
484
485    // Based on logic in x86_cpu_reset() (target/i386/cpu.c)
486    /// Set VMSA values to follow initialization for a VM running as a QEMU guest.
487    pub fn init_qemu(&mut self, _cpu: u64) {
488        self.ldtr.attrib = (ATTR_P_MASK | (2 << ATTR_TYPE_SHIFT)) >> ATTR_TYPE_SHIFT;
489        self.tr.attrib = (ATTR_P_MASK | (11 << ATTR_TYPE_SHIFT)) >> ATTR_TYPE_SHIFT;
490        self.cs.attrib = (ATTR_P_MASK | ATTR_S_MASK | ATTR_CS_MASK | ATTR_R_MASK | ATTR_A_MASK)
491            >> ATTR_TYPE_SHIFT;
492        self.ds.attrib = (ATTR_P_MASK | ATTR_S_MASK | ATTR_W_MASK | ATTR_A_MASK) >> ATTR_TYPE_SHIFT;
493        self.es.attrib = (ATTR_P_MASK | ATTR_S_MASK | ATTR_W_MASK | ATTR_A_MASK) >> ATTR_TYPE_SHIFT;
494        self.ss.attrib = (ATTR_P_MASK | ATTR_S_MASK | ATTR_W_MASK | ATTR_A_MASK) >> ATTR_TYPE_SHIFT;
495        self.fs.attrib = (ATTR_P_MASK | ATTR_S_MASK | ATTR_W_MASK | ATTR_A_MASK) >> ATTR_TYPE_SHIFT;
496        self.gs.attrib = (ATTR_P_MASK | ATTR_S_MASK | ATTR_W_MASK | ATTR_A_MASK) >> ATTR_TYPE_SHIFT;
497
498        self.g_pat = 0x0007040600070406;
499    }
500
501    /// Set CPU SKU values for a given VMSA.
502    pub fn cpu_sku(&mut self, mut family: u64, mut model: u64, mut stepping: u64) {
503        stepping &= 0xf;
504        model &= 0xff;
505        family &= 0xfff;
506
507        self.rdx = stepping;
508
509        if family > 0xf {
510            self.rdx |= 0xf00 | ((family - 0x0f) << 20);
511        } else {
512            self.rdx |= family << 8;
513        }
514
515        self.rdx |= ((model & 0xf) << 4) | ((model >> 4) << 16);
516    }
517
518    /// Set VMSA reset address register values.
519    pub fn reset_addr(&mut self, ra: u32) {
520        let reset_cs = ra & 0xffff0000;
521        let reset_ip = ra & 0x0000ffff;
522
523        self.rip = u64::from(reset_ip);
524        self.cs.base = u64::from(reset_cs);
525    }
526
527    /// Read binary content from a passed filename and deserialize it into a
528    /// VMSA struct. Validate that the passed file is 4096 bytes long,
529    /// which is expected by SEV measurement validation.
530    pub fn from_file(filename: &str) -> Result<Self, io::Error> {
531        let data = std::fs::read(filename)?;
532        if data.len() != 4096 {
533            return Err(io::Error::new(
534                io::ErrorKind::InvalidData,
535                format!("Expected VMSA length 4096, was {}", data.len()),
536            ));
537        }
538        let vmsa = Vmsa::decode(&mut &data[..], ())?;
539        Ok(vmsa)
540    }
541
542    /// Serialize a VMSA struct and write it to a passed filename,
543    /// This ensures it is padded to 4096 bytes which is expected
544    /// by SEV measurement validation.
545    pub fn to_file(&self, filename: &str) -> Result<(), io::Error> {
546        let mut vmsa_buf = Vec::new();
547        self.encode(&mut vmsa_buf, ())?;
548
549        const SIZE: usize = size_of::<Vmsa>();
550
551        // Pad to 4096 bytes
552        let buf: &mut [u8] = &mut [0; 4096];
553        buf[..SIZE].copy_from_slice(&vmsa_buf[..]);
554
555        fs::write(filename, buf)?;
556        Ok(())
557    }
558}