Architecture AVF

Android fournit une implémentation de référence de tous les composants nécessaires à l'implémentation du framework de virtualisation Android. Actuellement, cette implémentation est limitée à ARM64. Cette page décrit l'architecture du framework.

Arrière-plan

L'architecture Arm autorise jusqu'à quatre niveaux d'exception, le niveau d'exception 0 (EL0) étant le moins privilégié et le niveau d'exception 3 (EL3) le plus élevé. La plus grande partie du codebase Android (tous les composants de l'espace utilisateur) s'exécute sous EL0. Le reste de ce que l'on appelle communément "Android" est le noyau Linux, qui s'exécute sur EL1.

La couche EL2 permet d'introduire un hyperviseur qui permet d'isoler la mémoire et les appareils dans des VM préemptives individuelles au niveau EL1/EL0, avec de solides garanties de confidentialité et d'intégrité.

Hyperviseur

La machine virtuelle protégée basée sur le noyau (pKVM) repose sur l'hyperviseur KVM Linux, qui a été étendu avec la possibilité de limiter l'accès aux charges utiles exécutées dans les machines virtuelles invitées marquées comme "protégées" au moment de la création.

KVM/arm64 accepte différents modes d'exécution en fonction de la disponibilité de certaines fonctionnalités de processeur, à savoir les extensions d'hôte de virtualisation (VHE) (ARMv8.1 et versions ultérieures). Dans l'un de ces modes, communément appelé mode non VHE, le code de l'hyperviseur est divisé de l'image du noyau au démarrage et installé sur EL2, tandis que le noyau lui-même s'exécute sous EL1. Bien qu'il fasse partie du codebase Linux, le composant EL2 de KVM est un petit composant chargé du basculement entre plusieurs EL1. Le composant Hypervisor est compilé avec Linux, mais se trouve dans une section de mémoire distincte de l'image vmlinux. pKVM exploite cette conception en étendant le code de l'hyperviseur à de nouvelles fonctionnalités, ce qui lui permet de restreindre le noyau hôte et l'espace utilisateur Android, et de limiter l'accès de l'hôte à la mémoire de l'invité et à l'hyperviseur.

Modules pKVM des fournisseurs

Un module fournisseur pKVM est un module matériel spécifique qui contient des fonctionnalités propres à l'appareil, telles que les pilotes IOMMU (Input-Output Memory Management Unit). Ces modules vous permettent de transférer des fonctionnalités de sécurité nécessitant un accès EL2 (Exception de niveau 2) à pKVM.

Pour découvrir comment implémenter et charger un module fournisseur pKVM, consultez Implémenter un module fournisseur pKVM.

Procédure de démarrage

La figure suivante illustre la procédure de démarrage de pKVM:

Procédure de démarrage de pKVM

Figure 1.Procédure de démarrage de pKVM

  1. Le bootloader entre dans le noyau générique au niveau EL2.
  2. Le noyau générique détecte qu'il s'exécute sur EL2 et se prive d'EL1, tandis que pKVM et ses modules continuent de s'exécuter sur EL2. De plus, les modules pKVM des fournisseurs sont chargés à ce stade.
  3. Le noyau générique démarre normalement et charge tous les pilotes de périphérique nécessaires jusqu'à atteindre l'espace utilisateur. À ce stade, pKVM est en place et gère les tables des pages de l'étape 2.

La procédure de démarrage fait confiance au bootloader pour maintenir l'intégrité de l'image du noyau uniquement lors du démarrage précoce. Lorsque le noyau est défavorisé, il n'est plus considéré comme approuvé par l'hyperviseur, qui est alors responsable de sa propre protection, même si le noyau est compromis.

Le fait d'avoir le noyau Android et l'hyperviseur dans la même image binaire permet une interface de communication à couplage très fort. Ce couplage étroit garantit des mises à jour atomiques des deux composants, ce qui évite de devoir maintenir une interface stable entre eux et offre une grande flexibilité sans compromettre la gestion à long terme. Le couplage fort permet également d'optimiser les performances lorsque les deux composants peuvent coopérer sans affecter les garanties de sécurité fournies par l'hyperviseur.

