Architektura AVF

Zadbaj o dobrą organizację dzięki kolekcji Zapisuj i kategoryzuj treści zgodnie ze swoimi preferencjami.

System Android zapewnia implementację referencyjną wszystkich składników potrzebnych do zaimplementowania platformy wirtualizacji systemu Android. Obecnie ta implementacja jest ograniczona do ARM64. Ta strona wyjaśnia architekturę frameworka.

Tło

Architektura Arm dopuszcza do czterech poziomów wyjątków, przy czym poziom wyjątków 0 (EL0) jest najmniej uprzywilejowany, a poziom wyjątków 3 (EL3) najbardziej. Największa część bazy kodu systemu Android (wszystkie składniki przestrzeni użytkownika) działa na poziomie EL0. Reszta tego, co powszechnie nazywa się „Androidem”, to jądro Linuksa, które działa na EL1.

Warstwa EL2 umożliwia wprowadzenie hiperwizora, który umożliwia izolowanie pamięci i urządzeń w poszczególnych pVM w EL1/EL0, z silnymi gwarancjami poufności i integralności.

Nadzorca

Chroniona maszyna wirtualna oparta na jądrze (pKVM) jest zbudowana na hipernadzorcy Linux KVM , który został rozszerzony o możliwość ograniczenia dostępu do ładunków uruchomionych na gościnnych maszynach wirtualnych oznaczonych jako „chronione” w momencie tworzenia.

KVM/arm64 obsługuje różne tryby wykonywania w zależności od dostępności niektórych funkcji procesora, a mianowicie rozszerzenia hosta wirtualizacji (VHE) (ARMv8.1 i nowsze). W jednym z tych trybów, powszechnie znanym jako tryb non-VHE, kod hiperwizora jest rozdzielany z obrazu jądra podczas rozruchu i instalowany w EL2, podczas gdy samo jądro działa w EL1. Chociaż jest częścią bazy kodu Linuksa, komponent EL2 KVM jest małym komponentem odpowiedzialnym za przełączanie między wieloma EL1 i całkowicie kontrolowanym przez jądro hosta. Komponent hiperwizora jest kompilowany w systemie Linux, ale znajduje się w oddzielnej, dedykowanej sekcji pamięci obrazu vmlinux . pKVM wykorzystuje ten projekt, rozszerzając kod hiperwizora o nowe funkcje, które umożliwiają nałożenie ograniczeń na jądro hosta Androida i przestrzeń użytkownika oraz ograniczenie dostępu hosta do pamięci gościa i hiperwizora.

Procedura rozruchu

Procedura rozruchu pKVM jest przedstawiona na rysunku 1. Pierwszym krokiem jest wprowadzenie przez bootloader jądra Linux z obsługą pKVM w EL2. Podczas wczesnego rozruchu jądro wykrywa, że ​​działa na poziomie EL2, pozbawia się EL1, pozostawiając za sobą pKVM. Od tego momentu jądro Linuksa uruchamia się normalnie, ładując wszystkie niezbędne sterowniki urządzeń, aż do osiągnięcia przestrzeni użytkownika. Te kroki mają miejsce pod kontrolą pKVM.

Procedura rozruchu ufa bootloaderowi, że zachowa integralność obrazu jądra tylko podczas wczesnego rozruchu. Gdy jądro jest pozbawione uprawnień, hipernadzorca nie jest już uważany za zaufany, który jest następnie odpowiedzialny za ochronę samego siebie, nawet jeśli jądro jest zagrożone.

Procedura rozruchu pKVM

Rysunek 1. Procedura rozruchu pKVM

Posiadanie jądra Androida i hiperwizora w tym samym obrazie binarnym pozwala na bardzo ściśle powiązany interfejs komunikacyjny między nimi. To ścisłe połączenie gwarantuje atomowe aktualizacje dwóch komponentów, co pozwala uniknąć konieczności utrzymywania stabilnego interfejsu między nimi i oferuje dużą elastyczność bez uszczerbku dla długoterminowej łatwości konserwacji. Ścisłe połączenie umożliwia również optymalizację wydajności, gdy oba komponenty mogą współpracować bez wpływu na gwarancje bezpieczeństwa zapewniane przez hiperwizor.

