VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMRC/CPUMRCPatchHlp.asm@ 62145

Last change on this file since 62145 was 61776, checked in by vboxsync, 9 years ago

CPUM,APIC: Per-CPU APIC CPUID feature bit and MSR_IA32_APICBASE GP mask adjustments.

  • Changed the PDMAPICHLPR3::pfnChangeFeature to pfnSetFeatureLevel, removing the RC and R0 versions.
  • Only use pfnSetFeatureLevel from the APIC constructor to communicate to CPUM the max APIC feature level, not to globally flip CPUID[1].EDX[9].
  • Renamed APIC enmOriginalMode to enmMaxMode, changing the type of it and the corresponding config values to PDMAPICMODE. This makes the above simpler and eliminates two conversion functions. It also makes APICMODE private to the APIC again.
  • Introduced CPUMSetGuestCpuIdPerCpuApicFeature for the per-CPU APIC feature bit management.
  • Introduced CPUMCPUIDLEAF_F_CONTAINS_APIC which works same as CPUMCPUIDLEAF_F_CONTAINS_OSXSAVE and CPUMCPUIDLEAF_F_CONTAINS_APIC_ID. Updated existing CPU profiles with this.
  • Made the patch manager helper function actually handle CPUMCPUIDLEAF_F_CONTAINS_APIC and CPUMCPUIDLEAF_F_CONTAINS_OSXSAVE (the latter previously relied on CPUMSetGuestCpuIdFeature/CPUMClearGuestCpuIdFeature from CPUMSetGuestCR4).
  • Pushed CPUMSetGuestCpuIdFeature, CPUMGetGuestCpuIdFeature and CPUMClearGuestCpuIdFeature down to ring-3 only (now CPUMR3*). The latter two function are deprecated.
  • Added call to CPUMSetGuestCpuIdPerCpuApicFeature from load function just in case the APIC is disabled by the guest at the time of saving.
  • CPUMSetGuestCpuIdFeature ensures we've got a MSR_IA32_APICBASE register when enabling the APIC.
  • CPUMSetGuestCpuIdFeature adjust the MSR_IA32_APICBASE GP mask when enabling x2APIC so setting MSR_IA32_APICBASE_EXTD does not trap.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.2 KB
