Jump to content

Recommended Posts

User asked about checking for cpuid features that weren't supported by _WinAPI_IsProcessorFeaturePresent()

I researched it a bit and found that 'Andreik' executed some asm on the fly to get vendorID which quite frankly is amazing

So I ran with it and created a function that is more general purpose and good for x86 and x64

 

#include <String.au3>
#include <Memory.au3>
Test();
Func Test()
    Local $sFeat1D = ""
    Local $aFeat1D[32] = ["FPU","VME","DE","PSE","TSC","MSR","PAE","MCE", _
                          "CX8","APIC","?","SEP","MTRR","PGE","MCA","CMOV", _
                          "PAT","PSE36","PSN","CLFSH","?","DS","ACPI","MMX", _
                          "FXSR","SSE","SSE2","SS","HTT","TM","IA64","PBE"]

Local $iEdx = CpuID(0x00000001)[3]
    For $i = 0 to 31
        if Get_BitGroup_Dword($iEdx, $i, $i) = 1 Then $sFeat1D &= $aFeat1D[$i] & " "
    Next

    Local $sFeat1C = ""
    Local $aFeat1C[32] = ["SSE3","PCLMULQDQ","DTES64","MONITOR","DS-CPL","VMX","SMX","EST", _
                          "TM2","SSSE3","CNTX-ID","SDBG","FMA","CX16","XTPR","PDCM", _
                          "?","PCID","DCA","SSE4.1","SSE4.2","X2APIC","MOVBE","POPCNT", _
                          "TSC-DEADLINE","AES","XSAVE","OSXSAVE","AVX","F16C","RDRND","HYPERVISOR"]

    Local $iEcx = CpuID(0x00000001)[2]
    For $i = 0 to 31
        if Get_BitGroup_Dword($iEcx, $i, $i) = 1 Then $sFeat1C &= $aFeat1C[$i] & " "
    Next

MsgBox(0, "CpuId", CpuId_Vendor() & @CRLF & CpuId_Processor_Brand() & @cRLF & $sFeat1D & @cRLF & $sFeat1C)
EndFunc

;----------------------------------------------------------------------------
Func Get_BitGroup_Dword($iDword, $iLsb, $iMsb)
    Local $iVal1 = BitShift($iDword, $iLsb) ;>>
    Local Const $iMask = 0xFFFFFFFF
    Local $iVal2 = BitNOT(BitShift($iMask, ($iLsb-$iMsb-1))) ;~<<
    Return BitAND($iVal1, $iVal2)
EndFunc

Func RevBinStr($val)
    Local $rev
    For $n = BinaryLen($val) To 1 Step -1
        $rev &= Hex(BinaryMid($val, $n, 1))
    Next
    Return BinaryToString("0x" & $rev)
EndFunc

Func CpuId($iLeaf, $iSubLeaf = 0)
    Local $aE[4] = [0, 0, 0, 0]
    Local $aCPUID = __Cpuid_Get_Leaf(BitAND($iLeaf, 0xFFFF0000)) ;need to get max first
    If @error or $aCPUID[0] < $iLeaf Then Return SetError(1, @error, $aE)
    Return __Cpuid_Get_Leaf($iLeaf, $iSubLeaf)
EndFunc

Func CpuId_Vendor()
    Local $aCPUID = __Cpuid_Get_Leaf(0x0)
    Return RevBinStr($aCPUID[1]) & RevBinStr($aCPUID[3]) & RevBinStr($aCPUID[2])
EndFunc

Func CpuId_Processor_Brand()
    Local $sPBS = "NOT SUPPORT"
    Local $aCPUID = __Cpuid_Get_Leaf(0x80000000) ;need to get max extended value first
    If $aCPUID[0] < 0x80000004 Then Return SetError(1, 0, $sPBS)
    $aCPUID = __Cpuid_Get_Leaf(0x80000002)
    $sPBS = RevBinStr($aCPUID[0]) & RevBinStr($aCPUID[1]) & RevBinStr($aCPUID[2]) & RevBinStr($aCPUID[3])
    $aCPUID = __Cpuid_Get_Leaf(0x80000003)
    $sPBS &= RevBinStr($aCPUID[0]) & RevBinStr($aCPUID[1]) & RevBinStr($aCPUID[2]) & RevBinStr($aCPUID[3])
    $aCPUID = __Cpuid_Get_Leaf(0x80000004)
    $sPBS &= RevBinStr($aCPUID[0]) & RevBinStr($aCPUID[1]) & RevBinStr($aCPUID[2]) & RevBinStr($aCPUID[3])
    Return StringStripWS($sPBS, 7)
EndFunc

