VirtualBox

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

Last change on this file since 62517 was 62478, checked in by vboxsync, 8 years ago

(C) 2016

  • 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 62478 2016-07-22 18:29:06Z vboxsync $
2;; @file
3; CPUM - Patch Helpers.
4;
5
6; Copyright (C) 2015-2016 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