Co więcej, przyjęcie GKI w ekosystemie Androida automatycznie umożliwia wdrożenie hipernadzorcy pKVM na urządzeniach z Androidem w tym samym pliku binarnym, co jądro.

Ochrona dostępu do pamięci procesora

Architektura Arm określa jednostkę zarządzania pamięcią (MMU) podzieloną na dwa niezależne etapy, z których oba mogą być użyte do implementacji translacji adresów i kontroli dostępu do różnych części pamięci. MMU stopnia 1 jest sterowane przez EL1 i umożliwia pierwszy poziom translacji adresów. MMU stage 1 jest używane przez Linuksa do zarządzania wirtualną przestrzenią adresową udostępnianą każdemu procesowi w przestrzeni użytkownika i jego własnej wirtualnej przestrzeni adresowej.

MMU stopnia 2 jest sterowane przez EL2 i umożliwia zastosowanie drugiej translacji adresu na adres wyjściowy MMU stopnia 1, co daje w wyniku adres fizyczny (PA). Translacja etapu 2 może być używana przez hipernadzorców do kontrolowania i tłumaczenia dostępu do pamięci ze wszystkich maszyn wirtualnych gościa. Jak pokazano na rysunku 2, gdy oba etapy translacji są włączone, adres wyjściowy etapu 1 nazywany jest pośrednim adresem fizycznym (IPA). Uwaga: Adres wirtualny (VA) jest tłumaczony na IPA, a następnie na PA.

Ochrona dostępu do pamięci procesora

Rysunek 2. Ochrona dostępu do pamięci procesora

Historycznie rzecz biorąc, KVM działa z włączoną translacją etapu 2 podczas uruchamiania gości i z wyłączonym etapem 2 podczas uruchamiania jądra systemu Linux hosta. Ta architektura umożliwia dostęp do pamięci z MMU stage 1 hosta, aby przejść przez MMU stage 2, tym samym umożliwiając nieograniczony dostęp z hosta do stron pamięci gościa. Z drugiej strony pKVM umożliwia ochronę na etapie 2 nawet w kontekście hosta i stawia hypervisorowi za ochronę stron pamięci gościa zamiast hosta.

KVM w pełni wykorzystuje translację adresów na etapie 2 do implementacji złożonych mapowań IPA/PA dla gości, co stwarza iluzję ciągłej pamięci dla gości pomimo fizycznej fragmentacji. Jednak użycie MMU stage 2 dla hosta jest ograniczone tylko do kontroli dostępu. Etap 2 hosta jest mapowany na tożsamość, zapewniając, że ciągła pamięć w przestrzeni IPA hosta jest ciągła w przestrzeni PA. Ta architektura pozwala na użycie dużych mapowań w tabeli stron, a tym samym zmniejsza obciążenie bufora tłumaczenia (TLB). Ponieważ mapowanie tożsamości może być indeksowane przez PA, etap hosta 2 jest również używany do śledzenia własności strony bezpośrednio w tabeli stron.

Ochrona bezpośredniego dostępu do pamięci (DMA)

Jak opisano wcześniej, odmapowanie stron gościa z hosta Linuksa w tablicach stron procesora jest niezbędnym, ale niewystarczającym krokiem do ochrony pamięci gościa. pKVM musi również chronić przed dostępem do pamięci dokonywanym przez urządzenia obsługujące DMA pod kontrolą jądra hosta oraz przed możliwością ataku DMA zainicjowanego przez złośliwego hosta. Aby uniemożliwić takiemu urządzeniu dostęp do pamięci gościa, pKVM wymaga sprzętu jednostki zarządzania pamięcią wejścia-wyjścia (IOMMU) dla każdego urządzenia obsługującego DMA w systemie, jak pokazano na rysunku 3.

Ochrona dostępu do pamięci Dma

Rysunek 3. Ochrona dostępu do pamięci DMA

Co najmniej sprzęt IOMMU zapewnia środki przyznawania i odwoływania dostępu do odczytu/zapisu dla urządzenia do pamięci fizycznej z granulacją strony. Jednak ten sprzęt IOMMU ogranicza użycie urządzeń w pVM, ponieważ zakłada etap 2.

Aby zapewnić izolację między maszynami wirtualnymi, transakcje pamięciowe generowane w imieniu różnych jednostek muszą być rozpoznawalne przez IOMMU, aby do tłumaczenia można było użyć odpowiedniego zestawu tabel stron.

Ponadto zmniejszenie ilości kodu specyficznego dla SoC w EL2 jest kluczową strategią zmniejszania ogólnej zaufanej bazy obliczeniowej (TCB) pKVM i jest sprzeczne z włączeniem sterowników IOMMU do hipernadzorcy. Aby złagodzić ten problem, host w EL1 jest odpowiedzialny za pomocnicze zadania zarządzania IOMMU, takie jak zarządzanie energią, inicjalizacja i, w stosownych przypadkach, obsługa przerwań.

Jednak przekazanie hostowi kontroli nad stanem urządzenia nakłada dodatkowe wymagania na interfejs programistyczny sprzętu IOMMU, aby zapewnić, że sprawdzenie uprawnień nie może zostać pominięte w inny sposób, na przykład po zresetowaniu urządzenia.

Standardową i dobrze obsługiwaną IOMMU dla urządzeń Arm, która umożliwia zarówno izolację, jak i bezpośrednie przypisanie, jest architektura Arm System Memory Management Unit (SMMU). Ta architektura jest zalecanym rozwiązaniem referencyjnym.

Własność pamięci

Podczas uruchamiania zakłada się, że cała pamięć nie będąca hiperwizorem należy do hosta i jako taka jest śledzona przez hiperwizora. Po pojawieniu się pVM host przekazuje strony pamięci, aby umożliwić jej rozruch, a hiperwizor przenosi własność tych stron z hosta na pVM. W ten sposób hipernadzorca wprowadza ograniczenia kontroli dostępu w tabeli stron etapu 2 hosta, aby uniemożliwić mu ponowne uzyskanie dostępu do stron, zapewniając poufność gościowi.

Komunikacja między gospodarzem a gośćmi jest możliwa dzięki kontrolowanemu współdzieleniu pamięci między nimi. Goście mogą ponownie udostępnić niektóre swoje strony hostowi za pomocą hiperwywołania, które nakazuje hiperwizorowi ponowne mapowanie tych stron w tabeli stron hosta stage 2. Podobnie komunikacja hosta z TrustZone jest możliwa dzięki operacjom współdzielenia i/lub pożyczania pamięci, z których wszystkie są ściśle monitorowane i kontrolowane przez pKVM przy użyciu specyfikacji Firmware Framework for Arm (FF-A) .

Hiperwizor jest odpowiedzialny za śledzenie własności wszystkich stron pamięci w systemie i czy są one udostępniane lub wypożyczane innym podmiotom. Większość tego śledzenia stanu odbywa się za pomocą metadanych dołączonych do tabel strony 2 hosta i gościa, przy użyciu zarezerwowanych bitów we wpisach tabeli stron (PTE), które, jak sugeruje ich nazwa, są zarezerwowane do użytku oprogramowania.

Host musi upewnić się, że nie próbuje uzyskać dostępu do stron, które stały się niedostępne przez hipernadzorcę. Nielegalny dostęp do hosta powoduje wstrzyknięcie synchronicznego wyjątku do hosta przez hipernadzorcę, co może spowodować odebranie sygnału SEGV przez odpowiedzialne zadanie w przestrzeni użytkownika lub awarię jądra hosta. Aby zapobiec przypadkowym dostępom, strony przekazane gościom nie kwalifikują się do zamiany lub scalania przez jądro hosta.

Obsługa przerwań i timery

Przerwania są istotną częścią interakcji gościa z urządzeniami i komunikacji między procesorami, gdzie przerwania międzyprocesorowe (IPI) są głównym mechanizmem komunikacji. Model KVM polega na delegowaniu całego zarządzania przerwaniami wirtualnymi do hosta w EL1, który w tym celu zachowuje się jak niezaufana część hiperwizora.

pKVM oferuje pełną emulację Generic Interrupt Controller w wersji 3 (GICv3) opartą na istniejącym kodzie KVM. Timer i IPI są obsługiwane jako część tego niezaufanego kodu emulacji.

Obsługa GICv3

Interfejs między EL1 i EL2 musi zapewniać, że pełny stan przerwania jest widoczny dla hosta EL1, w tym kopie rejestrów hiperwizora związanych z przerwaniami. Ta widoczność jest zwykle osiągana przy użyciu regionów pamięci współużytkowanej, po jednym na procesor wirtualny (vCPU).

Kod obsługi środowiska wykonawczego rejestru systemowego można uprościć, aby obsługiwał tylko zalewkowanie rejestrów przerwań generowanych przez oprogramowanie (SGIR) i dezaktywacji rejestrów przerwań (DIR). Architektura nakazuje, aby te rejestry zawsze łapały w pułapkę EL2, podczas gdy inne pułapki do tej pory były przydatne tylko do złagodzenia erraty. Cała reszta jest obsługiwana sprzętowo.

Po stronie MMIO wszystko jest emulowane w EL1, ponownie wykorzystując całą obecną infrastrukturę w KVM. Wreszcie, Wait for Interrupt (WFI) jest zawsze przekazywany do EL1, ponieważ jest to jeden z podstawowych prymitywów planowania używanych przez KVM.

Obsługa timera

Wartość komparatora dla zegara wirtualnego musi być wystawiona na EL1 na każdym wychwytującym WFI, aby EL1 mógł wstrzykiwać przerwania zegara, gdy vCPU jest zablokowany. Zegar fizyczny jest całkowicie emulowany, a wszystkie pułapki przekazywane do EL1.

Obsługa MMIO

Aby komunikować się z monitorem maszyny wirtualnej (VMM) i wykonywać emulację GIC, pułapki MMIO muszą być przekazywane z powrotem do hosta w EL1 w celu dalszego triagingu. pKVM wymaga:

  • IPA i wielkość dostępu
  • Dane w przypadku zapisu
  • Endianowość procesora w punkcie pułapki

Dodatkowo pułapki z rejestrem ogólnego przeznaczenia (GPR) jako źródłem/celem są przekazywane za pomocą pseudorejestru transferu abstrakcyjnego.

Interfejsy gości

Gość może komunikować się z chronionym gościem za pomocą kombinacji hiperwywołań i dostępu do pamięci do uwięzionych regionów. Hipercalls są udostępniane zgodnie ze standardem SMCCC , z zakresem zarezerwowanym dla alokacji dostawcy przez KVM. Poniższe hiperwezwania mają szczególne znaczenie dla gości pKVM.

Ogólne hiperwezwania

  • PSCI zapewnia standardowy mechanizm dla gościa do kontrolowania cyklu życia swoich procesorów wirtualnych, w tym podłączania, wyłączania i zamykania systemu.
  • TRNG zapewnia standardowy mechanizm żądania entropii przez gościa od pKVM, który przekazuje wywołanie do EL3. Ten mechanizm jest szczególnie przydatny, gdy nie można zaufać hostowi w wirtualizacji sprzętowego generatora liczb losowych (RNG).

Hiperwywołania pKVM

  • Współdzielenie pamięci z gospodarzem. Cała pamięć gościa jest początkowo niedostępna dla hosta, ale dostęp hosta jest niezbędny do komunikacji z pamięcią współużytkowaną i dla urządzeń parawirtualizowanych, które opierają się na współdzielonych buforach. Hiperwywołania umożliwiające udostępnianie i cofanie udostępniania stron hostowi umożliwiają gościowi dokładne decydowanie, które części pamięci są udostępniane reszcie systemu Android bez konieczności uścisku dłoni.
  • Pułapkowanie dostępu do pamięci do hosta. Tradycyjnie, jeśli gość KVM uzyskuje dostęp do adresu, który nie odpowiada prawidłowemu regionowi pamięci, wątek vCPU wychodzi do hosta, a dostęp jest zwykle używany dla MMIO i emulowany przez VMM w przestrzeni użytkownika. Aby ułatwić tę obsługę, pKVM musi ogłosić szczegółowe informacje o instrukcji powodującej błąd, takie jak jej adres, parametry rejestrowania i potencjalnie ich zawartość, z powrotem do hosta, co może przypadkowo ujawnić poufne dane chronionego gościa, jeśli pułapka nie była przewidziana. pKVM rozwiązuje ten problem, traktując te błędy jako krytyczne, chyba że gość wcześniej wykonał hiperwezwanie w celu zidentyfikowania wadliwego zakresu IPA jako takiego, dla którego dozwolone są dostępy z powrotem do hosta. To rozwiązanie określane jest mianem osłony MMIO .

Wirtualne urządzenie we/wy (virtio)

Virtio to popularny, przenośny i dojrzały standard wdrażania i interakcji z urządzeniami parawirtualizowanymi. Większość urządzeń narażonych na chronionych gości realizowana jest za pomocą virtio. Virtio stanowi również podstawę implementacji vsock używanej do komunikacji między chronionym gościem a resztą Androida.

Urządzenia Virtio są zazwyczaj implementowane w przestrzeni użytkownika hosta przez VMM, który przechwytuje uwięzione dostępy pamięci od gościa do interfejsu MMIO urządzenia virtio i emuluje oczekiwane zachowanie. Dostęp MMIO jest stosunkowo drogi, ponieważ każdy dostęp do urządzenia wymaga podróży w obie strony do VMM iz powrotem, więc większość rzeczywistego transferu danych między urządzeniem a gościem odbywa się przy użyciu zestawu wirtualnych kolejek w pamięci. Kluczowym założeniem virtio jest to, że host może uzyskać arbitralny dostęp do pamięci gościa. To założenie jest widoczne w projekcie virtqueue, która może zawierać wskaźniki do buforów w gościu, do których emulacja urządzenia ma mieć bezpośredni dostęp.

Chociaż wcześniej opisane hiperwywołania dotyczące udostępniania pamięci mogą być używane do udostępniania buforów danych virtio od gościa do hosta, to udostępnianie jest z konieczności wykonywane na poziomie szczegółowości strony i może doprowadzić do ujawnienia większej ilości danych niż jest to wymagane, jeśli rozmiar bufora jest mniejszy niż rozmiar strony . Zamiast tego, gość jest skonfigurowany do przydzielania zarówno wirtualnych kolejek, jak i odpowiadających im buforów danych ze stałego okna pamięci współdzielonej, przy czym dane są kopiowane (odbijane) do iz okna zgodnie z wymaganiami.

Urządzenie wirtualne

Rysunek 4. Urządzenie Virtio

Interakcja z TrustZone

Chociaż goście nie mogą wchodzić w bezpośrednią interakcję z TrustZone, gospodarz nadal musi mieć możliwość wykonywania połączeń SMC do bezpiecznego świata. Te wywołania mogą określać fizycznie adresowane bufory pamięci, które są niedostępne dla hosta. Ponieważ bezpieczne oprogramowanie jest generalnie nieświadome dostępności bufora, złośliwy host może użyć tego bufora do wykonania ataku zdezorientowanego zastępcy (analogicznie do ataku DMA). Aby zapobiec takim atakom, pKVM przechwytuje wszystkie wywołania SMC hosta do EL2 i działa jako proxy między hostem a bezpiecznym monitorem w EL3.

Wywołania PSCI z hosta są przekazywane do oprogramowania układowego EL3 z minimalnymi modyfikacjami. W szczególności punkt wejścia dla procesora przechodzącego w tryb online lub wznawiającego działanie z trybu wstrzymania jest przepisany tak, że tablica stron etapu 2 jest instalowana w EL2 przed powrotem do hosta w EL1. Podczas rozruchu te zabezpieczenia wymuszone przez pKVM.

Ta architektura opiera się na SoC obsługującym PSCI, najlepiej poprzez użycie aktualnej wersji TF-A jako oprogramowania układowego EL3.

Firmware Framework for Arm (FF-A) standaryzuje interakcje między światem normalnym i bezpiecznym, szczególnie w obecności bezpiecznego hiperwizora. Większa część specyfikacji definiuje mechanizm współdzielenia pamięci z bezpiecznym światem, przy użyciu zarówno wspólnego formatu wiadomości, jak i dobrze zdefiniowanego modelu uprawnień dla stron bazowych. pKVM proxy przekazuje komunikaty FF-A, aby upewnić się, że host nie próbuje współdzielić pamięci ze stroną bezpieczną, do której nie ma wystarczających uprawnień.

Ta architektura opiera się na bezpiecznym oprogramowaniu światowym wymuszającym model dostępu do pamięci, aby zapewnić, że zaufane aplikacje i inne oprogramowanie działające w bezpiecznym świecie mogą uzyskać dostęp do pamięci tylko wtedy, gdy jest ona wyłączną własnością bezpiecznego świata lub została jawnie mu udostępniona przy użyciu FF -A. W systemie z S-EL2 wymuszanie modelu dostępu do pamięci powinno być wykonywane przez Secure Partition Manager Core (SPMC), taki jak Hafnium , który utrzymuje tabele stron Stage 2 dla bezpiecznego świata. W systemie bez S-EL2 TEE może zamiast tego wymusić model dostępu do pamięci poprzez tabele stron etapu 1.

Jeśli połączenie SMC do EL2 nie jest połączeniem PSCI lub zdefiniowanym komunikatem FF-A, nieobsłużone SMC są przekazywane do EL3. Zakłada się, że (koniecznie zaufane) bezpieczne oprogramowanie układowe może bezpiecznie obsługiwać nieobsługiwane SMC, ponieważ oprogramowanie układowe rozumie środki ostrożności potrzebne do utrzymania izolacji pVM.

Monitor maszyny wirtualnej

crosvm to monitor maszyny wirtualnej (VMM), który uruchamia maszyny wirtualne za pośrednictwem interfejsu KVM systemu Linux. To, co wyróżnia crosvm, to skupienie się na bezpieczeństwie przy użyciu języka programowania Rust i piaskownicy wokół urządzeń wirtualnych w celu ochrony jądra hosta.

Deskryptory plików i ioctls

KVM udostępnia urządzenie znakowe /dev/kvm w przestrzeni użytkownika za pomocą ioctls, które tworzą API KVM. Ioctl należą do następujących kategorii:

  • Systemowe ioctl wysyłają zapytania i ustawiają atrybuty globalne, które wpływają na cały podsystem KVM, i tworzą pVM.
  • Ioctls maszyny wirtualnej wysyłają zapytania i ustawiają atrybuty, które tworzą wirtualne procesory (vCPU) i urządzenia oraz wpływają na całą pVM, na przykład układ pamięci i liczbę wirtualnych procesorów (vCPU) i urządzeń.
  • Procesory ioctls vCPU wysyłają zapytania i ustawiają atrybuty sterujące działaniem pojedynczego procesora wirtualnego.
  • Ioctls urządzeń wysyłają zapytania i ustawiają atrybuty sterujące działaniem pojedynczego urządzenia wirtualnego.

Każdy proces crosvm uruchamia dokładnie jedną instancję maszyny wirtualnej. Ten proces używa ioctl systemu KVM_CREATE_VM do utworzenia deskryptora pliku VM, który może być użyty do wydawania ioctl pVM. KVM_CREATE_VCPU lub KVM_CREATE_DEVICE na VM FD tworzy vCPU/urządzenie i zwraca deskryptor pliku wskazujący na nowy zasób. ioctls na vCPU lub urządzeniu FD może być używany do sterowania urządzeniem, które zostało utworzone za pomocą ioctl na VM FD. W przypadku procesorów wirtualnych obejmuje to ważne zadanie uruchamiania kodu gościa.

Wewnętrznie crosvm rejestruje deskryptory plików maszyny wirtualnej w jądrze za pomocą interfejsu epoll wyzwalanego przez krawędź. Jądro następnie powiadamia crosvm o każdym oczekującym nowym zdarzeniu w którymkolwiek z deskryptorów plików.

pKVM dodaje nową funkcję, KVM_CAP_ARM_PROTECTED_VM , której można używać do uzyskiwania informacji o środowisku pVM i konfigurowania trybu chronionego dla maszyny wirtualnej. crosvm używa tego podczas tworzenia pVM, jeśli zostanie przekazana flaga --protected-vm , aby zapytać i zarezerwować odpowiednią ilość pamięci dla oprogramowania układowego pVM, a następnie włączyć tryb chroniony.

Przydział pamięci

Jednym z głównych zadań VMM jest przydzielanie pamięci maszyny wirtualnej i zarządzanie jej układem pamięci. crosvm generuje stały układ pamięci, luźno opisany w poniższej tabeli.

FDT w trybie normalnym PHYS_MEMORY_END - 0x200000
Wolna przestrzeń ...
Ramdysk ALIGN_UP(KERNEL_END, 0x1000000)
Jądro 0x80080000
Program rozruchowy 0x80200000
FDT w trybie BIOS 0x80000000
Baza pamięci fizycznej 0x80000000
Oprogramowanie układowe pVM 0x7FE00000
Pamięć urządzenia 0x10000 - 0x40000000

Pamięć fizyczna jest przydzielana za pomocą mmap , a pamięć jest przekazywana do maszyny wirtualnej w celu wypełnienia jej regionów pamięci, zwanych memslots , za pomocą ioctl KVM_SET_USER_MEMORY_REGION . Cała pamięć pVM gościa jest zatem przypisywana do instancji crosvm, która nią zarządza, i może spowodować zabicie procesu (zakończenie maszyny wirtualnej), jeśli hostowi zacznie brakować wolnej pamięci. Po zatrzymaniu maszyny wirtualnej pamięć jest automatycznie czyszczona przez hiperwizor i zwracana do jądra hosta.

W zwykłym KVM VMM zachowuje dostęp do całej pamięci gościa. Dzięki pKVM pamięć gościa nie jest mapowana z fizycznej przestrzeni adresowej hosta, gdy jest przekazywana gościowi. Jedynym wyjątkiem jest pamięć jawnie współdzielona przez gościa, na przykład w przypadku urządzeń virtio.

Regiony MMIO w przestrzeni adresowej gościa pozostają niezamapowane. Dostęp do tych regionów przez gościa jest blokowany i skutkuje zdarzeniem we/wy na VM FD. Ten mechanizm służy do implementacji urządzeń wirtualnych. W trybie chronionym gość musi potwierdzić, że region jego przestrzeni adresowej jest używany do MMIO przy użyciu hiperwezwania, aby zmniejszyć ryzyko przypadkowego wycieku informacji.

Planowanie

Każdy wirtualny procesor jest reprezentowany przez wątek POSIX i planowany przez program planujący Linux hosta. Wątek wywołuje ioctl KVM_RUN na vCPU FD, co powoduje przełączenie hipernadzorcy do kontekstu gościnnego vCPU. Harmonogram hosta uwzględnia czas spędzony w kontekście gościa jako czas używany przez odpowiedni wątek vCPU. KVM_RUN zwraca, gdy występuje zdarzenie, które musi być obsłużone przez VMM, takie jak I/O, koniec przerwania lub zatrzymanie vCPU. VMM obsługuje zdarzenie i ponownie wywołuje KVM_RUN .

Podczas KVM_RUN wątek pozostaje wywłaszczalny przez program planujący hosta, z wyjątkiem wykonania kodu hiperwizora EL2, który nie jest wywłaszczalny. Sama pVM gościa nie ma mechanizmu kontrolowania tego zachowania.

Ponieważ wszystkie wątki vCPU są zaplanowane tak jak inne zadania w przestrzeni użytkownika, podlegają wszystkim standardowym mechanizmom QoS. W szczególności każdy wątek vCPU może być powiązany z fizycznymi procesorami, umieszczany w zestawach procesorów, zwiększany lub ograniczany za pomocą ograniczenia wykorzystania, może mieć zmienioną politykę priorytetów/harmonogramu i nie tylko.

Urządzenia wirtualne

crosvm obsługuje wiele urządzeń, w tym:

  • virtio-blk dla złożonych obrazów dysków, tylko do odczytu lub do odczytu i zapisu
  • vhost-vsock do komunikacji z hostem
  • virtio-pci jako transport virtio
  • pl030 zegar czasu rzeczywistego (RTC)
  • 16550a UART do komunikacji szeregowej

Oprogramowanie układowe pVM

Oprogramowanie układowe pVM (pvmfw) to pierwszy kod wykonywany przez pVM, podobny do rozruchowej pamięci ROM urządzenia fizycznego. Głównym celem pvmfw jest załadowanie bezpiecznego rozruchu i pozyskanie unikalnego sekretu pVM. pvmfw nie jest ograniczony do użycia z żadnym konkretnym systemem operacyjnym, takim jak Microdroid , o ile system operacyjny jest obsługiwany przez crosvm i został prawidłowo podpisany.

Plik binarny pvmfw jest przechowywany na partycji flash o tej samej nazwie i jest aktualizowany za pomocą OTA .

Rozruch urządzenia

Do procedury rozruchu urządzenia obsługującego pKVM dodano następującą sekwencję kroków:

  1. Android Bootloader (ABL) ładuje pvmfw ze swojej partycji do pamięci i weryfikuje obraz.
  2. ABL uzyskuje swoje sekrety Device Identifier Composition Engine (DICE) (złożone identyfikatory urządzeń (CDI) i Boot Certificate Chain (BCC)) z głównego źródła zaufania.
  3. ABL wykonuje pomiary i wyprowadza DICE sekretów pvmfw (CDI) i dołącza je do pliku binarnego pvmfw.
  4. ABL dodaje węzeł obszaru pamięci zarezerwowanej dla linux,pkvm-guest-firmware-memory do DT, opisując lokalizację i rozmiar pliku binarnego pvmfw oraz sekrety, które zostały uzyskane w poprzednim kroku.
  5. ABL przekazuje kontrolę do systemu Linux, a Linux inicjuje pKVM.
  6. pKVM usuwa z mapy region pamięci pvmfw z tabel stron hosta Stage 2 i chroni go przed hostem (i gośćmi) przez cały czas pracy urządzenia.

Po uruchomieniu urządzenia Microdroid jest uruchamiany zgodnie z krokami w sekcji Sekwencja rozruchowa dokumentu Microdroid .

Uruchamianie pVM

Podczas tworzenia pVM, crosvm (lub inny VMM) musi utworzyć wystarczająco duży memslot, aby mógł zostać wypełniony obrazem pvmfw przez hiperwizor. VMM jest również ograniczony na liście rejestrów, których wartość początkową może ustawić (x0-x14 dla podstawowego vCPU, brak dla drugorzędnych vCPU). Pozostałe rejestry są zarezerwowane i stanowią część ABI hypervisor-pvmfw.

Po uruchomieniu pVM hiperwizor najpierw przekazuje kontrolę nad głównym procesorem wirtualnym pvmfw. Oprogramowanie układowe oczekuje, że crosvm załaduje jądro z podpisem AVB, które może być programem ładującym lub innym obrazem, oraz niepodpisanym FDT do pamięci ze znanymi przesunięciami. pvmfw sprawdza sygnaturę AVB i, jeśli się powiedzie, generuje drzewo zaufanych urządzeń z otrzymanego FDT, usuwa jego sekrety z pamięci i rozgałęzia się do punktu wejścia ładunku. Jeśli jeden z kroków weryfikacji nie powiedzie się, oprogramowanie układowe generuje hiperwezwanie SYSTEM_RESET SYSTEM_RESET.

Pomiędzy rozruchami informacje o instancji pVM są przechowywane na partycji (urządzenie virtio-blk) i szyfrowane za pomocą klucza tajnego pvmfw, aby zapewnić, że po ponownym uruchomieniu klucz tajny jest dostarczany do właściwej instancji.