web-dev-qa-db-fra.com

Virtualbox, comment forcer une CPU spécifique à l'invité

J'ai un XP invité dans VirtualBox, hôte Windows 8. L'invité montre le processeur de manière transparente comme l'hôte (i5 2500k). Toutefois, la plupart des installateurs ne reconnaissent pas ces processeurs et ne parviennent pas à Continuez à indiquer le processeur non pris en charge.

Y a-t-il un moyen de tromper l'invité à penser que c'est un vieux processeur? Si je me souviens de VMware correctement disposait d'une fonctionnalité de masquage de la CPU, existe-t-il quelque chose de similaire dans VirtualBox?

16
IUnknown

Principes de base de VirtualBox et CPUID

Vous devez définir le VBoxInternal/CPUM/HostCPUID Extradata de la machine virtuelle. Cela rendra les résultats personnalisés de VirtualBox Signaler pour le [~ # ~] cpuid [~ # ~] instruction à l'invité. En fonction de la valeur du registre EAX, cette instruction renvoie des informations sur le processeur - des éléments tels que le fournisseur, le type, la famille, la taille, la marque, la taille du cache, les fonctionnalités (MMX, SSE, SSE2, PAE, HTT), etc. Plus les résultats Vous mangez, plus les chances sont élevées de tromper l'invité.

Vous pouvez utiliser la commande vboxmanage setextradata pour configurer la machine virtuelle. Par exemple,

vboxmanage setextradata WinXP VBoxInternal/CPUM/HostCPUID/80000003/ebx 0x50202952

fera la déclaration CPUID 50202952₍₁₆₎ dans le registre EBX, lorsqu'elle sera appelée EAX définie sur 80000003₍₁₆₎. (À partir de maintenant, des chiffres hexadécimaux seront écrits comme 0xnn ou NNH.)

Réglage de la chaîne de vendeur CPU

Si EAX est 0 (ou 80000000H sur AMD), CPUID renvoie le fournisseur en tant que ASCII String dans les registres EBX, EDX, ECX (remarquez la commande). Pour une CPU AMD, ils ressemblent à ceci :

| Register | Value      | Description                    |
|----------|------------|--------------------------------|
| EBX      | 6874_7541h | The ASCII characters "h t u A" |
| ECX      | 444D_4163h | The ASCII characters "D M A c" |
| EDX      | 6974_6E65h | The ASCII characters "i t n e" |

(Extrait de - Spécification AMD CPUID , sous-section "CPUID FN0000_0000_FE")

Si vous concatéez EBX, EDX et ECX, vous obtiendrez AuthenticAMD.

Si vous avez BASH et les utilitaires UNIX traditionnels, vous pouvez facilement définir le fournisseur avec les commandes suivantes:

vm='WinXP'  # UUID works as well
# The vendor string needs to have 12 characters!
vendor='AuthenticAMD'
if [ ${#vendor} -ne 12 ]; then
    exit 1
fi
ascii2hex() { echo -n 0x; od -A n --endian little -t x4 | sed 's/ //g'; }

registers=(ebx edx ecx)
for (( i=0; i<${#vendor}; i+=4 )); do
    register=${registers[$(($i/4))]}
    value=`echo -n "${vendor:$i:4}" | ascii2hex`
    # set value to an empty string to reset the CPUID, i.e.
    # value=""
    for eax in 00000000 80000000; do
        key=VBoxInternal/CPUM/HostCPUID/${eax}/${register}
        vboxmanage setextradata "$vm" $key $value
    done
done

Définition de la chaîne de marque CPU

Si EAX est 80000002H, 80000003H, 80000003H, 80000004H, CPUID renvoie 16 ASCII caractères de la chaîne de marque dans Registers EAX, EBX, ECX, EDX, totalisant 3 * 16 = 48 caractères; la chaîne est - Terminé avec un caractère NULL . Notez que cette fonctionnalité a été introduite avec des processeurs Pentium 4. Voici comment la chaîne de la marque peut regarder sur un processeur Pentium 4:

| EAX Input Value | Return Values   | ASCII Equivalent |
|-----------------|-----------------|------------------|
| 80000002h       | EAX = 20202020h | "    "           |
|                 | EBX = 20202020h | "    "           |
|                 | ECX = 20202020h | "    "           |
|                 | EDX = 6E492020h | "nI  "           |
|-----------------|-----------------|------------------|
| 80000003h       | EAX = 286C6574h | "(let"           |
|                 | EBX = 50202952h | "P )R"           |
|                 | ECX = 69746E65h | "itne"           |
|                 | EDX = 52286D75h | "R(mu"           |
|-----------------|-----------------|------------------|
| 80000004h       | EAX = 20342029h | " 4 )"           |
|                 | EBX = 20555043h | " UPC"           |
|                 | ECX = 30303531h | "0051"           |
|                 | EDX = 007A484Dh | "☠zHM"           |
|-----------------|-----------------|------------------|

(Pris à partir de Intel Architecture Ensemble d'instructions Extensions Références de programmation , Sous-section 2.9, "Instruction CPUID", Tableau 2-30. ☠ est le caractère null (valeur numérique 0).)

Si vous mettez les résultats ensemble, vous obtiendrez Intel(R) Pentium(R) 4 CPU 1500MHz☠.

Si vous avez Bash et les utilitaires UNIX traditionnels, vous pouvez facilement définir la marque avec les commandes suivantes:

vm='WinXP'  # UUID works as well
# The brand string needs to have 47 characters!
# The null terminator is added automatically
brand='              Intel(R) Pentium(R) 4 CPU 1500MHz'
if [ ${#brand} -ne 47 ]; then
    exit 1
fi
ascii2hex() { echo -n 0x; od -A n --endian little -t x4 | sed 's/ //g'; }

eax_values=(80000002 80000003 80000004)
registers=(edx ecx ebx eax)
for (( i=0; i<${#brand}; i+=4 )); do
    eax=${eax_values[$((${i} / 4 / 4))]}
    register=${registers[$((${i} / 4 % 4 ))]}
    key=VBoxInternal/CPUM/HostCPUID/${eax}/${register}
    value=`echo -n "${brand:$i:4}" | ascii2hex`
    # set value to an empty string to reset the CPUID, i.e.
    # value=""
    vboxmanage setextradata "$vm" $key $value
done

Si vous avez une invite de commande Windows, vous pouvez définir la marque sur Intel(R) Core(TM)2 CPU 6600 @ 2.40 GHz1 en exécutant:

set vm=your-vm-name-or-uuid
vboxmanage setextradata %vm% VBoxInternal/CPUM/HostCPUID/80000002/eax 0x65746e49
vboxmanage setextradata %vm% VBoxInternal/CPUM/HostCPUID/80000002/ebx 0x2952286c
vboxmanage setextradata %vm% VBoxInternal/CPUM/HostCPUID/80000002/ecx 0x726f4320
vboxmanage setextradata %vm% VBoxInternal/CPUM/HostCPUID/80000002/edx 0x4d542865
vboxmanage setextradata %vm% VBoxInternal/CPUM/HostCPUID/80000003/eax 0x43203229
vboxmanage setextradata %vm% VBoxInternal/CPUM/HostCPUID/80000003/ebx 0x20205550
vboxmanage setextradata %vm% VBoxInternal/CPUM/HostCPUID/80000003/ecx 0x20202020
vboxmanage setextradata %vm% VBoxInternal/CPUM/HostCPUID/80000003/edx 0x20202020
vboxmanage setextradata %vm% VBoxInternal/CPUM/HostCPUID/80000004/eax 0x30303636
vboxmanage setextradata %vm% VBoxInternal/CPUM/HostCPUID/80000004/ebx 0x20402020
vboxmanage setextradata %vm% VBoxInternal/CPUM/HostCPUID/80000004/ecx 0x30342e32
vboxmanage setextradata %vm% VBoxInternal/CPUM/HostCPUID/80000004/edx 0x007a4847

Computer: Intel(R) Core(TM)2 CPU 6600 @ 2.40 GHz

1 Les valeurs HostCPUID ont été extraites du rapport de bogue Virtualbox # 7865 .

20
Cristian Ciupitu

Voici une approche qui permet de masquer la CPU hôte précisément comme un processeur spécifique plutôt que d'essayer de supporter les paramètres nécessaires. Vous aurez besoin d'un accès à une machine exécutant de la VirtualBox sur ce processeur hôte afin que vous puissiez jeter ses cpuid registres (il est probablement préférable de choisir une architecture qui est raisonnablement similaire à celle de votre CPU actuel en tant que modèle). Si vous n'en avez pas à la main, vous pouvez vous demander (j'ai eu le succès sur Reddit, par exemple).

  1. Créez un fichier "modèle" de la CPU que vous souhaitez imiter:

    vboxmanage list hostcpuids > i7_6600U
    
  2. Sur l'hôte cible, assurez-vous que le VM================= Vous ne courez pas; vous voudrez peut-être prendre une sauvegarde au cas où.
  3. Exécutez le script suivant pour charger le fichier de modèle (i7_6600U Ici) dans la définition de votre Vbox VM (my_vm_name ici):

    #!/bin/bash
    vm=my_vm_name
    model_file=i7_6600U
    
    egrep -e '^[[:digit:]abcdef]{8} ' $model_file |
    while read -r line; do
        leaf="0x`echo $line | cut -f1 -d' '`"
        # VBox doesn't like applying leaves between the below boundaries so skip those:
        if [[ $leaf -lt 0x0b || $leaf -gt 0x17 ]]; then
            echo "Applying: $line"
            vboxmanage modifyvm $vm --cpuidset $line
        fi
    done
    
  4. C'est tout, vous pouvez maintenant exécuter votre VM et profiter de la CPU masquageed (Remarque: il vous suffit d'exécuter le script ci-dessus une fois).

Si vous avez besoin de retourner la mascarrade de la CPU, vous pouvez utiliser vboxmanage modifyvm $vm --cpuidremove $leaf Pour chacune des feuilles de la boucle ci-dessus (man vboxmanage est votre ami).

Cela fonctionne parfaitement pendant quelques mois pour moi, en masquant un CPU Kaby Lake (I7_7500U) en tant que SkyLake One (I7_6600U) sur un hôte Ubuntu 17.04 Exécution de la Vbox 5.1.22. L'approche devrait fonctionner sur n'importe quel système d'exploitation hôte, à condition que vous puissiez créer un équivalent du script Little Bash ci-dessus pour ce système d'exploitation.

6
sxc731