VirtualBox

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

Last change on this file since 77847 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

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