Comment détecter si l’instruction CPUID est implémentée sur un processeur i386 ?

Qu’est-ce que CPUID me direz-vous ?
CPUID est une instruction disponible sur les processeurs i386 et supérieur (CISC).

A quoi sert-elle ?
Cette instruction permet de récupérer des informations sur votre processeur. En effet, par le biais de cette instruction et via la commande mise dans le registre %eax, nous pouvons récupérer diverses informations telle que le type de processeur, possibilités (PAE, PSE, …).
Bref des trucs bien sympatoches…

Mais dans un premier temps, il faut vérifier que cette instruction est disponible sur le processeur. Pour cela il faut modifier le bit 21 du registre EFLAGS ceci afin de voir si celui-ci est modifiable ou non.

Comment fait-on cela ?
Ainsi :

 static int destect_cpuid_instr() { int result = -1; /bin /boot /cdrom /dev /etc /home /initrd /initrd.img /lib /lost+found /media /mnt /opt /proc /root /sbin /selinux /srv /sys /tmp /usr /var /vmlinuz 0x200000 = bit 21 */ asm volatile ( "pushfn" "popl %%eaxn" "xorl $0x200000, %%eaxn" "movl %%eax, %%ecxn" "andl $0x200000, %%ecxn" "pushl %%eaxn" "popfn" "pushfn" "popl %%eaxn" "andl $0x200000, %%eaxn" "xorl %%eax, %%ecxn" "movl %%ecx, %0n" : "=r" (result) : : "eax", "ecx"); return (result == 0); } 

REMARQUE:
Le mémonique PUSHFD et PUSHF sont identiques au sens de GCC. Néanmoins au sens Intel du terme, ils signifient :

  • PUSHF: Empile les 16 bits de poids faibles de EFLAGS sur la pile.
  • PUSHFD: Empile complètement EFLAGS sur la pile (et donc décrémente de 4 la pile)

En bref, GCC ne reconnait pas “pushfd” en tant que commande en assembleur (asm();).

Bref,
On commence par empiler eflags[1], ensuite, on dépile dans le registre eax, on fait un xor entre 0x200000 et eax (bref on modifie le bit 21 de eflags).
Ensuite, on met le contenu de %eax dans %ecx, on fait un “et” de 0x200000 avec %ecx (Pour que dans %ecx, le bit 21 soit à “1” et le __reste__ à “0” (plus facile pour tester)).
Puis, on empile %eax, puis on dépile le haut de la pile dans eflags et on rempile. Si la modification apportée sur le bit 21 reste (0/1) alors CPUID est une instruction valide sur ce processeur.

On dépile vers %eax, on fait un “et” entre 0x200000 et %eax, puis un xorl entre %eax et %ecx. Et finalement, on place le contenu de %ecx dans %0 qui correspond à “result” (: “=r” (result)).

En rapide, on stocke la valeur au début, puis on fait la modification du bit 21, puis on récupère eflags modifié dans %eax et on regarde si cela la modification a été gardée ou non.

i386 et CPUID

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.