De plus, l'adoption de GKI dans l'écosystème Android permet automatiquement de déployer l'hyperviseur pKVM sur les appareils Android dans le même binaire que le noyau.

Protection contre l'accès à la mémoire du processeur

L'architecture Arm spécifie une unité de gestion de mémoire (MMU) divisée en deux étapes indépendantes, qui peuvent toutes deux être utilisées pour implémenter la traduction d'adresses et le contrôle des accès dans différentes parties de la mémoire. La MMU de l'étape 1 est contrôlée par EL1 et permet un premier niveau de traduction d'adresse. Linux utilise la MMU de l'étape 1 pour gérer l'espace d'adressage virtuel fourni à chaque processus d'espace utilisateur et à son propre espace d'adressage virtuel.

La MMU de l'étape 2 est contrôlée par EL2 et permet d'appliquer une deuxième traduction d'adresse sur l'adresse de sortie de l'MMU de l'étape 1, ce qui génère une adresse physique (PA). Les hyperviseurs peuvent utiliser la traduction de l'étape 2 pour contrôler et traduire les accès à la mémoire de toutes les VM invitées. Comme le montre la figure 2, lorsque les deux étapes de traduction sont activées, l'adresse de sortie de l'étape 1 est appelée adresse physique intermédiaire (IPA). Remarque: L'adresse virtuelle (VA) est traduite en IPA, puis en adresse IP.

Protection contre l'accès à la mémoire du processeur

Figure 2. Protection contre l'accès à la mémoire du processeur

À l'origine, KVM s'exécute avec la traduction de l'étape 2 activée lors de l'exécution des invités et l'étape 2 désactivée lors de l'exécution du noyau Linux hôte. Cette architecture permet aux accès à la mémoire de la MMU de l'étape 1 d'hôte de passer par la MMU de l'étape 2, autorisant ainsi un accès illimité depuis l'hôte aux pages de mémoire de l'invité. D'autre part, pKVM active la protection de l'étape 2 même dans le contexte de l'hôte et charge l'hyperviseur de protéger les pages de la mémoire de l'invité plutôt que l'hôte.

KVM exploite pleinement la traduction d'adresse à l'étape 2 pour implémenter des mappages IPA/PA complexes pour les clients, ce qui donne l'illusion d'une mémoire contiguë aux invités malgré la fragmentation physique. Toutefois, l'utilisation du MMU de l'étape 2 pour l'hôte est limitée au contrôle des accès uniquement. L'étape hôte 2 est mappée sur l'identité, ce qui garantit que la mémoire contiguë dans l'espace IPA de l'hôte est contiguë dans l'espace PA. Cette architecture permet d'utiliser des mappages volumineux dans le tableau des pages et réduit donc la pression sur le tampon de traduction en parallèle. Étant donné qu'un mappage d'identité peut être indexé par PA, l'étape hôte 2 permet également de suivre la propriété de la page directement dans la table des pages.

Protection de l'accès direct à la mémoire (DMA, Digital Memory Access)

Comme décrit précédemment, le fait de dissocier les pages d'invité de l'hôte Linux dans les tables des pages du processeur est une étape nécessaire, mais insuffisante pour protéger la mémoire invitée. pKVM doit également se protéger contre les accès à la mémoire effectués par des appareils compatibles avec la loi sur les marchés numériques sous le contrôle du noyau hôte, et contre la possibilité d'une attaque par zone de marché désignée initiée par un hôte malveillant. Pour empêcher un tel appareil d'accéder à la mémoire invitée, pKVM nécessite du matériel IOMMU (Input-Output Memory Management Unit) pour chaque appareil compatible avec la zone de marché désignée du système, comme illustré dans la figure 3.

Protection de l'accès à la mémoire DMA

Figure 3. Protection de l'accès à la mémoire DMA

