First post, by guest
This is a pretty tragic bug... I'm sure a lot of apps will use this rather obvious technique to distinguish between 287, 387 and 486 math unit.
The test code is an ancient "bound" OS/2 1.X era tool that can run under either OS/2 1.X (it still runs under NT/W2K as native OS/2 app) or as an ordinary DOS app with the bound in FAPI library supplying the necessary API mappings to the DOS world.
Basically, once it detects a math unit of any sort, the ability to do a projective infinity quickly id's the 287's, then test hooks the invalid opcode vector and executes a CMPXCHG instruction (which didn't exist on the 386). If the hook is hit, then the math unit is something later than a 387.
If you don't have the necessary OS/2 1.X toolkit onhand to build a FAPI app, I can supply the executable - contact me at aingenoso@hotmail.com
(this forum is REAL SLOW at sending out those confirmation emails!!! else this and the slew of other issues I've found today would be in the developer forum)
-------- NPXTYPE.ASM --------
;--------------------------------------------------------------------------
; Determine NPX type (287/387/486)
;--------------------------------------------------------------------------
.286p
.287
STDOUT = 1
extrn DOSSETVEC:FAR
extrn DOSDEVCONFIG:FAR
extrn DOSWRITE:FAR
extrn DOSEXIT:FAR
_stk segment para stack 'stack'
npxflag db ?
org 0
status dw ?
org 0
db 4096 dup (?)
_stk ends
dgroup group _stk
_cod segment para public 'code'
assume cs:_cod,ss:_stk,ds:_stk
msg1 db 'The co-processor '
msg1len EQU $-msg1
msg2 db 'is not present.',13,10
msg2len EQU $-msg2
msg3 db 'is a 80287.',13,10
msg3len EQU $-msg3
msg4 db 'is a 80387.',13,10
msg4len EQU $-msg4
msg5 db 'is a 80486 math unit.',13,10
msg5len EQU $-msg5
start label near
;
; DosDevConfig(&npxflag, 3, 0);
;
push ss
push offset npxflag
push 3
push bp ; BP=0 on entry
call DOSDEVCONFIG
cmp npxflag, 0
jne got_something ; something is there
mov bx, offset msg2 ; No math unit present
mov cx, msg2len
jmp terminate
;
; Test for projective infinity.
;
got_something:
finit ; Get a default control word
fld1 ; Create
fldz ; an
fdiv ; infinity
fld st ; Dup the infinity
fchs ; and change the sign
fcompp ; Compare the 2 infinities
fstsw status ; A 287 will say they are equal
mov ax, status ; a 387/486 will say they're
sahf ; different.
jne its387_486 ;
mov bx, offset msg3 ; A 80287 is present.
mov cx, msg3len
jmp terminate
;
; When this handler is executed it means a 386 is the CPU.
;
int6trapper label near
mov bx, offset msg4 ; A 80386 is present.
mov cx, msg4len
jmp terminate
;
; Determine if we're running a 386 or 486. We register an Int 6 handler
; and then try to execute one of the 486 opcodes.
;
its387_486:
push 6 ; Int 6
push cs ; &handler
push offset int6trapper ;
push ss ; A handy dummy at SS:0
push bp ; bp==0
call DOSSETVEC ;
db 0fH, 0C0H, 0C0H ; A 486 CMPXCHG instruction
mov bx, offset msg5 ; A 80486 is present.
mov cx, msg5len
jmp terminate
;
; DosWrite(stdout, msg1, msg1len, &SS:0);
;
terminate:
push STDOUT ; Handle
push cs ; &string
push offset msg1
push msg1len ; string len
push ss ; SS:0 is a handy for BytesWritten
push bp
call DOSWRITE
;
; DosWrite(stdout, cs:bx, cx, &SS:0); ; BX-->string, CX==mesage length
;
push STDOUT ; Handle
push cs ; &string
push bx ; cs:bx->string
push cx ; cx==string len
push ss ; SS:0 is a handy for BytesWritten
push bp
call DOSWRITE
;
; DosExit(0, 0);
;
push bp
push bp
call DOSEXIT
_cod ends
end start