From 29c4c94febe52fa85dea73cc129c3a984dab25a1 Mon Sep 17 00:00:00 2001 From: Francis Nixon Date: Fri, 18 Dec 2020 10:51:55 -0500 Subject: [PATCH 01/14] a sort of initial skeleton for cpuid. --- mythril/src/emulate/cpuid.rs | 35 ++++++++++++++++++++++++++++++++++- mythril/src/vm.rs | 4 +++- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/mythril/src/emulate/cpuid.rs b/mythril/src/emulate/cpuid.rs index 9c61c4e..e14cb95 100644 --- a/mythril/src/emulate/cpuid.rs +++ b/mythril/src/emulate/cpuid.rs @@ -1,10 +1,43 @@ use crate::error::Result; use crate::{vcpu, vmexit}; +//Used https://c9x.me/x86/html/file_module_x86_id_45.html as guid for implementing this. +const CPUID_NAME: u32 = 0; +const CPUID_MODEL_FAMILY_STEPPING: u32 = 1; +const CPUID_CACHE_TLB_INFO: u32 = 2; +const INTEL_CORE_CACHE_TOPOLOGY : u32 = 4; +const CPUID_BRAND_STRING_1: u32 = 0x80000002; +const CPUID_BRAND_STRING_2: u32 = 0x80000003; +const CPUID_BRAND_STRING_3: u32 = 0x80000004; +//todo //CPUID leaves above 2 and below 80000000H are visible only when +// // IA32_MISC_ENABLE[bit 22] has its default value of 0. + + + pub fn emulate_cpuid( - _vcpu: &mut vcpu::VCpu, + vcpu: &mut vcpu::VCpu, guest_cpu: &mut vmexit::GuestCpuState, ) -> Result<()> { + let eax = guest_cpu.rax as u32; + + match eax { + CPUID_NAME => { + if vcpu.vm.read().config.override_cpu_name(){ + todo!() + } + }, + CPUID_MODEL_FAMILY_STEPPING => todo!(), + INTEL_CORE_CACHE_TOPOLOGY => { + _vcpu.vm.read().config.cpus() + } + CPUID_BRAND_STRING_1 => todo!(), + CPUID_BRAND_STRING_2 => todo!(), + _ => { + // dbg!(eax); + // todo!("If you are reading this then a invalid arg was passed to cpuid. In principle we should prob fault here or something, but this probably indicates a bug.") + } + } + //FIXME: for now just use the actual cpuid let mut res = raw_cpuid::native_cpuid::cpuid_count( guest_cpu.rax as u32, diff --git a/mythril/src/vm.rs b/mythril/src/vm.rs index 1cec159..43831f5 100644 --- a/mythril/src/vm.rs +++ b/mythril/src/vm.rs @@ -365,6 +365,7 @@ pub struct VirtualMachineConfig { /// The size of this machines physical address space in MiB pub memory: u64, + override_cpu_name: bool } impl VirtualMachineConfig { @@ -387,6 +388,7 @@ impl VirtualMachineConfig { virtual_devices: ArrayVec::new(), host_devices: physical_devices, memory: memory, + override_cpu_name: todo!() }) } @@ -462,7 +464,7 @@ impl VirtualMachine { // Prepare the portion of per-core local apic state that is stored at the // VM level (as needed for logical addressing) let mut logical_apic_states = BTreeMap::new(); - for core in config.cpus.iter() { + for core in config.cpus.as_slice() { logical_apic_states.insert( core.clone(), virtdev::lapic::LogicalApicState::default(), From c4a6ff222b2edab625abd714ad087668a2369a8f Mon Sep 17 00:00:00 2001 From: Francis Nixon Date: Fri, 18 Dec 2020 13:08:39 -0500 Subject: [PATCH 02/14] got some basic cpuid stuff working. --- mythril/Cargo.lock | 7 ++++ mythril/Cargo.toml | 1 + mythril/src/emulate/cpuid.rs | 78 ++++++++++++++++++++++++++++-------- 3 files changed, 70 insertions(+), 16 deletions(-) diff --git a/mythril/Cargo.lock b/mythril/Cargo.lock index 1fc5619..2872b09 100644 --- a/mythril/Cargo.lock +++ b/mythril/Cargo.lock @@ -30,6 +30,12 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcb6dd1c2376d2e096796e234a70e17e94cc2d5d54ff8ce42b28cef1d0d359a4" +[[package]] +name = "bitfield" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" + [[package]] name = "bitflags" version = "1.2.1" @@ -156,6 +162,7 @@ version = "0.1.0" dependencies = [ "arraydeque", "arrayvec", + "bitfield", "bitflags", "byteorder", "iced-x86", diff --git a/mythril/Cargo.toml b/mythril/Cargo.toml index 6081519..81361a0 100644 --- a/mythril/Cargo.toml +++ b/mythril/Cargo.toml @@ -28,6 +28,7 @@ serde_json = {version = "^1", default-features = false, features = ["alloc"] } spin = "0.5" ux = { version = "0.1.3", default-features = false } managed = { version = "0.8.0", features = ["map", "alloc"], default-features = false } +bitfield = "0.13.2" [dependencies.arrayvec] version = "0.5.2" diff --git a/mythril/src/emulate/cpuid.rs b/mythril/src/emulate/cpuid.rs index e14cb95..8ed7995 100644 --- a/mythril/src/emulate/cpuid.rs +++ b/mythril/src/emulate/cpuid.rs @@ -1,42 +1,88 @@ use crate::error::Result; use crate::{vcpu, vmexit}; +use raw_cpuid::CpuIdResult; +use arrayvec::ArrayVec; +use core::convert::TryInto; +use bitfield::bitfield; //Used https://c9x.me/x86/html/file_module_x86_id_45.html as guid for implementing this. const CPUID_NAME: u32 = 0; const CPUID_MODEL_FAMILY_STEPPING: u32 = 1; const CPUID_CACHE_TLB_INFO: u32 = 2; -const INTEL_CORE_CACHE_TOPOLOGY : u32 = 4; +const INTEL_CORE_CACHE_TOPOLOGY: u32 = 4; const CPUID_BRAND_STRING_1: u32 = 0x80000002; const CPUID_BRAND_STRING_2: u32 = 0x80000003; const CPUID_BRAND_STRING_3: u32 = 0x80000004; +const MAX_CPUID_INPUT: u32 = 0x80000004; //todo //CPUID leaves above 2 and below 80000000H are visible only when // // IA32_MISC_ENABLE[bit 22] has its default value of 0. +// +// bitfield! { +// pub struct IntelCoreCacheTopologyEaxRes(u32) +// impl Debug; +// impl Copy; +// +// } -pub fn emulate_cpuid( - vcpu: &mut vcpu::VCpu, - guest_cpu: &mut vmexit::GuestCpuState, -) -> Result<()> { - let eax = guest_cpu.rax as u32; +bitfield! { + pub struct IntelTypeFamilyModelSteppingIDEaxRes(u32); + impl Debug; + stepping_id, _: 3,0; + model,_:7,4; + family_id,_:11,8; + processor_type,_:13,12; + extended_model_id,_:19,16; + extended_family_id,_:27,20; +} + +fn get_cpu_id_result(vcpu: &vcpu::VCpu, eax: u32, ecx: u32) -> Option { + const NAME_CREATION_ERROR_MESSAGE: &'static str = "Somehow bytes was not actually a 12 element array"; match eax { CPUID_NAME => { - if vcpu.vm.read().config.override_cpu_name(){ - todo!() + if vcpu.vm.read().config.override_cpu_name() { + let cpu_name = "MythrilCPU__"; + let bytes = cpu_name.chars().map(|char| char as u8).collect::>(); + let first_bytes: [u8; 4] = bytes[0..4].try_into().expect(NAME_CREATION_ERROR_MESSAGE); + let second_bytes: [u8; 4] = bytes[4..8].try_into().expect(NAME_CREATION_ERROR_MESSAGE); + let third_bytes: [u8; 4] = bytes[8..12].try_into().expect(NAME_CREATION_ERROR_MESSAGE); + return Some(CpuIdResult { + eax: MAX_CPUID_INPUT, + ebx: u32::from_le_bytes(first_bytes), + ecx: u32::from_le_bytes(second_bytes), + edx: u32::from_le_bytes(third_bytes), + }); } - }, - CPUID_MODEL_FAMILY_STEPPING => todo!(), + } + CPUID_MODEL_FAMILY_STEPPING => { + + } INTEL_CORE_CACHE_TOPOLOGY => { - _vcpu.vm.read().config.cpus() + let core_cpus = vcpu.vm.read().config.cpus(); + + todo!() + } + CPUID_BRAND_STRING_1..=CPUID_BRAND_STRING_2 => { + if vcpu.vm.read().config.override_cpu_name() { todo!("CPU Brand string not implemented yet") } + return None; } - CPUID_BRAND_STRING_1 => todo!(), - CPUID_BRAND_STRING_2 => todo!(), _ => { - // dbg!(eax); - // todo!("If you are reading this then a invalid arg was passed to cpuid. In principle we should prob fault here or something, but this probably indicates a bug.") + //TODO for code review. Idk how I feel about silently fallingback on real cpuid here. + // I would perhaps prefer to put a todo!() and explicitly implement stuff. + return None; } - } + }; + panic!() +} + +pub fn emulate_cpuid( + vcpu: &mut vcpu::VCpu, + guest_cpu: &mut vmexit::GuestCpuState, +) -> Result<()> { + let eax = guest_cpu.rax as u32; + //FIXME: for now just use the actual cpuid let mut res = raw_cpuid::native_cpuid::cpuid_count( From ceaa8e882167972c9a5d008123df629cb94d10fc Mon Sep 17 00:00:00 2001 From: Francis Nixon Date: Fri, 18 Dec 2020 14:03:01 -0500 Subject: [PATCH 03/14] handle CPUID_MODEL_FAMILY_STEPPING --- mythril/src/emulate/cpuid.rs | 101 +++++++++++++++++++++++------------ 1 file changed, 68 insertions(+), 33 deletions(-) diff --git a/mythril/src/emulate/cpuid.rs b/mythril/src/emulate/cpuid.rs index 8ed7995..05e8995 100644 --- a/mythril/src/emulate/cpuid.rs +++ b/mythril/src/emulate/cpuid.rs @@ -4,6 +4,8 @@ use raw_cpuid::CpuIdResult; use arrayvec::ArrayVec; use core::convert::TryInto; use bitfield::bitfield; +use bitflags::_core::num::flt2dec::to_shortest_exp_str; +use crate::apic::get_local_apic; //Used https://c9x.me/x86/html/file_module_x86_id_45.html as guid for implementing this. const CPUID_NAME: u32 = 0; @@ -37,27 +39,52 @@ bitfield! { extended_family_id,_:27,20; } -fn get_cpu_id_result(vcpu: &vcpu::VCpu, eax: u32, ecx: u32) -> Option { +bitfield! { + pub struct BrandCFlushMaxIDsInitialAPIC(u32); + impl Debug; + brand_idx, _: 7,0; + cflush,_:15,8; + max_processor_ids,_:23,16; + apic_id,_:31,24; +} + + +fn get_cpu_id_result(vcpu: &vcpu::VCpu, eax_in: u32, ecx_in: u32) -> CpuIdResult { const NAME_CREATION_ERROR_MESSAGE: &'static str = "Somehow bytes was not actually a 12 element array"; - match eax { - CPUID_NAME => { - if vcpu.vm.read().config.override_cpu_name() { - let cpu_name = "MythrilCPU__"; - let bytes = cpu_name.chars().map(|char| char as u8).collect::>(); - let first_bytes: [u8; 4] = bytes[0..4].try_into().expect(NAME_CREATION_ERROR_MESSAGE); - let second_bytes: [u8; 4] = bytes[4..8].try_into().expect(NAME_CREATION_ERROR_MESSAGE); - let third_bytes: [u8; 4] = bytes[8..12].try_into().expect(NAME_CREATION_ERROR_MESSAGE); - return Some(CpuIdResult { - eax: MAX_CPUID_INPUT, - ebx: u32::from_le_bytes(first_bytes), - ecx: u32::from_le_bytes(second_bytes), - edx: u32::from_le_bytes(third_bytes), - }); - } - } - CPUID_MODEL_FAMILY_STEPPING => { + let mut actual = raw_cpuid::native_cpuid::cpuid_count( + guest_cpu.rax as u32, + guest_cpu.rcx as u32, + ); + + match eax_in { + CPUID_NAME => cpuid_name(vcpu, &mut actual), + CPUID_MODEL_FAMILY_STEPPING => { + let family_model_stepping = IntelTypeFamilyModelSteppingIDEaxRes(actual.eax); + //we can change family_model_stepping, but for now just use actual. + let eax = family_model_stepping.0; + let mut brand_cflush_max_initial = BrandCFlushMaxIDsInitialAPIC(actual.ebx); + brand_cflush_max_initial.set_apic_id(get_local_apic().id());//in principle this is redundant + let ebx = brand_cflush_max_initial.0; + let mut ecx = actual.ecx; + let mut edx = actual.edx; + // I would have made type safe bindings for this but then I saw how many fields there where... + + // Disable MTRR + edx &= !(1 << 12); + + // Disable XSAVE + ecx &= !(1 << 26); + + // Hide hypervisor feature + ecx &= !(1 << 31); + CpuIdResult{ + eax, + ebx, + ecx, + edx + } } INTEL_CORE_CACHE_TOPOLOGY => { let core_cpus = vcpu.vm.read().config.cpus(); @@ -66,15 +93,31 @@ fn get_cpu_id_result(vcpu: &vcpu::VCpu, eax: u32, ecx: u32) -> Option { if vcpu.vm.read().config.override_cpu_name() { todo!("CPU Brand string not implemented yet") } - return None; + actual } _ => { //TODO for code review. Idk how I feel about silently fallingback on real cpuid here. // I would perhaps prefer to put a todo!() and explicitly implement stuff. - return None; + actual } - }; - panic!() + } +} + +fn cpuid_name(vcpu: &VCpu, actual: &mut CpuIdResult) -> CpuIdResult { + if vcpu.vm.read().config.override_cpu_name() { + let cpu_name = "MythrilCPU__"; + let bytes = cpu_name.chars().map(|char| char as u8).collect::>(); + let first_bytes: [u8; 4] = bytes[0..4].try_into().expect(NAME_CREATION_ERROR_MESSAGE); + let second_bytes: [u8; 4] = bytes[4..8].try_into().expect(NAME_CREATION_ERROR_MESSAGE); + let third_bytes: [u8; 4] = bytes[8..12].try_into().expect(NAME_CREATION_ERROR_MESSAGE); + return CpuIdResult { + eax: MAX_CPUID_INPUT, + ebx: u32::from_le_bytes(first_bytes), + ecx: u32::from_le_bytes(second_bytes), + edx: u32::from_le_bytes(third_bytes), + }; + } + actual } pub fn emulate_cpuid( @@ -83,19 +126,11 @@ pub fn emulate_cpuid( ) -> Result<()> { let eax = guest_cpu.rax as u32; + let ecx = guest_cpu.rcx as u32; + let mut res = get_cpu_id_result(vcpu, eax, ecx); - //FIXME: for now just use the actual cpuid - let mut res = raw_cpuid::native_cpuid::cpuid_count( - guest_cpu.rax as u32, - guest_cpu.rcx as u32, - ); - + //todo move this into get_cpu_id_result if guest_cpu.rax as u32 == 1 { - // Disable MTRR - res.edx &= !(1 << 12); - - // Disable XSAVE - res.ecx &= !(1 << 26); // Hide hypervisor feature res.ecx &= !(1 << 31); From e937d3658a53ff28088c659479e3bdfcb31623a5 Mon Sep 17 00:00:00 2001 From: Francis Nixon Date: Fri, 18 Dec 2020 15:19:19 -0500 Subject: [PATCH 04/14] refactored cpuid_model_family_stepping --- mythril/src/emulate/cpuid.rs | 115 +++++++++++++++++++++-------------- mythril/src/vcpu.rs | 1 + 2 files changed, 69 insertions(+), 47 deletions(-) diff --git a/mythril/src/emulate/cpuid.rs b/mythril/src/emulate/cpuid.rs index 05e8995..1156337 100644 --- a/mythril/src/emulate/cpuid.rs +++ b/mythril/src/emulate/cpuid.rs @@ -4,8 +4,8 @@ use raw_cpuid::CpuIdResult; use arrayvec::ArrayVec; use core::convert::TryInto; use bitfield::bitfield; -use bitflags::_core::num::flt2dec::to_shortest_exp_str; use crate::apic::get_local_apic; +use crate::vcpu::VCpu; //Used https://c9x.me/x86/html/file_module_x86_id_45.html as guid for implementing this. const CPUID_NAME: u32 = 0; @@ -28,25 +28,7 @@ const MAX_CPUID_INPUT: u32 = 0x80000004; // // } -bitfield! { - pub struct IntelTypeFamilyModelSteppingIDEaxRes(u32); - impl Debug; - stepping_id, _: 3,0; - model,_:7,4; - family_id,_:11,8; - processor_type,_:13,12; - extended_model_id,_:19,16; - extended_family_id,_:27,20; -} -bitfield! { - pub struct BrandCFlushMaxIDsInitialAPIC(u32); - impl Debug; - brand_idx, _: 7,0; - cflush,_:15,8; - max_processor_ids,_:23,16; - apic_id,_:31,24; -} fn get_cpu_id_result(vcpu: &vcpu::VCpu, eax_in: u32, ecx_in: u32) -> CpuIdResult { @@ -59,33 +41,8 @@ fn get_cpu_id_result(vcpu: &vcpu::VCpu, eax_in: u32, ecx_in: u32) -> CpuIdResult ); match eax_in { - CPUID_NAME => cpuid_name(vcpu, &mut actual), - CPUID_MODEL_FAMILY_STEPPING => { - let family_model_stepping = IntelTypeFamilyModelSteppingIDEaxRes(actual.eax); - //we can change family_model_stepping, but for now just use actual. - let eax = family_model_stepping.0; - let mut brand_cflush_max_initial = BrandCFlushMaxIDsInitialAPIC(actual.ebx); - brand_cflush_max_initial.set_apic_id(get_local_apic().id());//in principle this is redundant - let ebx = brand_cflush_max_initial.0; - let mut ecx = actual.ecx; - let mut edx = actual.edx; - // I would have made type safe bindings for this but then I saw how many fields there where... - - // Disable MTRR - edx &= !(1 << 12); - - // Disable XSAVE - ecx &= !(1 << 26); - - // Hide hypervisor feature - ecx &= !(1 << 31); - CpuIdResult{ - eax, - ebx, - ecx, - edx - } - } + CPUID_NAME => cpuid_name(vcpu, actual), + CPUID_MODEL_FAMILY_STEPPING => cpuid_model_family_stepping(actual) INTEL_CORE_CACHE_TOPOLOGY => { let core_cpus = vcpu.vm.read().config.cpus(); @@ -103,7 +60,71 @@ fn get_cpu_id_result(vcpu: &vcpu::VCpu, eax_in: u32, ecx_in: u32) -> CpuIdResult } } -fn cpuid_name(vcpu: &VCpu, actual: &mut CpuIdResult) -> CpuIdResult { +bitfield! { + pub struct IntelTypeFamilyModelSteppingIDEaxRes(u32); + impl Debug; + stepping_id, _: 3,0; + model,_:7,4; + family_id,_:11,8; + processor_type,_:13,12; + extended_model_id,_:19,16; + extended_family_id,_:27,20; +} + +bitfield! { + pub struct BrandCFlushMaxIDsInitialAPIC(u32); + impl Debug; + brand_idx, _: 7,0; + cflush,_:15,8; + max_processor_ids,_:23,16; + apic_id,_:31,24; +} + +bitfield! { + pub struct FeatureInformationECX(u32); + //there are a lot of features here, so only add the ones we care about for now. + xsave, _: 27,26; + hypervissor, _: 32,31; +} + +bitfield! { + pub struct FeatureInformationEDX(u32); + //there are a lot of features here, so only add the ones we care about for now. + mtrr, _: 13,12; +} + +fn cpuid_model_family_stepping(actual: CpuIdResult) -> CpuIdResult { + let family_model_stepping = IntelTypeFamilyModelSteppingIDEaxRes(actual.eax); + //we can change family_model_stepping, but for now just use actual. + let eax = family_model_stepping.0; + let mut brand_cflush_max_initial = BrandCFlushMaxIDsInitialAPIC(actual.ebx); + brand_cflush_max_initial.set_apic_id(todo!("Waiting on virtual APICs")); + brand_cflush_max_initial.set_max_processor_ids(todo!("Waiting on virtual APICs")); + let ebx = brand_cflush_max_initial.0; + let mut features_ecx = FeatureInformationECX(actual.ecx); + let mut features_edx = FeatureInformationEDX(actual.edx); + // I would have made type safe bindings for this but then I saw how many fields there where... + + // Disable MTRR + features_edx.set_mtrr(0); + + // Disable XSAVE + // ecx &= !(1 << 26); + features_ecx.set_xsave(0); + + // Hide hypervisor feature + features_ecx.set_hypervisor(0); + let ecx = features_ecx.0; + let edx = features_edx.0; + CpuIdResult { + eax, + ebx, + ecx, + edx + } +} + +fn cpuid_name(vcpu: &VCpu, actual: CpuIdResult) -> CpuIdResult { if vcpu.vm.read().config.override_cpu_name() { let cpu_name = "MythrilCPU__"; let bytes = cpu_name.chars().map(|char| char as u8).collect::>(); diff --git a/mythril/src/vcpu.rs b/mythril/src/vcpu.rs index cc89816..e60f4ad 100644 --- a/mythril/src/vcpu.rs +++ b/mythril/src/vcpu.rs @@ -104,6 +104,7 @@ pub struct VCpu { pub local_apic: virtdev::lapic::LocalApic, pending_interrupts: BTreeMap, stack: &'static mut [u8; PER_CORE_HOST_STACK_SIZE], + vcpu_apic_id: usize } impl VCpu { From 86e1d748d68e96266d8ad035523a0c2f13198d9d Mon Sep 17 00:00:00 2001 From: Francis Nixon Date: Fri, 18 Dec 2020 16:17:14 -0500 Subject: [PATCH 05/14] add some more leaves. Likely done with this issue for now until APIC works. --- mythril/src/emulate/cpuid.rs | 96 +++++++++++++++++++++++++++++------- 1 file changed, 77 insertions(+), 19 deletions(-) diff --git a/mythril/src/emulate/cpuid.rs b/mythril/src/emulate/cpuid.rs index 1156337..20eaccf 100644 --- a/mythril/src/emulate/cpuid.rs +++ b/mythril/src/emulate/cpuid.rs @@ -7,27 +7,25 @@ use bitfield::bitfield; use crate::apic::get_local_apic; use crate::vcpu::VCpu; -//Used https://c9x.me/x86/html/file_module_x86_id_45.html as guid for implementing this. const CPUID_NAME: u32 = 0; const CPUID_MODEL_FAMILY_STEPPING: u32 = 1; const CPUID_CACHE_TLB_INFO: u32 = 2; const INTEL_CORE_CACHE_TOPOLOGY: u32 = 4; +const THERMAL_AND_POWER_MANAGEMENT: u32 = 6; +const STRUCTURED_EXTENDED_FEATURE_FLAGS: u32 = 7; +const ARCHITECTURAL_PERFORMANCE: u32 = 0xA; +const EXTENDED_TOPOLOGY_ENUMERATION: u32 = 0xB; +const PROCESSOR_EXTENDED_STATE_ENUMERATION: u32 = 0xD; +const V2_EXTENDED_TOPOLOGY_ENUMERATION: u32 = 0x1F; +const EXTENDED_FUNCTION_CPUID_INFORMATION: u32 = 0x80000000; const CPUID_BRAND_STRING_1: u32 = 0x80000002; const CPUID_BRAND_STRING_2: u32 = 0x80000003; const CPUID_BRAND_STRING_3: u32 = 0x80000004; -const MAX_CPUID_INPUT: u32 = 0x80000004; +const MAX_CPUID_INPUT: u32 = 0x80000008; //todo //CPUID leaves above 2 and below 80000000H are visible only when // // IA32_MISC_ENABLE[bit 22] has its default value of 0. -// -// bitfield! { -// pub struct IntelCoreCacheTopologyEaxRes(u32) -// impl Debug; -// impl Copy; -// -// } - @@ -42,13 +40,43 @@ fn get_cpu_id_result(vcpu: &vcpu::VCpu, eax_in: u32, ecx_in: u32) -> CpuIdResult match eax_in { CPUID_NAME => cpuid_name(vcpu, actual), - CPUID_MODEL_FAMILY_STEPPING => cpuid_model_family_stepping(actual) - INTEL_CORE_CACHE_TOPOLOGY => { - let core_cpus = vcpu.vm.read().config.cpus(); - - todo!() + CPUID_MODEL_FAMILY_STEPPING => cpuid_model_family_stepping(actual), + INTEL_CORE_CACHE_TOPOLOGY => intel_cache_topo(actual), + THERMAL_AND_POWER_MANAGEMENT => { + todo!("Portions of this output are per core, but presumably we don't support this. Additionally there is stuff about APIC timers here, also unsure if supported.") + } + STRUCTURED_EXTENDED_FEATURE_FLAGS => { + // nothing here seems to suspicious so just return actual: + actual + } + ARCHITECTURAL_PERFORMANCE => { + // For now I assume performance counters are unsupported, but if one wanted + // to support performance counters this would need to be handled here, and other places + actual + } + EXTENDED_TOPOLOGY_ENUMERATION => { + todo!("This basically requires APIC stuff to be done.") } - CPUID_BRAND_STRING_1..=CPUID_BRAND_STRING_2 => { + PROCESSOR_EXTENDED_STATE_ENUMERATION => { + actual + } + // There are bunch more leaves after PROCESSOR_EXTENDED_STATE_ENUMERATION, however most of them seem unlikely to be used/ not relevant + V2_EXTENDED_TOPOLOGY_ENUMERATION => { + todo!("Requires APIC") + } + 0x40000000..=0x4FFFFFFF=> { + // these are software reserved. + actual + } + EXTENDED_FUNCTION_CPUID_INFORMATION => { + CpuIdResult{ + eax: MAX_CPUID_INPUT, + ebx: 0, + ecx: 0, + edx: 0 + } + } + CPUID_BRAND_STRING_1..=CPUID_BRAND_STRING_3 => { if vcpu.vm.read().config.override_cpu_name() { todo!("CPU Brand string not implemented yet") } actual } @@ -60,6 +88,33 @@ fn get_cpu_id_result(vcpu: &vcpu::VCpu, eax_in: u32, ecx_in: u32) -> CpuIdResult } } +bitfield! { + pub struct IntelCoreCacheTopologyEaxRes(u32); + impl Debug; + cache_type,_:4,0; + cache_level,_:7,5; + self_init_cache_level,_:8; + fully_associative,_:9; + max_addressable_ids_logical,_:14,25; + max_addressable_ids_physical,_:26,31; +} + + + +fn intel_cache_topo(mut actual: CpuIdResult) -> CpuIdResult { + let mut cache_topo_eax = IntelCoreCacheTopologyEaxRes(actual.eax); + cache_topo_eax.set_max_addressable_ids_logical(todo!("waiting on apics")); + cache_topo_eax.set_max_addressable_ids_physical(todo!("waiting on apics")); + let eax = cache_topo_eax.0; + CpuIdResult { + eax, + //no changes should be required for these: + ebx: actual.ebx, + ecx: actual.ecx, + edx: actual.edx + } +} + bitfield! { pub struct IntelTypeFamilyModelSteppingIDEaxRes(u32); impl Debug; @@ -82,15 +137,17 @@ bitfield! { bitfield! { pub struct FeatureInformationECX(u32); + impl Debug; //there are a lot of features here, so only add the ones we care about for now. - xsave, _: 27,26; - hypervissor, _: 32,31; + xsave, _: 26; + hypervissor, _: 31; } bitfield! { pub struct FeatureInformationEDX(u32); + impl Debug; //there are a lot of features here, so only add the ones we care about for now. - mtrr, _: 13,12; + mtrr, _: 12; } fn cpuid_model_family_stepping(actual: CpuIdResult) -> CpuIdResult { @@ -162,6 +219,7 @@ pub fn emulate_cpuid( res.edx = crate::percore::read_core_id().raw as u32; } + guest_cpu.rax = res.eax as u64 | (guest_cpu.rax & 0xffffffff00000000); guest_cpu.rbx = res.ebx as u64 | (guest_cpu.rbx & 0xffffffff00000000); guest_cpu.rcx = res.ecx as u64 | (guest_cpu.rcx & 0xffffffff00000000); From a956678e0557b4d7d1323845821d8a3ccc86cccd Mon Sep 17 00:00:00 2001 From: Francis Nixon Date: Fri, 18 Dec 2020 16:34:03 -0500 Subject: [PATCH 06/14] autoreformat. --- mythril/src/emulate/cpuid.rs | 54 +++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/mythril/src/emulate/cpuid.rs b/mythril/src/emulate/cpuid.rs index 20eaccf..d5dc2b0 100644 --- a/mythril/src/emulate/cpuid.rs +++ b/mythril/src/emulate/cpuid.rs @@ -1,11 +1,12 @@ +use crate::apic::get_local_apic; use crate::error::Result; +use crate::vcpu::VCpu; use crate::{vcpu, vmexit}; -use raw_cpuid::CpuIdResult; use arrayvec::ArrayVec; -use core::convert::TryInto; use bitfield::bitfield; -use crate::apic::get_local_apic; -use crate::vcpu::VCpu; +use bitflags::_core::num::flt2dec::to_shortest_exp_str; +use core::convert::TryInto; +use raw_cpuid::CpuIdResult; const CPUID_NAME: u32 = 0; const CPUID_MODEL_FAMILY_STEPPING: u32 = 1; @@ -25,13 +26,13 @@ const MAX_CPUID_INPUT: u32 = 0x80000008; //todo //CPUID leaves above 2 and below 80000000H are visible only when // // IA32_MISC_ENABLE[bit 22] has its default value of 0. - - - - -fn get_cpu_id_result(vcpu: &vcpu::VCpu, eax_in: u32, ecx_in: u32) -> CpuIdResult { - const NAME_CREATION_ERROR_MESSAGE: &'static str = "Somehow bytes was not actually a 12 element array"; - +fn get_cpu_id_result( + vcpu: &vcpu::VCpu, + eax_in: u32, + ecx_in: u32, +) -> CpuIdResult { + const NAME_CREATION_ERROR_MESSAGE: &'static str = + "Somehow bytes was not actually a 12 element array"; let mut actual = raw_cpuid::native_cpuid::cpuid_count( guest_cpu.rax as u32, @@ -99,8 +100,6 @@ bitfield! { max_addressable_ids_physical,_:26,31; } - - fn intel_cache_topo(mut actual: CpuIdResult) -> CpuIdResult { let mut cache_topo_eax = IntelCoreCacheTopologyEaxRes(actual.eax); cache_topo_eax.set_max_addressable_ids_logical(todo!("waiting on apics")); @@ -111,7 +110,7 @@ fn intel_cache_topo(mut actual: CpuIdResult) -> CpuIdResult { //no changes should be required for these: ebx: actual.ebx, ecx: actual.ecx, - edx: actual.edx + edx: actual.edx, } } @@ -151,12 +150,14 @@ bitfield! { } fn cpuid_model_family_stepping(actual: CpuIdResult) -> CpuIdResult { - let family_model_stepping = IntelTypeFamilyModelSteppingIDEaxRes(actual.eax); + let family_model_stepping = + IntelTypeFamilyModelSteppingIDEaxRes(actual.eax); //we can change family_model_stepping, but for now just use actual. let eax = family_model_stepping.0; let mut brand_cflush_max_initial = BrandCFlushMaxIDsInitialAPIC(actual.ebx); brand_cflush_max_initial.set_apic_id(todo!("Waiting on virtual APICs")); - brand_cflush_max_initial.set_max_processor_ids(todo!("Waiting on virtual APICs")); + brand_cflush_max_initial + .set_max_processor_ids(todo!("Waiting on virtual APICs")); let ebx = brand_cflush_max_initial.0; let mut features_ecx = FeatureInformationECX(actual.ecx); let mut features_edx = FeatureInformationEDX(actual.edx); @@ -173,21 +174,22 @@ fn cpuid_model_family_stepping(actual: CpuIdResult) -> CpuIdResult { features_ecx.set_hypervisor(0); let ecx = features_ecx.0; let edx = features_edx.0; - CpuIdResult { - eax, - ebx, - ecx, - edx - } + CpuIdResult { eax, ebx, ecx, edx } } fn cpuid_name(vcpu: &VCpu, actual: CpuIdResult) -> CpuIdResult { if vcpu.vm.read().config.override_cpu_name() { let cpu_name = "MythrilCPU__"; - let bytes = cpu_name.chars().map(|char| char as u8).collect::>(); - let first_bytes: [u8; 4] = bytes[0..4].try_into().expect(NAME_CREATION_ERROR_MESSAGE); - let second_bytes: [u8; 4] = bytes[4..8].try_into().expect(NAME_CREATION_ERROR_MESSAGE); - let third_bytes: [u8; 4] = bytes[8..12].try_into().expect(NAME_CREATION_ERROR_MESSAGE); + let bytes = cpu_name + .chars() + .map(|char| char as u8) + .collect::>(); + let first_bytes: [u8; 4] = + bytes[0..4].try_into().expect(NAME_CREATION_ERROR_MESSAGE); + let second_bytes: [u8; 4] = + bytes[4..8].try_into().expect(NAME_CREATION_ERROR_MESSAGE); + let third_bytes: [u8; 4] = + bytes[8..12].try_into().expect(NAME_CREATION_ERROR_MESSAGE); return CpuIdResult { eax: MAX_CPUID_INPUT, ebx: u32::from_le_bytes(first_bytes), From 908150932b04f4acbefc23666780184c4a1303c4 Mon Sep 17 00:00:00 2001 From: Francis Nixon Date: Fri, 22 Jan 2021 16:29:51 -0500 Subject: [PATCH 07/14] got compiling again, although with warnings. --- mythril/src/emulate/cpuid.rs | 43 ++++++++++++++++++------------------ mythril/src/vcpu.rs | 1 + 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/mythril/src/emulate/cpuid.rs b/mythril/src/emulate/cpuid.rs index d5dc2b0..0c49d76 100644 --- a/mythril/src/emulate/cpuid.rs +++ b/mythril/src/emulate/cpuid.rs @@ -1,10 +1,8 @@ -use crate::apic::get_local_apic; use crate::error::Result; use crate::vcpu::VCpu; use crate::{vcpu, vmexit}; use arrayvec::ArrayVec; use bitfield::bitfield; -use bitflags::_core::num::flt2dec::to_shortest_exp_str; use core::convert::TryInto; use raw_cpuid::CpuIdResult; @@ -26,17 +24,18 @@ const MAX_CPUID_INPUT: u32 = 0x80000008; //todo //CPUID leaves above 2 and below 80000000H are visible only when // // IA32_MISC_ENABLE[bit 22] has its default value of 0. +const NAME_CREATION_ERROR_MESSAGE: &'static str = + "Somehow bytes was not actually a 12 element array"; + fn get_cpu_id_result( vcpu: &vcpu::VCpu, eax_in: u32, ecx_in: u32, ) -> CpuIdResult { - const NAME_CREATION_ERROR_MESSAGE: &'static str = - "Somehow bytes was not actually a 12 element array"; let mut actual = raw_cpuid::native_cpuid::cpuid_count( - guest_cpu.rax as u32, - guest_cpu.rcx as u32, + eax_in, + ecx_in, ); match eax_in { @@ -78,7 +77,7 @@ fn get_cpu_id_result( } } CPUID_BRAND_STRING_1..=CPUID_BRAND_STRING_3 => { - if vcpu.vm.read().config.override_cpu_name() { todo!("CPU Brand string not implemented yet") } + if vcpu.vm.config.override_cpu_name() { todo!("CPU Brand string not implemented yet") } actual } _ => { @@ -92,12 +91,12 @@ fn get_cpu_id_result( bitfield! { pub struct IntelCoreCacheTopologyEaxRes(u32); impl Debug; - cache_type,_:4,0; - cache_level,_:7,5; - self_init_cache_level,_:8; - fully_associative,_:9; - max_addressable_ids_logical,_:14,25; - max_addressable_ids_physical,_:26,31; + cache_type,set_cache_type:4,0; + cache_level,set_cache_level:7,5; + self_init_cache_level,set_self_init_cache_level:8; + fully_associative,set_fully_associative:9; + max_addressable_ids_logical,set_max_addressable_ids_logical:14,25; + max_addressable_ids_physical,set_max_addressable_ids_physical:26,31; } fn intel_cache_topo(mut actual: CpuIdResult) -> CpuIdResult { @@ -130,23 +129,23 @@ bitfield! { impl Debug; brand_idx, _: 7,0; cflush,_:15,8; - max_processor_ids,_:23,16; - apic_id,_:31,24; + max_processor_ids,set_max_processor_ids:23,16; + apic_id, set_apic_id:31,24; } bitfield! { pub struct FeatureInformationECX(u32); impl Debug; //there are a lot of features here, so only add the ones we care about for now. - xsave, _: 26; - hypervissor, _: 31; + xsave, set_xsave: 26; + hypervisor, set_hypervisor: 31; } bitfield! { pub struct FeatureInformationEDX(u32); impl Debug; //there are a lot of features here, so only add the ones we care about for now. - mtrr, _: 12; + mtrr, set_mtrr: 12; } fn cpuid_model_family_stepping(actual: CpuIdResult) -> CpuIdResult { @@ -164,21 +163,21 @@ fn cpuid_model_family_stepping(actual: CpuIdResult) -> CpuIdResult { // I would have made type safe bindings for this but then I saw how many fields there where... // Disable MTRR - features_edx.set_mtrr(0); + features_edx.set_mtrr(false); // Disable XSAVE // ecx &= !(1 << 26); - features_ecx.set_xsave(0); + features_ecx.set_xsave(false); // Hide hypervisor feature - features_ecx.set_hypervisor(0); + features_ecx.set_hypervisor(false); let ecx = features_ecx.0; let edx = features_edx.0; CpuIdResult { eax, ebx, ecx, edx } } fn cpuid_name(vcpu: &VCpu, actual: CpuIdResult) -> CpuIdResult { - if vcpu.vm.read().config.override_cpu_name() { + if vcpu.vm.config.override_cpu_name() { let cpu_name = "MythrilCPU__"; let bytes = cpu_name .chars() diff --git a/mythril/src/vcpu.rs b/mythril/src/vcpu.rs index e60f4ad..6f49a4d 100644 --- a/mythril/src/vcpu.rs +++ b/mythril/src/vcpu.rs @@ -125,6 +125,7 @@ impl VCpu { local_apic: virtdev::lapic::LocalApic::new(), stack: get_per_core_mut!(HOST_STACK), pending_interrupts: BTreeMap::new(), + vcpu_apic_id: todo!() }; unsafe { From 01e0cc72486e1b361145d6f6d5b15eae62cbdc9f Mon Sep 17 00:00:00 2001 From: Francis Nixon Date: Fri, 22 Jan 2021 16:31:21 -0500 Subject: [PATCH 08/14] some reformatting and addressing warnings. --- mythril/src/emulate/cpuid.rs | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/mythril/src/emulate/cpuid.rs b/mythril/src/emulate/cpuid.rs index 0c49d76..e1f949e 100644 --- a/mythril/src/emulate/cpuid.rs +++ b/mythril/src/emulate/cpuid.rs @@ -32,11 +32,7 @@ fn get_cpu_id_result( eax_in: u32, ecx_in: u32, ) -> CpuIdResult { - - let mut actual = raw_cpuid::native_cpuid::cpuid_count( - eax_in, - ecx_in, - ); + let mut actual = raw_cpuid::native_cpuid::cpuid_count(eax_in, ecx_in); match eax_in { CPUID_NAME => cpuid_name(vcpu, actual), @@ -57,27 +53,25 @@ fn get_cpu_id_result( EXTENDED_TOPOLOGY_ENUMERATION => { todo!("This basically requires APIC stuff to be done.") } - PROCESSOR_EXTENDED_STATE_ENUMERATION => { - actual - } + PROCESSOR_EXTENDED_STATE_ENUMERATION => actual, // There are bunch more leaves after PROCESSOR_EXTENDED_STATE_ENUMERATION, however most of them seem unlikely to be used/ not relevant V2_EXTENDED_TOPOLOGY_ENUMERATION => { todo!("Requires APIC") } - 0x40000000..=0x4FFFFFFF=> { + 0x40000000..=0x4FFFFFFF => { // these are software reserved. actual } - EXTENDED_FUNCTION_CPUID_INFORMATION => { - CpuIdResult{ - eax: MAX_CPUID_INPUT, - ebx: 0, - ecx: 0, - edx: 0 - } - } + EXTENDED_FUNCTION_CPUID_INFORMATION => CpuIdResult { + eax: MAX_CPUID_INPUT, + ebx: 0, + ecx: 0, + edx: 0, + }, CPUID_BRAND_STRING_1..=CPUID_BRAND_STRING_3 => { - if vcpu.vm.config.override_cpu_name() { todo!("CPU Brand string not implemented yet") } + if vcpu.vm.config.override_cpu_name() { + todo!("CPU Brand string not implemented yet") + } actual } _ => { @@ -99,7 +93,7 @@ bitfield! { max_addressable_ids_physical,set_max_addressable_ids_physical:26,31; } -fn intel_cache_topo(mut actual: CpuIdResult) -> CpuIdResult { +fn intel_cache_topo(actual: CpuIdResult) -> CpuIdResult { let mut cache_topo_eax = IntelCoreCacheTopologyEaxRes(actual.eax); cache_topo_eax.set_max_addressable_ids_logical(todo!("waiting on apics")); cache_topo_eax.set_max_addressable_ids_physical(todo!("waiting on apics")); @@ -210,7 +204,6 @@ pub fn emulate_cpuid( //todo move this into get_cpu_id_result if guest_cpu.rax as u32 == 1 { - // Hide hypervisor feature res.ecx &= !(1 << 31); @@ -220,7 +213,6 @@ pub fn emulate_cpuid( res.edx = crate::percore::read_core_id().raw as u32; } - guest_cpu.rax = res.eax as u64 | (guest_cpu.rax & 0xffffffff00000000); guest_cpu.rbx = res.ebx as u64 | (guest_cpu.rbx & 0xffffffff00000000); guest_cpu.rcx = res.ecx as u64 | (guest_cpu.rcx & 0xffffffff00000000); From 7576f9f6c1ca17426d0497ebfd1882fdce31c220 Mon Sep 17 00:00:00 2001 From: Francis Nixon Date: Fri, 18 Dec 2020 10:51:55 -0500 Subject: [PATCH 09/14] a sort of initial skeleton for cpuid. --- mythril/src/emulate/cpuid.rs | 27 ------------------------ mythril/src/vm.rs | 41 ++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 27 deletions(-) diff --git a/mythril/src/emulate/cpuid.rs b/mythril/src/emulate/cpuid.rs index e1f949e..622fd6f 100644 --- a/mythril/src/emulate/cpuid.rs +++ b/mythril/src/emulate/cpuid.rs @@ -192,30 +192,3 @@ fn cpuid_name(vcpu: &VCpu, actual: CpuIdResult) -> CpuIdResult { } actual } - -pub fn emulate_cpuid( - vcpu: &mut vcpu::VCpu, - guest_cpu: &mut vmexit::GuestCpuState, -) -> Result<()> { - let eax = guest_cpu.rax as u32; - - let ecx = guest_cpu.rcx as u32; - let mut res = get_cpu_id_result(vcpu, eax, ecx); - - //todo move this into get_cpu_id_result - if guest_cpu.rax as u32 == 1 { - // Hide hypervisor feature - res.ecx &= !(1 << 31); - - // Hide TSC deadline timer - res.ecx &= !(1 << 24); - } else if guest_cpu.rax as u32 == 0x0b { - res.edx = crate::percore::read_core_id().raw as u32; - } - - guest_cpu.rax = res.eax as u64 | (guest_cpu.rax & 0xffffffff00000000); - guest_cpu.rbx = res.ebx as u64 | (guest_cpu.rbx & 0xffffffff00000000); - guest_cpu.rcx = res.ecx as u64 | (guest_cpu.rcx & 0xffffffff00000000); - guest_cpu.rdx = res.edx as u64 | (guest_cpu.rdx & 0xffffffff00000000); - Ok(()) -} diff --git a/mythril/src/vm.rs b/mythril/src/vm.rs index 43831f5..c5c8bf0 100644 --- a/mythril/src/vm.rs +++ b/mythril/src/vm.rs @@ -349,6 +349,7 @@ pub struct HostPhysicalDevices { /// A configuration for a `VirtualMachine` pub struct VirtualMachineConfig { +<<<<<<< HEAD /// The cores assigned as part of this configuration pub cpus: ArrayVec<[percore::CoreId; MAX_PER_VM_CORE_COUNT]>, @@ -365,6 +366,13 @@ pub struct VirtualMachineConfig { /// The size of this machines physical address space in MiB pub memory: u64, +======= + cpus: ArrayVec<[percore::CoreId; MAX_PER_VM_CORE_COUNT]>, + images: Vec<(String, GuestPhysAddr)>, + virtual_devices: DeviceMap, + physical_devices: PhysicalDeviceConfig, + memory: u64, // in MB +>>>>>>> a sort of initial skeleton for cpuid. override_cpu_name: bool } @@ -404,6 +412,39 @@ impl VirtualMachineConfig { self.images.push((image, addr)); Ok(()) } +<<<<<<< HEAD +======= + + /// Access the configurations virtual `DeviceMap` + pub fn virtual_devices(&self) -> &DeviceMap { + &self.virtual_devices + } + + /// Access the configurations virtual `DeviceMap` mutably + pub fn virtual_devices_mut(&mut self) -> &mut DeviceMap { + &mut self.virtual_devices + } + + /// Access the configurations physical hardware + pub fn physical_devices(&self) -> &PhysicalDeviceConfig { + &self.physical_devices + } + + /// Get the list of CoreIds assicated with this VM + pub fn cpus(&self) -> &ArrayVec<[percore::CoreId; MAX_PER_VM_CORE_COUNT]> { + &self.cpus + } + + /// Get the CoreId of the BSP for this VM + pub fn bsp_id(&self) -> percore::CoreId { + self.cpus[0] + } + + + pub fn override_cpu_name(&self) -> bool { + self.override_cpu_name + } +>>>>>>> a sort of initial skeleton for cpuid. } /// A virtual machine From 6ed3eb91acaeab76734f8c119e04bc50e32c0c3c Mon Sep 17 00:00:00 2001 From: Francis Nixon Date: Fri, 18 Dec 2020 13:08:39 -0500 Subject: [PATCH 10/14] got some basic cpuid stuff working. --- mythril/src/vm.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/mythril/src/vm.rs b/mythril/src/vm.rs index c5c8bf0..4ad54eb 100644 --- a/mythril/src/vm.rs +++ b/mythril/src/vm.rs @@ -349,7 +349,6 @@ pub struct HostPhysicalDevices { /// A configuration for a `VirtualMachine` pub struct VirtualMachineConfig { -<<<<<<< HEAD /// The cores assigned as part of this configuration pub cpus: ArrayVec<[percore::CoreId; MAX_PER_VM_CORE_COUNT]>, @@ -366,13 +365,6 @@ pub struct VirtualMachineConfig { /// The size of this machines physical address space in MiB pub memory: u64, -======= - cpus: ArrayVec<[percore::CoreId; MAX_PER_VM_CORE_COUNT]>, - images: Vec<(String, GuestPhysAddr)>, - virtual_devices: DeviceMap, - physical_devices: PhysicalDeviceConfig, - memory: u64, // in MB ->>>>>>> a sort of initial skeleton for cpuid. override_cpu_name: bool } From 09ca13e8d60d47df4bcf14ea2797ba5bb10fea7c Mon Sep 17 00:00:00 2001 From: Francis Nixon Date: Fri, 18 Dec 2020 14:03:01 -0500 Subject: [PATCH 11/14] handle CPUID_MODEL_FAMILY_STEPPING --- mythril/src/emulate/cpuid.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mythril/src/emulate/cpuid.rs b/mythril/src/emulate/cpuid.rs index 622fd6f..96ce259 100644 --- a/mythril/src/emulate/cpuid.rs +++ b/mythril/src/emulate/cpuid.rs @@ -3,8 +3,13 @@ use crate::vcpu::VCpu; use crate::{vcpu, vmexit}; use arrayvec::ArrayVec; use bitfield::bitfield; +<<<<<<< HEAD use core::convert::TryInto; use raw_cpuid::CpuIdResult; +======= +use bitflags::_core::num::flt2dec::to_shortest_exp_str; +use crate::apic::get_local_apic; +>>>>>>> handle CPUID_MODEL_FAMILY_STEPPING const CPUID_NAME: u32 = 0; const CPUID_MODEL_FAMILY_STEPPING: u32 = 1; From 96b40297533ddf57e99676d70eeda10e51c5ab6e Mon Sep 17 00:00:00 2001 From: Francis Nixon Date: Fri, 18 Dec 2020 15:19:19 -0500 Subject: [PATCH 12/14] refactored cpuid_model_family_stepping --- mythril/src/emulate/cpuid.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/mythril/src/emulate/cpuid.rs b/mythril/src/emulate/cpuid.rs index 96ce259..bab7bda 100644 --- a/mythril/src/emulate/cpuid.rs +++ b/mythril/src/emulate/cpuid.rs @@ -3,13 +3,10 @@ use crate::vcpu::VCpu; use crate::{vcpu, vmexit}; use arrayvec::ArrayVec; use bitfield::bitfield; -<<<<<<< HEAD use core::convert::TryInto; use raw_cpuid::CpuIdResult; -======= use bitflags::_core::num::flt2dec::to_shortest_exp_str; use crate::apic::get_local_apic; ->>>>>>> handle CPUID_MODEL_FAMILY_STEPPING const CPUID_NAME: u32 = 0; const CPUID_MODEL_FAMILY_STEPPING: u32 = 1; From 4c1a6efbd75570642d99fbe048722fd95defb43f Mon Sep 17 00:00:00 2001 From: Francis Nixon Date: Fri, 18 Dec 2020 16:34:03 -0500 Subject: [PATCH 13/14] autoreformat. --- mythril/src/vm.rs | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/mythril/src/vm.rs b/mythril/src/vm.rs index 4ad54eb..43831f5 100644 --- a/mythril/src/vm.rs +++ b/mythril/src/vm.rs @@ -404,39 +404,6 @@ impl VirtualMachineConfig { self.images.push((image, addr)); Ok(()) } -<<<<<<< HEAD -======= - - /// Access the configurations virtual `DeviceMap` - pub fn virtual_devices(&self) -> &DeviceMap { - &self.virtual_devices - } - - /// Access the configurations virtual `DeviceMap` mutably - pub fn virtual_devices_mut(&mut self) -> &mut DeviceMap { - &mut self.virtual_devices - } - - /// Access the configurations physical hardware - pub fn physical_devices(&self) -> &PhysicalDeviceConfig { - &self.physical_devices - } - - /// Get the list of CoreIds assicated with this VM - pub fn cpus(&self) -> &ArrayVec<[percore::CoreId; MAX_PER_VM_CORE_COUNT]> { - &self.cpus - } - - /// Get the CoreId of the BSP for this VM - pub fn bsp_id(&self) -> percore::CoreId { - self.cpus[0] - } - - - pub fn override_cpu_name(&self) -> bool { - self.override_cpu_name - } ->>>>>>> a sort of initial skeleton for cpuid. } /// A virtual machine From afe24144718f30796479467caf9abd17ad28e416 Mon Sep 17 00:00:00 2001 From: Francis Nixon Date: Fri, 26 Feb 2021 15:12:55 -0500 Subject: [PATCH 14/14] have a cpu apic id for each vcpu. --- .mythril_githooks/pre-commit | 13 ------------- mythril/src/emulate/cpuid.rs | 31 +++++++++++++++++++++++-------- mythril/src/vcpu.rs | 8 ++++---- mythril/src/virtdev/lapic.rs | 29 ++++++++++++++++++++++------- mythril/src/vm.rs | 11 +++++++++-- 5 files changed, 58 insertions(+), 34 deletions(-) delete mode 100755 .mythril_githooks/pre-commit diff --git a/.mythril_githooks/pre-commit b/.mythril_githooks/pre-commit deleted file mode 100755 index 63060eb..0000000 --- a/.mythril_githooks/pre-commit +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -diff=$(make check-fmt) -result=$? - -if [[ ${result} -ne 0 ]] ; then - cat <<\EOF -There are some code style issues, run `cargo fmt` first. -EOF - exit 1 -fi - -exit 0 diff --git a/mythril/src/emulate/cpuid.rs b/mythril/src/emulate/cpuid.rs index bab7bda..ee63041 100644 --- a/mythril/src/emulate/cpuid.rs +++ b/mythril/src/emulate/cpuid.rs @@ -5,8 +5,6 @@ use arrayvec::ArrayVec; use bitfield::bitfield; use core::convert::TryInto; use raw_cpuid::CpuIdResult; -use bitflags::_core::num::flt2dec::to_shortest_exp_str; -use crate::apic::get_local_apic; const CPUID_NAME: u32 = 0; const CPUID_MODEL_FAMILY_STEPPING: u32 = 1; @@ -41,7 +39,10 @@ fn get_cpu_id_result( CPUID_MODEL_FAMILY_STEPPING => cpuid_model_family_stepping(actual), INTEL_CORE_CACHE_TOPOLOGY => intel_cache_topo(actual), THERMAL_AND_POWER_MANAGEMENT => { - todo!("Portions of this output are per core, but presumably we don't support this. Additionally there is stuff about APIC timers here, also unsure if supported.") + todo!("Portions of this output are per core, but presumably we don't support thermal and power management.\ + Additionally there is stuff about APIC timers here, also unsure if supported.\ + Need reasonable defaults probably though\ + ") } STRUCTURED_EXTENDED_FEATURE_FLAGS => { // nothing here seems to suspicious so just return actual: @@ -71,15 +72,13 @@ fn get_cpu_id_result( edx: 0, }, CPUID_BRAND_STRING_1..=CPUID_BRAND_STRING_3 => { - if vcpu.vm.config.override_cpu_name() { + if vcpu.vm.override_cpu_name { todo!("CPU Brand string not implemented yet") } actual } _ => { - //TODO for code review. Idk how I feel about silently fallingback on real cpuid here. - // I would perhaps prefer to put a todo!() and explicitly implement stuff. - actual + unimplemented!("Unimplemented CPUID value: {:?}", actual); } } } @@ -173,7 +172,7 @@ fn cpuid_model_family_stepping(actual: CpuIdResult) -> CpuIdResult { } fn cpuid_name(vcpu: &VCpu, actual: CpuIdResult) -> CpuIdResult { - if vcpu.vm.config.override_cpu_name() { + if vcpu.vm.override_cpu_name { let cpu_name = "MythrilCPU__"; let bytes = cpu_name .chars() @@ -194,3 +193,19 @@ fn cpuid_name(vcpu: &VCpu, actual: CpuIdResult) -> CpuIdResult { } actual } + +pub fn emulate_cpuid(vcpu: &mut VCpu, guest_cpu: &mut vmexit::GuestCpuState) -> Result<()> { +//FIXME: for now just use the actual cpuid + let mut res = raw_cpuid::native_cpuid::cpuid_count( + guest_cpu.rax as u32, + guest_cpu.rcx as u32, + ); + + let res = get_cpu_id_result(vcpu, guest_cpu.rax as u32, guest_cpu.rcx as u32); + + guest_cpu.rax = res.eax as u64 | (guest_cpu.rax & 0xffffffff00000000); + guest_cpu.rbx = res.ebx as u64 | (guest_cpu.rbx & 0xffffffff00000000); + guest_cpu.rcx = res.ecx as u64 | (guest_cpu.rcx & 0xffffffff00000000); + guest_cpu.rdx = res.edx as u64 | (guest_cpu.rdx & 0xffffffff00000000); + Ok(()) +} diff --git a/mythril/src/vcpu.rs b/mythril/src/vcpu.rs index 6f49a4d..9413302 100644 --- a/mythril/src/vcpu.rs +++ b/mythril/src/vcpu.rs @@ -16,6 +16,7 @@ use core::mem; use core::pin::Pin; use x86::controlregs::{cr0, cr3, cr4}; use x86::msr; +use crate::virtdev::lapic::VirtualAPICID; extern "C" { pub fn vmlaunch_wrapper() -> u64; @@ -51,7 +52,7 @@ pub fn mp_entry_point() -> ! { vm }; - let mut vcpu = VCpu::new(vm).expect("Failed to create vcpu"); + let mut vcpu = VCpu::new(vm,VirtualAPICID(0)).expect("Failed to create vcpu"); let vm_id = vm.id; let is_vm_bsp = vm.bsp_id() == core_id; @@ -104,7 +105,6 @@ pub struct VCpu { pub local_apic: virtdev::lapic::LocalApic, pending_interrupts: BTreeMap, stack: &'static mut [u8; PER_CORE_HOST_STACK_SIZE], - vcpu_apic_id: usize } impl VCpu { @@ -115,6 +115,7 @@ impl VCpu { /// VMEXIT. pub fn new( vm: Pin<&'static VirtualMachine>, + virtual_apic_id: VirtualAPICID ) -> Result> { let vmx = vmx::Vmx::enable()?; let vmcs = vmcs::Vmcs::new()?.activate(vmx)?; @@ -122,10 +123,9 @@ impl VCpu { let vcpu = Self { vm: vm, vmcs: vmcs, - local_apic: virtdev::lapic::LocalApic::new(), + local_apic: virtdev::lapic::LocalApic::new(virtual_apic_id), stack: get_per_core_mut!(HOST_STACK), pending_interrupts: BTreeMap::new(), - vcpu_apic_id: todo!() }; unsafe { diff --git a/mythril/src/virtdev/lapic.rs b/mythril/src/virtdev/lapic.rs index d467d7f..8642fb8 100644 --- a/mythril/src/virtdev/lapic.rs +++ b/mythril/src/virtdev/lapic.rs @@ -95,7 +95,7 @@ impl TryFrom for ApicRegisterOffset { return Err(Error::InvalidValue(format!( "Invalid APIC register offset: 0x{:x}", offset - ))) + ))); } }; @@ -103,15 +103,30 @@ impl TryFrom for ApicRegisterOffset { } } -#[derive(Default)] +/// CPUID only returns APIC ID values up to 8 bits. +/// This does raise the question of what AMD are +/// going to do when they add more cores to threadripper. +/// And also what Xeon Phi does. +/// Apparently it does this: +/// "The local APIC registers have expanded fields for +/// the APIC ID, Logical APIC ID, and APIC Destination ID. " +/// https://www.intel.com/content/dam/www/public/us/en/ +/// documents/product-briefs/xeon-phi +/// -coprocessor-system-software-developers-guide.pdf +/// +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct VirtualAPICID(pub u8); + pub struct LocalApic { icr_destination: Option, + pub virtual_apic_id: VirtualAPICID, } impl LocalApic { - pub fn new() -> Self { + pub fn new(virtual_apic_id: VirtualAPICID) -> Self { LocalApic { icr_destination: None, + virtual_apic_id, } } @@ -167,9 +182,9 @@ impl LocalApic { if *core == percore::read_core_id() { continue; } - vm::virtual_machines().send_msg_core(vm::VirtualMachineMsg::GuestInterrupt{ + vm::virtual_machines().send_msg_core(vm::VirtualMachineMsg::GuestInterrupt { kind: crate::vcpu::InjectedInterruptType::ExternalInterrupt, - vector: vector as u8 + vector: vector as u8, }, *core, true)? } return Ok(()); @@ -190,9 +205,9 @@ impl LocalApic { if *core == percore::read_core_id() { continue; } - vm::virtual_machines().send_msg_core(vm::VirtualMachineMsg::GuestInterrupt{ + vm::virtual_machines().send_msg_core(vm::VirtualMachineMsg::GuestInterrupt { kind: crate::vcpu::InjectedInterruptType::ExternalInterrupt, - vector: vector as u8 + vector: vector as u8, }, *core, true)? } } diff --git a/mythril/src/vm.rs b/mythril/src/vm.rs index 43831f5..3515d4a 100644 --- a/mythril/src/vm.rs +++ b/mythril/src/vm.rs @@ -387,8 +387,8 @@ impl VirtualMachineConfig { images: ArrayVec::new(), virtual_devices: ArrayVec::new(), host_devices: physical_devices, - memory: memory, - override_cpu_name: todo!() + memory, + override_cpu_name: true }) } @@ -447,6 +447,12 @@ pub struct VirtualMachine { /// The number of vcpus that are up and waiting to start cpus_ready: AtomicU32, + + + /// Whether to display the cpu name as "Mythril CPU" in cpuid + pub override_cpu_name: bool + + } impl VirtualMachine { @@ -485,6 +491,7 @@ impl VirtualMachine { apic_access_page: Raw4kPage([0u8; 4096]), logical_apic_state: logical_apic_states, cpus_ready: AtomicU32::new(0), + override_cpu_name: config.override_cpu_name }) }