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

13

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

Existe uma maneira de enganar o convidado a pensar que este é um processador antigo? Se bem me lembro, o VMWare tinha um recurso de mascaramento da CPU, há algo semelhante no virtualbox?

IDesconhecido
fonte
Que software você está instalando que verifica o modelo da CPU?
Darth Android
Controles Double Agent, Orca e Wix. Isto é para um projeto VB6 que estamos tentando reviver.
sei o que você está

Respostas:

18

Noções básicas sobre VirtualBox e CPUID

Você precisa definir os VBoxInternal/CPUM/HostCPUIDextradados da máquina virtual. Isso fará o VirtualBox relatar resultados personalizados para a instrução CPUID ao convidado. Dependendo do valor do registro EAX, esta instrução retorna informações sobre o processador - itens como fornecedor, tipo, família, etapa, marca, tamanho do cache, recursos (MMX, SSE, SSE2, PAE, HTT), etc. Quanto mais resultados você mutilar, maiores as chances de enganar o hóspede.

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

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

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

Definindo a cadeia de fornecedores da CPU

Se EAX for 0 (ou 80000000h na AMD), o CPUID retornará o fornecedor como uma sequência ASCII nos registros EBX, EDX, ECX (observe o pedido). Para uma CPU 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 da especificação CPUID da AMD , subseção "CPUID Fn0000_0000_E")

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

Se você possui o Bash e os utilitários tradicionais do Unix, pode configurar 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 cadeia de caracteres da marca da CPU

Se EAX for 80000002h, 80000003h, 80000004h, CPUID retornará 16 caracteres ASCII da string da marca nos registros EAX, EBX, ECX, EDX, totalizando 3 * 16 = 48 caracteres; a cadeia é finalizada com um caractere nulo . Observe que esse recurso foi introduzido nos 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 da Referência de programação das extensões do 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, obterá Intel(R) Pentium(R) 4 CPU 1500MHz☠.

Se você possui o Bash e os utilitários tradicionais do Unix, pode 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 GHz1 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

Computador: CPU Intel (R) Core (2) 2 6600 a 2,40 GHz

1 Os HostCPUIDvalores foram retirados do relatório de bug do VirtualBox # 7865 .

Cristian Ciupitu
fonte
Obrigado. Minha VM foi interrompida com VERR_CFGM_INVALID_CHILD_PATH.
Ben Sinclair
1
O sed deve ser usado com a bandeira G:'s/ //g'
Ben Sinclair
1
Que ótima resposta! E com o advento das CPUs Kaby Lake, isso de repente se tornou mais interessante devido a uma certa política de Redmond para não oferecer suporte ao Windows 7 naquelas ... Parece que tudo o que falta são as instruções sobre como definir "EAX = 1: Informações do processador e bits de recursos ", como não são sequências simples (apenas com a marca da CPU, a CPU-Z ainda reconhece a CPU como KL); Alguém sabe?
precisa saber é o seguinte
1
De acordo com forums.virtualbox.org/viewtopic.php?f=2&t=77211#p359428 , pode haver uma maneira melhor (mais sucinta, mais suportada) de definir esses valores.
Mark # Amery
@ MarkAmery, obrigado pelo link. Funciona bem para a marca, mas não para o fornecedor, porque o fornecedor não está definido no registro EAX e o --cpuidsubcomando exige um valor para o registro EAX.
Cristian Ciupitu
5

Aqui está uma abordagem que permite mascarar a CPU host precisamente como uma CPU específica, em vez de tentar adivinhar as configurações necessárias. Você precisará acessar uma máquina executando o VirtualBox nessa CPU host para poder despejar seus cpuidregistros (provavelmente é melhor escolher uma arquitetura que seja razoavelmente semelhante à da sua CPU atual como modelo). Se você não tem um em mãos, pode perguntar (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, verifique se a VM que você deseja modificar não está em execução; você pode querer fazer um backup por precaução.
  3. Execute o script a seguir para carregar o arquivo de modelo ( i7_6600Uaqui) na definição da sua VM VBox ( my_vm_nameaqui):

    #!/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, 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á usá-lo vboxmanage modifyvm $vm --cpuidremove $leafpara cada uma das folhas no loop acima ( man vboxmanageé seu amigo).

Isso funcionou perfeitamente por alguns meses para mim, mascarando uma CPU Kaby Lake (i7_7500U) como Skylake (i7_6600U) em um host Ubuntu 17.04 executando o VBox 5.1.22. A abordagem deve funcionar em qualquer sistema operacional host, desde que você possa criar um equivalente ao pequeno script bash acima para esse sistema operacional.

sxc731
fonte
Em relação à parte "Definindo a cadeia de fornecedores da CPU", tenho um comentário: Você deve alterar o nome do fornecedor para "AuthenticAMD" na CPU AMD e "GenuineIntel" na CPU Intel. Se você usar "GenuineIntel" em uma CPU AMD, a máquina virtual será interrompida muito provavelmente.
21717 abulhol
Muito obrigado por isso! Funcionou como um encanto no meu Ryzen 7700K. Usei uma antiga placa-mãe AMD Socket SF2 para obter o CPUID executando um Ubuntu LiveCD, instalando o VirtualBox no ambiente ao vivo e executando o comando vboxmanage. No lado do host, instalei o Windows Subsystem para Linux para poder executar um prompt do Bash no Windows 10 e executar o script que você compartilhou. Agora sou capaz de induzir minha VM do Windows 7 a pensar que estou executando um A8-5600K.
Njbair 17/08
Ainda bem que isso funciona para você também! Eu deveria ter esclarecido que nada disso requer um host Linux; nem mesmo coletando o arquivo "modelo", tudo o que precisa é o VirtualBox sendo executado nessa máquina. O script bash pode parecer complicado, mas tudo o que faz é ler as linhas do arquivo de modelo, pular as folhas entre 0000000be 00000017(inclusive) e executá-las uma a uma, vboxmanage modifyvm my_vm_name --cpuidset <line>para que isso possa ser feito facilmente à mão, pois é único.
Sxc731
Não é demais, eu tinha o WSL instalado no computador host de qualquer maneira, e o Ubuntu LiveCD era apenas porque era a maneira mais rápida de ativar a antiga placa-mãe da AMD.
Njbair 18/08