Au minimum, le matériel IOMMU permet d'accorder et de révoquer l'accès en lecture/écriture d'un appareil à la mémoire physique au niveau de la précision des pages. Cependant, ce matériel IOMMU limite l'utilisation des périphériques dans les VM préemptives, car ils supposent une étape 2 de mappage d'identité.

Pour assurer l'isolation entre les machines virtuelles, les transactions de mémoire générées pour le compte de différentes entités doivent être identifiables par l'IOMMU afin que l'ensemble approprié de tables de page puisse être utilisé pour la traduction.

En outre, la réduction de la quantité de code spécifique au SoC au niveau d'EL2 est une stratégie clé pour réduire la base informatique de confiance (TCB) globale de pKVM et va à l'encontre de l'inclusion des pilotes IOMMU dans l'hyperviseur. Pour atténuer ce problème, l'hôte de EL1 est responsable des tâches auxiliaires de gestion IOMMU, telles que la gestion de l'alimentation, l'initialisation et, le cas échéant, la gestion des interruptions.

Toutefois, permettre à l'hôte de contrôler l'état de l'appareil impose des exigences supplémentaires sur l'interface de programmation du matériel IOMMU afin de garantir que les vérifications d'autorisation ne peuvent pas être contournées par d'autres moyens, par exemple après une réinitialisation d'appareil.

L'architecture IOMMU (System Memory Management Unit, unité de gestion de la mémoire système) (SMMU) (System Memory Management Unit, unité de gestion de la mémoire système) Arm permet une configuration IOMMU standard et bien compatible pour les appareils Arm, qui permet à la fois l'isolation et l'attribution directe. Cette architecture est la solution de référence recommandée.

Propriété de la mémoire

Au démarrage, toute la mémoire hors hyperviseur est supposée appartenir à l'hôte et est suivie en tant que telle par l'hyperviseur. Lorsqu'une pVM est générée, l'hôte fait don de pages de mémoire pour lui permettre de démarrer, et l'hyperviseur transfère la propriété de ces pages de l'hôte à la pVM. Ainsi, l'hyperviseur met en place des restrictions de contrôle d'accès dans la table des pages de l'étape 2 de l'hôte pour l'empêcher d'accéder à nouveau aux pages, ce qui assure la confidentialité de l'invité.

La communication entre l'hôte et les invités est rendue possible grâce au partage de mémoire contrôlé entre eux. Les invités sont autorisés à partager certaines de leurs pages avec l'hôte à l'aide d'un hyperappel, qui demande à l'hyperviseur de remapper ces pages dans la table des pages de l'étape 2 de l'hôte. De même, la communication de l'hôte avec TrustZone est rendue possible par des opérations de partage et/ou de prêt de mémoire, qui sont toutes étroitement surveillées et contrôlées par pKVM à l'aide de la spécification Firmware Framework for Arm (FF-A).

Étant donné que les exigences de mémoire d'une pVM peuvent changer au fil du temps, un hyperappel est fourni, ce qui permet de restituer à l'hôte la propriété de pages spécifiées appartenant à l'appelant. Dans la pratique, cet hyperappel est utilisé avec le protocole d'infobulle virtio pour permettre au VMM de demander un retour en mémoire à la pVM et à la pVM d'informer le VMM des pages abandonnées, de manière contrôlée.

L'hyperviseur est chargé de suivre la propriété de toutes les pages de mémoire du système et de savoir si elles sont partagées ou prêtées à d'autres entités. La plupart de ce suivi d'état est effectué à l'aide de métadonnées associées aux tables de page de l'étape 2 de l'hôte et des invités, en utilisant des bits réservés dans les entrées de table de page (PTE) qui, comme leur nom l'indique, sont réservés à l'utilisation du logiciel.

