VirtualBox

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

Last change on this file since 56296 was 54763, checked in by vboxsync, 10 years ago

PATM,CPUM: Redid the CPUID stuff by calling a patch helper function implemented by CPUM. This eliminates needing to expose CPUM guts to in patches that gets saved. Also reimplemented the lookup as a binary search (for the leaf, not sub-leaf).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 6.6 KB
Line 
1; $Id: CPUMRCPatchHlp.asm 54763 2015-03-15 03:15:58Z 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
27
28;*******************************************************************************
29;* External Symbols *
30;*******************************************************************************
31extern IMPNAME(g_VM)
32
33
34BEGIN_PATCH_HLP_SEG
35
36;;
37; Helper for PATMCpuidReplacement.
38;
39; We have at most 32 bytes of stack to play with, .
40;
41; @input eax, ecx(, edx, ebx)
42; @output eax, ebx, ecx, ebx
43;
44; @uses eflags (caller saves them)
45;
46BEGINPROC_EXPORTED CPUMPatchHlpCpuId
47 ; Save the registers we use for passthru and sub-leaf matching (eax is not used).
48 push edx
49 push ecx
50 push ebx
51
52 ; Use edi as VM pointer.
53 push edi
54 mov edi, IMP_SEG(ss, g_VM)
55
56%define CPUMCPUIDLEAF_SIZE_LOG2 5 ; ASSUMES CPUMCPUIDLEAF_size == 32
57
58 ;
59 ; Perform a binary search looking for leaf with the EAX value.
60 ;
61 mov edx, [ss:edi + VM.cpum + CPUM.GuestInfo + CPUMINFO.cCpuIdLeaves]
62 mov ecx, [ss:edi + VM.cpum + CPUM.GuestInfo + CPUMINFO.paCpuIdLeavesRC]
63 test edx, edx
64 jz cpuid_unknown
65 shl edx, CPUMCPUIDLEAF_SIZE_LOG2
66 add edx, ecx ; edx = end (exclusive); ecx = start.
67
68cpuid_lookup_leaf:
69 ; Find the middle element
70 mov ebx, edx
71cpuid_lookup_leaf_ebx_loeaded:
72 sub ebx, ecx
73 shr ebx, 1 + CPUMCPUIDLEAF_SIZE_LOG2
74 shl ebx, CPUMCPUIDLEAF_SIZE_LOG2
75 add ebx, ecx ; ebx = middle element.
76
77 ; Compare.
78 cmp eax, [ss:ebx + CPUMCPUIDLEAF.uLeaf]
79 jae cpuid_lookup_split_up
80
81 ; The leaf is before ebx.
82cpuid_lookup_split_down:
83 cmp ecx, ebx ; start == middle? if so, we failed.
84 mov edx, ebx ; end = middle;
85 jne cpuid_lookup_leaf_ebx_loeaded
86 jmp cpuid_unknown
87
88 ; The leaf is at or after ebx.
89cpuid_lookup_split_up:
90 je cpuid_match_eax
91 lea ecx, [ebx + CPUMCPUIDLEAF_size] ; start = middle + 1
92 cmp ecx, edx ; middle + 1 == start? if so, we failed.
93 jne cpuid_lookup_leaf
94 jmp cpuid_unknown
95
96 ;
97 ; We've to a matching leaf, does the sub-leaf match too?
98 ;
99cpuid_match_eax:
100 mov ecx, [esp + 4]
101 and ecx, [ss:ebx + CPUMCPUIDLEAF.fSubLeafMask]
102 cmp ecx, [ss:ebx + CPUMCPUIDLEAF.uSubLeaf]
103 je cpuid_fetch
104 ja cpuid_lookup_subleaf_forwards
105
106 ;
107 ; Search backwards.
108 ;
109cpuid_lookup_subleaf_backwards:
110 mov edx, [ss:edi + VM.cpum + CPUM.GuestInfo + CPUMINFO.paCpuIdLeavesRC] ; edx = first leaf
111
112cpuid_lookup_subleaf_backwards_loop:
113 cmp ebx, edx ; Is there a leaf before the current?
114 jbe cpuid_subleaf_not_found ; If not we're out of luck.
115 cmp eax, [ss:ebx - CPUMCPUIDLEAF_size + CPUMCPUIDLEAF.uLeaf]
116 jne cpuid_subleaf_not_found ; If the leaf before us does not have the same leaf number, we failed.
117 sub ebx, CPUMCPUIDLEAF_size
118 cmp ecx, [ss:ebx + CPUMCPUIDLEAF.uSubLeaf]
119 je cpuid_fetch ; If the subleaf matches, we're good!.
120 jb cpuid_lookup_subleaf_backwards_loop ; Still hope if the subleaf we're seeking is smaller.
121 jmp cpuid_subleaf_not_found ; Too bad.
122
123 ;
124 ; Search forward until we've got a matching sub-leaf (or not).
125 ;
126cpuid_lookup_subleaf_forwards:
127 ; Calculate the last leaf address.
128 mov edx, [ss:edi + VM.cpum + CPUM.GuestInfo + CPUMINFO.cCpuIdLeaves]
129 dec edx
130 shl edx, CPUMCPUIDLEAF_SIZE_LOG2
131 add edx, [ss:edi + VM.cpum + CPUM.GuestInfo + CPUMINFO.paCpuIdLeavesRC] ; edx = last leaf (inclusive)
132
133cpuid_subleaf_lookup:
134 cmp ebx, edx
135 jae cpuid_subleaf_not_found
136 cmp eax, [ss:ebx + CPUMCPUIDLEAF_size + CPUMCPUIDLEAF.uLeaf]
137 jne cpuid_subleaf_not_found
138 add ebx, CPUMCPUIDLEAF_size
139 cmp ecx, [ss:ebx + CPUMCPUIDLEAF.uSubLeaf]
140 ja cpuid_subleaf_lookup
141 je cpuid_fetch
142
143 ;
144 ; Out of range sub-leaves aren't quite as easy and pretty as we emulate them
145 ; here, but we do an adequate job.
146 ;
147cpuid_subleaf_not_found:
148 xor ecx, ecx
149 test dword [ss:ebx + CPUMCPUIDLEAF.fFlags], CPUMCPUIDLEAF_F_INTEL_TOPOLOGY_SUBLEAVES
150 jz cpuid_load_zeros_except_ecx
151 mov ecx, [esp + 4]
152 and ecx, 0ffh
153cpuid_load_zeros_except_ecx:
154 xor edx, edx
155 xor eax, eax
156 xor ebx, ebx
157 jmp cpuid_done
158
159 ;
160 ; Different CPUs have different ways of dealing with unknown CPUID leaves.
161 ;
162cpuid_unknown:
163 mov ebx, IMP_SEG(ss, g_VM)
164 mov dword [ss:edi + VM.cpum + CPUM.GuestInfo + CPUMINFO.enmUnknownCpuIdMethod], CPUMUNKNOWNCPUID_PASSTHRU
165 je cpuid_unknown_passthru
166 ; Load the default cpuid leaf.
167cpuid_unknown_def_leaf:
168 mov edx, [ss:edi + VM.cpum + CPUM.GuestInfo + CPUMINFO.DefCpuId + CPUMCPUID.uEdx]
169 mov ecx, [ss:edi + VM.cpum + CPUM.GuestInfo + CPUMINFO.DefCpuId + CPUMCPUID.uEcx]
170 mov eax, [ss:edi + VM.cpum + CPUM.GuestInfo + CPUMINFO.DefCpuId + CPUMCPUID.uEax]
171 mov ebx, [ss:edi + VM.cpum + CPUM.GuestInfo + CPUMINFO.DefCpuId + CPUMCPUID.uEbx]
172 jmp cpuid_done
173 ; Pass thru the input values unmodified (eax is still virgin).
174cpuid_unknown_passthru:
175 mov edx, [esp + 8]
176 mov ecx, [esp + 4]
177 mov ebx, [esp]
178 jmp cpuid_done
179
180 ;
181 ; Normal return.
182 ;
183cpuid_fetch:
184 mov edx, [ss:ebx + CPUMCPUIDLEAF.uEdx]
185 mov ecx, [ss:ebx + CPUMCPUIDLEAF.uEcx]
186 mov eax, [ss:ebx + CPUMCPUIDLEAF.uEax]
187 mov ebx, [ss:ebx + CPUMCPUIDLEAF.uEbx]
188
189cpuid_done:
190 pop edi
191 add esp, 12
192 ret
193ENDPROC CPUMPatchHlpCpuId
194
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