page 75, 110 ;-------------------------------------------------------------------- ; ; SYSID.ASM ; ; Version 4.4 ; ; Two subprograms used by SYSID.PAS: ; ; CPUID - identifies host CPU and NDP (if ; any) ; DISKREAD - reads absolute sectors from disk ; ; Steve Grant ; Long Beach, CA ; January 13, 1989 ; ;-------------------------------------------------------------------- .286P .8087 public CPUID, DISKREAD CODE segment byte ; Conditional jumps are all coded with the SHORT qualifier in ; order to minimize the size of the .OBJ file output of Turbo ; Assembler. ;-------------------------------------------------------------------- CPUID proc near assume cs:CODE, ds:DATA, es:nothing, ss:nothing ; 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 ; byte = NDP type ; word = NDP control word mCPU equ byte ptr [bx] mMSW equ word ptr [bx + 1] mGDT equ byte ptr [bx + 3] mIDT equ byte ptr [bx + 9] mchkint equ byte ptr [bx + 15] mNDP equ byte ptr [bx + 16] mNDPCW equ word ptr [bx + 17] f8088 equ 0 f8086 equ 1 fV20 equ 2 fV30 equ 3 f80188 equ 4 f80186 equ 5 f80286 equ 6 f80386 equ 7 funk = 0FFH false equ 0 true equ 1 push bp mov bp,sp push ds lds bx,[bp + 4] call cpu call chkint call ndp pop ds pop bp ret 4 ;-------------------------------------------------------------------- cpu: ; interrupt of multi-prefix string instruction sti mov cx,0FFFFH rep lods byte ptr es:[si] jcxz short cpu_02 call piq cmp dx,4 jne short cpu_01 mov mCPU,f8088 ret cpu_01: cmp dx,6 jne short cpu_08 mov mCPU,f8086 ret cpu_02: ; number of bits in displacement register used by shift mov al,0FFH mov cl,20H shl al,cl or al,al jnz short cpu_04 call piq cmp dx,4 jne short cpu_03 mov mCPU,fV20 ret cpu_03: cmp dx,6 jne short cpu_08 mov mCPU,fV30 ret cpu_04: ; order of write/decrement by PUSH SP push sp pop ax cmp ax,sp je short cpu_06 call piq cmp dx,4 jne short cpu_05 mov mCPU,f80188 ret cpu_05: cmp dx,6 jne short cpu_08 mov mCPU,f80186 ret cpu_06: smsw mMSW sgdt mGDT sidt mIDT ; try to alter flag register bits 15-12 pushf pop ax mov cx,ax xor cx,0F000H push cx popf pushf pop cx cmp ax,cx jne short cpu_07 mov mCPU,f80286 ret cpu_07: mov mCPU,f80386 ret cpu_08: mov mCPU,funk ret ;-------------------------------------------------------------------- piq: ; On exit: ; ; DX = length of prefetch instruction queue ; ; This subroutine 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 cx push cs pop es mov di,offset piq_01 - 1 push di std rep stosb mov al,opnop pop di pop cx xor dx,dx cli rep stosb rept count inc dx endm piq_01: sti ret ;-------------------------------------------------------------------- chkint: ; 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,01H ; set TF push ax popf push ss ; CPU may wait one ; instruction before ; recognizing single step ; interrupt pop ss chkint_01: ; shouldn't ever trap here ; restore old INT 01H vector push ds mov ax,2501H lds dx,old_int01 int 21H pop ds ret ;-------------------------------------------------------------------- new_int01: ; INT 01H handler (single step) ; ; On entry: ; ; SP => IP ; CS ; flags sti pop ax ; IP cmp ax,offset chkint_01 jb short new_int01_03 je short new_int01_01 mov mchkint,false jmp short new_int01_02 new_int01_01: mov mchkint,true new_int01_02: pop cx ; CS pop dx ; flags and dh,0FEH ; turn off TF push dx ; flags push cx ; CS new_int01_03: push ax ; IP iret ;-------------------------------------------------------------------- ndp: fnone equ 0 f8087 equ 1 f80287 equ 2 f80387 equ 3 funk = 0FFH mov word ptr ndp_cw,0000H cli ; The next three 80x87 instructions 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-6-1)/17+1 ; 4 loop $ ; 17*CX-12 ; 17*CX+6 fninit ; 8 8 mov cx,(8-0-1)/17+1 ; 4 loop $ ; 17*CX-12 ; 17*CX fnstcw ndp_cw ; 14 24 mov cx,(24-2-1)/17+1 ; 4 loop $ ; 17*CX-12 ; 17*CX+2 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: .287 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: .8087 frstor ndp_save fstcw mNDPCW ret ndp_05: mov mNDP,funk ret CPUID endp ;-------------------------------------------------------------------- DISKREAD proc near assume cs:CODE, ds:nothing, es:nothing ; On entry: ; ; BP ; SP => near return address ; offset of disk buffer ; segment " " " ; number of sectors to read ; starting logical sector number ; drive number (0=A, 1=B, etc.) ; ; On exit: ; ; AX = function result ; 00 - function successful ; 01..FF - DOS INT 25H error result drive equ [bp + 12] starting_sector equ [bp + 10] number_of_sectors equ [bp + 8] buffer equ [bp + 4] push bp mov bp,sp mov al,drive mov dx,starting_sector mov cx,number_of_sectors push ds lds bx,buffer int 25H inc sp ; fix broken stack inc sp pop ds jc short diskread_01 xor ax,ax diskread_01: pop bp ret 10 DISKREAD endp CODE ends ;-------------------------------------------------------------------- DATA segment byte ; storage for CPUID ; redirected INT 01H vector old_int01 label dword old_int01_ofs dw ? old_int01_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