News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Later set of CPUID procedures.

Started by hutch--, June 09, 2010, 02:41:28 AM

Previous topic - Next topic

hutch--

I tweaked these for an application I am working on, the main different is each procedure that calls CPUID is double protected by preserving all of the flags as well as reegisters as I found that Win2000 was fussy about the return state after CPUID is called. These are all testing up OK on the range of hardware and OS versions that I can test with. They are not pointed at pre Win2000 Windows versions including WinME but may in fact work on them if the instruction sets are enabled.


IF 0  ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    ----------------------------------------------
    Put these prototypes and the structure in your
    include file to use the procedures below
    ----------------------------------------------
    is_cpuid PROTO                  ; test if CPUID is available
    vendorstring PROTO :DWORD       ; get the vendor string
    cpu_string PROTO :DWORD         ; get the CPU string
    getmmi  PROTO   :DWORD          ; get the instruction sets
    mmistring PROTO :DWORD,:DWORD   ; format instruction set string

;  If the software that uses any of these procedures will have to work on very old
;  hardware you need to run "is_cpuid" first to test if the processor supports CPUID.
;  The following procedures cannot be run if the processor does not support CPUID.

    NOTE that these procedures are not aimed at Win9x, NT4 or WinME Windows versions and have
    not been tested on these versions. They are aimed at Win2000 upwards and test reliably on
    Win2000, WinXP and Win7 64 bit.

    They may work on earlier Win9x and similar 32 bit versions but the OS may not support or
    allow the usage of later multimedia instruction sets.

    "vendorstring" provide the "GenuineIntel" or "AuthenticAMD" string from the processor.
    "cpu_string" provides the model identifier string if it is available.
    "getmmi" tests for multimedia instruction sets and returns the information in the structure below.
    "mmistring" formats the data from "getmmi" for display purposes.

    X86ST STRUCT
      sse4a dd ?
      sse42 dd ?
      sse41 dd ?
      ssse3 dd ?
      sse3  dd ?
      sse2  dd ?
      sse   dd ?
      mmx   dd ?
      mmxx  dd ?
      amd3D dd ?
      amd3x dd ?
    X86ST ENDS

ENDIF ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

vendorstring proc pBuffer:DWORD

    IF 0  ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
        pBuffer needs to be at least 16 bytes in length
        vendorstring PROTO :DWORD
    ENDIF ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    pushad
    pushfd
   
    mov eax, 0                          ; set ID string for Intel
    cpuid

    mov eax, pBuffer                    ; load buffer address into ESI

    mov [eax],    ebx                   ; write results to buffer
    mov [eax+4],  edx
    mov [eax+8],  ecx
    mov [eax+12], DWORD PTR 0           ; terminate result

    popfd
    popad
   
    ret

vendorstring endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

is_cpuid proc

    IF 0  ; ¤¤¤¤¤¤¤¤¤¤¤¤
          is_cpuid PROTO
    ENDIF ; ¤¤¤¤¤¤¤¤¤¤¤¤

    LOCAL rval :DWORD

    pushad
    pushfd

  ; -------------------------------------------------
  ; test for CPUID so it does not crash on old timers
  ; -------------------------------------------------
    pushfd
    pop eax

    mov ecx, eax
    xor eax, 00000000001000000000000000000000b          ; set bit 21 of eflags
    push eax
    popfd
    pushfd
    pop eax

    xor eax, ecx            ; test if its changed
    jnz exists              ; if changed then CPUID
    mov rval, 0             ; returns 0 if no CPUID
    jmp quit
  ; -------------------------------------------------
  exists:
    mov rval, 1

  quit:
    popfd
    popad

    mov eax, rval

    ret

is_cpuid endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

cpu_string proc pBuffer:DWORD

    IF 0  ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
        cpu_string PROTO :DWORD
    ENDIF ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    LOCAL basicinf  :DWORD
    LOCAL extended  :DWORD

    pushad
    pushfd

    mov eax, 0                                  ; call basic info function
    cpuid
    mov basicinf, eax

    mov eax, 80000000h                          ; call extended info function
    cpuid
    mov extended, eax

    .if extended == 80000004h || extended == 80000008h
      jmp getID
    .endif

    .if basicinf == 00000001h
      cst pBuffer, "Early Unspecified x86 Processor"
      jmp quit
    .elseif basicinf == 00000002h
      cst pBuffer, "Pentium Pro, II or Celeron Processor"
      jmp quit
    .elseif basicinf == 00000003h
      cst pBuffer, "Pentium III Processor"
      jmp quit
    .else
      cst pBuffer, "Cannot Identify x86 Processor"
      jmp quit
    .endif

  getID:

    mov esi, pBuffer                    ; load buffer address into ESI
   
    mov eax, 80000002h                  ; extended function 2
    cpuid

    mov [esi],    eax                   ; write results to buffer
    mov [esi+4],  ebx
    mov [esi+8],  ecx
    mov [esi+12], edx

    mov eax, 80000003h                  ; extended function 3
    cpuid

    mov [esi+16], eax                   ; write results to buffer
    mov [esi+20], ebx
    mov [esi+24], ecx
    mov [esi+28], edx

    mov eax, 80000004h                  ; extended function 4
    cpuid

    mov [esi+32], eax                   ; write results to buffer
    mov [esi+36], ebx
    mov [esi+40], ecx
    mov [esi+44], edx

    mov [esi+48], DWORD PTR 0           ; terminate result

  quit:
    popfd
    popad

    ret

