Un desarrollador logra arrancar Linux en x86 con Rust y KVM usando el protocolo PVH

El desarrollador Stjepan Poljak ha documentado cómo arrancar un kernel de Linux en sistemas x86 de 64 bits desde su proyecto de virtualización escrito en Rust, utilizando el protocolo de arranque PVH de Xen. Este método simplifica parte del proceso tradicional de inicio del sistema operativo y permite avanzar en la implementación de una máquina virtual basada en KVM sin tener que reproducir primero toda la secuencia de arranque de una BIOS convencional.

Las claves del arranque PVH de Linux en x86 en 20 segundos

  • Stjepan Poljak ha ampliado su proyecto de virtualización en Rust, que ya arrancaba Linux en ARM64, para trabajar también con x86.
  • El método utiliza PVH, un protocolo de Xen que simplifica la entrada del kernel en una máquina virtual.
  • KVM permite configurar directamente determinados registros y segmentos de la CPU virtual.
  • El kernel necesita información sobre el punto de entrada, el mapa de memoria y los parámetros de arranque.
  • El código de inicialización para x86 de 64 bits está disponible en GitHub.

La experiencia muestra una de las dificultades que aparecen al desarrollar un hipervisor o un monitor de máquinas virtuales (VMM) desde cero: arrancar un kernel no consiste únicamente en cargar un archivo en memoria y saltar a una dirección. El entorno debe proporcionar el estado de procesador esperado por Linux, describir la memoria disponible y entregar los parámetros que necesita el sistema operativo durante sus primeras instrucciones.

En sus notas publicadas el 25 de septiembre de 2026, Poljak explica que anteriormente había intentado utilizar la estructura boot_params del protocolo de arranque tradicional de Linux. Al considerar ese camino demasiado complejo para conseguir resultados iniciales, optó por PVH, una alternativa que reduce parte del trabajo que debe realizar el software de virtualización.

Por qué PVH simplifica el arranque de Linux

En un equipo x86 convencional, el procesador comienza su ejecución en el vector de reinicio, situado en la dirección física 0xFFFFFFF0. A partir de ahí, el firmware toma el control y participa en la preparación del entorno de arranque. En un recorrido clásico con BIOS, el firmware puede cargar el primer sector de un dispositivo arrancable, comprobar su firma y transferir la ejecución al código inicial, que continúa preparando el sistema.

Ese código suele comenzar en modo real de 16 bits. Para llegar al modo protegido de 32 bits necesita preparar, entre otros elementos, una tabla global de descriptores o GDT (Global Descriptor Table), desactivar interrupciones durante la transición y activar el bit correspondiente del registro de control CR0. Después, un salto lejano permite cargar el selector de código adecuado.

Si el sistema operativo va a funcionar en modo de 64 bits, todavía hay más trabajo de preparación relacionado con el estado del procesador y la paginación. En un proyecto de virtualización propio, reproducir todas estas fases puede convertirse en una tarea considerable antes de llegar siquiera a ejecutar el kernel.

PVH ofrece un camino diferente. Este protocolo, procedente de Xen, permite al software de virtualización entregar Linux un entorno de inicio con un estado definido, sin necesidad de imitar íntegramente la secuencia de firmware y cargador tradicional. En el procedimiento descrito por Poljak, el kernel entra inicialmente en un estado de modo protegido de 32 bits y realiza por sí mismo la transición necesaria hacia el modo de 64 bits.

La diferencia es relevante para un VMM basado en KVM. En lugar de construir desde el principio toda la infraestructura de arranque de una máquina física, el desarrollador puede preparar directamente parte del estado de la CPU virtual y proporcionar al kernel la información que exige la interfaz PVH.

Eso no elimina el trabajo de inicialización. Lo desplaza hacia la configuración explícita de los registros, los segmentos, la memoria y las estructuras específicas del protocolo.

Qué información necesita el kernel para arrancar mediante PVH

El primer paso consiste en identificar si la imagen ELF del kernel de Linux admite el protocolo. Para ello, el desarrollador explica que hay que inspeccionar las notas ELF de Xen y localizar XEN_ELFNOTE_PHYS32_ENTRY, de tipo 18. Su descriptor contiene el punto de entrada físico de 32 bits en el que debe comenzar la ejecución del huésped.

Los kernels que admiten la reubicación mediante PVH también pueden incluir XEN_ELFNOTE_PHYS32_RELOC, de tipo 19. Esta nota describe restricciones relacionadas con la alineación y las direcciones físicas que debe respetar la carga de un kernel reubicable.

Una vez localizado el punto de entrada, el VMM debe preparar la memoria y las estructuras que recibirá Linux. El procedimiento recogido en las notas de Poljak incluye:

  • Cargar en memoria los segmentos ELF del kernel.
  • Copiar la línea de comandos del kernel a una dirección accesible.
  • Construir un mapa de memoria con entradas HvmMemEntry.
  • Crear y rellenar la estructura HvmStartInfo.
  • Colocar las entradas de memoria y la estructura de inicio en la memoria de la máquina virtual.
  • Cargar también el initramfs cuando se utilice, junto con su línea de comandos y una entrada HvmModuleEntry que describa su ubicación.