L'hôte doit s'assurer qu'il ne tente pas d'accéder à des pages rendues inaccessibles par l'hyperviseur. Un accès illégal à l'hôte entraîne l'injection d'une exception synchrone dans l'hôte par l'hyperviseur, ce qui peut entraîner le plantage de la tâche d'espace utilisateur responsable ou le plantage du noyau de l'hôte. Pour éviter tout accès accidentel, les pages données aux invités ne peuvent plus être échangées ni fusionnées par le noyau hôte.

Interrompre le traitement et les minuteurs

Les interruptions constituent un élément essentiel de la manière dont un invité interagit avec les appareils et pour la communication entre les processeurs, où les interruptions interprocesseurs (IPI) constituent le principal mécanisme de communication. Le modèle KVM consiste à déléguer toute la gestion des interruptions virtuelles à l'hôte dans EL1, qui, à cette fin, se comporte comme une partie non approuvée de l'hyperviseur.

pKVM propose une émulation complète du contrôleur d'interruption générique version 3 (GICv3) basée sur le code KVM existant. Le minuteur et les IPI sont gérés dans le cadre de ce code d'émulation non approuvé.

Compatibilité avec GICv3

L'interface entre EL1 et EL2 doit garantir que l'état d'interruption complet est visible par l'hôte EL1, y compris les copies des registres hyperviseurs liés aux interruptions. Cette visibilité est généralement obtenue à l'aide de régions de mémoire partagée, une par processeur virtuel (vCPU).

Le code de prise en charge de l'environnement d'exécution du registre système peut être simplifié pour ne prendre en charge que le piégeage du registre SGIR (Software Generated Interrupt Register) et du registre d'interruption de désactivation (DIR). L'architecture exige que ces registres soient toujours piégés dans la méthode EL2, tandis que les autres pièges ne servent jusqu'à présent qu'à limiter les errata. Tout le reste est géré par le matériel.

Du côté des MMIO, tout est émulé au niveau de EL1, en réutilisant toute l'infrastructure actuelle dans KVM. Enfin, la fonctionnalité Wait for Interrupt (WFI) est toujours transmise à EL1, car il s'agit de l'une des primitives de planification de base utilisées par KVM.

Prise en charge des minuteurs

La valeur de comparaison du minuteur virtuel doit être exposée à EL1 sur chaque WFI de blocage afin que EL1 puisse injecter des interruptions de minuteur lorsque le processeur virtuel est bloqué. Le minuteur physique est entièrement émulé, et toutes les interruptions sont transmises à EL1.

Gestion des MMIO

Pour communiquer avec le moniteur de machine virtuelle (VMM) et effectuer l'émulation GIC, les interruptions MMIO doivent être transmises à l'hôte dans EL1 afin d'effectuer un tri supplémentaire. pKVM nécessite les éléments suivants:

  • IPA et taille de l'accès
  • Des données en cas d'écriture
  • Finition du CPU au moment du piégeage

En outre, les interruptions avec un registre à usage général (GPR) en tant que source/destination sont relayées à l'aide d'un pseudo-registre de transfert abstrait.

Interfaces invitées

Un invité peut communiquer avec un invité protégé en combinant des hyperappels et un accès à la mémoire vers des régions piégées. Les hyperappels sont exposés conformément à la norme SMCCC, avec une plage réservée à l'allocation des fournisseurs par KVM. Les hyperappels suivants sont particulièrement importants pour les clients pKVM.

Hyperappels génériques

  • La PSCI fournit un mécanisme standard permettant à l'invité de contrôler le cycle de vie de ses processeurs virtuels, y compris l'activation, la suppression et l'arrêt du système.
  • TRNG fournit un mécanisme standard permettant à l'invité de demander l'entropie à la pKVM qui relaie l'appel à EL3. Ce mécanisme est particulièrement utile lorsque l'hôte ne peut pas virtualiser un générateur de nombres aléatoires matériel.