cpu_string endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

getmmi proc pStruct:DWORD

IF 0  ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    X86ST STRUCT
      sse4a dd ?
      sse42 dd ?
      sse41 dd ?
      ssse3 dd ?
      sse3  dd ?
      sse2  dd ?
      sse   dd ?
      mmx   dd ?
      mmxx  dd ?
      amd3D dd ?
      amd3x dd ?
    X86ST ENDS

    --------------------------------------
    pass the address of an X86ST structure
    results are written to the members
    --------------------------------------

    getmmi  PROTO   :DWORD

ENDIF ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    pushad
    pushfd

    mov ecx, SIZEOF X86ST / 4

    mov eax, pStruct
  @@:
    mov DWORD PTR [eax], 0
    add eax, 4
    sub ecx, 1
    jnz @B

  ; INTEL

    mov eax, 1
    cpuid

    mov eax, pStruct

    bt ecx, 20                                      ; sse4.2
    setc BYTE PTR (X86ST PTR [eax]).sse42

    bt ecx, 19                                      ; sse4.1
    setc BYTE PTR (X86ST PTR [eax]).sse41

    bt ecx, 9                                       ; ssse3
    setc BYTE PTR (X86ST PTR [eax]).ssse3

    bt ecx, 0                                       ; sse3
    setc BYTE PTR (X86ST PTR [eax]).sse3

    bt edx, 26                                      ; sse2
    setc BYTE PTR (X86ST PTR [eax]).sse2

    bt edx, 25                                      ; sse
    setc BYTE PTR (X86ST PTR [eax]).sse

    bt edx, 23                                      ; mmx
    setc BYTE PTR (X86ST PTR [eax]).mmx

  ; AMD

    mov eax, 80000001h
    cpuid

    mov eax, pStruct

    bt edx, 22                                      ; AMD mmx extended
    setc BYTE PTR (X86ST PTR [eax]).mmxx

    bt ecx, 6                                       ; AMD sse4a
    setc BYTE PTR (X86ST PTR [eax]).sse4a

    bt edx, 31                                      ; AMD 3DNow
    setc BYTE PTR (X86ST PTR [eax]).amd3D

    bt edx, 30                                      ; AMD 3DNowExt
    setc BYTE PTR (X86ST PTR [eax]).amd3x

    popfd
    popad

    ret

getmmi endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

mmistring proc pStruct:DWORD,pbuffer:DWORD

IF 0  ; ----------------------------------------------------------------------

  Arguments are,
      pStruct = address of a X86ST structure that has been written with getmmi
      pbuffer = address of buffer large enough to accept the string results
                128 BYTE buffer is OK.

    getmmi  PROTO   :DWORD
    mmistring PROTO :DWORD,:DWORD

ENDIF ; ----------------------------------------------------------------------

    LOCAL cloc  :DWORD

    push esi
    push edi

    mov edi, pStruct
    mov esi, pbuffer
    mov cloc, 0

    mov cloc, rv(szappend,esi,"Processor supports",cloc)

  ; INTEL

    .if BYTE PTR (X86ST PTR [edi]).mmx == 1
      mov cloc, rv(szappend,esi," mmx",cloc)
    .endif

    .if BYTE PTR (X86ST PTR [edi]).sse == 1
      mov cloc, rv(szappend,esi," sse",cloc)
    .endif

    .if BYTE PTR (X86ST PTR [edi]).sse2 == 1
      mov cloc, rv(szappend,esi," sse2",cloc)
    .endif

    .if BYTE PTR (X86ST PTR [edi]).sse3 == 1
      mov cloc, rv(szappend,esi," sse3",cloc)
    .endif

    .if BYTE PTR (X86ST PTR [edi]).ssse3 == 1
      mov cloc, rv(szappend,esi," ssse3",cloc)
    .endif

    .if BYTE PTR (X86ST PTR [edi]).sse41 == 1
      mov cloc, rv(szappend,esi," sse4.1",cloc)
    .endif

    .if BYTE PTR (X86ST PTR [edi]).sse42 == 1
      mov cloc, rv(szappend,esi," sse4.2",cloc)
    .endif

  ; AMD

    .if BYTE PTR (X86ST PTR [edi]).mmxx == 1
      mov cloc, rv(szappend,esi," mmx ext",cloc)
    .endif

    .if BYTE PTR (X86ST PTR [edi]).sse4a == 1
      mov cloc, rv(szappend,esi," sse4a",cloc)
    .endif

    .if BYTE PTR (X86ST PTR [edi]).amd3D == 1
      mov cloc, rv(szappend,esi," 3DNow",cloc)
    .endif

    .if BYTE PTR (X86ST PTR [edi]).amd3x == 1
      mov cloc, rv(szappend,esi," 3DNow ext",cloc)
    .endif

    pop edi
    pop esi

    ret

mmistring endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php