-
Notifications
You must be signed in to change notification settings - Fork 2
/
GETCPU.ASM
573 lines (428 loc) · 15.8 KB
/
GETCPU.ASM
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
;°±²ÛßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßÛ²±°
;°±²Û Subroutine to detect processor type Û²±°
;°±²Û Steve Grant Û²±°
;°±²Û Jersey City, NJ Û²±°
;°±²Û April 7, 1990 Û²±°
;°±²Û V20 detection bug fixed by FRIENDS software 1992. Û²±°
;°±²ÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÛ²±°
.486P
.387
;--------------------------------------------------------------------
; Macro definitions
; On some Intel chips interrupts are enabled after a POPF instruction
; even if IF is clear.
POPF2 macro
local a1,a2
jmp short a2
a1: iret
a2: push cs
call a1
endm
;--------------------------------------------------------------------
CODE segment word use16
public CPUID
CPUID proc near
assume cs:CODE, ds:DATA
; On entry:
;
; BP
; SP => near return address
; offset of a cpu_info_t record
; segment " " " "
;
; On exit, the cpu_info_t record has been filled in as follows:
;
; byte = CPU type
; word = Machine Status Word
; 6 bytes = Global Descriptor Table
; 6 bytes = Interrupt Descriptor Table
; boolean = segment register change/interrupt flag
; boolean = 80386 flag word size (0 => 16)
; boolean = 80386 multiplication bug flag
; byte = NDP type
; word = NDP control word
cpu_info equ [bp + 4]
mCPU equ byte ptr [bx]
mMSW equ [bx + 1]
mGDT equ [bx + 3]
mIDT equ [bx + 9]
mchkint equ byte ptr [bx + 15]
mopsize equ byte ptr [bx + 16]
mmult equ byte ptr [bx + 17]
mNDP equ byte ptr [bx + 18]
mNDPCW equ [bx + 19]
f8088 equ 0
f8086 equ 1
fV20 equ 2
fV30 equ 3
f80188 equ 4
f80186 equ 5
f80286 equ 6
f80386 equ 7
; f80386SX equ 8
f80486 equ 9
funk = 0FFH
false equ 0
true equ 1
trapflag equ 01H
push bp
mov bp, sp
push ds
lds bx, cpu_info
call cpu
;call ndp
pop ds
pop bp
ret 4
;--------------------------------------------------------------------
CPU proc near
; The 8088 and 8086 do not handle interrupts of multi-prefix string
; instructions correctly; they resume processing after the interrupt
; with only the last prefix in effect. The 8088 has a 4-byte
; prefetch instruction queue; the 8086, a 6-byte queue.
sti ; timer tick will interrupt us
mov dx,10
TryAgain: mov cx, 0FFFFH
rep lods byte ptr es:[si]
cmp cx,0
jne Is808x
dec dx
jne TryAgain
jmp short cpu_03
Is808x: call piq
cmp dx, 4
jne short cpu_01
mov mCPU, f8088
call chkint
ret
cpu_01: cmp dx, 6
jne short cpu_02
mov mCPU, f8086
call chkint
ret
cpu_02: mov mCPU, funk
ret
cpu_03:
; The V20 and V30 use the entire displacement register in processing
; bit shift instructions. The V20 has a 4-byte prefetch instruction
; queue; the V30, a 6-byte queue.
mov al, 0FFh
mov cl, 21h
shr al, cl
jne short cpu_06
call piq
cmp dx, 4
ja short cpu_04
mov mCPU, fV20
ret
cpu_04: cmp dx, 6
jne short cpu_05
mov mCPU, fV30
ret
cpu_05: mov mCPU, funk
ret
cpu_06:
; The 80188, 80186, 80286, 80386, 80386SX, and 80486 all trap invalid
; opcodes via INT 6. The handler itself sets CX to 1 and adjusts the
; return address to point to the instruction following the invalid
; opcode.
; save old INT 06H vector
push bx
mov ax, 3506H
int 21H
mov old_int06_ofs, bx
mov old_int06_seg, es
pop bx
; redirect INT 06H vector
push ds
mov ax, 2506H
mov dx, seg new_int06
mov ds, dx
mov dx, offset new_int06
int 21H
pop ds
xor cx, cx
; The instruction SMSW DX is invalid on the 80186 and 80188. The
; 80188 has a 4-byte prefetch instruction queue; the 80186, a 6-byte
; queue.
smsw dx
jcxz cpu_09
call piq
cmp dx, 4
jne short cpu_07
mov mCPU, f80188
jmp short cpu_14
cpu_07: cmp dx, 6
jne short cpu_08
mov mCPU, f80186
jmp short cpu_14
cpu_08:
mov mCPU, funk
jmp short cpu_14
cpu_09:
mov mMSW, dx
sgdt mGDT
sidt mIDT
; The instruction MOV EDX,EDX is invalid on the 80286.
mov edx,edx
jcxz cpu_10
mov mCPU,f80286
jmp short cpu_14
cpu_10:
; The instruction XADD DX, DX is invalid on the 80386.
xadd dx,dx
jcxz cpu_13
mov mCPU, f80386
; Some early 80386's do not perform 32-bit multiplication correctly.
mov eax, 0417A000H
mov edx, 81H
mul edx
cmp edx, 2
jne short cpu_11
cmp eax, 0FE7A000H
jne short cpu_11
mov mmult, true
jmp short cpu_12
cpu_11: mov mmult, false
cpu_12: call opsize
jmp short cpu_14
; BIX ibm.at/hardware #4663
cpu_13: mov mCPU, f80486
mov mmult, true
call opsize
cpu_14:
; restore old INT 06H vector
push ds
mov ax, 2506H
lds dx, old_int06
int 21H
pop ds
ret
;--------------------------------------------------------------------
piq proc near
; On exit:
;
; DX = length of prefetch instruction queue
;
; This procedure uses self-modifying code but can nevertheless
; be run repeatedly in the course of the calling program.
count = 7
opincdx equ 42H ; inc dx opcode
opnop equ 90H ; nop opcode
mov al, opincdx
mov cx, count
push cs
pop es
mov di, offset piq_02 - 1
push cx
push di
std
rep stosb
mov al, opnop
pop di
mov dx, 1 ; STI
cli
mov cx, offset piq_02 - piq_01
loop $ ; make sure queue is full
piq_01: pop cx
rep stosb
sti
rept count
inc dx
endm
piq_02: ret
piq endp
;--------------------------------------------------------------------
chkint proc near
; Some early 8088's and 8086's fail to disable interrupts immediately
; following a segment register load.
; save old INT 01H vector
push bx
mov ax, 3501H
int 21H
mov old_int01_ofs, bx
mov old_int01_seg, es
pop bx
; redirect INT 01H vector
push ds
mov ax, 2501H
mov dx, seg new_int01
mov ds, dx
mov dx, offset new_int01
int 21H
pop ds
; set TF and change SS -- did we trap on following instruction?
pushf
pop ax
or ah, trapflag
push ax
cli ; so an external interrupt
; doesn't get single step
; trapped
POPF2
push ss ; CPU may wait one
; instruction before
; recognizing single step
; interrupt
pop ss
chkint_01: ; shouldn't ever trap here
sti ; by now TF has been reset by
; the handler
; restore old INT 01H vector
push ds
mov ax, 2501H
lds dx, old_int01
int 21H
pop ds
ret
chkint endp
;--------------------------------------------------------------------
opsize proc near
; check whether operand size is 16 or 32 bits
pushf
mov ax, sp
popf
inc ax
inc ax
cmp ax, sp
jnz short opsize_1
mov mopsize, false
ret
opsize_1: mov mopsize, true
ret
opsize endp
;--------------------------------------------------------------------
CPU endp
;--------------------------------------------------------------------
new_int01:
; INT 01H handler (single step)
;
; On entry:
;
; SP => IP
; CS
; flags
;
; On exit:
;
; if trapped on or before POP SS nothing
; if trapped immediately after mchkint = false, TF cleared
; if trapped later mchkint = true, TF cleared
sti
pop ax ; IP
cmp ax, offset chkint_01
jb short new_int01_3
je short new_int01_1
mov mchkint, true
jmp short new_int01_2
new_int01_1: mov mchkint, false
new_int01_2: pop cx ; CS
pop dx ; flags
and dh, not trapflag
push dx ; flags
push cx ; CS
new_int01_3: push ax ; IP
iret
;--------------------------------------------------------------------
new_int06:
; INT 06H handler (invalid opcode)
;
; On entry:
;
; CX = 0
; SP => IP of invalid instruction
; CS of invalid instruction
; flags
;
; On exit:
;
; CX = 1
; return address on stack points to instruction following
; invalid instruction
sti
inc cx
pop ax
add ax, 3
push ax
iret
;--------------------------------------------------------------------
NDP proc near
fnone equ 0
f8087 equ 1
f80287 equ 2
f80387 equ 3
funk = 0FFH
mov ndp_cw, 0000H
cli
; The first three 80x87 instructions below cannot carry the WAIT
; prefix, because there may not be an 80x87 for which to wait. The
; WAIT is therefore emulated with a MOV CX,<value>! LOOP $
; combination.
; CPU NDP
fnsave ndp_save ; 14 221
mov cx, (221 - 23 + 16) / 17 + 1 ; 4
loop $ ; 17*CX+5
; 17*CX+23
fninit ; 8 8
mov cx, (8 - 17 + 16) / 17 + 1 ; 4
loop $ ; 17*CX+5
; 17*CX+17
fnstcw ndp_cw ; 14 24
mov cx, (24 - 23 + 16) / 17 + 1 ; 4
loop $ ; 17*CX+5
; 17*CX+23
sti
mov ax, ndp_cw
cmp ax, 0000H
jne short ndp_01
mov mNDP, fnone
ret
ndp_01: cmp ax, 03FFH
jne short ndp_02
mov mNDP, f8087
jmp short ndp_04
ndp_02: cmp ax, 037FH
jne short ndp_05
fld1
fldz
fdiv
fld1
fchs
fldz
fdiv
fcom
fstsw ndp_sw
mov ax, ndp_sw
and ah, 41H ; C3, C0
cmp ah, 40H ; ST(0) = ST(1)
jne short ndp_03
mov mNDP, f80287
jmp short ndp_04
ndp_03: cmp ah, 01H ; ST(0) < ST(1)
jne short ndp_05
mov mNDP, f80387
ndp_04: frstor ndp_save
fstcw mNDPCW
ret
ndp_05: mov mNDP, funk
ret
ndp endp
;--------------------------------------------------------------------
CPUID endp
CODE ends
DATA segment word use16
; storage for CPUID
; redirected INT 01H, 06H vectors
old_int01 label dword
old_int01_ofs dw ?
old_int01_seg dw ?
old_int06 label dword
old_int06_ofs dw ?
old_int06_seg dw ?
; storage for NDPID
; 80x87 control word after initialization, status word after divide by zero
ndp_cw dw ?
ndp_save db 94 dup (?)
ndp_sw dw ?
DATA ends
end