@@ -4,6 +4,8 @@ use raw_cpuid::CpuIdResult;
44use arrayvec:: ArrayVec ;
55use core:: convert:: TryInto ;
66use 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.
911const 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
80123pub 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 ) ;
0 commit comments