Hyperappels pKVM

  • Partage de mémoire avec l'hôte. Toute la mémoire de l'invité est initialement inaccessible à l'hôte, mais l'accès à l'hôte est nécessaire pour la communication en mémoire partagée et pour les appareils paravirtualisés qui reposent sur des tampons partagés. Les hyperappels pour le partage et l'annulation du partage de pages avec l'hôte permettent à l'invité de décider exactement quelles parties de la mémoire sont rendues accessibles au reste d'Android sans avoir besoin d'un handshake.
  • Remise de la mémoire à l'hôte. Toute la mémoire de l'invité appartient généralement à l'invité jusqu'à ce qu'elle soit détruite. Cet état peut ne pas être adapté aux VM de longue durée dont les exigences de mémoire varient au fil du temps. L'hyperappel relinquish permet à un invité de transférer explicitement la propriété des pages à l'hôte sans nécessiter la fermeture de l'invité.
  • Piègement des accès à la mémoire de l'hôte. Traditionnellement, si un invité KVM accède à une adresse qui ne correspond pas à une région de mémoire valide, le thread du processeur virtuel quitte l'hôte. L'accès est généralement utilisé pour MMIO et émulé par le VMM dans l'espace utilisateur. Pour faciliter cette gestion, pKVM doit annoncer les détails de l'instruction défaillante, tels que son adresse, ses paramètres d'enregistrement et éventuellement leur contenu à l'hôte, ce qui peut exposer involontairement des données sensibles d'un invité protégé si le piège n'a pas été anticipé. pKVM résout ce problème en traitant ces erreurs comme fatales, sauf si l'invité a précédemment émis une plage d'appels hyper-appel pour identifier Cette solution est appelée défense MMIO.

Appareil d'E/S virtuel (virtio)

Virtio est une norme populaire, portable et mature, pour l'implémentation et l'interaction avec des appareils paravirtualisés. La majorité des appareils exposés à des invités protégés sont implémentés à l'aide de virtio. Virtio est également à la base de l'implémentation de comparaison entre un invité protégé et le reste d'Android.

Les appareils Virtio sont généralement mis en œuvre dans l'espace utilisateur de l'hôte par le VMM, qui intercepte les accès à la mémoire piégés de l'invité à l'interface MMIO de l'appareil virtio et émule le comportement attendu. L'accès MMIO est relativement coûteux, car chaque accès à l'appareil nécessite un aller-retour vers le VMM, puis retour. La majeure partie du transfert de données réel entre l'appareil et l'invité s'effectue à l'aide d'un ensemble de files d'attente virtuelles en mémoire. Une hypothèse clé de virtio est que l'hôte peut accéder à la mémoire de l'invité de manière arbitraire. Cette hypothèse est évidente dans la conception de la file d'attente virtuelle, qui peut contenir des pointeurs vers des tampons de l'invité auxquels l'émulation d'appareil est censée accéder directement.

Bien que les hyperappels de partage de mémoire décrits précédemment puissent être utilisés pour partager des tampons de données virtio de l'invité à l'hôte, ce partage est nécessairement effectué au niveau de la page et peut exposer plus de données que nécessaire si la taille de la mémoire tampon est inférieure à celle d'une page. Au lieu de cela, l'invité est configuré pour allouer à la fois les files d'attente virtqueues et leurs tampons de données correspondants à partir d'une fenêtre fixe de mémoire partagée, les données étant copiées (rejetées) vers et depuis la fenêtre selon les besoins.

Appareil virtuel

Figure 4. Appareil Virtio

Interaction avec TrustZone

Bien que les invités ne puissent pas interagir directement avec TrustZone, l'hôte doit toujours être en mesure d'émettre des appels SMC dans le monde sécurisé. Ces appels peuvent spécifier des tampons de mémoire adressés physiquement et qui sont inaccessibles à l'hôte. Étant donné que le logiciel sécurisé n'est généralement pas conscient de l'accessibilité du tampon, un hôte malveillant peut l'utiliser pour effectuer une attaque confus deputy (analogue à une attaque par zone de marché désignée). Pour éviter de telles attaques, pKVM piége tous les appels SMC de l'hôte à EL2 et agit comme un proxy entre l'hôte et la surveillance sécurisée au niveau de EL3.

