Problema

En entornos de virtualización con Proxmox, es frecuente intentar pasar una GPU dedicada a una VM Windows (XP, 7 o versiones más recientes) usando PCI passthrough. Cuando la máquina virtual se basa en el modelo de máquina i440fx, algunos usuarios se encuentran con un bucle de reinicio que termina en el STOP: 0x000000A5 (ACPI_BIOS_ERROR). El síntoma típico es un bootloop continuo, sin que la VM llegue a cargar el sistema operativo. Aunque el error parece estar relacionado con la BIOS del invitado, la causa raíz a menudo está en la configuración de la VM y no en la propia GPU.

Causa

Proxmox genera automáticamente dos dispositivos pci‑bridge (pci.1 y pci.2) para cada VM basada en i440fx. Estos puentes son simplemente reservas de espacio de direcciones; no se usan cuando la VM solo necesita dispositivos pasados directamente (hostpci0‑hostpci3, vga, balloon, etc.). Sin embargo, el firmware ACPI de Windows XP/7 verifica la topología PCI y, al encontrar un puente que no está completamente mapeado, devuelve el código 0xA5 con el subcódigo ACPI_ROOT_PCI_RESOURCE_FAILURE.

Las causas más habituales son:

  1. Presencia incondicional de los puentes – Proxmox no ofrece una opción de configuración para desactivarlos.
  2. Compatibilidad de la BIOS del host – En hardware antiguo o con BIOS no totalmente ACPI‑compliant, la presencia de los puentes desencadena la falla.
  3. Uso del modelo de máquina i440fx – El modelo q35 no crea estos puentes, pero para Windows XP el i440fx es obligatorio porque el controlador IDE de q35 (ICH9 AHCI) no es compatible con SeaBIOS/CSMWrap.
  4. Configuraciones de dispositivos adicionales – Añadir dispositivos detrás de los puentes (por ejemplo, virtio‑rng‑pci o xHCI) no soluciona el problema porque el propio puente sigue existiendo.

En la práctica, el error desaparece cuando los puentes son eliminados del comando de arranque de QEMU. Como Proxmox no permite su supresión mediante la UI, la solución pasa por intervenir en el binario kvm que Proxmox invoca.

Solución

La estrategia general consiste en interceptar la llamada a kvm y remover los argumentos -device pci-bridge,... antes de que QEMU los reciba. El proceso se puede resumir en tres pasos:

  1. Crear un wrapper que reescriba la línea de comandos, filtre los puentes y delegue al binario real (kvm.distrib).
  2. Divertir el binario original usando dpkg-divert (o el gestor de paquetes equivalente) para que /usr/bin/kvm apunte al wrapper sin sobrescribir el paquete oficial.
  3. Mantener una lista de allow‑list con los IDs de VM que pueden ejecutarse sin puentes. El wrapper aborta el arranque si una VM no está en la lista y todavía referencia pci.1 o pci.2, evitando bucles silenciosos.

Implementación paso a paso

  1. Instalar el wrapper

    curl -sSL https://gitlab.com/zubrjan/2am-idea/raw/master/pve-kvm-nobridge-setup.sh -o /usr/local/sbin/pve-kvm-nobridge-setup.sh
    chmod +x /usr/local/sbin/pve-kvm-nobridge-setup.sh
    /usr/local/sbin/pve-kvm-nobridge-setup.sh --install
    

    El script realiza tres auto‑tests contra una VM real, crea la diversión y genera el archivo de configuración /etc/pve-kvm-nobridge.conf.

  2. Agregar la VM a la allow‑list (suponiendo VMID 301)

    /usr/local/sbin/pve-kvm-nobridge-setup.sh --add-vm 301
    
  3. Revisar el log para confirmar que el wrapper se está usando:

    tail -f /var/log/pve-kvm-nobridge/301.cmd
    
  4. Iniciar la VM normalmente con qm start 301. Si el wrapper detecta referencias a pci.1 o pci.2 en la configuración, abortará y mostrará un mensaje claro.

El wrapper también protege contra actualizaciones del paquete pve-qemu-kvm. Después de cada actualización, verifica que la diversión siga activa (dpkg-divert --list /usr/bin/kvm). Si desaparece, reinstale el wrapper.

