2016-04-10 1 views
3

J'imprime des informations sur la CPU dans mon OS en utilisant l'instruction CPUID.Chaîne de marque CPUID brisée?

Lire et imprimer la chaîne du vendeur (GenuineIntel) fonctionne bien, mais la lecture de la chaîne de marque me donne peu de chaîne étrange.

ok cpu-info <= Run command 
CPU Vendor name: GenuineIntel <= Vendor string is good 
CPU Brand: D: l(R) Core(TMD: CPU  MD: <= What..? 
ok 

chaîne du vendeur censé être:

Intel(R) Core(TM) i5 CPU  M 540 

Mais ce que je suis arrivé est:

D: l(R) Core(TMD: CPU  MD: 

C++ Code:

  char vendorString[13] = { 0, }; 
      Dword eax, ebx, ecx, edx; 
      ACpuid(0, &eax, &ebx, &ecx, &edx); 
      *((Dword*)vendorString) = ebx; 
      *((Dword*)vendorString + 1) = edx; 
      *((Dword*)vendorString + 2) = ecx; 
      Console::Output.Write(L"CPU vendor name: "); 
      for (int i = 0; i < 13; i++) { 
       Console::Output.Write((wchar_t)(vendorString[i])); 
      } 
      Console::Output.WriteLine(); 

      char brandString[48] = { 0, }; 
      ACpuid(0x80000002, &eax, &ebx, &ecx, &edx); 
      *((Dword*)brandString) = eax; 
      *((Dword*)brandString + 1) = ebx; 
      *((Dword*)brandString + 2) = ecx; 
      *((Dword*)brandString + 3) = edx; 
      ACpuid(0x80000003, &eax, &ebx, &ecx, &edx); 
      *((Dword*)brandString + 4) = eax; 
      *((Dword*)brandString + 5) = ebx; 
      *((Dword*)brandString + 6) = ecx; 
      *((Dword*)brandString + 7) = edx; 
      ACpuid(0x80000004, &eax, &ebx, &ecx, &edx); 
      *((Dword*)brandString + 8) = eax; 
      *((Dword*)brandString + 9) = ebx; 
      *((Dword*)brandString + 10) = ecx; 
      *((Dword*)brandString + 11) = edx; 
      Console::Output.Write(L"CPU brand: "); 
      for (int i = 0; i < 48; i++) { 
       Console::Output.Write((wchar_t) brandString[i]); 
      } 
      Console::Output.WriteLine(); 

REMARQUE:

  1. Ce programme est une application UEFI. Pas de problème avec les permissions.

  2. La console est une classe wrapper pour la console EFI. Pas de truc en C#

  3. Dword = entier non signé 32 bits

Code Assemblée (MASM):

;Cpuid command 
;ACpuid(Type, pEax, pEbx, pEcx, pEdx) 
ACpuid Proc 
    ;Type => Rcx 
    ;pEax => Rdx 
    ;pEbx => R8 
    ;pEcx => R9 
    ;pEdx => [ rbp + 48 ] ? 
    push rbp 
    mov rbp, rsp 
    push rax 
    push rsi 

    mov rax, rcx 
    cpuid 
    mov [ rdx ], eax 
    mov [ r8 ], ebx 
    mov [ r9 ], ecx 
    mov rsi, [ rbp + 48 ] 
    mov [ rsi ], rdx 

    pop rsi 
    pop rax 
    pop rbp 
    ret 
ACpuid Endp 
+0

question stupide. Votre programme a-t-il des autorisations complètes? – Auriga

+0

Voulez-vous dire C++ ou C#? –

+0

@MichaelPetch C++. La console est un espace de nom pour la console EFI (et Console :: Output est la sortie de la console) Not console class in C#. – Gippeumi

Répondre

5

Je suis d'accord avec Ross Ridge que vous devez utiliser le compilateur intrinsèque __cpuid. En ce qui concerne les raisons pour lesquelles votre code ne fonctionne probablement pas tel quel, certains bogues peuvent causer des problèmes.


CPUID détruit le contenu de RAX, RBX, RCX et RDX et pourtant vous faites cela dans votre code:

cpuid 
mov [ rdx ], eax 

RDX a été détruit au moment où mov [ rdx ], eax est exécuté, le pointeur se trouvant dans RDX inv alid. Vous devrez déplacer RDX dans un autre registre avant d'utiliser l'instruction CPUID.

par l'Windows 64-bit Calling Convention ce sont les registres volatils qui doivent être conservés par l'appelant :

Les registres RAX, RCX, RDX, R8, R9, R10, R11 sont considérés comme volatils et doit être considéré comme détruit lors d'appels de fonction (sauf si une analyse, telle qu'une optimisation de programme dans son ensemble, peut prouver la sécurité).

Ce sont les non-volatiles qui doivent être conservés par le callee:

Les registres RBX, RBP, RDI, RSI, RER, R12, R13, R14 et R15 sont considérées comme non volatiles et doivent être sauvegardées et restaurées par une fonction qui les utilise.

Nous pouvons utiliser R10 (un registre volatile) pour stocker temporairement RDX. Plutôt que d'utiliser RSI dans le code, nous pouvons réutiliser R10 pour mettre à jour la valeur à pEdx. Nous n'aurons pas besoin de conserver RSI si nous ne l'utilisons pas. CPUID ne détruit RBX, et RBX est non volatile, nous avons donc besoin de le préserver. RAX est volatile, nous n'avons donc pas besoin de le préserver.


Dans votre code, vous avez cette ligne:

mov [ rsi ], rdx 

RSI est une adresse mémoire (pEdx) fournie par l'appelant pour stocker la valeur dans EDX. Le code que vous avez déplacerait le contenu du registre de 8 octets RDX vers un emplacement de mémoire qui attendait un octet DWORD. Cela pourrait potentiellement effacer les données dans l'appelant. Cela devrait avoir été:

mov [ rsi ], edx 

Avec tous ce qui précède à l'esprit que nous pourrions coder la routine ACpuid ainsi:

option casemap:none 
.code 

;Cpuid command 
;ACpuid(Type, pEax, pEbx, pEcx, pEdx) 
ACpuid Proc 
    ;Type => Rcx 
    ;pEax => Rdx 
    ;pEbx => R8 
    ;pEcx => R9 
    ;pEdx => [ rbp + 48 ] ? 
    push rbp 
    mov rbp, rsp 
    push rbx   ; Preserve RBX (destroyed by CPUID) 

    mov r10, rdx  ; Save RDX before CPUID 
    mov rax, rcx 
    cpuid 
    mov [ r10 ], eax 
    mov [ r8 ], ebx 
    mov [ r9 ], ecx 
    mov r10, [ rbp + 48 ] 
    mov [ r10 ], edx ; Last parameter is pointer to 32-bit DWORD, 
        ; Move EDX to the memory location, not RDX 

    pop rbx 
    pop rbp 
    ret 
ACpuid Endp 

end 
+0

Je suggère également de changer la signature de la fonction pour simplement passer un pointeur à un struct! Code plus simple sur les deux extrémités de cette façon. (Mais encore beaucoup plus compliqué que d'utiliser un compilateur intégré comme '__cpuid()'). –

+0

@PeterCordes: Je ne change pas intentionnellement la structure de son code. J'identifiais les principaux problèmes qui auraient pu expliquer le mauvais fonctionnement de son code. La meilleure solution est dans la première ligne de ma réponse. Utilisez le compilateur __cpuid intrinsèque et la routine assembleur est inutile. –