Arquitectura de AVF

Android proporciona una implementación de referencia de todos los componentes necesarios para implementar Android Virtualization Framework. Actualmente, esta implementación se limita a ARM64. En esta página, se explica la arquitectura del framework.

Información general

La arquitectura ARM permite hasta cuatro niveles de excepción, donde el nivel de excepción 0 (EL0) es el con menos privilegios y el nivel de excepción 3 (EL3) el más alto. La parte más grande de la base de código de Android (todos los componentes del espacio del usuario) se ejecuta en EL0. El resto de lo que comúnmente se llama "Android" es el kernel de Linux, que se ejecuta en EL1.

La capa EL2 permite la introducción de un hipervisor que permite aislar la memoria y los dispositivos en pVM individuales en EL1/EL0, con garantías estrictas de confidencialidad y de integridad.

Hipervisor

La máquina virtual basada en kernel protegida (pKVM) se basa en el hipervisor KVM de Linux, que se amplió con la capacidad de restringir el acceso a las cargas útiles que se ejecutan en máquinas virtuales invitadas marcadas como “protegidas” en el momento de la creación.

KVM/arm64 admite diferentes modos de ejecución según la disponibilidad de ciertas funciones de CPU, es decir, las extensiones de host de virtualización (VHE) (ARMv8.1 y posteriores). En uno de esos modos, comúnmente conocido como modo no VHE, el código del hipervisor se divide de la imagen del kernel durante el inicio y se instala en EL2, mientras que el kernel se ejecuta en EL1. Aunque forma parte de la base de código de Linux, el componente EL2 de KVM es un pequeño componente a cargo del cambio entre varios EL1. El componente del hipervisor se compila con Linux, pero se encuentra en una sección separada y dedicada de la memoria de la imagen vmlinux. La pKVM aprovecha este diseño extendiendo el código del hipervisor con funciones nuevas, lo que le permite establecer restricciones en el kernel del host de Android y el espacio del usuario, y limitar el acceso del host a la memoria de invitado y al hipervisor.

Módulos de proveedores de la pKVM

Un módulo de proveedor de la pKVM es un módulo específico de hardware que contiene funciones específicas del dispositivo, como los controladores de unidad de administración de memoria de entrada y salida (IOMMU). Estos módulos te permiten transferir funciones de seguridad que requieren acceso de nivel de excepción 2 (EL2) a la pKVM.

Para obtener información sobre cómo implementar y cargar un módulo de proveedor de la pKVM, consulta Cómo implementar un módulo de proveedores de la pKVM.

Procedimiento de inicio

En la siguiente figura, se muestra el procedimiento de inicio de la pKVM:

Procedimiento de inicio de la pKVM

Figura 1: Procedimiento de inicio de la pKVM

  1. El bootloader ingresa al kernel genérico en EL2.
  2. El kernel genérico detecta que se está ejecutando en EL2 y desprivilegia a EL1, mientras que la pKVM y sus módulos continúan ejecutándose en EL2. Además, en este momento, se cargan los módulos de proveedores de la pKVM.
  3. El kernel genérico se inicia de forma normal y carga todos los controladores del dispositivo necesarios hasta llegar al espacio del usuario. En este punto, la pKVM está implementada y maneja las tablas de páginas de la etapa 2.

El procedimiento de inicio confía en el bootloader para mantener la integridad de la imagen del kernel solo durante el inicio anticipado. Cuando se deniega el kernel, ya no se lo considera de confianza por el hipervisor, que es responsable de protegerse a sí mismo incluso si el kernel está comprometido.

Tener el kernel de Android y el hipervisor en la misma imagen binaria permite una interfaz de comunicación con acoplamiento alto entre ellos. Este acoplamiento estricto garantiza actualizaciones atómicas de los dos componentes, lo que evita la necesidad de mantener estable la interfaz entre ellos y ofrece una gran flexibilidad sin comprometer la capacidad de mantenimiento a largo plazo. El acoplamiento alto también permite optimizaciones de rendimiento cuando ambos componentes pueden cooperar sin afectar las garantías de seguridad que proporciona el hipervisor.

Además, la adopción de GKI en el ecosistema de Android permite automáticamente que el hipervisor de la pKVM se implemente en dispositivos Android en el mismo objeto binario que el kernel.

