Virtualbox, cómo forzar una CPU específica al invitado

14

Tengo un invitado XP en VirtualBox, host de Windows 8. El invitado muestra el procesador de forma transparente igual que el host (i5 2500k). Sin embargo, la mayoría de los instaladores no reconocen estos procesadores y no continúan declarando procesadores no compatibles.

¿Hay alguna manera de engañar al invitado para que piense que este es un procesador antiguo? Si recuerdo correctamente VMWare tenía una función de enmascaramiento de CPU, ¿hay algo similar en virtualbox?

I Desconocido
fuente
¿Qué software está instalando que verifica el modelo de CPU?
Darth Android
Controles de doble agente, Orca y Wix. Esto es para un proyecto VB6 que estamos tratando de revivir.
IDesconocido el

Respuestas:

19

Conceptos básicos de VirtualBox y CPUID

VBoxInternal/CPUM/HostCPUIDDebe configurar los extradatos de la máquina virtual. Esto hará que VirtualBox informe los resultados personalizados para la instrucción CPUID al invitado. Dependiendo del valor del registro EAX, esta instrucción devuelve información sobre el procesador: cosas como proveedor, tipo, familia, pasos, marca, tamaño de caché, características (MMX, SSE, SSE2, PAE, HTT), etc. Cuantos más resultados usted destroza, mayor es la posibilidad de engañar al invitado.

Puede usar el vboxmanage setextradatacomando para configurar la máquina virtual. Por ejemplo,

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

hará que CPUID devuelva 50202952₍₁₆₎ en el registro EBX, cuando se llame con EAX configurado en 80000003₍₁₆₎. (De ahora en adelante, los números hexadecimales se escribirán como 0xNN o NNh).

Establecer la cadena del proveedor de la CPU

Si EAX es 0 (o 80000000h en AMD), CPUID devuelve al proveedor como una cadena ASCII en los registros EBX, EDX, ECX (observe el pedido). Para una CPU AMD, se ven así:

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

(Tomado de la especificación AMD CPUID , subsección "CPUID Fn0000_0000_E")

Si concatena EBX, EDX y ECX, obtendrá AuthenticAMD.

Si tiene Bash y las utilidades tradicionales de Unix, puede configurar fácilmente el proveedor con los siguientes 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

Establecer la cadena de marca de la CPU

Si EAX es 80000002h, 80000003h, 80000004h, CPUID devuelve 16 caracteres ASCII de la cadena de la marca en los registros EAX, EBX, ECX, EDX, totalizando 3 * 16 = 48 caracteres; la cadena termina con un carácter nulo . Tenga en cuenta que esta característica se introdujo con los procesadores Pentium 4. Así es como se puede ver la cadena de la marca en un procesador 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"           |
|-----------------|-----------------|------------------|

(Tomado de Intel Architecture Instruction Set Extensions Programming Reference , subsection 2.9, "CPUID Instruction", table 2-30. ☠ es el carácter nulo (valor numérico 0)).

Si pones los resultados juntos, obtendrás Intel(R) Pentium(R) 4 CPU 1500MHz☠.

Si tiene Bash y las utilidades tradicionales de Unix, puede configurar fácilmente la marca con los siguientes 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

Si tiene un símbolo del sistema de Windows, puede establecer la marca en Intel(R) Core(TM)2 CPU 6600 @ 2.40 GHz1 ejecutando:

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

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

1 Los HostCPUIDvalores se tomaron del informe de error de VirtualBox # 7865 .