Les appels PSCI de l'hôte sont transférés au micrologiciel EL3 avec des modifications minimales. Plus précisément, le point d'entrée d'un processeur qui se met en ligne ou qui reprend l'état de suspension est réécrit de sorte que la table des pages de l'étape 2 soit installée sur EL2 avant de revenir à l'hôte sur EL1. Au démarrage, cette protection est appliquée par pKVM.

Cette architecture repose sur le SoC compatible avec la PSCI, de préférence via l'utilisation d'une version à jour de TF-A en tant que micrologiciel EL3.

Le framework du micrologiciel pour Arm (FF-A) standardise les interactions entre le monde normal et le monde sécurisé, en particulier en présence d'un hyperviseur sécurisé. Une partie importante de la spécification définit un mécanisme de partage de mémoire avec le monde sécurisé, à l'aide d'un format de message commun et d'un modèle d'autorisations bien défini pour les pages sous-jacentes. pKVM sert de proxy aux messages FF-A pour garantir que l'hôte ne tente pas de partager de la mémoire avec le côté sécurisé pour lequel il ne dispose pas d'autorisations suffisantes.

Cette architecture repose sur le logiciel sécurisé appliquant le modèle d'accès à la mémoire, pour garantir que les applications de confiance et tout autre logiciel exécuté dans le monde sécurisé ne peuvent accéder à la mémoire que s'il appartient exclusivement au monde sécurisé ou s'il a été explicitement partagé avec lui à l'aide de FF-A. Sur un système avec S-EL2, l'application du modèle d'accès à la mémoire doit être effectuée par un SPMC (Secure Partition Manager Core), tel que Hafnium, qui gère les tables de page de l'étape 2 pour le monde sécurisé. Sur un système sans S-EL2, le TEE peut à la place appliquer un modèle d'accès à la mémoire via ses tables de page de l'étape 1.

Si l'appel SMC à EL2 n'est pas un appel PSCI ou un message défini par FF-A, les SMC non gérés sont transférées à EL3. On part du principe que le micrologiciel sécurisé (nécessairement fiable) peut gérer les SMC non gérées en toute sécurité, car il comprend les précautions nécessaires pour maintenir l'isolation des VM préemptives.

Moniteur de machine virtuelle

crosvm est un moniteur de machine virtuelle (VMM) qui exécute des machines virtuelles via l'interface KVM de Linux. Ce qui rend crosvm unique, c'est l'accent mis sur la sécurité, qui repose sur l'utilisation du langage de programmation Rust et d'un bac à sable autour des appareils virtuels afin de protéger le noyau hôte. Pour en savoir plus sur crosvm, consultez sa documentation officielle.

Descripteurs de fichiers et ioctls

KVM expose l'appareil de caractères /dev/kvm à l'espace utilisateur avec les ioctls qui constituent l'API KVM. Les ioctls appartiennent aux catégories suivantes:

  • Les ioctls du système interrogent et définissent des attributs globaux qui affectent l'ensemble du sous-système KVM, puis créent des pVM.
  • Les ioctls de VM interrogent et définissent des attributs qui créent des processeurs virtuels (vCPU) et des appareils, et affectent une pVM entière, tels que l'organisation de la mémoire et le nombre de processeurs virtuels et d'appareils.
  • Les ioctls de vCPU interrogent et définissent des attributs qui contrôlent le fonctionnement d'un seul processeur virtuel.
  • Les ioctls des appareils interrogent et définissent les attributs qui contrôlent le fonctionnement d'un seul appareil virtuel.

Chaque processus crosvm exécute exactement une instance d'une machine virtuelle. Ce processus utilise l'ioctl du système KVM_CREATE_VM pour créer un descripteur de fichier de VM pouvant être utilisé pour émettre des ioctls pVM. Sur un FD de VM, un ioctl KVM_CREATE_VCPU ou KVM_CREATE_DEVICE crée un vCPU/appareil et renvoie un descripteur de fichier pointant vers la nouvelle ressource. Les ioctls sur un vCPU ou un FD d'appareil peuvent être utilisés pour contrôler l'appareil créé à l'aide de "ioctl" sur un FD de VM. Pour les vCPU, il s'agit de la tâche importante d'exécuter le code invité.