Protección de acceso a la memoria de la CPU

La arquitectura de Arm especifica una unidad de administración de memoria (MMU) dividida en dos etapas independientes, que se pueden usar para implementar la traducción de direcciones y el control de acceso en diferentes partes de la memoria. EL1 controla el MMU de etapa 1 y permite un primer nivel de traducción de direcciones. Linux usa la MMU de etapa 1 para administrar el espacio de direcciones virtuales proporcionado a cada proceso de espacio de usuario y a su propio espacio de direcciones virtuales.

EL2 controla la MMU de etapa 2 y permite aplicar una segunda traducción de dirección en la dirección de salida del MMU de etapa 1, lo que genera una dirección física (PA). Los hipervisores pueden usar la traducción de la etapa 2 para controlar y traducir los accesos a la memoria de todas las VM invitadas. Como se muestra en la figura 2, cuando ambas etapas de traducción están habilitadas, la dirección de salida de la etapa 1 se denomina dirección física intermedia (IPA). Nota: La dirección virtual (VA) se traduce en un IPA y, luego, en un PA.

Protección de acceso a la memoria de la CPU

Figura 2: Protección de acceso a la memoria de la CPU

Históricamente, KVM se ejecuta con la traducción de la etapa 2 habilitada mientras se ejecutan los invitados y con la etapa 2 inhabilitada mientras se ejecuta el kernel de Linux del host. Esta arquitectura permite que los accesos a la memoria desde el MMU de etapa de host 1 pasen por el MMU de etapa 2, por lo que permite el acceso sin restricciones desde el host a las páginas de memoria de invitado. Por otro lado, la pKVM habilita la protección de la etapa 2 incluso en el contexto del host. Además, el hipervisor se encarga de proteger las páginas de la memoria del invitado, en lugar del host.

KVM hace un uso completo de la traducción de direcciones en la etapa 2 para implementar asignaciones complejas de IPA/PA para los invitados, lo que crea la ilusión de memoria contigua para los invitados, a pesar de la fragmentación física. Sin embargo, el uso del MMU de etapa 2 para el host se limita solo al control de acceso. La etapa de host 2 se asigna a la identidad, lo que garantiza que la memoria contigua en el espacio de IPA del host sea contigua en el espacio de PA. Esta arquitectura permite el uso de asignaciones grandes en la tabla de páginas y, en consecuencia, reduce la presión sobre el búfer de traducción (TLB). Debido a que PA puede indexar una asignación de identidad, la etapa de host 2 también se usa para realizar un seguimiento de la propiedad de la página directamente en la tabla de páginas.

Protección de acceso directo a la memoria (DMA)

Como se describió anteriormente, anular la asignación de las páginas de invitado del host de Linux en las tablas de páginas de la CPU es un paso necesario, pero insuficiente para proteger la memoria de invitado. La pKVM también debe proteger contra los accesos a la memoria que realizan los dispositivos compatibles con DMA bajo el control del kernel del host y la posibilidad de un ataque de DMA iniciado por un host malicioso. Para evitar que un dispositivo de este tipo acceda a la memoria de invitado, la pKVM requiere hardware de unidad de administración de memoria de entrada y salida (IOMMU) para cada dispositivo compatible con DMA en el sistema, como se muestra en la figura 3.

Protección de acceso a la memoria de DMA

Figura 3: Protección de acceso a la memoria DMA

Como mínimo, el hardware de IOMMU proporciona los medios para otorgar y revocar el acceso de lectura/escritura de un dispositivo a la memoria física con el nivel de detalle de la página. Sin embargo, este hardware de IOMMU limita el uso de dispositivos en las pVM, ya que suponen una etapa 2 con asignación de identidad.

Para garantizar el aislamiento entre las máquinas virtuales, el IOMMU debe poder distinguir las transacciones de memoria generadas en nombre de diferentes entidades, de modo que se pueda usar el conjunto apropiado de tablas de páginas para la traducción.

Además, reducir la cantidad de código específico de SoC en EL2 es una estrategia clave para reducir la base de procesamiento confiable (TCB) general de la pKVM y se contrapone a la inclusión de controladores IOMMU en el hipervisor. Para mitigar este problema, el host en EL1 es responsable de las tareas auxiliares de administración de IOMMU, como la administración de energía, la inicialización y, cuando corresponda, el manejo de interrupciones.

