I finished the 8/16 bit detection code (this is what was missing from my original code, I'll rewrite the 32-bit non CPUID code while I finish my CPUID database. The code I am posting in this thread does not include macro definitions, inc files, etc - you'll see all that packaged together when I finish the ground up rewrite (unless you want to see it, then I'll zip it and post it here).
bits 16
%include "boot.inc"
%include "cpuid.inc"
%include "i386.inc"
;-----------------------------------------------------------------------+
; Set order and alignment of sections +
;-----------------------------------------------------------------------+
SECTION .text
SECTION .code follows=.text align=16
SECTION .data align=16
SECTION .bss align=16
;-----------------------------------------------------------------------+
; To build a version that will work properly under DOS, use ORG 100h. +
;-----------------------------------------------------------------------+
org 100h
SECTION .text
;-----------------------------------------------------------------------+
; Clear screen. +
; Set up segments and stack. +
;-----------------------------------------------------------------------+
.start:
mov ax,3 ; clear screen and set text
int 10h ; mode 3.
mov dx,cs
mov ds,dx
mov es,dx
mov dx,stackseg ; initialise the stack, using the same
mov ss,dx ; values used in the boot sector.
mov sp,stacksize ; Don't assume that the boot sector
; had cleaned it up first.
xor dx,dx
;-----------------------------------------------------------------------+
; Now we've set DS and ES to the same as CS, lets check what we can do +
; with the flags (this will detect a 32-bit processor). +
;-----------------------------------------------------------------------+
mov si,Str_Out_Array16 ; this has to be preserved for pre 386
push byte -1
popf ; clear flags [15-0]
pushf
pop ax ; read flags back
cld
bt ax,0Fh ; is bit 15 set?
jc is16bit ; yes, it's an 80(1)86
bt ax,0Eh ; is bit 14 set?
jc is32bit ; yes, it's a 386+
;-----------------------------------------------------------------------+
; If we got here, we have a 286. +
;-----------------------------------------------------------------------+
i80286:
MkClass16 Str_286
MkFamily16 Str_286
MkModel16 Str_286
mov dx,8
jmp i16.end
[section .data]
align 8
Str_Out_Array16:
SOA_Class16 equ $-Str_Out_Array ; Compatability Class
.Class dw Str_CPU_Class,24
dw Str_Blank,1 ; 3,4
SOA_Family16 equ $-Str_Out_Array ; Processor Family
.Family dw Str_CPU_Family,24
dw Str_Blank,1 ;
SOA_Model16 equ $-Str_Out_Array ; CPU Model
.Model dw Str_CPU_Model,24
dw Str_Blank,1 ; Cx...
Str_Out16_Sz equ ($-Str_Out_Array16)>>3 ; Number of elements in array
__SECT__
;-----------------------------------------------------------------------+
; Is it an 8018x or 808x processor? +
;-----------------------------------------------------------------------+
is16bit:
mov ax,-1 ; Set all bits in ax
shr ax,020h ; attempt to shift right 32
or ax,ax ; did it clear ax?
jz i808x ; yes, it's 808x or Vx0
;-----------------------------------------------------------------------+
; It's an 8018x. +
;-----------------------------------------------------------------------+
i8018x:
MkClass16 Str_18x
MkFamily16 Str_18x
call test8bit ; is it 8-bit?
jz i80188 ; yes? It's 80188
MkModel16 Str_186 ; it's a 186
mov dx,7
jmp i16.end
i80188:
MkModel16 Str_188 ; it's a 188
mov dx,6
jmp i16.end
;-----------------------------------------------------------------------+
; It's an 808x, 80C8x or NEC V20/30. +
;-----------------------------------------------------------------------+
i808x:
MkClass16 Str_808x
mov ax,sp ; copy sp
pusha ; executes as 2-byte nop on 808x
nop
cmp ax,sp ; has SP changed?
jne Vx0 ; yes, it's an NEC Vx0
mov ax,0FFFh
push si
mov di,si
MkFamily16 Str_808x
.1
mov cx,0FFFFh
rep es:movsb ; copy 2^32 bits from ES:DI to DS:SI
; these are set to the same places
or cx,cx ; is CX 0?
jnz .3 ; no, it's an 808x
dec ax ; dec dx
jnz .1 ; outer loop
;-----------------------------------------------------------------------+
; It's an 80C8x. +
;-----------------------------------------------------------------------+
call test8bit ; is it 8-bit?
jz .2 ; yes? It's a V20
MkModel16 Str_80C86 ; it's an 8086
mov dx,3
jmp i16.end
.2
MkModel16 Str_80C88 ; it's an 8088
mov dx,2
jmp i16.end
;-----------------------------------------------------------------------+
; It's an 808x. +
;-----------------------------------------------------------------------+
.3
pop si ; restore SI
call test8bit ; is it 8-bit?
jz i8088 ; yes? It's a V20
MkModel16 Str_8086 ; it's an 8086
mov dx,1
jmp i16.end
i8088:
MkModel16 Str_8088 ; it's an 8088
mov dx,0
jmp i16.end
;-----------------------------------------------------------------------+
; It's an NEC V20 or V30. +
;-----------------------------------------------------------------------+
Vx0:
popa
MkFamily16 Str_Vx0
call test8bit ; is it 8-bit?
jz V20 ; yes? It's a V20
MkModel16 Str_V30 ; it's a V30
mov dx,5
jmp i16.end
V20:
MkModel16 Str_V20 ; it's a V20
mov dx,4
jmp i16.end
;-----------------------------------------------------------------------+
; test8bit routine tests whether we have an 8 or 16-bit data bus. +
;-----------------------------------------------------------------------+
[section .code]
test8bit:
mov ax,-1
mov [.1], byte 040h ; try to change code at .1 to inc
nop
nop
nop
nop
.1 nop ; if executes as inc, it's 8-bit
nop ; and ZF is set.
ret
__SECT__
;-----------------------------------------------------------------------+
; Some strings to define the CPU class/family/model for 8/16 bit CPUs. +
;-----------------------------------------------------------------------+
[section .data]
Str_Vx0 db "NEC Vx0"
Str_Vx0_Sz equ $-Str_Vx0
Str_V20 db "NEC V20"
Str_V20_Sz equ $-Str_V20
Str_V30 db "NEC V30"
Str_V30_Sz equ $-Str_V30
Str_808x db "808x"
Str_808x_Sz equ $-Str_808x
Str_8086 db "8086"
Str_8086_Sz equ $-Str_8086
Str_8088 db "8088"
Str_8088_Sz equ $-Str_8088
Str_80C86 db "80C86"
Str_80C86_Sz equ $-Str_80C86
Str_80C88 db "80C88"
Str_80C88_Sz equ $-Str_80C88
Str_18x db "8018x"
Str_18x_Sz equ $-Str_18x
Str_186 db "80186"
Str_186_Sz equ $-Str_186
Str_188 db "80188"
Str_188_Sz equ $-Str_188
Str_286 db "286"
Str_286_Sz equ $-Str_286
__SECT__
;-----------------------------------------------------------------------+
; Display error message if not a 32-bit processor. +
;-----------------------------------------------------------------------+
i16:
.end:
hlt
jmp $-1 ; make sure we halt again if we are
; resumed by an interrupt.
;-------------------------------------------------------------------------------+
; Now for the 32-bit processor detection code... +
; +
; If we got here, we know we have a 386 or later processor. +
;-------------------------------------------------------------------------------+
is32bit:
IntStart ; setup interrupt vectors
call Int_Setup ; first call installs our new interrupts
mov si,Str_Out_Array ; this has to be preserved throughout...
;-------------------------------------------------------------------------------+
; Int06_New: Invalid opcode handler +
; +
; input: BX = 0 +
; +
; output: BX = 0FFFFh +
; +
; Sets BX to 0ffffh (as an invalid opcode semaphore), and then increments the +
; return IP by 3 before returning control to the original code. +
;-------------------------------------------------------------------------------+
[section .code]
Int06_New:
push bp
mov bp,sp
dec bx
add word [SS:BP],3
pop bp
iret
__SECT__
;-------------------------------------------------------------------------------+
; Int0D_New: General Protection Exception handler +
; +
; input: BX = 0 +
; +
; output: BX = 01h +
; +
; Sets BX to 01h (as a #GP semaphore), and then increments the return IP by 3 +
; before returning control to the original code. +
;-------------------------------------------------------------------------------+
[section .code]
Int0D_New:
push bp
mov bp,sp
inc bx
add word [SS:BP + 2],3
pop bp
iret
__SECT__
;-------------------------------------------------------------------------------+
; Int_Setup: Set up Int handlers +
; +
; input [bp-4] = new int 6 offset +
; [bp-2] = new int 6 segment +
; +
; output: none +
; +
; This routine simply exchanges the old Int6 address and the new one, thus +
; saving the original vector on the first call and restoring it on the +
; second. +
;-------------------------------------------------------------------------------+
[section .text]
Int_Setup:
push dx
push ds
push byte 0
pop ds ; interrupt vector table...
mov edx,[IVT_int06]
xchg edx,[es:new_int06]
mov [IVT_int06],edx
mov edx,[IVT_int07]
xchg edx,[es:new_int07]
mov [IVT_int07],edx
mov edx,[IVT_int0D]
xchg edx,[es:new_int0D]
mov [IVT_int0D],edx
pop ds
pop dx
ret
__SECT__
;-------------------------------------------------------------------------------+
; prints: print string +
; +
; input: ES:BP pointer to string +
; CX string length in bytes +
; +
; output: none +
;-------------------------------------------------------------------------------+
[section .code]
prints:
push dx
push ax
push bx
push cx
mov ah,03h
xor bh,bh
int 10h
pop cx
mov ax,01301h
mov bx,7
int 10h
pop bx
pop ax
pop dx
ret
__SECT__
[section .data]
new_int06 dd 0 ; store int 06 vector
new_int07 dd 0 ; store int 06 vector
new_int0D dd 0 ; store int 0D vector
__SECT__
;-----------------------------------------------------------------------+
; This array is used to hold pointers to the various data elements +
; which describe the processor. +
;-----------------------------------------------------------------------+
[section .data]
align 8
Str_Out_Array:
SOA_Class equ $-Str_Out_Array ; Compatability Class
.Class dw Str_CPU_Class,24
dw Str_Blank,1 ; 3,4
SOA_Type equ $-Str_Out_Array ; Processor Type
.Type dw Str_CPU_Type,24 ; Single, Overdrive, Dual
dw Str_Blank,1 ;
SOA_Family equ $-Str_Out_Array ; Processor Family
.Family dw Str_CPU_Family,24
dw Str_Blank,1 ;
SOA_Model equ $-Str_Out_Array ; CPU Model
.Model dw Str_CPU_Model,24
dw Str_Blank,1 ; Cx...
SOA_Mask equ $-Str_Out_Array ; Stepping, revision...
.Mask dw Str_CPU_Mask,24
dw Str_Blank,1 ;
SOA_FPU equ $-Str_Out_Array ; FPU Type
.FPU dw Str_FPU_Type,24
dw Str_Blank,1 ;
SOA_IDType equ $-Str_Out_Array ; Method used for ID
.IDType dw Str_CPUID_Type,24
dw Str_Feat,Str_Feat_Sz ; All
SOA_VID equ $-Str_Out_Array ; Vendor ID String
.VID dw Str_CPU_V_ID,24
dw Str_VendorID,12 ; Completed (CPUID Only)
SOA_Vendor equ $-Str_Out_Array ; Vendor name (or generic...)
.Vendor dw Str_Vendor,24
dw Str_Blank,1 ; All 386, 486
SOA_ID equ $-Str_Out_Array ; CPU ID
.ID dw Str_CPUID_Val,24
dw Str_IDVal,4 ; All 486+
SOA_Clock equ $-Str_Out_Array ; Clock multiplier
.Clock dw Str_CPU_Clock,24
dw Str_Blank,1 ;
Str_Out_Sz equ ($-Str_Out_Array)>>3 ; Number of elements in array
;-----------------------------------------------------------------------+
; The first few data items are part of the output used to display the +
; information returned by this code. +
;-----------------------------------------------------------------------+
Str_CPU_Class db "Compatibility : " ; 386, 486, Y
; Pentium
Str_CPU_Type db "Processor type : " ; Overdrive, Dual, etc
Str_CPU_Family db "Family : " ; 386/486/Pentium, etc
Str_CPU_Model db "Model : " ; 486DX, K6-III, etc
; Cx486.... Y
Str_CPU_Mask db "Stepping/Revision : " ; If known...
Str_FPU_Type db "FPU type : " ; 287 - 487, built-in
Str_CPUID_Type db "Identification method : " ;CPUID, BIOS, reset, Y
; feature test,
; Cyrix DIRs,
; IBM MSRs
Str_CPU_V_ID db "Vendor ID : " ; CPUID Vendor ID
Str_Vendor db "CPU Vendor : " ; Intel or compatible,
; Cyrix or compatible,
; NexGen, IBM, etc
Str_CPUID_Val db "Processor ID : " ; From CPUID, DIRs, etc
Str_FSB_Clock db "FSB Clock : " ; If known...
Str_CPU_Clock db "Core Clock : " ; If known...
Str_Clk_Ratio db "Core/Bus Clock Ratio : " ; If known...
Str_Blank db " "
Str_Blank_Sz equ $-Str_Blank
;-----------------------------------------------------------------------+
; Some strings to define the CPU class/family/model. +
;-----------------------------------------------------------------------+
Str_386 db "386"
Str_386_Sz equ $-Str_386
Str_486 db "486"
Str_486_Sz equ $-Str_486
Str_P6 db "P6"
Str_P6_Sz equ $-Str_P6
;-----------------------------------------------------------------------+
; Array of CPUID methods strings +
;-----------------------------------------------------------------------+
ID_Arr:
istruc ID_Array
at ID_Array.Feat, dd Str_Feat + (Str_Feat_Sz<<10h)
at ID_Array.CPUID, dd Str_CPUID + (Str_CPUID_Sz<<10h)
at ID_Array.Reset, dd Str_Reset + (Str_Reset_Sz<<10h)
at ID_Array.IBM, dd Str_IBM_MSR + (Str_IBM_MSR_Sz<<10h)
at ID_Array.BIOS, dd Str_BIOS + (Str_BIOS_Sz<<10h)
at ID_Array.CxDIRs, dd Str_Cx_DIR + (Str_Cx_DIR_Sz<<10h)
at ID_Array.CxFeat, dd Str_Cx_Feat + (Str_Cx_Feat_Sz<<10h)
at ID_Array.Unknown, dd Str_Unknown + (7 << 10h)
iend
Str_Feat db "CPU Features"
Str_Feat_Sz equ $-Str_Feat
Str_CPUID db "CPUID"
Str_CPUID_Sz equ $-Str_CPUID
Str_Reset db "Reset"
Str_Reset_Sz equ $-Str_Reset
Str_IBM_MSR db "IBM MSRs"
Str_IBM_MSR_Sz equ $-Str_IBM_MSR
Str_BIOS db "BIOS"
Str_BIOS_Sz equ $-Str_BIOS
Str_Cx_DIR db "Cyrix DIRs"
Str_Cx_DIR_Sz equ $-Str_Cx_DIR
Str_Cx_Feat db "Cyrix features"
Str_Cx_Feat_Sz equ $-Str_Cx_Feat
Str_VendorID db " "
;-----------------------------------------------------------------------+
; Other strings... +
;-----------------------------------------------------------------------+
Str_IDVal db " "
CPUID_Val dd 0
CPUID_Arr:
.Type db 0
.Family db 0,0
.Model db 0
.Mask db 0
CPUID_Arr_Sz equ $-CPUID_Arr
__SECT__