Cuándo aplicar esta solución

  • Entornos con GPU passthrough donde la VM usa el modelo de máquina i440fx (por ejemplo, Windows XP SP3 o Windows 7 32‑bit) y necesita ACPI activo.
  • Errores de arranque que terminan en STOP: 0x000000A5 con subcódigo 0x2 (ACPI_ROOT_PCI_RESOURCE_FAILURE).
  • Configuraciones que no requieren dispositivos detrás de los puentes (solo hostpci, vga, balloon, IDE).
  • No aplicar si la VM usa el modelo q35, ya que los puentes no se crean y la solución no es necesaria.
  • No aplicar a entornos donde se dependen de dispositivos virtio‑rng‑pci, xHCI u otros que se asignan detrás de los puentes, a menos que se migren a pci.0.

Código

# Wrapper installation script (simplificado)
#!/usr/bin/env bash
REAL="/usr/bin/kvm.distrib"
CONF="/etc/pve-kvm-nobridge.conf"
VMID="$1"

if [[ "$1" == "--install" ]]; then
    dpkg-divert --divert /usr/bin/kvm.distrib --rename /usr/bin/kvm
    cat <<'EOF' > /usr/local/sbin/pve-kvm-nobridge
#!/usr/bin/env bash
REAL="/usr/bin/kvm.distrib"
ARGS=()
ALLOWLIST=$(cat /etc/pve-kvm-nobridge.conf)

while [[ $# -gt 0 ]]; do
    case "$1" in
        -id)
            VMID="$2"
            shift 2
            ;;
        -device)
            if [[ "$2" =~ ^pci-bridge ]]; then
                shift 2
                continue
            fi
            ;;
        *)
            ARGS+=("$1")
            shift
            ;;
    esac
done

if grep -q "^$VMID$" "$ALLOWLIST"; then
    exec -a "$0" "$REAL" "${ARGS[@]}"
else
    echo "VM $VMID no está en la allow‑list. Abortando."
    exit 1
fi
EOF
    chmod +x /usr/local/sbin/pve-kvm-nobridge
    ln -sf /usr/local/sbin/pve-kvm-nobridge /usr/bin/kvm
    echo "# Lista de VM permitidas" > "$CONF"
    echo "301" >> "$CONF"
    echo "Instalación completada."
    exit 0
fi

Verificación

  1. Comprobar que el wrapper está activo

    which kvm   # debe devolver /usr/bin/kvm (enlace al wrapper)
    kvm --version   # debe mostrar la versión de QEMU sin errores
    
  2. Iniciar la VM y observar el log

    qm start 301
    grep -i "pci-bridge" /var/log/pve-kvm-nobridge/301.cmd
    

    No debe aparecer ninguna línea con pci-bridge.

  3. Confirmar que Windows arranca y que el STOP: 0xA5 no se produce. En caso de fallo, revisa que la VM sigue usando machine: pc-i440fx-5.0 y que no hay dispositivos ocultos detrás de pci.1/2.

  4. Después de una actualización de Proxmox, repite dpkg-divert --list /usr/bin/kvm. Si el wrapper desaparece, ejecuta nuevamente el script --install.

Notas adicionales

  • No desactivar ACPI en la VM. Quitar ACPI evita el error 0xA5 pero degrada gravemente el rendimiento de Windows XP, que pasa a usar el temporizador PIT y consume un vCPU completo.
  • Mantener la máquina i440fx para XP. Cambiar a q35 obliga a usar controladores AHCI que SeaBIOS/CSMWrap no soporta en modo legado.
  • Evitar --usb0 host=... en VMs envueltas, ya que Proxmox coloca el controlador xHCI detrás del puente eliminado. En su lugar, pasa el controlador USB completo mediante hostpci<n>.
  • Clonar VMs: la afinidad NUMA y la allow‑list no se copian automáticamente. Añade el nuevo VMID a /etc/pve-kvm-nobridge.conf antes de arrancar.
  • Depuración rápida: qm monitor <vmid> y info pci muestra cuántos puentes están presentes en tiempo de ejecución. Un recuento de 0 confirma la eliminación exitosa.

Con este enfoque, los entornos de GPU passthrough en Proxmox dejan de tropezar con el error ACPI_BIOS_ERROR 0xA5 y pueden ejecutar Windows XP/7 de forma estable, sin sacrificar ACPI ni rendimiento.