Mit CPUID die Prozessor Modell Nummer auslesen



  • Hallo so müsste ich ja eigentlich laut Intel Manuel die Prozessor Modell Nummer auslesen können.

    Als Ausgabe in EAX bekomme ich hier immer 10.

    mov eax,1
    cpuid
    and eax,11110000b
    

    Das Programm CPUID sagt das meine Modell Nummer 1 ist.
    Und in einem Beispiel Code habe ich gesehen das nach and eax,11110000b noch ein shr eax,4 kommt. Dann bekomme ich am Ende auch in EAX eine 1 heraus.

    Aber warum muss man da nochmal rum shiften?

    Davon steht nichts in den Intel Manuals. _



  • cpuid schrieb:

    Davon steht nichts in den Intel Manuals.

    In den Intel Manuals steht, welche Bits von EAX mit welchen Werten gefüllt werden. Intel geht davon aus, dass Du weißt, wohin Du sie shiften musst, um an die Einzelheiten zu gelangen.

    Wenn Du den vollständigen Quelltext Deines Programms postest, noch Betriebssystem und Compiler/Assembler mitteilst, dann könnte ich versuchen, Dir die Binärlogik mithilfe eines Programms näher zu bringen.

    viele grüße
    ralph



  • Weißt du eigentlich, was der "and eax,F0" Befehl genau macht?
    (und wie man die Binärnummern zur Ausgabe bekommt?)



  • Assembler: MASM
    OS: Windows XP

    Und ja ich weiss was der and Befehl macht. Aber ich weiss nicht woher man wissen soll das man hier shiften muss anstatt Intel das mit ins Manuel reinschreiben ...

    .686p                                   
    .model flat, stdcall                     
    option casemap :none 
    
    include     \masm32\include\windows.inc
    include     \masm32\include\kernel32.inc
    includelib  \masm32\lib\kernel32.lib
    include     \masm32\include\masm32.inc
    includelib  \masm32\lib\masm32.lib
    include \masm32\include\user32.inc 
    includelib \masm32\lib\user32.lib 
    
    .data 
    
    nr dd 0,0
    
    .code 
    start:
    
    	mov eax,1 
    	cpuid 
    	and eax,11110000b
    
    	shr eax,4
    	add eax,30h
    
    	mov dword ptr [nr] ,eax
    
    	invoke StdOut, addr nr
    
    	invoke Sleep,1000
    	invoke ExitProcess,0
    
    end start
    


  • cpuid schrieb:

    ... anstatt Intel das mit ins Manuel reinschreiben ...

    Im Manual steht noch sowas wie "see Figure 3-5 oder 3-6 oder so" :

    in  EAX = 1
    
    out EAX :
    
    bitnr:
    
    00-03   Stepping ID
    04-07   Model
    08-11   Family ID
    16-19   Extended Model ID
    20-27   Extended Family ID
    


  • rkhb schrieb:

    Wenn Du den vollständigen Quelltext Deines Programms postest, noch Betriebssystem und Compiler/Assembler mitteilst, dann könnte ich versuchen, Dir die Binärlogik mithilfe eines Programms näher zu bringen.

    cpuid schrieb:

    Assembler: MASM
    OS: Windows XP

    Nun denn, hier erstmal das Programm zur (späteren) Erklärung:

    .686p
    .model flat, stdcall
    option casemap :none
    
    include		\masm32\include\windows.inc
    include		\masm32\include\kernel32.inc
    includelib	\masm32\lib\kernel32.lib
    
    .DATA
    	lfd db "1)  ";
    	hex db "0123456789ABCDEF"
    	buf db "-",10
    
    .DATA?
    	hStdOut dd ?
    	bin db 40 DUP (?)
    	int32 dd ?
    	NumberOfBytesWritten dd ?
    
    .CODE
    
    int2bin PROC
    int2bin ENDP
    
    Int2Bin PROC	; http://dcla.rkhb.de/umwandlung/int2bin.html
    	pushad
    	mov edx,[int32]			; Integer
    	mov edi, OFFSET bin		; Binärzahl (Puffer muss jetzt 40 Bytes fassen können)
    	mov ecx,8			; äußere Schleife: 8 Nibbles
    	Schleife1:
    	push ecx
    	mov ecx,4			; innere Schleife: 4 Bits
    	Schleife2:
    	shl edx,1
    	setc al				; AL je nach herausgeschobenen Bit setzen
    	or al,30h			; ASCII
    	stosb				; und in bin abspeichern
    	loop Schleife2			; innere Schleife
    	mov al,32			; Leerzeichen
    	stosb
    	pop ecx				; äußere Schleife
    	loop Schleife1
    	mov byte ptr [edi-1],10		; \n ersetzt letztes Leerzeichen
    	popad
    	ret
    Int2Bin ENDP
    
    WriteBin PROC
    	pushad
    	invoke WriteFile, DWORD PTR [hStdOut], ADDR lfd, 4, ADDR NumberOfBytesWritten, 0
    	add BYTE PTR [lfd], 1
    	invoke WriteFile, DWORD PTR [hStdOut], ADDR bin, 40, ADDR NumberOfBytesWritten, 0
    	popad
    	ret
    WriteBin ENDP
    
    WriteChar PROC
    	pushad
    	invoke WriteFile, DWORD PTR [hStdOut], ADDR lfd, 4, ADDR NumberOfBytesWritten, 0
    	invoke WriteFile, DWORD PTR [hStdOut], ADDR buf, 2, ADDR NumberOfBytesWritten, 0
    	popad
    	ret
    WriteChar ENDP
    
    main PROC
    	invoke GetStdHandle, STD_OUTPUT_HANDLE
    	mov DWORD PTR [hStdOut], eax
    
    	mov eax,1			; Funktionsnummer für CPUID
    	mov dword ptr [int32], eax
    	call Int2Bin
    	call WriteBin			; 1) binäre Ausgabe der Funktionsnummer
    
    	cpuid
    
    	mov dword ptr [int32], eax	; Ergebnis von CPUID
    	call Int2Bin
    	call WriteBin			; 2) binäre Ausgabe des Ergebnisses von CPUID
    
    	mov edx, 11110000b		; AND-Maske
    	mov dword ptr [int32], edx
    	call Int2Bin
    	call WriteBin			; 3) binäre Ausgabe der AND-Maske
    
    	and eax, 11110000b		; CPUID-Ergebnis undieren
    	mov dword ptr [int32], eax
    	call Int2Bin
    	call WriteBin			; 4) binäre Ausgabe des Ergebnisses der AND-Operation
    
    	shr eax,4			; nach rechts, um es besser umwandeln zu können
    	mov dword ptr [int32], eax
    	call Int2Bin
    	call WriteBin			; 5) binäre Ausgabe des Ergebnisses der Shift-Operation
    
    	mov ebx, OFFSET hex
    	xlat				; in Hexziffer(ASCII) umwandeln
    	mov BYTE PTR [buf] ,al
    	call Int2Bin
    	call WriteChar			; 6) Ausgabe der Hexzahl
    
    	invoke ExitProcess,0		; und tschüss.
    main ENDP
    
    END main
    

    Die Ausgabe des Programms sieht bei mir folgendermaßen aus:
    `

    1. 0000 0000 0000 0000 0000 0000 0000 0001

    2. 0000 0000 0000 0000 0000 0110 1111 1011

    3. 0000 0000 0000 0000 0000 0000 1111 0000

    4. 0000 0000 0000 0000 0000 0000 1111 0000

    5. 0000 0000 0000 0000 0000 0000 0000 1111

    6. F

    `

    1. Zunächst ist wichtig, dass Du Dir ein Register (EAX, EBX, ECX, EDX) nur als ein Bündel von 32 Bits vorstellst. Ob diese 32 Bit nun ein Buchstabe, eine Zahl, eine Adresse oder was ganz anderes darstellen soll, bestimmt der Programmierer (manchmal ist seine Wahl ein bisschen eingeschränkt, aber das ist hier nicht wichtig). Als erstes füllst Du EAX mit einer Funktionsnummer für CPUID (mov eax,1). Wie die 32 Bits von EAX danach aussehen, erzählt Dir die Zeile 1) des Programms.

    Die 32 Bits von EAX werden von rechts nach links durchnummeriert. Die '1' ganz rechts, trägt also die Bezeichnung Bit0 und die '0' ganz links heißt Bit31 (Bit0 bis Bit31 ergibt 32 Bits).

    1. Nun wird CPUID aufgerufen. Die CPU guckt nach der Funktionsnummer und gibt ein Ergebnis in EAX aus. Wie das aussieht, erzählt Dir Zeile 2) des Programms. Nun musst Du in das Manual Deiner CPU gucken, um zu erfahren, was das bedeuten soll. Wenn Du einen Intel-Prozessor hast, guckst Du in das Intel-Manual, wenn Du einen AMD-Prozessor, guckst Du in das AMD-Manual. Das liegt daran, dass sich die CPUID-Ausgaben der verschiedenen Prozessoren unterscheiden können.

    Das zuständige Intel-Manual heißt "Intel® 64 and IA-32 Architectures Software Developer's Manual Combined Volumes 2A, 2B, and 2C: Instruction Set Reference, A-Z" (http://www.intel.de/content/www/de/de/processors/architectures-software-developer-manuals.html). Hier stehen alle Informationen in Kapitel 3.2 (Instructions A-L) unter "CPUID - CPU Identification". Auf Table 3.17 steht, dass bei einem Initial Value von EAX=01H in EAX "Type, Family, Model, and Stepping ID (see Figure 3-5)" ausgegeben wird. Figure 3-5 befindet sich recht viek weiter unten und teilt Dir mit, welche Informationen in welchen Bits von EAX landen. Die kleinen Zahlen oben sind die Bitnummerierung.

    1. Dich interessiert die Information "Model", die sich nach Figure 3-5 an Bit4 bis Bit7 befindet. Wenn Du jetzt in Zeile 2) des Programms von rechts abzählst (mit Null beginnend), dann siehst Du, dass es sich um den zweiten Vier-Block von rechts handelt. Alles übrige interessiert Dich nicht. Dieses "übrige" wird jetzt brutal auf Null gesetzt, damit es keine Verwirrung stiften kann. Dazu dient der AND-Befehl. Nur wo in Zeile 3) eine '1' steht, wird der Inhalt von Zeile 2) durchgelassen und erscheint in Zeile 4).

    2. In Zeile 4) hast Du nur noch einen Block mit Information, das ist der zweite von rechts. Alle anderen Blöcke mit jeweils 4 Bits sind auf Null gesetzt. Jetzt kommt das, was Intel beim besten Willen nicht wissen kann, nämlich was Du mit diesem Block anstellen willst. Du willst offenbar, dass der Inhalt des Blocks als Zahl ausgegeben wird. Mit vier Bits kann man eine Zahl von 0 bis 15 darstellen, einfacher zu programmieren ist eine Hex-Zahl von 0 bis F. Mit dem Befehl XLAT wird jeweils ein Buchstabe (ASCII) aus dem String hex="0123456789ABCDEF" geholt, und zwar jeweils die Stelle, die in AL steht (ab Null zählend). Steht also in AL eine 6, dann wird die 7. Ziffer geholt - das ist die '6' - und in AL gespeichert. Aber wie kommt man zu so einem Wert in AL, die Model-Nummer in EAX steht doch ganz woanders?

    3. Die Modelnummer muss nach rechts. Das Ergebnis siehst Du in Zeile 5) des Programms. Nun haben wir in AL eine Bitfolge, die man als Zähler (Index) für XLAT gebrauchen kann.

    4. Nach dem Shift-Befehl steht Model in AL und mit dem XLAT-Befehl wird der Wert in AL in eine ASCII-Hexadezimalziffer umgewandelt. Das Ergebnis wird in Zeile 6) ausgegeben.

    viele grüße
    ralph

    P.S.: Da wir hier nicht in einem Chat sind (und ich deshalb auch für Lurker und Googler schreibe), wirst Du nicht aufschreien "Das habe ich doch schon längst alles seit Jahren gewusst!!!", sondern Dir überlegen, welchen Denkfehler Du auf Intel abschieben willst.


Anmelden zum Antworten