El mapa de memoria permite al kernel conocer qué regiones tiene disponibles. HvmStartInfo reúne información necesaria para el arranque mediante PVH, mientras que HvmModuleEntry identifica el módulo inicial que se entrega al sistema operativo. En este caso, el término módulo se refiere a los módulos de Xen previstos por el protocolo, no a los módulos del kernel que se cargan posteriormente: el ejemplo práctico de Linux es el initramfs.

Estas estructuras forman parte de la interfaz que conecta al hipervisor con el kernel. Si alguna dirección, tamaño o dato de inicialización no coincide con lo que espera Linux, el arranque puede detenerse antes de que el sistema operativo llegue a inicializar sus subsistemas habituales.

KVM permite configurar directamente el estado de la CPU virtual

Otra parte importante de la implementación consiste en preparar los registros y los segmentos del procesador virtual. Poljak señala que RIP, el registro que determina la siguiente instrucción que se ejecutará, debe apuntar a la entrada obtenida de la nota ELF de tipo 18. El registro RBX debe contener la dirección física de HvmStartInfo, de acuerdo con el protocolo PVH descrito.

También hay que preparar los registros de segmento para que representen un estado válido de modo protegido. En el arranque convencional, los descriptores se encontrarían en una GDT alojada en la memoria del huésped y el procesador obtendría de ella los atributos de cada segmento al cargar sus selectores.

Con KVM, el desarrollador puede establecer directamente buena parte de ese estado mediante las interfaces de la CPU virtual. El código compartido utiliza la estructura kvm_segment y la operación KVM_SET_SREGS para configurar los segmentos sin tener que reproducir toda la secuencia de carga de una GDT dentro de la máquina virtual.

El ejemplo incluye un segmento de código con selector 1 << 3, un segmento de datos con selector 2 << 3 y un segmento de tarea (TR) preparado con un límite de 0x67, siguiendo los requisitos que el autor atribuye al protocolo PVH de Xen. También especifica atributos como el nivel de privilegio, el tamaño de dirección, la granularidad y los permisos de acceso.

La inicialización contempla otros registros. Poljak indica que CR0 debe tener activado el bit PE, que CR4 se inicializa a cero en su implementación y que determinados indicadores de RFLAGS, como VM, IF y TF, deben quedar desactivados para el estado inicial descrito. Estos valores forman parte de la preparación concreta de su VMM y no deben interpretarse como una receta universal para cualquier configuración de arranque x86.

La referencia técnica para las estructuras de inicio se encuentra en las cabeceras de Linux dedicadas a Xen, mientras que el propio código del kernel documenta la configuración de registros que realiza su entrada PVH. Ambas fuentes ayudan a relacionar la preparación de la máquina virtual con lo que espera recibir el kernel.

Un paso más para el hipervisor escrito en Rust

El proyecto de Poljak ya podía arrancar Linux en ARM64 y ahora incorpora el camino inicial para x86 de 64 bits. La implementación está publicada en el repositorio kvm-rust, dentro del archivo de inicialización específico de la arquitectura x86. El autor advierte que todavía quedan funcionalidades por completar en el lado x86 del VMM.

La publicación no describe un hipervisor terminado ni una implementación completa del arranque tradicional de Linux. Su aportación consiste en mostrar cómo utilizar PVH para alcanzar el punto de entrada del kernel y disponer de una base funcional sobre la que continuar desarrollando la virtualización.

Para quienes trabajan en hipervisores, emulación o sistemas operativos, el enfoque ofrece una forma de reducir el alcance inicial del problema. En lugar de implementar primero cada etapa del arranque de una máquina física, pueden apoyarse en una interfaz definida para preparar la CPU virtual y las estructuras de memoria que necesita Linux.

El código también permite examinar de forma práctica cómo se relacionan Rust, las interfaces de KVM y el protocolo de Xen durante la inicialización de un sistema invitado.

Preguntas frecuentes

¿Qué es PVH en Linux?

PVH es un protocolo de arranque procedente de Xen que define cómo entregar al kernel un estado inicial y la información necesaria para comenzar su ejecución en una máquina virtual.

¿Por qué usar PVH en un proyecto con KVM?

Permite simplificar parte del arranque frente a la reproducción completa del camino tradicional de BIOS y cargador. El VMM sigue teniendo que preparar los registros, el mapa de memoria y las estructuras de inicio.

¿Qué función tienen las notas ELF de Xen?

La nota XEN_ELFNOTE_PHYS32_ENTRY, de tipo 18, identifica el punto de entrada físico de 32 bits del kernel. La nota de tipo 19 puede describir restricciones de alineación y dirección física para kernels PVH reubicables.

¿Dónde está disponible el código de la implementación?

El código de inicialización para x86 de 64 bits está disponible en el repositorio de GitHub del proyecto kvm-rust: https://github.com/StjepanPoljak/kvm-rust/blob/main/src/arch/x86_64/init.rs

Suscríbete al boletín SysAdmin

Este es tu recurso para las últimas noticias y consejos sobre administración de sistemas, Linux, Windows, cloud computing, seguridad de la nube, etc. Lo enviamos 2 días a la semana. Recuerda revisar tu email para confirmar la suscripción.

¡Apúntate a nuestro newsletter!


– patrocinadores –

Noticias destacadas

– patrocinadores –

¡SUSCRÍBETE AL BOLETÍN
DE LOS SYSADMINS!

Scroll al inicio
×