Func CpuId_Signature_Info()
    Local $aRet[6] = [0, 0, 0, 0, 0 ,0]
    Local Enum $eStep = 0, $eModel, $eFamily, $eType, $eExtModel, $eExtFamily
    Local $aCPUID = __Cpuid_Get_Leaf(0x00000000) ;need to get max id value first
    If $aCPUID[0] < 0x00000001 Then Return SetError(1, 0, $aRet)
    $aCPUID = __Cpuid_Get_Leaf(0x00000001)
    Local $iEax = $aCPUID[0]
    $aRet[$eStep]      = Get_BitGroup_Dword($iEax, 0, 3)
    $aRet[$eModel]     = Get_BitGroup_Dword($iEax, 4, 7)
    $aRet[$eFamily]    = Get_BitGroup_Dword($iEax, 8, 11)
    $aRet[$eType]      = Get_BitGroup_Dword($iEax, 12, 13)
    $aRet[$eExtModel]  = Get_BitGroup_Dword($iEax, 16, 19)
    $aRet[$eExtFamily] = Get_BitGroup_Dword($iEax, 20, 27)
    Return $aRet
EndFunc

Func __Cpuid_Get_Leaf($iLeaf, $iSubLeaf = 0)

    Local Const $sCode32 =  "0x"     & _ ; use32
                            "55"     & _ ; push ebp
                            "89E5"   & _ ; mov ebp, esp
                            "53"     & _ ; push ebx
                            "8B4508" & _ ; mov eax, [ebp + 08] ;$iLeaf
                            "8B4D0C" & _ ; mov ecx, [epb + 12] ;$iSubLeaf
                            "31DB"   & _ ; xor ebx, ebx ; set ebx = 0
                            "31D2"   & _ ; xor edx, edx ; set edx = 0
                            "0FA2"   & _ ; cpuid
                            "8B6D10" & _ ; mov ebp, [ebp + 16] ;ptr int[4]
                            "894500" & _ ; mov [ebp + 00], eax
                            "895D04" & _ ; mov [edi + 04], ebx
                            "894D08" & _ ; mov [edi + 08], ecx
                            "89550C" & _ ; mov [edi + 12], edx
                            "5B"     & _ ; pop ebx
                            "5D"     & _ ; pop ebp
                            "C3"         ; ret

    Local Const $sCode64 =  "0x"         & _ ; use 64
                            "53"         & _ ; push rbx
                            "89C8"       & _ ; mov  eax, ecx ;$ileaf
                            "89D1"       & _ ; mov  ecx, edx ;$iSubleaf
                            "31DB"       & _ ; xor  ebx, ebx
                            "31D2"       & _ ; xor  edx, edx
                            "0FA2"       & _ ; cpuid
                            "67418900"   & _ ; mov  [r8d], eax ;ptr int[4]
                            "6741895804" & _ ; mov  [r8d + 04], ebx
                            "6741894808" & _ ; mov  [r8d + 08], ecx
                            "674189500C" & _ ; mov  [r8d + 12], edx
                            "5B"         & _ ; pop rbx
                            "C3"             ; ret


    Local Const $sCode = @AutoItX64 ? $sCode64 : $sCode32
    Local Const $iSize = BinaryLen($sCode)
    Local $aE_X[4] = [0, 0, 0, 0]
    Local $iErr

    Do
        $iErr = 1
        Local $pBuffer = _MemVirtualAlloc(0, $iSize, BitOR($MEM_COMMIT, $MEM_RESERVE), $PAGE_EXECUTE_READWRITE)
        If $pBuffer = 0 Then ExitLoop
        $iErr = 2
        DllStructSetData(DllStructCreate("BYTE[" & $iSize & "]", $pBuffer), 1, $sCode)
        If @error Then ExitLoop
        $iErr = 3
        Local $tRet = DllStructCreate("int EAX;int EBX;int ECX;int EDX;")
        If @error Then ExitLoop
        $iErr = 4
        Local $aRet = DllCallAddress("uint:cdecl", $pBuffer, "int", Int($iLeaf), "int", Int($iSubLeaf), "ptr", DllStructGetPtr($tRet))
        If @error Then ExitLoop
        $iErr = 0;Success?
    Until(True)

    _MemVirtualFree($pBuffer, $iSize, $MEM_DECOMMIT)

    ConsoleWrite($iErr <> 0 ? "Error " & $iErr & @CRLF : Hex($aRet[0], 8) & " Leaf: 0x" & Hex($iLeaf, 8) & " SubLeaf: 0x" & Hex($iSubLeaf, 8) & @CRLF)

    For $i = 0 To $iErr <> 0 ? -1 : UBound($aE_X) - 1
        $aE_X[$i] = "0x" & Hex(DllStructGetData($tRet, $i + 1))
        ConsoleWrite("E" & Chr(65 + $i) & "X: " & $aE_X[$i] & @CRLF)
    Next

    Return SetError($iErr, @error, $aE_X)
EndFunc

 

Most of the processor features can be checked with CPUID(0xXXXXXXXX) and using GET_BitGroup_Dword($iE_X, $iBitpos, $iBitpos) as shown in the example

I broke the weirder ones out into their own specialized functions

Edited by Bilgus
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...