Skip to content

Commit a195a9e

Browse files
handle CPUID_MODEL_FAMILY_STEPPING
1 parent 764576b commit a195a9e

File tree

2 files changed

+68
-34
lines changed

2 files changed

+68
-34
lines changed

mythril/src/emulate/cpuid.rs

Lines changed: 67 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ use raw_cpuid::CpuIdResult;
44
use arrayvec::ArrayVec;
55
use core::convert::TryInto;
66
use bitfield::bitfield;
7+
use bitflags::_core::num::flt2dec::to_shortest_exp_str;
8+
use crate::apic::get_local_apic;
79

810
//Used https://c9x.me/x86/html/file_module_x86_id_45.html as guid for implementing this.
911
const CPUID_NAME: u32 = 0;
@@ -37,27 +39,52 @@ bitfield! {
3739
extended_family_id,_:27,20;
3840
}
3941

40-
fn get_cpu_id_result(vcpu: &vcpu::VCpu, eax: u32, ecx: u32) -> Option<CpuIdResult> {
42+
bitfield! {
43+
pub struct BrandCFlushMaxIDsInitialAPIC(u32);
44+
impl Debug;
45+
brand_idx, _: 7,0;
46+
cflush,_:15,8;
47+
max_processor_ids,_:23,16;
48+
apic_id,_:31,24;
49+
}
50+
51+
52+
fn get_cpu_id_result(vcpu: &vcpu::VCpu, eax_in: u32, ecx_in: u32) -> CpuIdResult {
4153
const NAME_CREATION_ERROR_MESSAGE: &'static str = "Somehow bytes was not actually a 12 element array";
4254

43-
match eax {
44-
CPUID_NAME => {
45-
if vcpu.vm.read().config.override_cpu_name() {
46-
let cpu_name = "MythrilCPU__";
47-
let bytes = cpu_name.chars().map(|char| char as u8).collect::<ArrayVec<[u8; 12]>>();
48-
let first_bytes: [u8; 4] = bytes[0..4].try_into().expect(NAME_CREATION_ERROR_MESSAGE);
49-
let second_bytes: [u8; 4] = bytes[4..8].try_into().expect(NAME_CREATION_ERROR_MESSAGE);
50-
let third_bytes: [u8; 4] = bytes[8..12].try_into().expect(NAME_CREATION_ERROR_MESSAGE);
51-
return Some(CpuIdResult {
52-
eax: MAX_CPUID_INPUT,
53-
ebx: u32::from_le_bytes(first_bytes),
54-
ecx: u32::from_le_bytes(second_bytes),
55-
edx: u32::from_le_bytes(third_bytes),
56-
});
57-
}
58-
}
55+
56+
let mut actual = raw_cpuid::native_cpuid::cpuid_count(
57+
guest_cpu.rax as u32,
58+
guest_cpu.rcx as u32,
59+
);
60+
61+
match eax_in {
62+
CPUID_NAME => cpuid_name(vcpu, &mut actual),
5963
CPUID_MODEL_FAMILY_STEPPING => {
64+
let family_model_stepping = IntelTypeFamilyModelSteppingIDEaxRes(actual.eax);
65+
//we can change family_model_stepping, but for now just use actual.
66+
let eax = family_model_stepping.0;
67+
let mut brand_cflush_max_initial = BrandCFlushMaxIDsInitialAPIC(actual.ebx);
68+
brand_cflush_max_initial.set_apic_id(get_local_apic().id());//in principle this is redundant
69+
let ebx = brand_cflush_max_initial.0;
70+
let mut ecx = actual.ecx;
71+
let mut edx = actual.edx;
72+
// I would have made type safe bindings for this but then I saw how many fields there where...
6073

74+
// Disable MTRR
75+
edx &= !(1 << 12);
76+
77+
// Disable XSAVE
78+
ecx &= !(1 << 26);
79+
80+
// Hide hypervisor feature
81+
ecx &= !(1 << 31);
82+
CpuIdResult{
83+
eax,
84+
ebx,
85+
ecx,
86+
edx
87+
}
6188
}
6289
INTEL_CORE_CACHE_TOPOLOGY => {
6390
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<CpuIdResul
6693
}
6794
CPUID_BRAND_STRING_1..=CPUID_BRAND_STRING_2 => {
6895
if vcpu.vm.read().config.override_cpu_name() { todo!("CPU Brand string not implemented yet") }
69-
return None;
96+
actual
7097
}
7198
_ => {
7299
//TODO for code review. Idk how I feel about silently fallingback on real cpuid here.
73100
// I would perhaps prefer to put a todo!() and explicitly implement stuff.
74-
return None;
101+
actual
75102
}
76-
};
77-
panic!()
103+
}
104+
}
105+
106+
fn cpuid_name(vcpu: &VCpu, actual: &mut CpuIdResult) -> CpuIdResult {
107+
if vcpu.vm.read().config.override_cpu_name() {
108+
let cpu_name = "MythrilCPU__";
109+
let bytes = cpu_name.chars().map(|char| char as u8).collect::<ArrayVec<[u8; 12]>>();
110+
let first_bytes: [u8; 4] = bytes[0..4].try_into().expect(NAME_CREATION_ERROR_MESSAGE);
111+
let second_bytes: [u8; 4] = bytes[4..8].try_into().expect(NAME_CREATION_ERROR_MESSAGE);
112+
let third_bytes: [u8; 4] = bytes[8..12].try_into().expect(NAME_CREATION_ERROR_MESSAGE);
113+
return CpuIdResult {
114+
eax: MAX_CPUID_INPUT,
115+
ebx: u32::from_le_bytes(first_bytes),
116+
ecx: u32::from_le_bytes(second_bytes),
117+
edx: u32::from_le_bytes(third_bytes),
118+
};
119+
}
120+
actual
78121
}
79122

80123
pub fn emulate_cpuid(
@@ -83,22 +126,12 @@ pub fn emulate_cpuid(
83126
) -> Result<()> {
84127
let eax = guest_cpu.rax as u32;
85128

129+
let ecx = guest_cpu.rcx as u32;
130+
let mut res = get_cpu_id_result(vcpu, eax, ecx);
86131

87-
//FIXME: for now just use the actual cpuid
88-
let mut res = raw_cpuid::native_cpuid::cpuid_count(
89-
guest_cpu.rax as u32,
90-
guest_cpu.rcx as u32,
91-
);
92-
132+
//todo move this into get_cpu_id_result
93133
if guest_cpu.rax as u32 == 1 {
94-
// Disable MTRR
95-
res.edx &= !(1 << 12);
96-
97-
// Disable XSAVE
98-
res.ecx &= !(1 << 26);
99134

100-
// Hide hypervisor feature
101-
res.ecx &= !(1 << 31);
102135
}
103136

104137
guest_cpu.rax = res.eax as u64 | (guest_cpu.rax & 0xffffffff00000000);

mythril/src/vcpu.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ pub struct VCpu {
6767
pub vmcs: vmcs::ActiveVmcs,
6868
pending_interrupts: BTreeMap<u8, InjectedInterruptType>,
6969
stack: Vec<u8>,
70+
vcpu_apic
7071
}
7172

7273
impl VCpu {

0 commit comments

Comments
 (0)