Cristian Ciupitu
fuente
Gracias. Tengo mi VM rota con VERR_CFGM_INVALID_CHILD_PATH.
Ben Sinclair
1
sed tiene que usarse con la bandera G:'s/ //g'
Ben Sinclair
1
¡Qué gran respuesta! Y con el advenimiento de las CPU Kaby Lake, esto de repente se ha vuelto más interesante debido a una determinada política de Redmond para no admitir Windows 7 en esos ... Parece que todo lo que falta son las instrucciones sobre cómo configurar "EAX = 1: Información del procesador y bits de funciones ", ya que no son cadenas simples (solo con la marca de CPU, CPU-Z todavía reconoce la CPU como KL); ¿alguien sabe?
sxc731
1
Según los foros.virtualbox.org/viewtopic.php?f=2&t=77211#p359428 , puede haber una forma mejor (más sucinta, más compatible) de establecer estos valores.
Mark Amery
@ MarkAmery, gracias por el enlace. Funciona bien para la marca, pero no tanto para el proveedor porque el proveedor no está establecido en el registro EAX y el --cpuidsubcomando requiere un valor para el registro EAX.
Cristian Ciupitu
5

Aquí hay un enfoque que permite enmascarar la CPU del host precisamente como una CPU específica en lugar de intentar adivinar las configuraciones necesarias. Necesitará acceso a una máquina que ejecute VirtualBox en esa CPU host para poder volcar sus cpuidregistros (probablemente sea mejor elegir una arquitectura que sea razonablemente similar a la de su CPU real como modelo). Si no tiene uno a mano, puede preguntar (he tenido éxito en Reddit, por ejemplo).

  1. Cree un archivo "modelo" desde la CPU que desea emular:

    vboxmanage list hostcpuids > i7_6600U
    
  2. En el host de destino, asegúrese de que la máquina virtual que desea modificar no se esté ejecutando; es posible que desee realizar una copia de seguridad por si acaso.
  3. Ejecute el siguiente script para cargar el archivo del modelo ( i7_6600Uaquí) en la definición de su VM VBox ( my_vm_nameaquí):

    #!/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. Eso es todo, ahora puede ejecutar su VM y disfrutar de la CPU enmascarada (nota: solo necesita ejecutar el script anterior una vez).

Si alguna vez necesita deshacer la mascarada de la CPU, puede usarla vboxmanage modifyvm $vm --cpuidremove $leafpara cada una de las hojas en el bucle anterior ( man vboxmanagees su amigo).

Esto ha funcionado sin problemas durante un par de meses para mí, disfrazando una CPU Kaby Lake (i7_7500U) como una Skylake (i7_6600U) en un host Ubuntu 17.04 con VBox 5.1.22. El enfoque debería funcionar en cualquier sistema operativo host, siempre que pueda crear un equivalente del pequeño script bash anterior para ese sistema operativo.

sxc731
fuente
Con respecto a la parte "Configuración de la cadena del proveedor de la CPU", tengo un comentario: debe asegurarse de cambiar el nombre del proveedor a "AuthenticAMD" en la CPU AMD y "GenuineIntel" en la CPU Intel. Si usa "GenuineIntel" en una CPU AMD, la máquina virtual se romperá muy probablemente.
abulhol
¡Muchas gracias por esto! Funcionó de maravilla en mi Ryzen 7700K. Utilicé una antigua placa base AMD Socket SF2 para obtener el CPUID ejecutando un Ubuntu LiveCD, instalando VirtualBox en el entorno en vivo y ejecutando el comando vboxmanage. En el lado del host, instalé el Subsistema de Windows para Linux para poder ejecutar un indicador de Bash en Windows 10 y ejecutar el script que compartió. Ahora puedo engañar a mi VM de Windows 7 para que piense que estoy ejecutando un A8-5600K.
njbair
¡Me alegro de que esto también funcione para ti! Debería haber aclarado que nada de esto requiere un host Linux; ni siquiera recopila el archivo "modelo", todo lo que necesita es VirtualBox ejecutándose en esa máquina. El script de bash puede parecer complicado, pero todo lo que hace es leer las líneas del archivo del modelo, omitiendo las hojas entre 0000000by 00000017(inclusive) y ejecutándolas una por una vboxmanage modifyvm my_vm_name --cpuidset <line>para que esto se pueda hacer fácilmente a mano, ya que es único.
sxc731
No es gran cosa, tenía WSL instalado en la computadora host de todos modos, y Ubuntu LiveCD fue solo porque era la forma más rápida de activar la antigua placa base AMD.
njbair