VirtualBox

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

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