From 91a4b090da47acfa0ce89047c97f551e4fb1107a Mon Sep 17 00:00:00 2001 From: Daniel Verkamp Date: Wed, 29 Jun 2022 14:37:40 -0700 Subject: [PATCH] hypervisor: x86_64: add Default impl for Sregs Replace the Sregs Default implementation with one that provides the register values at reset, based on the Intel software developer manual. The x86_64 tests need to be adjusted to only check the CR0 bits they intend to match, since the default Sregs value now includes other set bits. BUG=b:237095693 TEST=Boot x86-64 Linux kernel TEST=cargo test -p x86_64 Change-Id: If966941df43225572e79ebd9213671348e2846f4 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3735640 Reviewed-by: Alexandre Courbot Tested-by: kokoro Commit-Queue: Daniel Verkamp --- hypervisor/src/x86_64.rs | 99 +++++++++++++++++++++++++++++++++++++++- x86_64/src/regs.rs | 4 +- 2 files changed, 100 insertions(+), 3 deletions(-) diff --git a/hypervisor/src/x86_64.rs b/hypervisor/src/x86_64.rs index 8decaadb7d..01f199c57e 100644 --- a/hypervisor/src/x86_64.rs +++ b/hypervisor/src/x86_64.rs @@ -630,7 +630,7 @@ pub struct DescriptorTable { /// State of a VCPU's special registers. #[repr(C)] -#[derive(Debug, Default, Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct Sregs { pub cs: Segment, pub ds: Segment, @@ -655,6 +655,103 @@ pub struct Sregs { pub interrupt_bitmap: [u64; 4usize], } +impl Default for Sregs { + fn default() -> Self { + // Intel SDM Vol. 3A, 3.4.5.1 ("Code- and Data-Segment Descriptor Types") + const SEG_TYPE_DATA: u8 = 0b0000; + const SEG_TYPE_DATA_WRITABLE: u8 = 0b0010; + + const SEG_TYPE_CODE: u8 = 0b1000; + const SEG_TYPE_CODE_READABLE: u8 = 0b0010; + + const SEG_TYPE_ACCESSED: u8 = 0b0001; + + // Intel SDM Vol. 3A, 3.4.5 ("Segment Descriptors") + const SEG_S_SYSTEM: u8 = 0; // System segment. + const SEG_S_CODE_OR_DATA: u8 = 1; // Data/code segment. + + // 16-bit real-mode code segment (reset vector). + let code_seg = Segment { + base: 0xffff0000, + limit: 0xffff, + selector: 0xf000, + type_: SEG_TYPE_CODE | SEG_TYPE_CODE_READABLE | SEG_TYPE_ACCESSED, // 11 + present: 1, + s: SEG_S_CODE_OR_DATA, + ..Default::default() + }; + + // 16-bit real-mode data segment. + let data_seg = Segment { + base: 0, + limit: 0xffff, + selector: 0, + type_: SEG_TYPE_DATA | SEG_TYPE_DATA_WRITABLE | SEG_TYPE_ACCESSED, // 3 + present: 1, + s: SEG_S_CODE_OR_DATA, + ..Default::default() + }; + + // 16-bit TSS segment. + let task_seg = Segment { + base: 0, + limit: 0xffff, + selector: 0, + type_: SEG_TYPE_CODE | SEG_TYPE_CODE_READABLE | SEG_TYPE_ACCESSED, // 11 + present: 1, + s: SEG_S_SYSTEM, + ..Default::default() + }; + + // Local descriptor table. + let ldt = Segment { + base: 0, + limit: 0xffff, + selector: 0, + type_: SEG_TYPE_DATA | SEG_TYPE_DATA_WRITABLE, // 2 + present: 1, + s: SEG_S_SYSTEM, + ..Default::default() + }; + + // Global descriptor table. + let gdt = DescriptorTable { + base: 0, + limit: 0xffff, + }; + + // Interrupt descriptor table. + let idt = DescriptorTable { + base: 0, + limit: 0xffff, + }; + + let cr0 = (1 << 4) // CR0.ET (reserved, always 1) + | (1 << 30); // CR0.CD (cache disable) + + Sregs { + cs: code_seg, + ds: data_seg, + es: data_seg, + fs: data_seg, + gs: data_seg, + ss: data_seg, + tr: task_seg, + ldt, + gdt, + idt, + cr0, + cr2: 0, + cr3: 0, + cr4: 0, + cr8: 0, + efer: 0, + apic_base: 0, + interrupt_bitmap: Default::default(), + } + } +} + /// State of a VCPU's floating point unit. #[repr(C)] #[derive(Debug, Copy, Clone)] diff --git a/x86_64/src/regs.rs b/x86_64/src/regs.rs index 9b3af0a313..a4195546ab 100644 --- a/x86_64/src/regs.rs +++ b/x86_64/src/regs.rs @@ -381,7 +381,7 @@ mod tests { assert_eq!(0, sregs.tr.base); assert_eq!(0xfffff, sregs.tr.limit); assert_eq!(0, sregs.tr.avl); - assert_eq!(X86_CR0_PE, sregs.cr0); + assert_eq!(X86_CR0_PE, sregs.cr0 & X86_CR0_PE); assert_eq!(EFER_LME, sregs.efer); } @@ -399,6 +399,6 @@ mod tests { assert_eq!(0x9000, sregs.cr3); assert_eq!(X86_CR4_PAE, sregs.cr4); - assert_eq!(X86_CR0_PG, sregs.cr0); + assert_eq!(X86_CR0_PG, sregs.cr0 & X86_CR0_PG); } }