\\ Home : Articoli : Stampa
L'istruzione CPUID
Di Ercand (del 11/01/2008 @ 20:30:44, in C++, linkato 3523 volte)

CPUID è una istruzione, utile per identificare la CPU, introdotta dai processori Intel Pentium. Da allora questa è diventata l’istruzione ufficiale per ottenere le informazioni dei processori x86. Tutte le moderne cpu supportano questa istruzione, prima di allora ottenere le stesse informazioni era più complicato.

L’istruzione CPUID supporta due tipi di funzioni, quelle standard, che forniscono le informazioni base del processore, e quelle extended che forniscono le informazioni avanzate del processore.

I dati forniti da questa istruzione dipendono completamente dal valore che il registro EAX ha nel momento in cui è eseguita l’istruzione CPUID, ciò significa che impostando il registro EAX con valori diversi otterremo differenti informazioni.

Per le informazioni standard dovremo impostare EAX con un valore (useremo spesso la notazione esadecimale in questo articolo quindi cercate di prendere confidenza con questo tipo di scrittura) minimo pari a 0x00000000 per quelle estese invece il valore minimo è 0x80000000, i valori massimi per cui ha senso chiamare l’istruzione cambiano tra processori differenti, questo valore può essere recuperato insieme alle altre informazioni.

Una volta impostato EAX, ed aver eseguito l’istruzione CPUID, tutte le informazioni riguardanti il processore saranno memorizzate in quattro registri, questi registri hanno i nomi di EAX, EBX, ECX e EDX; tutti e quattro i registri hanno una dimensione di 32bit ed operando in determinati modi su questi bit ( usando principalmente gli operatori per lo shift, AND e OR logico ) si possono estrarre tutte le informazioni in esse contenute ed usarle come meglio crediamo nelle nostre applicazioni.

Per usare l’istruzione CPUID dovremo far uso del linguaggio assembly, programmare in questo modo è difficile da digerire soprattutto per chi è alle prime armi quindi, per comodità, ho scritto questa funzione che esegue tutte le operazioni necessarie.

 

static void cpuid(DWORD op, DWORD *EAX, DWORD *EBX,
                  DWORD *ECX, DWORD *EDX)
{
#ifdef _WIN32
    DWORD A, B, C, D;
    _asm{
        mov eax, op
            cpuid
            mov A, eax
            mov B, ebx
            mov C, ecx
            mov D, edx
    }
    *EAX = A;
    *EBX = B;
    *ECX = C;
    *EDX = D;
#endif
}

Questa funzione prende il parametro “op” e lo inserisce in EAX dopodichè è eseguita l’istruzione CPUID ed i valori dei quattro registri, che ora contengono una qualche informazione, sono inseriti nei rispettivi puntatori che abbiamo passato alla funzione, ora che abbiamo a disposizione tutti e quattro i valori possiamo lavorarci sopra ed estrarne le informazioni.

Ora che abbiamo finito questa introduzione passiamo alla pratica.

CPUID 0x0

Chiamiamo la funzione e passiamogli un valore pari a 0x0 ed i relativi quattro puntatori a DWORD.

cpuid (0x0, &EAX, &EBX, &ECX, &EDX);

Con questi registri possiamo ricavare determinate informazioni; il contenuto di questi registri può essere interpretato basandosi su dei documenti, scaricabili dai siti dei produttori delle relative cpu, che ne spiegano il significato, questi appena ottenuti dovranno essere così trattati:

Il registro EAX contiene il massimo valore che può essere passato al parametro “op” ( questo è il valore massimo che abbiamo accennato all’inizio dell’articolo ) per recuperare le informazioni standard.

I registri EBX, ECX e EDX contengono una stringa detta Vendor ID. Questa è una stringa che contraddistingue i vari produttori di cpu, ad esempio la Intel usa una stringa che corrisponde a GenuineIntel mentre la AMD come stringa usa AuthenticAMD, per comprendere meglio come funziona facciamo un esempio pratico.

Nel caso in cui fossimo possessori di un processore Intel i registri appena ottenuti avrebbero questi valori:

EBX = 0x756E6547

EDX = 0x49656E69

ECX = 0x6C65746E

Considerando che un carattere occupa una dimensione di 8bit, ed essendo i registri grandi 32bit, abbiamo che essi contengono 32/8 = 4 caratteri, più precisamente prendendo 8bit alla volta abbiamo che

EBX = 0x756E6547 = uneG

La stringa è stata ottenuta estraendo i quattro caratteri, infatti 75 = u, 6E = n, 65 = e, 47 = G

Con lo stesso ragionamento possiamo sapere a quali caratteri corrispondono i valori contenuti negli altri registri, in questo caso abbiamo:

EDX = Ieni

ECX = letn

CPUID 0x1

Chiamiamo la funzione passando un valore 0x1 ed i relativi quattro puntatori a DWORD.

cpuid (0x1, &EAX, &EBX, &ECX, &EDX);

Vediamo più in dettaglio solo il registro EAX.

Il registro EAX contiene un gruppo d’informazioni che contraddistinguono le molte famiglie di processori che ci sono in commercio, la struttura del registro si presenta così

Il valore Family identifica quelle cpu che appartengono ad uno stesso gruppo di processori (esempio la famiglia dei Pentium 3 o dei Pentium 4 ecc...).

Il valore Model contraddistingue i vari processori che appartengono ad una stessa famiglia, per esempio i processori AMD K7 hanno un valore di family pari a 0x6, ma tra i K7 ci sono i core Barton, Duron, Thunderbird ed altri che sono identificabili proprio grazie a questo valore.

Il valore Stepping identifica una particolare versione di un processore appartenente allo stesso modello.

Facciamo un esempio pratico estraendo il valore di Model.

DWORD Model = (EAX << 4) & 0xF;

Qui abbiamo semplicemente shiftato di 4 bit EAX e fatto un’operazione di AND per recuperare solo i primi 4 bit che ci servivano, lo stesso meccanismo si usa per ottenere tutti gli altri valori.

Quanto i valori family e model assumono dei valori particolari devono essere combinati insieme ad Extended Family e Extended Model, maggiori informazioni su come comportarsi in questi casi (che differiscono tra i vari produttori) si trovano nelle documentazioni ufficiali.

Tutto ciò che è stato scritto fin qua ha avuto l’obbiettivo di far comprendere il funzionamento dell’istruzione CPUID e dare così le basi per poter proseguire da soli e cercare tutte le feature supportate dal vostro processore. Oltre ai casi trattati nell’articolo ci sono molte altre caratteristiche del processore che possono essere conosciute (e vi assicuro che sono davvero molte), si possono sapere i set d’istruzioni supportate ( SSE, SSE2, MMX ecc…), conoscere la quantità di cache a disposizione, se è un processore con più di un core ed altro.

Documenti utili.

Intel® Processor Identification and the CPUID Instruction

ftp://download.intel.com/design/processor/applnots/24161832.pdf

CPUID Specification

http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/25481.pdf