Virtualbox, como forçar uma CPU específica para o convidado

13

Eu tenho um convidado do XP no VirtualBox, host do Windows 8. O convidado mostra o processador de forma transparente mesmo que o host (i5 2500k). No entanto, a maioria dos instaladores não reconhece esses processadores e não consegue continuar indicando o processador não suportado.

Existe uma maneira de enganar o convidado a pensar que isso é um processador antigo? Se eu me lembro corretamente que o VMWare tinha um recurso de mascaramento da CPU, existe algo semelhante no VirtualBox?

    
por IUnknown 29.07.2013 / 22:47

2 respostas

18

Noções básicas do VirtualBox e do CPUID

Você precisa definir o VBoxInternal/CPUM/HostCPUID extradata da máquina virtual. Isso fará com que o VirtualBox relate os resultados personalizados da instrução CPUID para o convidado. Dependendo do valor do registrador EAX, esta instrução retorna informações sobre o processador - coisas como fornecedor, tipo, família, stepping, marca, tamanho do cache, recursos (MMX, SSE, SSE2, PAE, HTT) etc. você mangle, maiores as chances de enganar o convidado.

Você pode usar o comando vboxmanage setextradata para configurar a máquina virtual. Por exemplo,

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

fará com que o CPUID retorne 50202952₍₁₆₎ no registro EBX, quando chamado com o EAX definido como 80000003₍₁₆₎. (De agora em diante, os números hexadecimais serão gravados como 0xNN ou NNh.)

Definindo a string do fornecedor da CPU

Se o EAX for 0 (ou 80000000h na AMD), o CPUID retornará o fornecedor como uma string ASCII nos registros EBX, EDX, ECX (observe o pedido). Para um processador AMD, eles se parecem com isso:

| 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" |

(extraído de Especificação AMD CPUID , subseção "CPUID Fn0000_0000_E")

Se você concatenar EBX, EDX e ECX, você receberá AuthenticAMD .

Se você tiver o Bash e os utilitários tradicionais do Unix, poderá definir facilmente o fornecedor com os seguintes comandos:

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

Definindo a string da marca da CPU

Se o EAX for 80000002h, 80000003h, 80000004h, o CPUID retornará 16 caracteres ASCII da string de marca nos registros EAX, EBX, ECX, EDX, totalizando 3 * 16 = 48 caracteres; a string é terminada com um caractere nulo . Observe que esse recurso foi introduzido com processadores Pentium 4. É assim que a string da marca pode parecer em um processador 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"           |
|-----------------|-----------------|------------------|

(extraído de Referência de programação das extensões de conjunto de instruções da arquitetura Intel® , subseção 2.9, "Instrução CPUID", tabela 2-30. ☠ é o caractere nulo (valor numérico 0) .)

Se você juntar os resultados, receberá Intel(R) Pentium(R) 4 CPU 1500MHz☠ .

Se você tiver o Bash e os utilitários tradicionais do Unix, poderá definir facilmente a marca com os seguintes comandos:

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

Se você tiver um prompt de comando do Windows, poderá definir a marca como Intel(R) Core(TM)2 CPU 6600 @ 2.40 GHz 1 executando:

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

1OsvaloresdeHostCPUIDforamobtidosdorelatóriodeerrosdoVirtualBox # 7865 .

    
por 29.06.2014 / 00:30
5

Aqui está uma abordagem que permite mascarar a CPU do host precisamente como uma CPU específica, em vez de tentar adivinhar as configurações necessárias. Você precisará de acesso a uma máquina executando o VirtualBox naquela CPU do host para poder descarregar seus cpuid registradores (provavelmente é melhor escolher uma arquitetura que seja razoavelmente similar àquela de sua CPU atual como modelo). Se você não tem um à mão, você pode perguntar por aí (eu tive sucesso no Reddit, por exemplo).

  1. Crie um arquivo "modelo" da CPU que você gostaria de emular:

    vboxmanage list hostcpuids > i7_6600U
    
  2. No host de destino, certifique-se de que a VM que você deseja modificar não esteja em execução; você pode querer fazer um backup apenas no caso.
  3. Execute o seguinte script para carregar o arquivo de modelo ( i7_6600U here) na definição da sua VM VBox ( my_vm_name here):

    #!/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. É isso aí, agora você pode executar sua VM e aproveitar a CPU mascarada (nota: você só precisa executar o script acima uma vez).

Se você precisar reverter o disfarce da CPU, poderá usar vboxmanage modifyvm $vm --cpuidremove $leaf para cada uma das folhas no loop acima ( man vboxmanage é seu amigo).

Isso tem funcionado sem problemas por alguns meses para mim, mascarando uma CPU Kaby Lake (i7_7500U) como uma do Skylake (i7_6600U) em um host Ubuntu 17.04 rodando VBox 5.1.22. A abordagem deve funcionar em qualquer sistema operacional host, desde que você possa criar um equivalente do pequeno script bash acima para esse SO.

    
por 13.08.2017 / 18:48