Sin embargo, cuando se permite que el host controle el estado del dispositivo, se imponen requisitos adicionales en la interfaz de programación del hardware de IOMMU para garantizar que las verificaciones de permisos no se puedan omitir por otros medios, por ejemplo, después de un restablecimiento del dispositivo.

Una IOMMU estándar y compatible para dispositivos ARM que posibilita el aislamiento y la asignación directa es la arquitectura de la unidad de administración de memoria del sistema (SMMU). Esta arquitectura es la solución de referencia recomendada.

Propiedad de la memoria

En el momento del inicio, se supone que toda la memoria que no es del hipervisor es propiedad del host, y el hipervisor le hace un seguimiento como tal. Cuando se genera una pVM, el host dona páginas de memoria para permitir que se inicie y el hipervisor traslada la propiedad de esas páginas del host a la pVM. Por lo tanto, el hipervisor coloca restricciones de control de acceso en la tabla de páginas de la etapa 2 del host para evitar que acceda a las páginas nuevamente, lo que proporciona confidencialidad al invitado.

La comunicación entre el host y los invitados es posible gracias al uso compartido de memoria controlado entre ellos. Los invitados pueden compartir algunas de sus páginas con el host mediante una hiperllamada, que le indica al hipervisor que vuelva a asignar esas páginas en la tabla de páginas de la etapa de host. De manera similar, la comunicación del host con TrustZone es posible mediante el uso compartido de memoria o las operaciones de préstamo, las cuales se supervisan y controlan de cerca por la pKVM mediante la especificación de Firmware Framework para Arm (FF-A).

Dado que los requisitos de memoria de una pVM pueden cambiar con el tiempo, se proporciona una hiperllamada que permite que la propiedad de páginas específicas que pertenecen al llamador ceda al host. En la práctica, esta hiperllamada se usa con el protocolo de globo de Virtio para permitir que VMM solicite memoria a la pVM y que la pVM le notifique a la VMM sobre páginas abandonadas de una manera controlada.

El hipervisor es responsable de rastrear la propiedad de todas las páginas de memoria del sistema y si se comparten o se prestan a otras entidades. La mayor parte de este seguimiento de estado se realiza con metadatos adjuntos a las tablas de páginas de la etapa 2 del host y de los invitados, con bits reservados en las entradas de tablas de páginas (PTE), que, como su nombre sugiere, están reservados para uso de software.

El host debe asegurarse de no intentar acceder a páginas a las que el hipervisor no puede acceder. Un acceso al host ilegal provoca que el hipervisor inserte una excepción síncrona en el host, lo que puede provocar que la tarea de espacio de usuario responsable reciba una señal SEGV o que falle el kernel del host. Para evitar los accesos accidentales, las páginas donadas a los invitados no son aptas para que el kernel del host las intercambie o las combine.

Interrupción de manejo y temporizadores

Las interrupciones son una parte esencial de la forma en que un invitado interactúa con los dispositivos y para la comunicación entre las CPU, donde las interrupciones del interprocesador (IPIs) son el principal mecanismo de comunicación. El modelo de KVM es delegar toda la administración de interrupciones virtuales al host en EL1, que, para ese propósito, se comporta como una parte no confiable del hipervisor.

La pKVM ofrece una emulación completa del controlador de interrupción genérico versión 3 (GICv3) basada en el código de KVM existente. El temporizador y los IPI se controlan como parte de este código de emulación no confiable.

Compatibilidad con GICv3

La interfaz entre EL1 y EL2 debe garantizar que el estado de interrupción completo sea visible para el host EL1, incluidas las copias de los registros del hipervisor relacionados con las interrupciones. Por lo general, esta visibilidad se logra con regiones de memoria compartida, una por CPU virtual (vCPU).

El código de compatibilidad del entorno de ejecución del registro del sistema se puede simplificar para admitir solo la captura de registros de interrupción generada por software (SGIR) y de desactivación de registro de interrupción (DIR). La arquitectura exige que estos registros siempre se trapen en EL2, mientras que las otras trampas solo han sido útiles para mitigar errata hasta ahora. Todo lo demás se maneja en hardware.

