From d419e30df19475ae44b51a8668f64cad3135459e Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 27 Nov 2020 00:17:59 +0100 Subject: [PATCH] hypervisor: x86: Add a SegmentRegistorOps trait In order to validate emulated memory accesses, we need to be able to get all the segments descriptor attributes. This is done by abstracting the SegmentRegister attributes through a trait that each hypervisor will have to implement. Signed-off-by: Samuel Ortiz --- hypervisor/src/arch/x86/mod.rs | 57 +++++++++++++++++++++++++++ hypervisor/src/kvm/x86_64/mod.rs | 67 +++++++++++++++++++++++++++++++- 2 files changed, 123 insertions(+), 1 deletion(-) diff --git a/hypervisor/src/arch/x86/mod.rs b/hypervisor/src/arch/x86/mod.rs index bf539e37b..21b2539ce 100644 --- a/hypervisor/src/arch/x86/mod.rs +++ b/hypervisor/src/arch/x86/mod.rs @@ -65,3 +65,60 @@ pub enum Exception { } pub mod regs; + +// Abstracted segment register ops. +// Each x86 hypervisor should implement those. +pub trait SegmentRegisterOps { + // Segment type + fn segment_type(&self) -> u8; + fn set_segment_type(&mut self, val: u8); + + // Descriptor Privilege Level (DPL) + fn dpl(&self) -> u8; + fn set_dpl(&mut self, val: u8); + + // Granularity + fn granularity(&self) -> u8; + fn set_granularity(&mut self, val: u8); + + // Memory Presence + fn present(&self) -> u8; + fn set_present(&mut self, val: u8); + + // Long mode + fn long(&self) -> u8; + fn set_long(&mut self, val: u8); + + // Available for system use (AVL) + fn avl(&self) -> u8; + fn set_avl(&mut self, val: u8); + + // Descriptor type (System or code/data) + fn desc_type(&self) -> u8; + fn set_desc_type(&mut self, val: u8); + + // D/B + fn db(&self) -> u8; + fn set_db(&mut self, val: u8); +} + +// Code segment +pub const CODE_SEGMENT_TYPE: u8 = 0x8; + +// Read/Write or Read/Exec segment +pub const RWRX_SEGMENT_TYPE: u8 = 0x2; + +// Expand down segment +pub const EXPAND_DOWN_SEGMENT_TYPE: u8 = 0x4; + +pub fn segment_type_code(t: u8) -> bool { + t & CODE_SEGMENT_TYPE != 0 +} + +pub fn segment_type_ro(t: u8) -> bool { + t & !RWRX_SEGMENT_TYPE == 0 +} + +pub fn segment_type_expand_down(t: u8) -> bool { + !segment_type_code(t) && (t & EXPAND_DOWN_SEGMENT_TYPE != 0) +} diff --git a/hypervisor/src/kvm/x86_64/mod.rs b/hypervisor/src/kvm/x86_64/mod.rs index 3f3343033..240a22b09 100644 --- a/hypervisor/src/kvm/x86_64/mod.rs +++ b/hypervisor/src/kvm/x86_64/mod.rs @@ -10,7 +10,7 @@ use vm_memory::GuestAddress; -use crate::arch::x86::{msr_index, MTRR_ENABLE, MTRR_MEM_TYPE_WB}; +use crate::arch::x86::{msr_index, SegmentRegisterOps, MTRR_ENABLE, MTRR_MEM_TYPE_WB}; use crate::kvm::{Cap, Kvm, KvmError, KvmResult}; use serde_derive::{Deserialize, Serialize}; @@ -28,6 +28,71 @@ pub use { kvm_bindings::KVM_CPUID_FLAG_SIGNIFCANT_INDEX as CPUID_FLAG_VALID_INDEX, }; +impl SegmentRegisterOps for SegmentRegister { + fn segment_type(&self) -> u8 { + self.type_ + } + fn set_segment_type(&mut self, val: u8) { + self.type_ = val; + } + + fn dpl(&self) -> u8 { + self.dpl + } + + fn set_dpl(&mut self, val: u8) { + self.dpl = val; + } + + fn present(&self) -> u8 { + self.present + } + + fn set_present(&mut self, val: u8) { + self.present = val; + } + + fn long(&self) -> u8 { + self.l + } + + fn set_long(&mut self, val: u8) { + self.l = val; + } + + fn avl(&self) -> u8 { + self.avl + } + + fn set_avl(&mut self, val: u8) { + self.avl = val; + } + + fn desc_type(&self) -> u8 { + self.s + } + + fn set_desc_type(&mut self, val: u8) { + self.s = val; + } + + fn granularity(&self) -> u8 { + self.g + } + + fn set_granularity(&mut self, val: u8) { + self.g = val; + } + + fn db(&self) -> u8 { + self.db + } + + fn set_db(&mut self, val: u8) { + self.db = val; + } +} + pub const KVM_TSS_ADDRESS: GuestAddress = GuestAddress(0xfffb_d000); macro_rules! msr {