Author Topic: My version of a CPU identification utility  (Read 24059 times)

TWell

  • Member
  • ****
  • Posts: 748
Re: My version of a CPU identification utility
« Reply #30 on: February 23, 2014, 09:42:02 PM »
Processor name too?
Code: [Select]
char *cpu_name(char *name)
{
__asm{
push ebx
mov edi, dword ptr name
mov dword ptr [edi], 0
mov eax, 80000000h
cpuid
cmp eax, 80000000h
jna pass
mov eax, 80000002h
cpuid
mov dword ptr [edi], eax
mov dword ptr [edi+4], ebx
mov dword ptr [edi+8], ecx
mov dword ptr [edi+12], edx
mov eax, 80000003h
cpuid
mov dword ptr [edi+16], eax
mov dword ptr [edi+20], ebx
mov dword ptr [edi+24], ecx
mov dword ptr [edi+28], edx
mov eax, 80000004h
cpuid
mov dword ptr [edi+32], eax
mov dword ptr [edi+36], ebx
mov dword ptr [edi+40], ecx
mov dword ptr [edi+44], edx
pass:
pop ebx
}
return name;
}
Code: [Select]
char s[50];
printf("cpu name: %s\n", cpu_name(s));
shorter
Code: [Select]
char *cpu_name(char *name)
{
int idx;
__asm{
push ebx
mov edi, name
mov dword ptr [edi], 0
mov eax, 80000000h
cpuid
cmp eax, 80000004h
jb pass
mov idx, 80000002h
next:
mov eax, idx
cpuid
mov dword ptr [edi], eax
mov dword ptr [edi+4], ebx
mov dword ptr [edi+8], ecx
mov dword ptr [edi+12], edx
add edi, 16
add idx, 1
cmp idx, 80000004h
jna next
pass:
pop ebx
}
return name;
}
« Last Edit: February 24, 2014, 05:51:20 PM by TWell »

Mark44

  • Regular Member
  • *
  • Posts: 40
Re: My version of a CPU identification utility
« Reply #31 on: February 24, 2014, 05:20:56 AM »
Tim,
That would be easy enough to add. I didn't include this information in the original code, thinking that the microarchitecture would be enough. As it turns out, the microarchitecture is a relatively new descriptor that started somewhere around the P6 time. (I could be wrong about this.) 

Anyway, I'll incorporate your code into the utility and repost it shortly.
Mark

dedndave

  • Member
  • *****
  • Posts: 8829
  • Still using Abacus 2.0
    • DednDave
Re: My version of a CPU identification utility
« Reply #32 on: February 24, 2014, 11:35:33 AM »
Code: [Select]
;--------------------------------------------------

BrandStr PROC

    mov     eax,80000000h
    push    ebx
    cpuid
    push    eax
    .if eax>=80000004h
        push    edi
        mov     edi,3
        push    0A0Dh
        .repeat
            lea     eax,[edi+80000001h]
            cpuid
            push    edx
            push    ecx
            push    ebx
            push    eax
            dec     edi
        .until ZERO?
        mov     edi,esp
        mov     al,20h
        mov     ecx,48
        repz    scasb
        dec     edi
        print   edi
        add     esp,52
        pop     edi
    .endif
    pop     eax
    pop     ebx
    ret

BrandStr ENDP

;--------------------------------------------------

EDIT: added code to verify brand string is supported
also, returns maximum supported extended function in EAX
« Last Edit: February 24, 2014, 12:41:23 PM by dedndave »

Mark44

  • Regular Member
  • *
  • Posts: 40
Re: My version of a CPU identification utility
« Reply #33 on: February 24, 2014, 06:36:52 PM »
dedndave, I've incorporated your earlier code and restructured my code, as some of the functions were getting pretty long. I'll need to digest the latest contribution, but will add it into the mix tomorrow.

Thanks!

Mark

dedndave

  • Member
  • *****
  • Posts: 8829
  • Still using Abacus 2.0
    • DednDave
Re: My version of a CPU identification utility
« Reply #34 on: February 24, 2014, 11:35:49 PM »
it's simple code to display the brand string
the brand string quite often has numerous leading spaces - so, they are stripped off
here's a little demo program...

dedndave

  • Member
  • *****
  • Posts: 8829
  • Still using Abacus 2.0
    • DednDave
Re: My version of a CPU identification utility
« Reply #35 on: February 25, 2014, 01:20:38 AM »
i see a little boo boo in my thinking, though
i pushed 0A0Dh onto the stack, thinking i'd get a carriage return/line feed
but - the string is typically null terminated, so that never gets displayed   :P
you can just push a 0

jj2007

  • Member
  • *****
  • Posts: 11526
  • Assembler is fun ;-)
    • MasmBasic
Re: My version of a CPU identification utility
« Reply #36 on: February 25, 2014, 02:17:19 AM »
you can just push a 0

; no push
        print   edi, 13, 10
        add     esp,52-4


Gunther

  • Member
  • *****
  • Posts: 3722
  • Forgive your enemies, but never forget their names
Re: My version of a CPU identification utility
« Reply #37 on: February 25, 2014, 03:33:40 AM »
Jochen,

; no push
        print   edi, 13, 10
        add     esp,52-4[/tt]


 :t

Gunther
Get your facts first, and then you can distort them.

TWell

  • Member
  • ****
  • Posts: 748
Re: My version of a CPU identification utility
« Reply #38 on: February 25, 2014, 03:51:38 AM »
Just lucky, if this works?
Code: [Select]
;CPUName.asm
.586
.MODEL FLAT, STDCALL
OPTION CASEMAP :NONE

INCLUDELIB kernel32.lib
ExitProcess PROTO :DWORD

INCLUDELIB user32.lib
MessageBoxA PROTO :DWORD,:DWORD,:DWORD,:DWORD

CPUString PROTO buf:DWORD

.data
sApp db "CPUName",0

.data?
sCpu db 100 DUP(?)

.code
start PROC
mov eax, 0
cpuid
mov DWORD PTR sCpu, ebx
mov DWORD PTR sCpu+4, edx
mov DWORD PTR sCpu+8, ecx
mov DWORD PTR sCpu+12, 0A0Dh
INVOKE CPUString, ADDR sCpu+14
INVOKE MessageBoxA, 0, ADDR sCpu, ADDR sApp, 0
INVOKE ExitProcess,0
start ENDP

CPUString PROC USES edi ebx, buf:DWORD
LOCAL idx:DWORD
mov edi, buf
mov dword ptr [edi], 0
mov eax, 80000000h
cpuid
cmp eax, 80000004h
jb pass
mov idx, 80000002h
next:
mov eax, idx
cpuid
mov dword ptr [edi], eax
mov dword ptr [edi+4], ebx
mov dword ptr [edi+8], ecx
mov dword ptr [edi+12], edx
add edi, 16
add idx, 1
cmp idx, 80000004h
jna next
pass:
ret
CPUString ENDP

END start

GoneFishing

  • Member
  • *****
  • Posts: 1071
  • Gone fishing
Re: My version of a CPU identification utility
« Reply #39 on: February 25, 2014, 04:04:40 AM »
Just lucky, if this works?
Compiled after some minor changes( name -> _name etc.)
APPCRASH :
Quote
  Exception Code:   80000003
  Exception Offset:   0000108d

TWell

  • Member
  • ****
  • Posts: 748
Re: My version of a CPU identification utility
« Reply #40 on: February 25, 2014, 04:26:05 AM »
least missing ret.
name changed to buf.
.586 inserted

GoneFishing

  • Member
  • *****
  • Posts: 1071
  • Gone fishing
Re: My version of a CPU identification utility
« Reply #41 on: February 25, 2014, 05:53:52 AM »
It works after adding RET  :t

Mark44

  • Regular Member
  • *
  • Posts: 40
Re: My version of a CPU identification utility
« Reply #42 on: February 26, 2014, 05:12:30 AM »
In the attached version (source file and release exe), the code now prints the processor name, together with the Intel microarchitecture, if it's one that I know about (i.e., was listed in the current and 2007 Intel Optimization references). I also found and fixed a bug where the code mistakenly reused the SSE2 bit to indicate the presence of SSE3.

Unfortunately for some of you, my code still has inline assembly.

One thing that I had trouble with was trying to allocate heap memory for a couple of strings. When I allocated them with either malloc() or calloc(), I couldn't free() the pointers without generating a bad pointer exception. Things worked fine if I didn't try to free the pointers, but it's not good practice to allocate heap storage without freeing it when you're done. All this was happening with VS 10. I was able to workaround the problem by using _malloca() and _freea, but I have no idea why the older run-time library functions were acting up.

Below are the functions that contain inline assembly, together with a summary of how much or how little they changed.

cpu_info function - unchanged from before except for description comment.
Code: [Select]
// Get version and feature information from cpuid, leaf EAX = 1.
void cpu_info(struct CpuData *returnData)
{
__asm{
push ebx
mov eax, 1H
cpuid
mov ebx, returnData
; After the call to cpuid, store EAX, ECX, and EDX in the CpuData struct.
mov (dword ptr [ebx]).eaxReg, eax
mov (dword ptr [ebx]).ecxReg, ecx
mov (dword ptr[ebx]).edxReg, edx
pop ebx
}

}
printCpuidData function - logic changed extensively.
Code: [Select]
// Now check for support for AVX2.
// Can't check for AVX2 unless the CPU supports AVX.
if (AVX && OSXSAVE && (OSFlags & 0x6))
{

// Call cpuid with EAX = 7 and ECX = 0.
// If bit 5 in the returned EBX is 1, AVX2 is supported.
__asm{
push eax
push ecx
mov eax, 7
xor ecx, ecx
cpuid
mov cacheEBX, ebx
pop ecx
pop eax
}
AVX2 = (cacheEBX & 0x20) >> 5;
printf("CPU and OS %s AVX2.\n", AVX2 ? "support" : "do not support");
}
else printf("CPU and OS do not support AVX2.\n");
AVXSupportInOS function - no change.
Code: [Select]
int AVXSupportInOS()
{
// Read the contents of the extended control register (XCR) specified
// in the ECX register.
// Currently, only XCR0 is supported, so set ECX to zero before
// executing xgetbv (get value of extended control register.
// If bits 1 and 2 are set, XMM state and YMM state are enabled by the OS.
int OSFlags;
__asm{
xor ecx, ecx
xgetbv 
mov OSFlags, eax
}
return OSFlags;
}

cpu_name function - This is new, and is based on the code that TWell and dedndave contributed in this thread.
Code: [Select]
void cpu_name(char *name)
{
__asm{
push ebx
mov edi, dword ptr name
mov dword ptr [edi], 0
mov eax, 80000000h
cpuid
cmp eax, 80000004h  ; If eax < 80000004h, processor name isn't supported.
jna pass

xor esi, esi
loop1:
lea eax, [esi + 80000002h]
cpuid
mov dword ptr [edi], eax
mov dword ptr [edi+4], ebx
mov dword ptr [edi+8], ecx
mov dword ptr [edi+12], edx
add edi, 16
inc esi
cmp esi, 3
jb loop1

pass:
pop ebx
}
}


dedndave

  • Member
  • *****
  • Posts: 8829
  • Still using Abacus 2.0
    • DednDave
Re: My version of a CPU identification utility
« Reply #43 on: February 26, 2014, 05:28:36 AM »
all looks correct, here

prescott w/htt
Code: [Select]
Processor name: Intel(R) Pentium(R) 4 CPU 3.00GHz
Extended + family ID: 0f
Extended + model ID: 04
Stepping: 3
Microarchitecture: NetBurst
CPU has FP unit.
CPU supports MMX.
CPU supports SSE.
CPU supports SSE2.
CPU supports SSE3.
CPU does not support SSE 4.1.
CPU does not support SSE 4.2.
CPU does not support AVX.
CPU and OS do not support AVX2.

you might add a line for SSSE3
also, some AMD processors have 3DNow! and 3DNow!+

Mark44

  • Regular Member
  • *
  • Posts: 40
Re: My version of a CPU identification utility
« Reply #44 on: February 26, 2014, 06:24:28 AM »
dedndave,
Checking for SSSE3 is pretty simple - bit 9 in the returned ECX register from cpuid.

As far as AMD features go, neither of my two computers has an AMD processor, so I haven't been including any tests for those features.