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); } }