Line 
1; $Id: CPUMRCPatchHlp.asm 61776 2016-06-20 23:25:06Z vboxsync $
2;; @file
3; CPUM - Patch Helpers.
4;
5
6; Copyright (C) 2015 Oracle Corporation
7;
8; This file is part of VirtualBox Open Source Edition (OSE), as
9; available from http://www.virtualbox.org. This file is free software;
10; you can redistribute it and/or modify it under the terms of the GNU
11; General Public License (GPL) as published by the Free Software
12; Foundation, in version 2 as it comes in the "COPYING" file of the
13; VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15;
16
17
18;*******************************************************************************
19;* Header Files *
20;*******************************************************************************
21%include "VBox/asmdefs.mac"
22%include "VBox/vmm/cpum.mac"
23%include "CPUMInternal.mac"
24%include "VBox/vmm/vm.mac"
25%include "VMMRC.mac"
26%include "iprt/x86.mac"
27
28
29;*******************************************************************************
30;* External Symbols *
31;*******************************************************************************
32extern IMPNAME(g_VM)
33
34
35BEGIN_PATCH_HLP_SEG
36
37;;
38; Helper for PATMCpuidReplacement.
39;
40; We have at most 32 bytes of stack to play with, .
41;
42; @input eax, ecx(, edx, ebx)
43; @output eax, ebx, ecx, ebx
44;
45; @uses eflags (caller saves them)
46;
47BEGINPROC_EXPORTED CPUMPatchHlpCpuId
48 ; Save the registers we use for passthru and sub-leaf matching (eax is not used).
49 push edx
50 push ecx
51 push ebx
52
53 ; Use edi as VM pointer.
54 push edi
55 mov edi, IMP_SEG(ss, g_VM)
56
57%define CPUMCPUIDLEAF_SIZE_LOG2 5 ; ASSUMES CPUMCPUIDLEAF_size == 32
58
59 ;
60 ; Perform a binary search looking for leaf with the EAX value.
61 ;
62 mov edx, [ss:edi + VM.cpum + CPUM.GuestInfo + CPUMINFO.cCpuIdLeaves]
63 mov ecx, [ss:edi + VM.cpum + CPUM.GuestInfo + CPUMINFO.paCpuIdLeavesRC]
64 test edx, edx
65 jz cpuid_unknown
66 shl edx, CPUMCPUIDLEAF_SIZE_LOG2
67 add edx, ecx ; edx = end (exclusive); ecx = start.
68
69cpuid_lookup_leaf:
70 ; Find the middle element
71 mov ebx, edx
72cpuid_lookup_leaf_ebx_loaded:
73 sub ebx, ecx
74 shr ebx, 1 + CPUMCPUIDLEAF_SIZE_LOG2
75 shl ebx, CPUMCPUIDLEAF_SIZE_LOG2
76 add ebx, ecx ; ebx = middle element.
77
78 ; Compare.
79 cmp eax, [ss:ebx + CPUMCPUIDLEAF.uLeaf]
80 jae cpuid_lookup_split_up
81
82 ; The leaf is before ebx.
83cpuid_lookup_split_down:
84 cmp ecx, ebx ; start == middle? if so, we failed.
85 mov edx, ebx ; end = middle;
86 jne cpuid_lookup_leaf_ebx_loaded
87 jmp cpuid_unknown
88
89 ; The leaf is at or after ebx.
90cpuid_lookup_split_up:
91 je cpuid_match_eax
92 lea ecx, [ebx + CPUMCPUIDLEAF_size] ; start = middle + 1
93 cmp ecx, edx ; middle + 1 == start? if so, we failed.
94 jne cpuid_lookup_leaf
95 jmp cpuid_unknown
96
97 ;
98 ; We've to a matching leaf, does the sub-leaf match too?
99 ;
100cpuid_match_eax:
101 mov ecx, [esp + 4]
102 and ecx, [ss:ebx + CPUMCPUIDLEAF.fSubLeafMask]
103 cmp ecx, [ss:ebx + CPUMCPUIDLEAF.uSubLeaf]
104 je cpuid_fetch
105 ja cpuid_lookup_subleaf_forwards
106
107 ;
108 ; Search backwards.
109 ;
110cpuid_lookup_subleaf_backwards:
111 mov edx, [ss:edi + VM.cpum + CPUM.GuestInfo + CPUMINFO.paCpuIdLeavesRC] ; edx = first leaf
112
113cpuid_lookup_subleaf_backwards_loop:
114 cmp ebx, edx ; Is there a leaf before the current?
115 jbe cpuid_subleaf_not_found ; If not we're out of luck.
116 cmp eax, [ss:ebx - CPUMCPUIDLEAF_size + CPUMCPUIDLEAF.uLeaf]
117 jne cpuid_subleaf_not_found ; If the leaf before us does not have the same leaf number, we failed.
118 sub ebx, CPUMCPUIDLEAF_size
119 cmp ecx, [ss:ebx + CPUMCPUIDLEAF.uSubLeaf]
120 je cpuid_fetch ; If the subleaf matches, we're good!.
121 jb cpuid_lookup_subleaf_backwards_loop ; Still hope if the subleaf we're seeking is smaller.
122 jmp cpuid_subleaf_not_found ; Too bad.
123
124 ;
125 ; Search forward until we've got a matching sub-leaf (or not).
126 ;
127cpuid_lookup_subleaf_forwards:
128 ; Calculate the last leaf address.
129 mov edx, [ss:edi + VM.cpum + CPUM.GuestInfo + CPUMINFO.cCpuIdLeaves]
130 dec edx
131 shl edx, CPUMCPUIDLEAF_SIZE_LOG2
132 add edx, [ss:edi + VM.cpum + CPUM.GuestInfo + CPUMINFO.paCpuIdLeavesRC] ; edx = last leaf (inclusive)
133
134cpuid_subleaf_lookup:
135 cmp ebx, edx
136 jae cpuid_subleaf_not_found
137 cmp eax, [ss:ebx + CPUMCPUIDLEAF_size + CPUMCPUIDLEAF.uLeaf]
138 jne cpuid_subleaf_not_found
139 add ebx, CPUMCPUIDLEAF_size
140 cmp ecx, [ss:ebx + CPUMCPUIDLEAF.uSubLeaf]
141 ja cpuid_subleaf_lookup
142 je cpuid_fetch
143
144 ;
145 ; Out of range sub-leaves aren't quite as easy and pretty as we emulate them
146 ; here, but we do an adequate job.
147 ;
148cpuid_subleaf_not_found:
149 xor ecx, ecx
150 test dword [ss:ebx + CPUMCPUIDLEAF.fFlags], CPUMCPUIDLEAF_F_INTEL_TOPOLOGY_SUBLEAVES
151 jz cpuid_load_zeros_except_ecx
152 mov ecx, [esp + 4]
153 and ecx, 0ffh
154cpuid_load_zeros_except_ecx:
155 xor edx, edx
156 xor eax, eax
157 xor ebx, ebx
158 jmp cpuid_done
159
160 ;
161 ; Different CPUs have different ways of dealing with unknown CPUID leaves.
162 ;
163cpuid_unknown:
164 mov ebx, IMP_SEG(ss, g_VM)
165 mov dword [ss:edi + VM.cpum + CPUM.GuestInfo + CPUMINFO.enmUnknownCpuIdMethod], CPUMUNKNOWNCPUID_PASSTHRU
166 je cpuid_unknown_passthru
167 ; Load the default cpuid leaf.
168cpuid_unknown_def_leaf:
169 mov edx, [ss:edi + VM.cpum + CPUM.GuestInfo + CPUMINFO.DefCpuId + CPUMCPUID.uEdx]
170 mov ecx, [ss:edi + VM.cpum + CPUM.GuestInfo + CPUMINFO.DefCpuId + CPUMCPUID.uEcx]
171 mov eax, [ss:edi + VM.cpum + CPUM.GuestInfo + CPUMINFO.DefCpuId + CPUMCPUID.uEax]
172 mov ebx, [ss:edi + VM.cpum + CPUM.GuestInfo + CPUMINFO.DefCpuId + CPUMCPUID.uEbx]
173 jmp cpuid_done
174 ; Pass thru the input values unmodified (eax is still virgin).
175cpuid_unknown_passthru:
176 mov edx, [esp + 8]
177 mov ecx, [esp + 4]
178 mov ebx, [esp]
179 jmp cpuid_done
180
181 ;
182 ; Normal return unless flags (we ignore APIC_ID as we only have a single CPU with ID 0).
183 ;
184cpuid_fetch:
185 test dword [ss:ebx + CPUMCPUIDLEAF.fFlags], CPUMCPUIDLEAF_F_CONTAINS_APIC | CPUMCPUIDLEAF_F_CONTAINS_OSXSAVE
186 jnz cpuid_fetch_with_flags
187 mov edx, [ss:ebx + CPUMCPUIDLEAF.uEdx]
188 mov ecx, [ss:ebx + CPUMCPUIDLEAF.uEcx]
189 mov eax, [ss:ebx + CPUMCPUIDLEAF.uEax]
190 mov ebx, [ss:ebx + CPUMCPUIDLEAF.uEbx]
191
192cpuid_done:
193 pop edi
194 add esp, 12
195 ret
196
197
198 ;
199 ; Need to adjust the result according to VCpu state.
200 ;
201 ; APIC: CPUID[0x00000001].EDX[9] &= pVCpu->cpum.s.fCpuIdApicFeatureVisible;
202 ; CPUID[0x80000001].EDX[9] &= pVCpu->cpum.s.fCpuIdApicFeatureVisible;
203 ;
204 ; OSXSAVE: CPUID[0x00000001].ECX[27] = CR4.OSXSAVE;
205 ;
206cpuid_fetch_with_flags:
207 mov edx, [ss:ebx + CPUMCPUIDLEAF.uEdx]
208 mov ecx, [ss:ebx + CPUMCPUIDLEAF.uEcx]
209
210 mov eax, [ss:edi + VM.offVMCPU]
211
212 ; APIC
213 test dword [ss:ebx + CPUMCPUIDLEAF.fFlags], CPUMCPUIDLEAF_F_CONTAINS_APIC
214 jz cpuid_fetch_with_flags_done_apic
215 test byte [ss:edi + eax + VMCPU.cpum + CPUMCPU.fCpuIdApicFeatureVisible], 0ffh
216 jnz cpuid_fetch_with_flags_done_apic
217 and edx, ~X86_CPUID_FEATURE_EDX_APIC
218cpuid_fetch_with_flags_done_apic:
219
220 ; OSXSAVE
221 test dword [ss:ebx + CPUMCPUIDLEAF.fFlags], CPUMCPUIDLEAF_F_CONTAINS_OSXSAVE
222 jz cpuid_fetch_with_flags_done_osxsave
223 and ecx, ~X86_CPUID_FEATURE_ECX_OSXSAVE
224 test dword [ss:edi + eax + VMCPU.cpum + CPUMCPU.Guest.cr4], X86_CR4_OSXSAVE
225 jz cpuid_fetch_with_flags_done_osxsave
226 or ecx, X86_CPUID_FEATURE_ECX_OSXSAVE
227cpuid_fetch_with_flags_done_osxsave:
228
229 ; Load the two remaining registers and jump to the common normal exit.
230 mov eax, [ss:ebx + CPUMCPUIDLEAF.uEax]
231 mov ebx, [ss:ebx + CPUMCPUIDLEAF.uEbx]
232 jmp cpuid_done
233
234ENDPROC CPUMPatchHlpCpuId
235
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette