Arquitetura AVF

O Android fornece uma implementação de referência de todos os componentes necessários para implementar o Android Virtualization Framework. Atualmente esta implementação está limitada ao ARM64. Esta página explica a arquitetura da estrutura.

Fundo

A arquitetura Arm permite até quatro níveis de exceção, sendo o nível de exceção 0 (EL0) o menos privilegiado e o nível de exceção 3 (EL3) o mais privilegiado. A maior parte da base de código do Android (todos os componentes do espaço do usuário) é executada em EL0. O resto do que é comumente chamado de “Android” é o kernel Linux, que roda em EL1.

A camada EL2 permite a introdução de um hipervisor que permite isolar memória e dispositivos em pVMs individuais em EL1/EL0, com fortes garantias de confidencialidade e integridade.

Hipervisor

A máquina virtual baseada em kernel protegida (pKVM) é construída sobre o hipervisor Linux KVM , que foi estendido com a capacidade de restringir o acesso às cargas em execução em máquinas virtuais convidadas marcadas como 'protegidas' no momento da criação.

KVM/arm64 suporta diferentes modos de execução dependendo da disponibilidade de certos recursos da CPU, nomeadamente, Virtualization Host Extensions (VHE) (ARMv8.1 e posterior). Em um desses modos, comumente conhecido como modo não-VHE, o código do hipervisor é separado da imagem do kernel durante a inicialização e instalado no EL2, enquanto o próprio kernel é executado no EL1. Embora faça parte da base de código do Linux, o componente EL2 do KVM é um pequeno componente responsável pela alternância entre vários EL1s e totalmente controlado pelo kernel do host. O componente hipervisor é compilado com Linux, mas reside em uma seção de memória separada e dedicada da imagem vmlinux . O pKVM aproveita esse design estendendo o código do hipervisor com novos recursos que permitem impor restrições ao kernel do host Android e ao espaço do usuário, além de limitar o acesso do host à memória convidada e ao hipervisor.

Módulos de fornecedor pKVM

Um módulo de fornecedor pKVM é um módulo específico de hardware que contém funcionalidades específicas do dispositivo, como drivers de unidade de gerenciamento de memória de entrada-saída (IOMMU). Esses módulos permitem portar recursos de segurança que exigem acesso de nível de exceção 2 (EL2) ao pKVM.

Para saber como implementar e carregar um módulo de fornecedor pKVM, consulte Implementar um módulo de fornecedor pKVM .

Procedimento de inicialização

A figura a seguir descreve o procedimento de inicialização do pKVM:

Procedimento de inicialização pKVM

Figura 1. Procedimento de inicialização pKVM

  1. O bootloader entra no kernel genérico em EL2.
  2. O kernel genérico detecta que está rodando em EL2 e se priva de EL1 enquanto o pKVM e seus módulos continuam rodando em EL2. Além disso, os módulos do fornecedor pKVM são carregados neste momento.
  3. O kernel genérico inicia normalmente, carregando todos os drivers de dispositivos necessários até atingir o espaço do usuário. Neste ponto, o pKVM está instalado e lida com as tabelas de páginas do estágio 2.

O procedimento de inicialização confia no carregador de inicialização para manter a integridade da imagem do kernel somente durante a inicialização inicial. Quando o kernel é desprivilegiado, ele não é mais considerado confiável pelo hipervisor, que é então responsável por se proteger mesmo se o kernel estiver comprometido.

Ter o kernel do Android e o hipervisor na mesma imagem binária permite uma interface de comunicação fortemente acoplada entre eles. Este forte acoplamento garante atualizações atômicas dos dois componentes, o que evita a necessidade de manter a interface entre eles estável e oferece uma grande flexibilidade sem comprometer a capacidade de manutenção a longo prazo. O forte acoplamento também permite otimizações de desempenho quando ambos os componentes podem cooperar sem impactar as garantias de segurança fornecidas pelo hipervisor.

Além disso, a adoção do GKI no ecossistema Android permite automaticamente que o hipervisor pKVM seja implantado em dispositivos Android no mesmo binário do kernel.

Proteção de acesso à memória da CPU

A arquitetura Arm especifica uma unidade de gerenciamento de memória (MMU) dividida em dois estágios independentes, ambos os quais podem ser usados ​​para implementar tradução de endereços e controle de acesso a diferentes partes da memória. A MMU do estágio 1 é controlada pelo EL1 e permite um primeiro nível de tradução de endereços. O MMU de estágio 1 é usado pelo Linux para gerenciar o espaço de endereço virtual fornecido a cada processo do espaço do usuário e ao seu próprio espaço de endereço virtual.

A MMU do estágio 2 é controlada pelo EL2 e permite a aplicação de uma segunda tradução de endereço no endereço de saída da MMU do estágio 1, resultando em um endereço físico (PA). A tradução do estágio 2 pode ser usada por hipervisores para controlar e traduzir acessos à memória de todas as VMs convidadas. Conforme mostrado na figura 2, quando ambos os estágios de tradução estão habilitados, o endereço de saída do estágio 1 é chamado de endereço físico intermediário (IPA). Nota: O endereço virtual (VA) é traduzido em um IPA e depois em um PA.

Proteção de acesso à memória da CPU

Figura 2. Proteção de acesso à memória da CPU

Historicamente, o KVM é executado com a tradução do estágio 2 habilitada durante a execução de convidados e com o estágio 2 desabilitado durante a execução do kernel Linux host. Essa arquitetura permite que acessos à memória da MMU do estágio 1 do host passem pela MMU do estágio 2, permitindo assim acesso irrestrito do host às páginas de memória do convidado. Por outro lado, o pKVM permite a proteção do estágio 2 mesmo no contexto do host e coloca o hipervisor encarregado de proteger as páginas de memória do convidado em vez do host.

O KVM faz uso total da tradução de endereços no estágio 2 para implementar mapeamentos IPA/PA complexos para convidados, o que cria a ilusão de memória contígua para convidados, apesar da fragmentação física. Entretanto, o uso da MMU de estágio 2 para o host é restrito apenas ao controle de acesso. O estágio 2 do host é mapeado por identidade, garantindo que a memória contígua no espaço IPA do host seja contígua no espaço PA. Essa arquitetura permite o uso de grandes mapeamentos na tabela de páginas e consequentemente reduz a pressão no buffer lookaside de tradução (TLB). Como um mapeamento de identidade pode ser indexado pelo PA, o estágio 2 do host também é usado para rastrear a propriedade da página diretamente na tabela de páginas.

Proteção de acesso direto à memória (DMA)

Conforme descrito anteriormente, o desmapeamento das páginas convidadas do host Linux nas tabelas de páginas da CPU é uma etapa necessária, mas insuficiente para proteger a memória convidada. O pKVM também precisa proteger contra acessos à memória feitos por dispositivos compatíveis com DMA sob o controle do kernel do host e contra a possibilidade de um ataque DMA iniciado por um host malicioso. Para evitar que tal dispositivo acesse a memória convidada, o pKVM requer hardware de unidade de gerenciamento de memória de entrada-saída (IOMMU) para cada dispositivo compatível com DMA no sistema, conforme mostrado na figura 3.

Proteção de acesso à memória DMA

Figura 3. Proteção de acesso à memória DMA

No mínimo, o hardware IOMMU fornece os meios de conceder e revogar o acesso de leitura/gravação de um dispositivo à memória física com granularidade de página. No entanto, este hardware IOMMU limita o uso de dispositivos em pVMs, pois eles assumem um estágio 2 mapeado por identidade.

Para garantir o isolamento entre máquinas virtuais, as transações de memória geradas em nome de diferentes entidades devem ser distinguíveis pelo IOMMU para que o conjunto apropriado de tabelas de páginas possa ser usado para a tradução.

Além disso, reduzir a quantidade de código específico do SoC em EL2 é uma estratégia chave para reduzir a base geral de computação confiável (TCB) do pKVM e contraria a inclusão de drivers IOMMU no hipervisor. Para mitigar esse problema, o host no EL1 é responsável pelas tarefas auxiliares de gerenciamento do IOMMU, como gerenciamento de energia, inicialização e, quando apropriado, tratamento de interrupções.

No entanto, colocar o host no controle do estado do dispositivo impõe requisitos adicionais à interface de programação do hardware IOMMU para garantir que as verificações de permissão não possam ser ignoradas por outros meios, por exemplo, após uma reinicialização do dispositivo.

Um IOMMU padrão e bem suportado para dispositivos Arm que torna possível o isolamento e a atribuição direta é a arquitetura Arm System Memory Management Unit (SMMU). Esta arquitetura é a solução de referência recomendada.

Propriedade de memória

No momento da inicialização, presume-se que toda a memória não-hipervisor pertence ao host e é rastreada como tal pelo hipervisor. Quando um pVM é gerado, o host doa páginas de memória para permitir sua inicialização e o hipervisor transfere a propriedade dessas páginas do host para o pVM. Assim, o hipervisor implementa restrições de controle de acesso na tabela de páginas do estágio 2 do host para evitar que ele acesse as páginas novamente, proporcionando confidencialidade ao convidado.

A comunicação entre o anfitrião e os convidados é possível através do compartilhamento controlado de memória entre eles. Os convidados podem compartilhar algumas de suas páginas com o host usando uma hiperchamada, que instrui o hipervisor a remapear essas páginas na tabela de páginas do estágio 2 do host. Da mesma forma, a comunicação do host com o TrustZone é possível por meio de operações de compartilhamento e/ou empréstimo de memória, todas monitoradas e controladas de perto pelo pKVM usando a especificação Firmware Framework for Arm (FF-A) .

Como os requisitos de memória de um pVM podem mudar com o tempo, é fornecida uma hiperchamada que permite que a propriedade de páginas específicas pertencentes ao chamador seja devolvida ao host. Na prática, esta hiperchamada é usada com o protocolo virtio Balloon para permitir que o VMM solicite memória de volta do pVM e para que o pVM notifique o VMM sobre páginas abandonadas, de maneira controlada.

O hipervisor é responsável por rastrear a propriedade de todas as páginas de memória do sistema e se elas estão sendo compartilhadas ou emprestadas a outras entidades. A maior parte desse rastreamento de estado é feita usando metadados anexados às tabelas de páginas do estágio 2 do host e dos convidados, usando bits reservados nas entradas da tabela de páginas (PTEs) que, como o nome sugere, são reservadas para uso de software.

O host deve garantir que não tentará acessar páginas que tenham sido tornadas inacessíveis pelo hipervisor. Um acesso ilegal ao host faz com que uma exceção síncrona seja injetada no host pelo hipervisor, o que pode resultar na recepção de um sinal SEGV pela tarefa responsável do espaço do usuário ou na falha do kernel do host. Para evitar acessos acidentais, as páginas doadas aos convidados tornam-se inelegíveis para troca ou fusão pelo kernel do host.

Tratamento de interrupções e temporizadores

As interrupções são uma parte essencial da forma como um convidado interage com os dispositivos e para a comunicação entre CPUs, onde as interrupções entre processadores (IPIs) são o principal mecanismo de comunicação. O modelo KVM consiste em delegar todo o gerenciamento de interrupções virtuais ao host no EL1, que para esse fim se comporta como uma parte não confiável do hipervisor.

O pKVM oferece uma emulação completa do Generic Interrupt Controller versão 3 (GICv3) baseada no código KVM existente. O temporizador e os IPIs são tratados como parte deste código de emulação não confiável.

Suporte GICv3

A interface entre EL1 e EL2 deve garantir que o estado completo da interrupção seja visível para o host EL1, incluindo cópias dos registros do hipervisor relacionados às interrupções. Essa visibilidade normalmente é obtida usando regiões de memória compartilhada, uma por CPU virtual (vCPU).

O código de suporte de tempo de execução do registro do sistema pode ser simplificado para suportar apenas o registro de interrupção gerado por software (SGIR) e o registro de interrupção desativado (DIR). A arquitetura exige que esses registros sempre façam armadilhas para EL2, enquanto as outras armadilhas até agora só foram úteis para mitigar erratas. Todo o resto está sendo tratado em hardware.

Do lado do MMIO, tudo é emulado no EL1, reaproveitando toda a infraestrutura atual em KVM. Finalmente, Wait for Interrupt (WFI) é sempre retransmitido para EL1, porque esta é uma das primitivas básicas de agendamento que o KVM usa.

Suporte de temporizador

O valor do comparador para o temporizador virtual deve ser exposto ao EL1 em ​​cada WFI de interceptação para que o EL1 possa injetar interrupções do temporizador enquanto a vCPU estiver bloqueada. O temporizador físico é totalmente emulado e todas as armadilhas retransmitidas para EL1.

Manuseio de MMIO

Para se comunicar com o monitor de máquina virtual (VMM) e executar a emulação do GIC, as interceptações MMIO devem ser retransmitidas de volta ao host no EL1 para triagem adicional. pKVM requer o seguinte:

  • IPA e tamanho do acesso
  • Dados em caso de gravação
  • Endianness da CPU no ponto de captura

Além disso, as armadilhas com um registro de uso geral (GPR) como origem/destino são retransmitidas usando um pseudo-registro de transferência abstrata.

Interfaces de convidados

Um convidado pode se comunicar com um convidado protegido usando uma combinação de hiperchamadas e acesso à memória para regiões presas. As hiperchamadas são expostas de acordo com o padrão SMCCC , com intervalo reservado para alocação de fornecedor por KVM. As hiperchamadas a seguir são de particular importância para convidados pKVM.

Hiperchamadas genéricas

  • A PSCI fornece um mecanismo padrão para o convidado controlar o ciclo de vida de suas vCPUs, incluindo on-line, off-line e desligamento do sistema.
  • TRNG fornece um mecanismo padrão para o convidado solicitar entropia do pKVM que retransmite a chamada para EL3. Esse mecanismo é particularmente útil quando não se pode confiar no host para virtualizar um gerador de números aleatórios (RNG) de hardware.

Hiperchamadas pKVM

  • Compartilhamento de memória com o host. Toda a memória guest é inicialmente inacessível ao host, mas o acesso ao host é necessário para comunicação de memória compartilhada e para dispositivos paravirtualizados que dependem de buffers compartilhados. Hiperchamadas para compartilhar e cancelar o compartilhamento de páginas com o host permitem que o convidado decida exatamente quais partes da memória serão disponibilizadas para o restante do Android sem a necessidade de um aperto de mão.
  • Cedência de memória para o host. Toda a memória do convidado geralmente pertence ao convidado até ser destruída. Este estado pode ser inadequado para VMs de longa duração com requisitos de memória que variam ao longo do tempo. A hiperchamada relinquish permite que um convidado transfira explicitamente a propriedade das páginas de volta para o host sem exigir o encerramento do convidado.
  • Interceptação de acesso à memória para o host. Tradicionalmente, se um convidado KVM acessa um endereço que não corresponde a uma região de memória válida, o thread vCPU sai para o host e o acesso é normalmente usado para MMIO e emulado pelo VMM no espaço do usuário. Para facilitar esse tratamento, o pKVM é obrigado a anunciar detalhes sobre a instrução com falha, como seu endereço, parâmetros de registro e potencialmente seu conteúdo, de volta ao host, o que poderia expor involuntariamente dados confidenciais de um convidado protegido se a armadilha não fosse antecipada. O pKVM resolve esse problema tratando essas falhas como fatais, a menos que o convidado tenha emitido anteriormente uma hiperchamada para identificar o intervalo IPA com falha como aquele para o qual os acessos são permitidos para retornar ao host. Esta solução é conhecida como guarda MMIO .

Dispositivo de E/S virtual (virtio)

Virtio é um padrão popular, portátil e maduro para implementação e interação com dispositivos paravirtualizados. A maioria dos dispositivos expostos a convidados protegidos são implementados usando virtio. Virtio também sustenta a implementação vsock usada para comunicação entre um convidado protegido e o restante do Android.

Os dispositivos Virtio são normalmente implementados no espaço do usuário do host pelo VMM, que intercepta os acessos de memória capturados do convidado para a interface MMIO do dispositivo virtio e emula o comportamento esperado. O acesso MMIO é relativamente caro porque cada acesso ao dispositivo requer uma viagem de ida e volta ao VMM e vice-versa, portanto, a maior parte da transferência real de dados entre o dispositivo e o convidado ocorre usando um conjunto de virtqueues na memória. Uma suposição fundamental do virtio é que o host pode acessar a memória do convidado arbitrariamente. Essa suposição é evidente no design do virtqueue, que pode conter ponteiros para buffers no convidado que a emulação do dispositivo pretende acessar diretamente.

Embora as hiperchamadas de compartilhamento de memória descritas anteriormente possam ser usadas para compartilhar buffers de dados virtio do convidado para o host, esse compartilhamento é necessariamente realizado na granularidade da página e pode acabar expondo mais dados do que o necessário se o tamanho do buffer for menor que o de uma página . Em vez disso, o convidado é configurado para alocar as virtqueues e seus buffers de dados correspondentes de uma janela fixa de memória compartilhada, com os dados sendo copiados (devolvidos) de e para a janela conforme necessário.

Dispositivo virtual

Figura 4. Dispositivo Virtio

Interação com TrustZone

Embora os convidados não possam interagir diretamente com o TrustZone, o host ainda deve ser capaz de emitir chamadas SMC para o mundo seguro. Essas chamadas podem especificar buffers de memória endereçados fisicamente que são inacessíveis ao host. Como o software seguro geralmente não tem conhecimento da acessibilidade do buffer, um host mal-intencionado poderia usar esse buffer para executar um ataque delegado confuso (análogo a um ataque DMA). Para evitar tais ataques, o pKVM captura todas as chamadas SMC do host para EL2 e atua como um proxy entre o host e o monitor seguro em EL3.

As chamadas PSCI do host são encaminhadas para o firmware EL3 com modificações mínimas. Especificamente, o ponto de entrada para uma CPU que fica on-line ou retoma da suspensão é reescrito para que a tabela de páginas do estágio 2 seja instalada em EL2 antes de retornar ao host em EL1. Durante a inicialização, essas proteções são aplicadas pelo pKVM.

Esta arquitetura depende do SoC que suporta PSCI, preferencialmente através do uso de uma versão atualizada do TF-A como seu firmware EL3.

Firmware Framework for Arm (FF-A) padroniza as interações entre os mundos normal e seguro, especialmente na presença de um hipervisor seguro. A maior parte da especificação define um mecanismo para compartilhar memória com o mundo seguro, usando um formato de mensagem comum e um modelo de permissões bem definido para as páginas subjacentes. O pKVM faz proxy de mensagens FF-A para garantir que o host não esteja tentando compartilhar memória com o lado seguro para o qual não tem permissões suficientes.

Esta arquitetura depende do software do mundo seguro que impõe o modelo de acesso à memória, para garantir que aplicativos confiáveis ​​e qualquer outro software em execução no mundo seguro possam acessar a memória apenas se for de propriedade exclusiva do mundo seguro ou tiver sido explicitamente compartilhado com ele usando FF -A. Em um sistema com S-EL2, a aplicação do modelo de acesso à memória deve ser feita por um Secure Partition Manager Core (SPMC), como o Hafnium , que mantém tabelas de páginas do estágio 2 para o mundo seguro. Em um sistema sem S-EL2, o TEE pode, em vez disso, impor um modelo de acesso à memória através de suas tabelas de páginas do estágio 1.

Se a chamada SMC para EL2 não for uma chamada PSCI ou uma mensagem definida por FF-A, os SMCs não tratados serão encaminhados para EL3. A suposição é que o firmware seguro (necessariamente confiável) pode lidar com SMCs não manipulados com segurança porque o firmware compreende as precauções necessárias para manter o isolamento do pVM.

Monitor de máquina virtual

crosvm é um monitor de máquina virtual (VMM) que executa máquinas virtuais por meio da interface KVM do Linux. O que torna o crosvm único é seu foco na segurança com o uso da linguagem de programação Rust e uma sandbox em torno de dispositivos virtuais para proteger o kernel host. Para mais informações sobre o crosvm, consulte sua documentação oficial aqui .

Descritores de arquivos e ioctls

KVM expõe o dispositivo de caractere /dev/kvm ao espaço do usuário com ioctls que compõem a API KVM. Os ioctls pertencem às seguintes categorias:

  • Os ioctls do sistema consultam e definem atributos globais que afetam todo o subsistema KVM e criam pVMs.
  • Os ioctls da VM consultam e definem atributos que criam CPUs virtuais (vCPUs) e dispositivos e afetam um pVM inteiro, como incluir o layout da memória e o número de CPUs virtuais (vCPUs) e dispositivos.
  • Os ioctls da vCPU consultam e definem atributos que controlam a operação de uma única CPU virtual.
  • Os ioctls do dispositivo consultam e definem atributos que controlam a operação de um único dispositivo virtual.

Cada processo crosvm executa exatamente uma instância de uma máquina virtual. Este processo usa o ioctl do sistema KVM_CREATE_VM para criar um descritor de arquivo VM que pode ser usado para emitir ioctls pVM. Um ioctl KVM_CREATE_VCPU ou KVM_CREATE_DEVICE em uma VM FD cria um vCPU/dispositivo e retorna um descritor de arquivo apontando para o novo recurso. ioctls em uma vCPU ou dispositivo FD podem ser usados ​​para controlar o dispositivo que foi criado usando o ioctl em uma VM FD. Para vCPUs, isso inclui a importante tarefa de executar o código convidado.

Internamente, o crosvm registra os descritores de arquivo da VM com o kernel usando a interface epoll acionada por borda. O kernel então notifica o crosvm sempre que há um novo evento pendente em qualquer um dos descritores de arquivo.

O pKVM adiciona um novo recurso, KVM_CAP_ARM_PROTECTED_VM , que pode ser usado para obter informações sobre o ambiente pVM e configurar o modo protegido para uma VM. crosvm usa isso durante a criação do pVM se o sinalizador --protected-vm for passado, para consultar e reservar a quantidade apropriada de memória para o firmware do pVM e, em seguida, para ativar o modo protegido.

Alocação de memória

Uma das principais responsabilidades de um VMM é alocar a memória da VM e gerenciar seu layout de memória. crosvm gera um layout de memória fixo descrito vagamente na tabela abaixo.

FDT em modo normal PHYS_MEMORY_END - 0x200000
Espaço livre ...
Ramdisk ALIGN_UP(KERNEL_END, 0x1000000)
Núcleo 0x80080000
Carregador de inicialização 0x80200000
FDT no modo BIOS 0x80000000
Base de memória física 0x80000000
firmware pVM 0x7FE00000
Memória do dispositivo 0x10000 - 0x40000000

A memória física é alocada com mmap e a memória é doada à VM para preencher suas regiões de memória, chamadas memslots , com o ioctl KVM_SET_USER_MEMORY_REGION . Toda a memória pVM convidada é, portanto, atribuída à instância crosvm que a gerencia e pode resultar na eliminação do processo (encerramento da VM) se o host começar a ficar sem memória livre. Quando uma VM é interrompida, a memória é automaticamente apagada pelo hipervisor e retornada ao kernel do host.

No KVM normal, o VMM mantém acesso a toda a memória convidada. Com o pKVM, a memória do convidado não é mapeada do espaço de endereço físico do host quando é doada ao convidado. A única exceção é a memória compartilhada explicitamente pelo convidado, como para dispositivos virtio.

As regiões MMIO no espaço de endereço do convidado não são mapeadas. O acesso a essas regiões pelo convidado fica preso e resulta em um evento de E/S na VM FD. Este mecanismo é usado para implementar dispositivos virtuais. No modo protegido, o convidado deve reconhecer que uma região de seu espaço de endereço será utilizada para MMIO por meio de uma hiperchamada, para reduzir o risco de vazamento acidental de informações.

Agendamento

Cada CPU virtual é representada por um thread POSIX e agendada pelo agendador host Linux. O encadeamento chama o ioctl KVM_RUN no vCPU FD, resultando na alternância do hipervisor para o contexto de vCPU convidado. O agendador de host considera o tempo gasto em um contexto convidado como o tempo usado pelo thread de vCPU correspondente. KVM_RUN retorna quando há um evento que deve ser tratado pelo VMM, como E/S, fim de interrupção ou interrupção da vCPU. O VMM trata o evento e chama KVM_RUN novamente.

Durante KVM_RUN , o encadeamento permanece preemptivo pelo agendador do host, exceto para execução do código do hipervisor EL2, que não é preemptivo. O próprio pVM convidado não possui mecanismo para controlar esse comportamento.

Como todos os threads de vCPU são agendados como qualquer outra tarefa do espaço do usuário, eles estão sujeitos a todos os mecanismos de QoS padrão. Especificamente, cada thread de vCPU pode ser vinculado a CPUs físicas, colocado em cpusets, aumentado ou limitado usando limitação de utilização, ter sua política de prioridade/agendamento alterada e muito mais.

Dispositivos virtuais

crosvm oferece suporte a vários dispositivos, incluindo os seguintes:

  • virtio-blk para imagens de disco compostas, somente leitura ou leitura-gravação
  • vhost-vsock para comunicação com o host
  • virtio-pci como transporte virtio
  • relógio em tempo real pl030 (RTC)
  • 16550a UART para comunicação serial

firmware pVM

O firmware pVM (pvmfw) é o primeiro código executado por um pVM, semelhante à ROM de inicialização de um dispositivo físico. O objetivo principal do pvmfw é inicializar a inicialização segura e derivar o segredo exclusivo do pVM. O pvmfw não está limitado ao uso com nenhum sistema operacional específico, como Microdroid , desde que o sistema operacional seja suportado pelo crosvm e tenha sido devidamente assinado.

O binário pvmfw é armazenado em uma partição flash de mesmo nome e é atualizado usando OTA .

Inicialização do dispositivo

A seguinte sequência de etapas é adicionada ao procedimento de inicialização de um dispositivo habilitado para pKVM:

  1. O Android Bootloader (ABL) carrega o pvmfw de sua partição na memória e verifica a imagem.
  2. O ABL obtém seus segredos do Device Identifier Composition Engine (DICE) (Compound Device Identifiers (CDIs) e Boot Certificate Chain (BCC)) de uma raiz de confiança.
  3. O ABL realiza medição e derivação DICE dos segredos do pvmfw (CDIs) e os anexa ao binário pvmfw.
  4. O ABL adiciona um nó de região de memória reservada linux,pkvm-guest-firmware-memory ao DT, descrevendo a localização e o tamanho do binário pvmfw e os segredos que ele derivou na etapa anterior.
  5. O ABL transfere o controle para o Linux e o Linux inicializa o pKVM.
  6. O pKVM desmapeia a região de memória pvmfw das tabelas de páginas do estágio 2 do host e a protege do host (e dos convidados) durante todo o tempo de atividade do dispositivo.

Após a inicialização do dispositivo, o Microdroid é inicializado de acordo com as etapas na seção Sequência de inicialização do documento Microdroid .

inicialização pVM

Ao criar um pVM, o crosvm (ou outro VMM) deve criar um memslot suficientemente grande para ser preenchido com a imagem pvmfw pelo hipervisor. O VMM também está restrito na lista de registros cujo valor inicial ele pode definir (x0-x14 para vCPU primária, nenhum para vCPUs secundárias). Os registros restantes são reservados e fazem parte da ABI hypervisor-pvmfw.

Quando o pVM é executado, o hipervisor primeiro transfere o controle da vCPU primária para o pvmfw. O firmware espera que o crosvm carregue um kernel assinado pelo AVB, que pode ser um gerenciador de inicialização ou qualquer outra imagem, e um FDT não assinado na memória em deslocamentos conhecidos. O pvmfw valida a assinatura AVB e, se for bem-sucedido, gera uma árvore de dispositivos confiáveis ​​a partir do FDT recebido, limpa seus segredos da memória e ramifica para o ponto de entrada da carga útil. Se uma das etapas de verificação falhar, o firmware emite uma hiperchamada PSCI SYSTEM_RESET .

Entre as inicializações, as informações sobre a instância pVM são armazenadas em uma partição (dispositivo virtio-blk) e criptografadas com o segredo do pvmfw para garantir que, após uma reinicialização, o segredo seja provisionado para a instância correta.