En el lado de MMIO, todo se emula en EL1, por lo que se reutiliza toda la infraestructura actual en KVM. Por último, Esperar la interrupción (WFI) siempre se retransmite a EL1, ya que esta es una de las primitivas de programación básicas que usa KVM.

Compatibilidad con cronómetros

El valor comparativo para el temporizador virtual debe exponerse a EL1 en cada WFI de captura para que EL1 pueda inyectar interrupciones del temporizador mientras la CPU virtual está bloqueada. El temporizador físico se emula por completo, y todas las trampas se retransmiten a EL1.

Control de MMIO

Para comunicarse con el monitor de máquina virtual (VMM) y realizar la emulación GIC, las trampas de MMIO deben retransmitirse al host en EL1 para una clasificación adicional. La pKVM requiere lo siguiente:

  • IPA y tamaño del acceso
  • Datos en caso de escritura
  • Endianidad de la CPU en el punto de captura

Además, las trampas con un registro de uso general (GPR) como fuente/destino se retransmiten mediante un seudoregistro de transferencia abstracto.

Interfaces de invitado

Un invitado puede comunicarse con un invitado protegido mediante una combinación de hiperllamadas y acceso a la memoria de las regiones atrapadas. Las hiperllamadas se exponen según el estándar SMCCC, con un rango reservado para una asignación de proveedores por parte de KVM. Las siguientes hiperllamadas son de especial importancia para los invitados de la pKVM.

Hiperllamadas genéricas

  • PSCI proporciona un mecanismo estándar para que el invitado controle el ciclo de vida de sus CPU virtuales, incluida la integración y el uso sin conexión, y el cierre del sistema.
  • TRNG proporciona un mecanismo estándar para que el invitado solicite entropía a la pKVM que retransmite la llamada a EL3. Este mecanismo es muy útil cuando no se puede confiar en que el host virtualice un generador de números aleatorios de hardware (RNG).

Hiperllamadas de la pKVM

  • Uso compartido de la memoria con el organizador. Al principio, el host no puede acceder a toda la memoria de invitado, pero el acceso al host es necesario para la comunicación de memoria compartida y los dispositivos paravirtualizados que dependen de búferes compartidos. Las hiperllamadas para compartir y dejar de compartir páginas con el host permiten al invitado decidir exactamente a qué partes de la memoria puede acceder el resto de Android sin la necesidad de un protocolo de enlace.
  • Renuncia de memoria al host. Por lo general, toda la memoria del invitado pertenece al invitado hasta que se destruye. Este estado puede ser inadecuado para las VMs de larga duración con requisitos de memoria que varían con el tiempo. La hiperllamada relinquish permite que un invitado transfiera de forma explícita la propiedad de las páginas al host sin requerir la cancelación del invitado.
  • Captura de acceso a la memoria al host. Por lo general, si un invitado de KVM accede a una dirección que no corresponde a una región de memoria válida, el subproceso de CPU virtual sale al host, y el acceso se suele usar para MMIO y el VMM lo emula en el espacio de usuario. Para facilitar este manejo, la pKVM debe anunciar detalles sobre la instrucción con errores, como su dirección, los parámetros de registro y posiblemente su contenido de vuelta al host, lo que podría exponer de manera involuntaria datos sensibles de un invitado protegido si no se había previsto la trampa. La pKVM resuelve este problema al tratar estos errores como irrecuperables, a menos que el invitado haya emitido una llamada de IPA de trampa para identificar al host con errores y que así lo identifique. Esta solución se conoce como guarda de MMIO.

Dispositivo de E/S virtual (virtio)

Virtio es un estándar popular, portátil y consolidado para implementar dispositivos paravirtualizados y también interactuar con ellos. La mayoría de los dispositivos expuestos a invitados protegidos se implementan con Virtio. Virtio también respalda la implementación vsock que se usa para la comunicación entre un invitado protegido y el resto de Android.

Por lo general, el VMM implementa los dispositivos Virtio en el espacio de usuario del host, lo que intercepta los accesos a la memoria atrapada del invitado a la interfaz MMIO del dispositivo Virtio y emula el comportamiento esperado. El acceso a MMIO es relativamente costoso porque cada acceso al dispositivo requiere un recorrido de ida y vuelta a la VMM y viceversa, por lo que la mayor parte de la transferencia de datos real entre el dispositivo y el invitado se realiza con un conjunto de colas virtuales en la memoria. Una suposición clave de Virtio es que el host puede acceder a la memoria del invitado de manera arbitraria. Esta suposición es evidente en el diseño de la virtqueue, que puede contener punteros a búferes en el invitado a los que la emulación del dispositivo está destinada a acceder directamente.

Aunque los hiperllamadas de uso compartido de memoria que se describieron antes se podrían usar para compartir búferes de datos de Virtio del invitado al host, este uso compartido se realiza necesariamente en el nivel de detalle de la página y podría exponer más datos de los necesarios si el tamaño del búfer es menor que el de una página. En cambio, el invitado está configurado para asignar las virtqueues y sus búferes de datos correspondientes desde una ventana fija de memoria compartida, y los datos se copian (rebotan) hacia y desde la ventana según sea necesario.

Dispositivo virtual

Figura 4: Dispositivo Virtio

Interacción con TrustZone

Aunque los invitados no pueden interactuar directamente con TrustZone, el organizador aún debe poder emitir llamadas de SMC en el mundo seguro. Estas llamadas pueden especificar búferes de memoria con dirección física a los que no puede acceder el host. Debido a que el software seguro generalmente no es consciente de la accesibilidad del búfer, un host malicioso podría usar este búfer para realizar un ataque de engaño de aplicación delegada (análogo a un ataque de DMA). Para evitar estos ataques, la pKVM captura todas las llamadas de SMC del host a EL2 y actúa como un proxy entre el host y el monitor seguro en EL3.

Las llamadas a la PSCI del host se reenvían al firmware EL3 con modificaciones mínimas. Específicamente, el punto de entrada para una CPU que se pone en línea o se reanuda desde la suspensión se reescribe para que la tabla de páginas de la etapa 2 se instale en EL2 antes de regresar al host en EL1. La pKVM aplica esta protección durante el inicio.

Esta arquitectura se basa en el SoC compatible con PSCI, preferentemente a través del uso de una versión actualizada de TF-A como su firmware EL3.

El framework de firmware para Arm (FF-A) estandariza las interacciones entre el mundo normal y el seguro, especialmente en la presencia de un hipervisor seguro. Una parte importante de la especificación define un mecanismo para compartir memoria con el mundo seguro, a través de un formato de mensaje común y un modelo de permisos bien definido para las páginas subyacentes. La pKVM procesa los mensajes FF-A para garantizar que el host no intente compartir memoria con el lado seguro para el que no tiene permisos suficientes.

Esta arquitectura se basa en el software del mundo seguro que aplica el modelo de acceso a la memoria para garantizar que las apps de confianza y cualquier otro software que se ejecute en el mundo seguro puedan acceder a la memoria solo si son propiedad exclusiva del mundo seguro o si se compartió de forma explícita con ella a través de FF-A. En un sistema con S-EL2, la aplicación del modelo de acceso a la memoria debe realizarse con un Secure Partition Manager Core (SPMC), como Hafnium, que mantiene las tablas de páginas de la etapa 2 para el mundo seguro. En un sistema sin S-EL2, el TEE puede aplicar un modelo de acceso a la memoria a través de sus tablas de páginas de etapa 1.

Si la llamada de SMC a EL2 no es una llamada a la PSCI o un mensaje definido por FF-A, las SMC no controladas se reenvían a EL3. Se da por supuesto que el firmware seguro (necesario de confianza) puede manejar las SMC no controladas de forma segura, ya que el firmware comprende las precauciones necesarias para mantener el aislamiento de la pVM.

Supervisor de máquina virtual

crosvm es un monitor de máquina virtual (VMM) que ejecuta máquinas virtuales a través de la interfaz KVM de Linux. Lo que hace que crosvm sea único es su enfoque en la seguridad con el uso del lenguaje de programación de Rust y una zona de pruebas en torno a dispositivos virtuales para proteger el kernel del host. Para obtener más información sobre crosvm, consulta su documentación oficial aquí.

Descriptores de archivos e ioctl

KVM expone el dispositivo de caracteres /dev/kvm al espacio del usuario con ioctl que conforman la API de KVM. Las ioctl pertenecen a las siguientes categorías:

  • Las ioctls del sistema consultan y establecen los atributos globales que afectan a todo el subsistema de KVM, y crean pVMs.
  • Las ioctl de VM consultan y establecen atributos que crean dispositivos y CPU virtuales, y afectan a una pVM completa, por ejemplo, incluir el diseño de la memoria y la cantidad de CPU virtuales y dispositivos.
  • ioctl de CPU virtual consulta y establece atributos que controlan el funcionamiento de una CPU virtual única.
  • Las ioctls del dispositivo consultan y establecen atributos que controlan el funcionamiento de un solo dispositivo virtual.

Cada proceso crosvm ejecuta exactamente una instancia de una máquina virtual. En este proceso, se usa la ioctl de sistema KVM_CREATE_VM para crear un descriptor de archivos de VM que se puede usar para emitir ioctl de pVM. Un ioctl KVM_CREATE_VCPU o KVM_CREATE_DEVICE en un FD de VM crea una CPU virtual/dispositivo y muestra un descriptor de archivos que apunta al recurso nuevo. Se pueden usar ioctls en un FD de CPU virtual o dispositivo para controlar el dispositivo que se creó con ioctl en un FD de VM. Para las CPU virtuales, esto incluye la importante tarea de ejecutar el código de invitado.

De forma interna, crosvm registra los descriptores de archivos de la VM con el kernel mediante la interfaz epoll activada por el perímetro. Luego, el kernel notifica a crosvm cada vez que hay un evento nuevo pendiente en cualquiera de los descriptores de archivos.

La pKVM agrega una función nueva, KVM_CAP_ARM_PROTECTED_VM, que se puede usar para obtener información sobre el entorno de pVM y configurar el modo protegido para una VM. Crosvm usa esto durante la creación de la pVM si se pasa la marca --protected-vm, para consultar y reservar la cantidad adecuada de memoria para el firmware de pVM y, luego, habilitar el modo protegido.

Asignación de memoria

Una de las principales responsabilidades de un VMM es asignar su memoria y administrar su diseño de memoria. crosvm genera un diseño de memoria fijo que se describe de forma general en la siguiente tabla.

FDT en modo normal PHYS_MEMORY_END - 0x200000
Liberar ...
Ramdisk ALIGN_UP(KERNEL_END, 0x1000000)
Kernel 0x80080000
Bootloader 0x80200000
FDT en modo BIOS 0x80000000
Base de memoria física 0x80000000
firmware de pVM 0x7FE00000
Memoria del dispositivo 0x10000 - 0x40000000

La memoria física se asigna con mmap, y esta se dona a la VM para propagar sus regiones de memoria, llamadas memslots, con la ioctl KVM_SET_USER_MEMORY_REGION. Por lo tanto, toda la memoria pVM invitada se atribuye a la instancia crosvm que la administra y puede provocar que el proceso finalice (finalice la VM) si el host comienza a quedarse sin memoria libre. Cuando se detiene una VM, el hipervisor limpia de forma automática la memoria y la devuelve al kernel del host.

Con un KVM normal, la VMM retiene el acceso a toda la memoria de invitado. Con la pKVM, la memoria de invitado no se asigna del espacio de direcciones físicas del host cuando se dona al invitado. La única excepción es la memoria compartida explícitamente por el invitado, como para los dispositivos Virtio.

Las regiones MMIO del espacio de direcciones del invitado no se asignan. El acceso del invitado a estas regiones está atrapado y da como resultado un evento de E/S en el FD de la VM. Este mecanismo se utiliza para implementar dispositivos virtuales. En el modo protegido, el invitado debe confirmar que una región de su espacio de direcciones se usa para MMIO a través de un hiperllamada, a fin de reducir el riesgo de filtración accidental de información.

Programación

Cada CPU virtual está representada por un subproceso POSIX y está programada por el programador de Linux del host. El subproceso llama a ioctl KVM_RUN en el FD de la CPU virtual, lo que hace que el hipervisor cambie al contexto de la CPU virtual invitada. El programador de host registra el tiempo dedicado a un contexto de invitado como el tiempo que usa el subproceso de CPU virtual correspondiente. KVM_RUN se muestra cuando hay un evento que la VMM debe controlar, como la E/S, el fin de la interrupción o la CPU virtual detenida. El VMM controla el evento y vuelve a llamar a KVM_RUN.

Durante KVM_RUN, el programador host no interrumpe el subproceso, excepto la ejecución del código del hipervisor EL2, que no es interrumpible. La pVM invitada no tiene un mecanismo para controlar este comportamiento.

Debido a que todos los subprocesos de la CPU virtual se programan como cualquier otra tarea del espacio del usuario, están sujetos a todos los mecanismos estándar de QoS. Específicamente, cada subproceso de CPU virtual puede asociarse a CPU físicas, colocarse en conjuntos de CPU, aumentar o limitar mediante la restricción del uso, cambiar su política de prioridad o programación, y mucho más.

Dispositivos virtuales

crosvm admite diferentes dispositivos, entre los que se incluyen los siguientes:

  • virtio-blk para imágenes de disco compuestos, de solo lectura o de lectura y escritura
  • vhost-vsock para la comunicación con el host
  • virtio-pci como virtio transport
  • Reloj en tiempo real (RTC) pl030
  • 16550a UART para comunicación en serie

firmware de pVM

El firmware de la pVM (pvmfw) es el primer código que ejecuta una pVM, similar a la ROM de inicio de un dispositivo físico. El objetivo principal de pvmfw es iniciar el inicio seguro y derivar el secreto único de la pVM. El software pvmfw no está limitado a usarlo con ningún SO específico, como Microdroid, siempre y cuando el SO sea compatible con la VM.

El objeto binario pvmfw se almacena en una partición flash del mismo nombre y se actualiza de forma OTA.

Inicio del dispositivo

Se agrega la siguiente secuencia de pasos al procedimiento de inicio de un dispositivo habilitado para pKVM:

  1. El bootloader de Android (ABL) carga pvmfw de su partición en la memoria y verifica la imagen.
  2. La ABL obtiene sus secretos del Motor de composición identificador de dispositivos (DICE) (identificadores de dispositivos compuestos (CDI) y cadena de certificados del DICE) de una raíz de confianza.
  3. La ABL deriva los CDI necesarios para pvmfw y los agrega al objeto binario de pvmfw.
  4. El ABL agrega al DT un nodo de la región de memoria reservada linux,pkvm-guest-firmware-memory y describe la ubicación y el tamaño del objeto binario pvmfw y los secretos que derivó en el paso anterior.
  5. El ABL entrega el control a Linux y Linux inicializa la pKVM.
  6. La pKVM desasigna la región de memoria pvmfw de las tablas de páginas de la etapa 2 del host y la protege del host (y de los invitados) durante el tiempo de actividad del dispositivo.

Después del inicio del dispositivo, Microdroid se inicia según los pasos de la sección Secuencia de inicio del documento Microdroid.

inicio de pVM

Cuando se crea una pVM, crosvm (o alguna otra VMM) debe crear una ranura de memoria lo suficientemente grande como para que el hipervisor propague la imagen de pvmfw. La VMM también está restringida en la lista de registros cuyo valor inicial puede establecer (x0-x14 para la CPU virtual principal, ninguna para las CPU virtuales secundarias). Los registros restantes están reservados y forman parte de la ABI de hypervisor-pvmfw.

Cuando se ejecuta la pVM, el hipervisor primero le da el control de la CPU virtual principal a pvmfw. El firmware espera que crosvm haya cargado un kernel firmado por AVB, que puede ser un bootloader o cualquier otra imagen, y un FDT sin firmar en la memoria en compensaciones conocidas. pvmfw valida la firma del AVB y, si tiene éxito, genera un árbol de dispositivos de confianza a partir del FDT recibido, borra sus secretos de la memoria y las ramas al punto de entrada de la carga útil. Si falla uno de los pasos de verificación, el firmware emite una hiperllamada SYSTEM_RESET de PSCI.

Entre inicios, la información sobre la instancia de pVM se almacena en una partición (dispositivo virtio-blk) y se encripta con el secreto de pvmfw para garantizar que, después de un reinicio, el secreto se aprovisione a la instancia correcta.