@@ -4,6 +4,8 @@ use raw_cpuid::CpuIdResult;
4
4
use arrayvec:: ArrayVec ;
5
5
use core:: convert:: TryInto ;
6
6
use bitfield:: bitfield;
7
+ use bitflags:: _core:: num:: flt2dec:: to_shortest_exp_str;
8
+ use crate :: apic:: get_local_apic;
7
9
8
10
//Used https://c9x.me/x86/html/file_module_x86_id_45.html as guid for implementing this.
9
11
const CPUID_NAME : u32 = 0 ;
@@ -37,27 +39,52 @@ bitfield! {
37
39
extended_family_id, _: 27 , 20 ;
38
40
}
39
41
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 {
41
53
const NAME_CREATION_ERROR_MESSAGE : & ' static str = "Somehow bytes was not actually a 12 element array" ;
42
54
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) ,
59
63
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...
60
73
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
+ }
61
88
}
62
89
INTEL_CORE_CACHE_TOPOLOGY => {
63
90
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
66
93
}
67
94
CPUID_BRAND_STRING_1 ..=CPUID_BRAND_STRING_2 => {
68
95
if vcpu. vm . read ( ) . config . override_cpu_name ( ) { todo ! ( "CPU Brand string not implemented yet" ) }
69
- return None ;
96
+ actual
70
97
}
71
98
_ => {
72
99
//TODO for code review. Idk how I feel about silently fallingback on real cpuid here.
73
100
// I would perhaps prefer to put a todo!() and explicitly implement stuff.
74
- return None ;
101
+ actual
75
102
}
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
78
121
}
79
122
80
123
pub fn emulate_cpuid (
@@ -83,22 +126,12 @@ pub fn emulate_cpuid(
83
126
) -> Result < ( ) > {
84
127
let eax = guest_cpu. rax as u32 ;
85
128
129
+ let ecx = guest_cpu. rcx as u32 ;
130
+ let mut res = get_cpu_id_result ( vcpu, eax, ecx) ;
86
131
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
93
133
if guest_cpu. rax as u32 == 1 {
94
- // Disable MTRR
95
- res. edx &= !( 1 << 12 ) ;
96
-
97
- // Disable XSAVE
98
- res. ecx &= !( 1 << 26 ) ;
99
134
100
- // Hide hypervisor feature
101
- res. ecx &= !( 1 << 31 ) ;
102
135
}
103
136
104
137
guest_cpu. rax = res. eax as u64 | ( guest_cpu. rax & 0xffffffff00000000 ) ;
0 commit comments