News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

My version of a CPU identification utility

Started by Mark44, February 22, 2014, 04:08:06 AM

Previous topic - Next topic

TWell

#30
Processor name too?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;
}

char s[50];
printf("cpu name: %s\n", cpu_name(s));
shorterchar *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;
}

Mark44

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

#32
;--------------------------------------------------

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

Mark44

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

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

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

Quote from: dedndave on February 25, 2014, 01:20:38 AM
you can just push a 0

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


Gunther

Jochen,

Quote from: jj2007 on February 25, 2014, 02:17:19 AM
; no push
        print   edi, 13, 10
        add     esp,52-4[/tt]


:t

Gunther
You have to know the facts before you can distort them.

TWell

Just lucky, if this works?
;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

Quote from: TWell on February 25, 2014, 03:51:38 AM
Just lucky, if this works?
Compiled after some minor changes( name -> _name etc.)
APPCRASH :
Quote
  Exception Code:   80000003
  Exception Offset:   0000108d

TWell

least missing ret.
name changed to buf.
.586 inserted

GoneFishing


Mark44

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.
// 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.
// 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.
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.
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

all looks correct, here

prescott w/htt
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

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.