En interne, crosvm enregistre les descripteurs de fichier de la VM auprès du noyau à l'aide de l'interface epoll déclenchée par une périphérie. Le noyau informe ensuite crosvm chaque fois qu'un nouvel événement est en attente dans l'un des descripteurs de fichier.

pKVM ajoute une nouvelle fonctionnalité, KVM_CAP_ARM_PROTECTED_VM, qui permet d'obtenir des informations sur l'environnement des VM préemptives et de configurer le mode protégé pour une VM. crosvm l'utilise lors de la création de VM préemptives si l'indicateur --protected-vm est transmis, pour interroger et réserver la quantité de mémoire appropriée au micrologiciel de VM préemptives, puis pour activer le mode protégé.

Allocation de mémoire

L'une des principales responsabilités d'un VMM est d'allouer la mémoire de la VM et de gérer l'organisation de sa mémoire. crosvm génère une disposition de mémoire fixe, décrite vaguement dans le tableau ci-dessous.

FDT en mode normal PHYS_MEMORY_END - 0x200000
Libérer espace ...
Disque RAM ALIGN_UP(KERNEL_END, 0x1000000)
Noyau 0x80080000
Bootloader (chargeur d'amorçage) 0x80200000
FDT en mode BIOS 0x80000000
Base de mémoire physique 0x80000000
Micrologiciel de VM préemptive 0x7FE00000
Mémoire de l'appareil 0x10000 - 0x40000000

La mémoire physique est allouée avec mmap, et la mémoire est attribuée à la VM pour remplir ses régions de mémoire, appelées emplacements memslots, avec l'ioctl KVM_SET_USER_MEMORY_REGION. Toute la mémoire des pVM invitées est donc attribuée à l'instance crosvm qui la gère et peut entraîner la fermeture du processus (arrêt de la VM) si l'hôte commence à manquer de mémoire disponible. Lorsqu'une VM est arrêtée, la mémoire est automatiquement effacée par l'hyperviseur et renvoyée au noyau hôte.

Sous KVM standard, le VMM conserve l'accès à toute la mémoire de l'invité. Avec pKVM, la mémoire de l'invité est dissociée de l'espace d'adressage physique de l'hôte lorsqu'elle est donnée à l'invité. La seule exception concerne la mémoire explicitement partagée en retour par l'invité, par exemple pour les appareils Virtio.

Les régions MMIO de l'espace d'adressage de l'invité ne sont pas mappées. L'accès à ces régions par l'invité est bloqué et entraîne un événement d'E/S sur le FD de la VM. Ce mécanisme permet d'implémenter des appareils virtuels. En mode protégé, l'invité doit confirmer qu'une région de son espace d'adressage est utilisée pour MMIO à l'aide d'un hyperappel, afin de réduire le risque de fuite accidentelle d'informations.

Planification

Chaque processeur virtuel est représenté par un thread POSIX et planifié par le planificateur Linux hôte. Le thread appelle l'ioctl KVM_RUN sur le processeur virtuel invité, ce qui entraîne le basculement de l'hyperviseur vers le contexte du processeur virtuel invité. Le programmeur hôte prend en compte le temps passé dans un contexte d'invité comme le temps utilisé par le thread de processeur virtuel correspondant. KVM_RUN est renvoyé lorsqu'un événement doit être géré par le VMM, tel que les E/S, la fin d'une interruption ou le processeur virtuel arrêté. Le VMM gère l'événement et appelle à nouveau KVM_RUN.

Pendant KVM_RUN, le thread reste préemptif par le programmeur hôte, à l'exception de l'exécution du code de l'hyperviseur EL2, qui n'est pas préemptive. La VM invitée invitée ne dispose d'aucun mécanisme permettant de contrôler ce comportement.

Étant donné que tous les threads de processeur virtuel sont planifiés comme toute autre tâche d'espace utilisateur, ils sont soumis à tous les mécanismes QoS standards. Plus précisément, chaque thread de processeur virtuel peut être associé à des processeurs physiques, placé dans des cpusets, augmenté ou plafonné à l'aide de la limitation d'utilisation, leur règle de priorité/planification peut être modifiée, etc.

Appareils virtuels

crosvm est compatible avec un certain nombre d'appareils, y compris les suivants:

  • virtio-blk pour les images disque composites, en lecture seule ou en lecture/écriture
  • vhost-vsock pour la communication avec l'hôte
  • virtio-pci comme transport virtio
  • Horloge en temps réel (RTC) pl030
  • 16550a UART pour la communication série

Micrologiciel de VM préemptive

Le micrologiciel pVM (pvmfw) est le premier code exécuté par une pVM, semblable à la ROM de démarrage d'un appareil physique. L'objectif principal de pvmfw est d'amorcer le démarrage sécurisé et d'obtenir son secret unique. pvmfw n'est pas limité à une utilisation signée avec un système d'exploitation spécifique, tel que Microdroid, à condition que l'OS soit correctement compatible.

Le binaire pvmfw est stocké dans une partition Flash du même nom et mis à jour à l'aide d'une OTA.

Démarrage de l'appareil

La séquence d'étapes suivante est ajoutée à la procédure de démarrage d'un appareil compatible avec pKVM:

  1. Le bootloader Android (ABL) charge pvmfw de sa partition dans la mémoire et vérifie l'image.
  2. L'ABL obtient ses secrets du moteur de composition d'identifiants d'appareil (DICE, Device Identifier Composition Engine) (identifiants CCD et chaîne de certificats DICE) auprès d'une racine de confiance.
  3. ABL dérive les IDC nécessaires pour pvmfw et les ajoute au binaire pvmfw.
  4. ABL ajoute un nœud de région de mémoire réservée linux,pkvm-guest-firmware-memory au DT, décrivant l'emplacement et la taille du binaire pvmfw et les secrets qu'il a dérivés à l'étape précédente.
  5. ABL laisse le contrôle à Linux, et Linux initialise pKVM.
  6. pKVM annule le mappage de la région de mémoire pvmfw des tables des pages de l'étape 2 de l'hôte et le protège de l'hôte (et des invités) tout au long du temps d'activité de l'appareil.

Après le démarrage de l'appareil, Microdroid est démarré en suivant les étapes de la section Séquence de démarrage du document Microdroid.

Démarrage des VM préemptives

Lors de la création d'une pVM, crosvm (ou un autre VMM) doit créer un emplacement memslot suffisamment grand pour que l'hyperviseur puisse insérer l'image pvmfw. Le VMM peut également figurer dans la liste des registres dont il peut définir la valeur initiale (x0-x14 pour le vCPU principal, aucune pour les vCPU secondaires). Les registres restants sont réservés et font partie de l'ABI hypervisor-pvmfw.

Lorsque la pVM est exécutée, l'hyperviseur remet d'abord le contrôle du processeur virtuel principal à pvmfw. Le micrologiciel s'attend à ce que crosvm ait chargé un noyau signé AVB, qui peut être un bootloader ou toute autre image, et un FDT non signé en mémoire à des décalages connus. pvmfw valide la signature AVB et, en cas de réussite, génère une arborescence d'appareils de confiance à partir du FDT reçu, efface ses secrets de la mémoire et branches jusqu'au point d'entrée de la charge utile. Si l'une des étapes de validation échoue, le micrologiciel émet un hyperappel PSCI SYSTEM_RESET.

Entre les démarrages, les informations sur l'instance pVM sont stockées dans une partition (appareil virtio-blk) et chiffrées avec le secret pvmfw pour garantir que le secret est provisionné sur la bonne instance après un redémarrage.