VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-CpuDetect.asm@ 104792

Last change on this file since 104792 was 98103, checked in by vboxsync, 2 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.3 KB
Line 
1; $Id: bs3-mode-CpuDetect.asm 98103 2023-01-17 14:15:46Z vboxsync $
2;; @file
3; BS3Kit - Bs3CpuDetect
4;
5
6;
7; Copyright (C) 2007-2023 Oracle and/or its affiliates.
8;
9; This file is part of VirtualBox base platform packages, as
10; available from https://www.virtualbox.org.
11;
12; This program is free software; you can redistribute it and/or
13; modify it under the terms of the GNU General Public License
14; as published by the Free Software Foundation, in version 3 of the
15; License.
16;
17; This program is distributed in the hope that it will be useful, but
18; WITHOUT ANY WARRANTY; without even the implied warranty of
19; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20; General Public License for more details.
21;
22; You should have received a copy of the GNU General Public License
23; along with this program; if not, see <https://www.gnu.org/licenses>.
24;
25; The contents of this file may alternatively be used under the terms
26; of the Common Development and Distribution License Version 1.0
27; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28; in the VirtualBox distribution, in which case the provisions of the
29; CDDL are applicable instead of those of the GPL.
30;
31; You may elect to license modified versions of this file under the
32; terms and conditions of either the GPL or the CDDL or both.
33;
34; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35;
36
37%include "bs3kit-template-header.mac"
38
39BS3_EXTERN_DATA16 g_uBs3CpuDetected
40
41
42;;
43; Rough CPU detection, mainly for detecting really old CPUs.
44;
45; A Bs3CpuDetectEx can be added if this is insufficient.
46;
47; @returns BS3CPU_xxx in xAX.
48; @cproto BS3_DECL(BS3CPU) Bs3CpuDetect(void);
49;
50; @uses xAX.
51;
52; @remarks ASSUMES we're in ring-0 when not in some kind of real mode.
53;
54; @note We put the real mode version of this code in the RMTEXT16 segment
55; to save space elsewhere. We generate a far call stub that goes
56; to the right segment.
57;
58%if TMPL_MODE == BS3_MODE_RM
59BS3_BEGIN_RMTEXT16
60BS3_PROC_BEGIN_MODE Bs3CpuDetect, BS3_PBC_FAR
61%else
62TMPL_BEGIN_TEXT
63BS3_PROC_BEGIN_MODE Bs3CpuDetect, BS3_PBC_HYBRID
64%endif
65CPU 8086
66 push xBP
67 mov xBP, xSP
68 pushf ; xBP - xCB*1
69 push xCX ; xBP - xCB*2
70 push xDX ; xBP - xCB*3
71 push xBX ; xBP - xCB*4
72 sub xSP, 20h ; xBP - xCB*4 - 20h
73
74%ifndef TMPL_CMN_PAGING
75 %ifdef TMPL_RM
76 %if 1 ; this is simpler
77 ;
78 ; FLAGS bits 15:12 are always set on 8086, 8088, V20, V30, 80186, and
79 ; 80188. FLAGS bit 15 is always zero on 286+, whereas bit 14 is NT and
80 ; bits 13:12 are IOPL.
81 ;
82 test byte [xBP - xCB + 1], 80h ; Top byte of saved flags.
83 jz .286plus
84 %else
85 ;
86 ; When executing 'PUSH SP' the 8086, 8088, V20, V30, 80186, and 80188
87 ; should be pushing the updated SP value instead of the initial one.
88 ;
89 push xSP
90 pop xAX
91 cmp xAX, xSP
92 je .286plus
93 %endif
94
95 ;
96 ; Older than 286.
97 ;
98 ; Detect 8086/8088/V20/V30 vs. 80186/80188 by checking for pre 80186
99 ; shift behavior. the 80186/188 and later will mask the CL value according
100 ; to the width of the destination register, whereas 8086/88 and V20/30 will
101 ; perform the exact number of shifts specified.
102 ;
103 mov cl, 20h ; Shift count; 80186/88 and later will mask this by 0x1f (or 0xf)?
104 mov dx, 7fh
105 shl dx, cl
106 cmp dx, 7fh ; If no change, this is a 80186/88.
107 mov xAX, BS3CPU_80186
108 je .return
109
110 ;
111 ; Detect 8086/88 vs V20/30 by exploiting undocumented POP CS encoding
112 ; that was redefined on V20/30 to SET1.
113 ;
114 xor ax, ax ; clear
115 push cs
116 db 0fh ; 8086/88: pop cs V20/30: set1 bl,cl
117 db 14h, 3ch ; 8086/88: add al, 3ch
118 ; 8086/88: al = 3ch V20/30: al = 0, cs on stack, bl modified.
119 cmp al, 3ch
120 jne .is_v20_or_v30
121 mov xAX, BS3CPU_8086
122 jmp .return
123
124.is_v20_or_v30:
125 pop xCX ; unclaimed CS
126 mov xAX, BS3CPU_V20
127 jmp .return
128
129 %endif ; TMPL_RM
130
131CPU 286
132.286plus:
133 ;
134 ; The 4th bit of the machine status word / CR0 indicates the precense
135 ; of a 80387 or later co-processor (a 80287+80386 => ET=0). 486 and
136 ; later should be hardcoding this to 1, according to the documentation
137 ; (need to test on 486SX). The initial idea here then would be to
138 ; assume 386+ if ET=1.
139 ;
140 ; The second idea was to check whether any reserved bits are set,
141 ; because the 286 here has bits 4 thru 15 all set. Unfortunately, it
142 ; turned out the 386SX and AMD 486DX-40 also sets bits 4 thru 15 when
143 ; using SMSW. So, nothing conclusive to distinguish 386 from 286, but
144 ; we've probably got a safe 486+ detection here.
145 ;
146 ;; @todo check if LOADALL can set any of the reserved bits on a 286 or 386.
147 smsw ax
148 test ax, ~(X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS | X86_CR0_ET | X86_CR0_NE)
149 jz .486plus
150
151 ;
152 ; The 286 stores 0xff in the high byte of the SIDT and SGDT base
153 ; address (since it only did 24-bit addressing and the top 8-bit was
154 ; reserved for the 386). ASSUMES low IDT (which is the case for BS3Kit).
155 ;
156 sidt [xBP - xCB*4 - 20h]
157 cmp byte [xBP - xCB*4 - 20h + 2 + 3], 0ffh
158 jne .386plus
159
160 %if 0
161 ;
162 ; Detect 80286 by checking whether the IOPL and NT bits of EFLAGS can be
163 ; modified or not. There are different accounts of these bits. Dr.Dobb's
164 ; (http://www.drdobbs.com/embedded-systems/processor-detection-schemes/184409011)
165 ; say they are undefined on 286es and will always be zero. Whereas Intel
166 ; iAPX 286 Programmer's Reference Manual (both order #210498-001 and
167 ; #210498-003) documents both IOPL and NT, but with comment 4 on page
168 ; C-43 stating that they cannot be POPFed in real mode and will both
169 ; remain 0. This is different from the 386+, where the NT flag isn't
170 ; privileged according to page 3-37 in #230985-003. Later Intel docs
171 ; (#235383-052US, page 4-192) documents real mode as taking both NT and
172 ; IOPL from what POPF reads off the stack - which is the behavior
173 ; observed a 386SX here.
174 ;
175 test al, X86_CR0_PE ; This flag test doesn't work in protected mode, ...
176 jnz .386plus ; ... so ASSUME 386plus if in PE for now.
177
178 pushf ; Save a copy of the original flags for restoring IF.
179 pushf
180 pop ax
181 xor ax, X86_EFL_IOPL | X86_EFL_NT ; Try modify IOPL and NT.
182 and ax, ~X86_EFL_IF ; Try clear IF.
183 push ax ; Load modified flags.
184 popf
185 pushf ; Get actual flags.
186 pop dx
187 popf ; Restore IF, IOPL and NT.
188 cmp ax, dx
189 je .386plus ; If any of the flags are set, we're on 386+.
190
191 ; While we could in theory be in v8086 mode at this point and be fooled
192 ; by a flaky POPF implementation, we assume this isn't the case in our
193 ; execution environment.
194 %endif
195.is_286:
196 mov ax, BS3CPU_80286
197 jmp .return
198%endif ; !TMPL_CMN_PAGING
199
200CPU 386
201.386plus:
202.486plus:
203 ;
204 ; Check for CPUID and AC. The former flag indicates CPUID support, the
205 ; latter was introduced with the 486.
206 ;
207 mov ebx, esp ; Save esp.
208 and esp, 0fffch ; Clear high word and don't trigger ACs.
209 pushfd
210 mov eax, [esp] ; eax = original EFLAGS.
211 xor dword [esp], X86_EFL_ID | X86_EFL_AC ; Flip the ID and AC flags.
212 popfd ; Load modified flags.
213 pushfd ; Save actual flags.
214 xchg eax, [esp] ; Switch, so the stack has the original flags.
215 xor eax, [esp] ; Calc changed flags.
216 popf ; Restore EFLAGS.
217 mov esp, ebx ; Restore possibly unaligned ESP.
218 test eax, X86_EFL_ID
219 jnz .have_cpuid ; If ID changed, we've got CPUID.
220 test eax, X86_EFL_AC
221 mov xAX, BS3CPU_80486
222 jnz .return ; If AC changed, we've got a 486 without CPUID (or similar).
223 mov xAX, BS3CPU_80386
224 jmp .return
225
226CPU 586
227.have_cpuid:
228 ;
229 ; Do a very simple minded check here using the (standard) family field.
230 ; While here, we also check for PAE.
231 ;
232 mov eax, 1
233 cpuid
234
235 ; Calc the extended family and model values before we mess up EAX.
236 mov cl, ah
237 and cl, 0fh
238 cmp cl, 0fh
239 jnz .not_extended_family
240 mov ecx, eax
241 shr ecx, 20
242 and cl, 7fh
243 add cl, 0fh
244.not_extended_family: ; cl = family
245 mov ch, al
246 shr ch, 4
247 cmp cl, 0fh
248 jae .extended_model
249 cmp cl, 06h ; actually only intel, but we'll let this slip for now.
250 jne .done_model
251.extended_model:
252 shr eax, 12
253 and al, 0f0h
254 or ch, al
255.done_model: ; ch = model
256
257 ; Start assembling return flags, checking for PSE + PAE.
258 mov eax, X86_CPUID_FEATURE_EDX_PSE | X86_CPUID_FEATURE_EDX_PAE
259 and eax, edx
260 mov ah, al
261 AssertCompile(X86_CPUID_FEATURE_EDX_PAE_BIT > BS3CPU_F_PAE_BIT - 8) ; 6 vs 10-8=2
262 and al, X86_CPUID_FEATURE_EDX_PAE
263 shr al, X86_CPUID_FEATURE_EDX_PAE_BIT - (BS3CPU_F_PAE_BIT - 8)
264 AssertCompile(X86_CPUID_FEATURE_EDX_PSE_BIT == BS3CPU_F_PSE_BIT - 8) ; 3 vs 11-8=3
265 and ah, X86_CPUID_FEATURE_EDX_PSE
266 or ah, al
267 or ah, (BS3CPU_F_CPUID >> 8)
268
269 ; Add the CPU type based on the family and model values.
270 cmp cl, 6
271 jne .not_family_06h
272 mov al, BS3CPU_PPro
273 cmp ch, 1
274 jbe .return
275 mov al, BS3CPU_PProOrNewer
276 jmp .NewerThanPPro
277
278.not_family_06h:
279 mov al, BS3CPU_PProOrNewer
280 ja .NewerThanPPro
281 cmp cl, 5
282 mov al, BS3CPU_Pentium
283 je .return
284 cmp cl, 4
285 mov al, BS3CPU_80486
286 je .return
287 cmp cl, 3
288 mov al, BS3CPU_80386
289 je .return
290
291.NewerThanPPro:
292
293 ; Check for extended leaves and long mode.
294 push xAX ; save PAE+PProOrNewer
295 mov eax, 0x80000000
296 cpuid
297 sub eax, 0x80000001 ; Minimum leaf 0x80000001
298 cmp eax, 0x00010000 ; At most 0x10000 leaves.
299 ja .no_ext_leaves
300
301 mov eax, 0x80000001
302 cpuid
303 pop xAX ; restore PAE+PProOrNewer
304 test edx, X86_CPUID_EXT_FEATURE_EDX_LONG_MODE
305 jz .no_long_mode
306 or ah, ((BS3CPU_F_CPUID_EXT_LEAVES | BS3CPU_F_LONG_MODE) >> 8)
307 jmp .no_check_for_nx
308.no_long_mode:
309 or ah, (BS3CPU_F_CPUID_EXT_LEAVES >> 8)
310.no_check_for_nx:
311 test edx, X86_CPUID_EXT_FEATURE_EDX_NX
312 jz .return
313 or ax, BS3CPU_F_NX
314 jmp .return
315
316.no_ext_leaves:
317 pop xAX ; restore PAE+PProOrNewer
318
319CPU 8086
320.return:
321 ;
322 ; Save the return value.
323 ;
324 mov [BS3_DATA16_WRT(g_uBs3CpuDetected)], ax
325
326 ;
327 ; Epilogue.
328 ;
329 add xSP, 20h
330 pop xBX
331 pop xDX
332 pop xCX
333 popf
334 pop xBP
335 BS3_HYBRID_RET
336
337BS3_PROC_END_MODE Bs3CpuDetect
338
339
340%if TMPL_MODE == BS3_MODE_RM
341BS3_BEGIN_TEXT16_NEARSTUBS
342BS3_PROC_BEGIN_MODE Bs3CpuDetect, BS3_PBC_NEAR
343 call far TMPL_FAR_NM(Bs3CpuDetect)
344 ret
345BS3_PROC_END_MODE Bs3CpuDetect
346%endif
347
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