Android zapewnia referencyjną implementację wszystkich komponentów potrzebnych do wdrożenia platformy wirtualizacji Androida. Obecnie ta implementacja jest ograniczona do architektur ARM64. Na tej stronie omawiamy architekturę platformy.
Tło
Architektura Arm zezwala na maksymalnie 4 poziomy wyjątków, przy czym poziom wyjątku 0 (EL0) jest najmniej uprzywilejowany, a poziom wyjątku 3 (EL3) najwyższy. Największa część bazy kodu Androida (wszystkie komponenty przestrzeni użytkownika) działa w EL0. Pozostałym elementem nazywanym potocznie „Androidem” jest jądro Linuksa, które działa w środowisku EL1.
Warstwa EL2 umożliwia wprowadzenie hipernadzorcy, który umożliwia izolowanie pamięci i urządzeń w poszczególnych pVM w EL1/EL0 z dobrymi gwarancjami poufności i integralności.
Hipernadzorca
Chroniona maszyna wirtualna oparta na jądrze (pKVM) jest oparta na hipernadzorcy KVM z systemem Linux, który umożliwia ograniczenie dostępu do ładunków uruchomionych w maszynach wirtualnych gościa, które są oznaczone jako „chronione” w momencie utworzenia.
KVM/arm64 obsługuje różne tryby wykonywania w zależności od dostępności niektórych funkcji procesora, np. rozszerzeń hosta wirtualizacji (VHE) (ARM 8.1 i nowsze). W jednym z tych trybów, nazywanym potocznie trybem innym niż VHE, kod hipernadzorcy jest rozdzielany z obrazu jądra podczas uruchamiania i instalowany w EL2, podczas gdy sam jądro działa w EL1. Chociaż komponent EL2 KVM jest częścią bazy kodu na Linuksie, to niewielki komponent odpowiedzialny za przełączanie się między wieloma EL1. Komponent hipernadzorcy jest skompilowany z Linuksem, ale znajduje się w osobnej, dedykowanej sekcji pamięci obrazu vmlinux
. pKVM wykorzystuje ten projekt, rozszerzając kod hipernadzorcy o nowe funkcje, które pozwalają wprowadzić ograniczenia w jądrze hosta Androida i przestrzeń użytkownika oraz ograniczyć dostęp hosta do pamięci gościa i hipernadzorcy.
Moduły dostawcy pKVM
Moduł dostawcy pKVM to moduł sprzętowy zawierający funkcje specyficzne dla urządzenia, takie jak sterowniki IOMMU do zarządzania pamięcią wejścia-wyjścia. Te moduły umożliwiają przeniesienie do pKVM funkcji zabezpieczeń wymagających dostępu na poziomie wyjątku 2 (EL2).
Aby dowiedzieć się, jak wdrożyć i wczytać moduł dostawcy pKVM, zapoznaj się z sekcją Implementowanie modułu dostawcy pKVM.
Procedura rozruchowa
Poniższy rysunek przedstawia procedurę rozruchu pKVM:
- Program rozruchowy wchodzi do ogólnego jądra w EL2.
- Ogólne jądro wykrywa, że działa w środowisku EL2, i zmienia swoje uprawnienia na EL1, podczas gdy pKVM i jego moduły nadal działają w EL2. Dodatkowo w tym czasie są wczytywane moduły dostawcy pKVM.
- Ogólne jądro uruchamia się normalnie, wczytując wszystkie niezbędne sterowniki urządzeń, aż dotrze do przestrzeni użytkownika. Na tym etapie działa pKVM i obsługuje tabele na stronie etapu 2.
Procedura rozruchowa ufa programowi rozruchowemu do utrzymania integralności obrazu jądra tylko podczas jego wczesnego rozruchu. Gdy jądro zostanie pozbawione uprawnień, przestaje być uważane za zaufane przez hipernadzorcę, który odpowiada za jego ochronę, nawet jeśli jądro zostało przejęte.
Jądro Androida i hipernadzorca w tym samym obrazie binarnym umożliwiają bardzo ściśle powiązany interfejs komunikacyjny. To ścisłe połączenie gwarantuje niepodzielne aktualizacje 2 komponentów, co pozwala uniknąć konieczności utrzymywania stabilności interfejsu między nimi i zapewnia dużą elastyczność bez negatywnego wpływu na długoterminowe działanie. Ścisłe połączenie umożliwia też optymalizację wydajności, gdy oba komponenty mogą ze sobą współpracować bez wpływu na gwarancje bezpieczeństwa zapewniane przez hipernadzorcę.
Ponadto rozpowszechnienie GKI w ekosystemie Androida automatycznie pozwala hipernadzorcy pKVM na urządzenia 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 2 niezależne etapy. Oba te etapy można wykorzystać do wdrożenia tłumaczenia adresów i kontroli dostępu do różnych części pamięci. MMU na etapie 1 jest sterowany przez EL1 i umożliwia pierwszy poziom translacji adresów. System MMU etapu 1 jest używany w Linuksie do zarządzania wirtualną przestrzenią adresową udostępnianą każdemu procesowi przestrzeni użytkownika i do jej własnej wirtualnej przestrzeni adresowej.
Moduł MMU etapu 2 jest sterowany przez EL2 i umożliwia zastosowanie translacji drugiego adresu do adresu wyjściowego jednostki MMU etapu 1, co skutkuje adresem fizycznym (PA). Hipernadzorcy mogą używać translacji na etapie 2 do kontrolowania i przekładania dostępu do pamięci ze wszystkich maszyn wirtualnych w trybie gościa. Jak widać na ilustracji 2, gdy włączone są oba etapy translacji, adres wyjściowy etapu 1 jest nazywany pośrednim adresem fizycznym (IPA). Uwaga: adres wirtualny jest przekształcany na adres IPA, a następnie na adres PA.
Dawniej KVM działa z włączonym translacją na etapie 2 podczas uruchamiania gości i z wyłączonym etapem 2 podczas uruchamiania jądra hosta Linuxa. Ta architektura umożliwia dostęp do pamięci z MMU hosta etapu 1 przez MMU 2 etapu, co pozwala na nieograniczony dostęp z hosta do stron pamięci gościa. Z drugiej strony pKVM włącza ochronę na poziomie 2 nawet w kontekście hosta i oddaje hipernadzorcę za ochronę stron pamięci gości, a nie hosta.
KVM w pełni wykorzystuje tłumaczenie adresów na etapie 2, aby wdrożyć złożone mapowania IPA/PA dla gości, co stwarza wrażenie ciągłej pamięci dla gości pomimo fragmentacji fizycznej. Jednak korzystanie z pamięci MMU etapu 2 w przypadku hosta jest ograniczone tylko do kontroli dostępu. Etap 2 hosta jest mapowany na podstawie tożsamości, dzięki czemu ciągła pamięć w przestrzeni IPA hosta jest przylegająca do przestrzeni PA. Ta architektura umożliwia używanie dużych mapowań w tabeli stron, co zmniejsza presję na bufor porównawczy translacji (TLB). Mapowanie tożsamości może być indeksowane przez PA, dlatego etap 2 hosta służy też do śledzenia własności strony bezpośrednio w tabeli stron.
Zabezpieczenie z bezpośrednim dostępem do pamięci (DMA)
Jak pisaliśmy wcześniej, usunięcie mapowania stron gościa z hosta z Linuksem w tabelach na stronach procesora jest niezbędnym, ale niewystarczającym sposobem na ochronę pamięci gości. pKVM musi też chronić pamięć przed dostępem do pamięci przez urządzenia z obsługą DMA, które znajdują się pod kontrolą jądra hosta, oraz przed możliwym atakiem DMA zainicjowanym przez złośliwego hosta. Aby uniemożliwić takiemu urządzeniu dostęp do pamięci dla gości, pKVM wymaga sprzętu do zarządzania pamięcią wejścia-wyjścia (IOMMU) każdego urządzenia z obsługą DMA w systemie, jak pokazano na rys. 3.
Sprzęt IOMMU przynajmniej zapewnia sposób na przyznanie i odwołanie dostępu do odczytu i zapisu w pamięci fizycznej urządzenia z dokładnością do strony. Jednak to urządzenie IOMMU ogranicza możliwość użycia urządzeń w pVM, ponieważ zakłada etap 2 mapowania tożsamości.
Aby odizolować maszyny wirtualne, IOMMU musi odróżniać transakcje pamięci wygenerowane w imieniu różnych podmiotów. Pozwoli to na użycie odpowiedniego zestawu tabel stron do tłumaczenia.
Ponadto zmniejszenie ilości kodu związanego z układem SOC w elemencie EL2 to kluczowa strategia zmniejszenia ogólnej zaufanej bazy obliczeniowej (TCB) pKVM i przeciwdziałanie uwzględnieniu sterowników IOMMU w hipernadzorcy. Aby rozwiązać ten problem, host EL1 odpowiada za pomocnicze zadania zarządzania IOMMU, takie jak zarządzanie zasilaniem, inicjowanie i, w stosownych przypadkach, obsługa przerywania.
Zapewnienie hosta kontroli nad stanem urządzenia nakłada jednak dodatkowe wymagania dotyczące interfejsu programowania sprzętu IOMMU, tak aby kontrole uprawnień nie mogły zostać pominięte innymi sposobami, na przykład po zresetowaniu urządzenia.
Standardowa i dobrze obsługiwana architektura IOMMU dla urządzeń Arm, która umożliwia zarówno izolację, jak i bezpośrednie przypisanie, to architektura Arm System Memory Management Unit (SMMU). Ta architektura jest zalecanym rozwiązaniem referencyjnym.
Własność pamięci
W momencie uruchomienia zakłada się, że cała pamięć niebędąca hipernadzorcą należy do hosta i jest śledzona przez hipernadzorcę. Po wygenerowaniu maszyny wirtualnej host przekazuje strony pamięci, aby umożliwić jej uruchomienie, a hipernadzorca przenosi ich własność z hosta na maszynę wirtualną. Dlatego hipernadzorca stosuje ograniczenia kontroli dostępu do tabeli na etapie 2 hosta, aby uniemożliwić mu ponowne wejście na strony, zapewniając poufność gościowi.
Komunikacja między gospodarzem a gośćmi jest możliwa dzięki kontrolowanemu udostępnianiu pamięci między nimi. Goście mogą udostępnić gospodarzowi niektóre swoje strony za pomocą hipernadzorcy, który instruuje hipernadzorcę, aby zmapował te strony w tabeli strony 2 etapu hosta. Analogicznie komunikacja hosta z TrustZone jest możliwa dzięki transakcjom udostępniania pamięci lub wypożyczania. Wszystkie te działania są ściśle monitorowane i kontrolowane przez pKVM z wykorzystaniem specyfikacji platformy oprogramowania dla Arm (FF-A).
Wymagania dotyczące pamięci maszyny wirtualnej mogą się z czasem zmieniać, dlatego zapewniane jest hiperwywołanie, które umożliwia przeniesienie własności określonych stron należących do wywołującego z powrotem do hosta. W praktyce to hiperwywołanie jest używane razem z protokołem virtio balloon, aby umożliwić VMM żądanie pamięci z powrotem z pVM, a pVM w sposób kontrolowany powiadamiać VMM o wycofanych stronach.
Hipernadzorca jest odpowiedzialny za śledzenie własności wszystkich stron pamięci w systemie oraz tego, czy są one udostępniane lub wypożyczane innym podmiotom. W większości przypadków śledzenie stanu odbywa się z wykorzystaniem metadanych dołączonych do dwustronicowych tabel gospodarza i gości, wykorzystując zarezerwowane bity we wpisach tabeli stron (PTE), które, jak sama nazwa wskazuje, są zarezerwowane do użytku w oprogramowaniu.
Host musi upewnić się, że nie próbuje uzyskać dostępu do stron, które zostały zablokowane przez hipernadzorcę. Nielegalny dostęp do hosta powoduje wstrzyknięcie do hosta synchronicznego wyjątku, co może doprowadzić do odebrania sygnału SEGV przez odpowiedzialne zadanie przestrzeni użytkownika lub do awarii jądra hosta. Aby zapobiec przypadkowemu dostępowi, strony przekazane gościom nie kwalifikują się do zamiany ani scalania przez jądro hosta.
Przerwij obsługę i liczniki czasu
Przerwy są istotną częścią sposobu interakcji gościa z urządzeniami i komunikacji między procesorami, przy czym głównym mechanizmem komunikacji są zakłócenia działania (IPI). Model KVM służy do delegowania całego wirtualnego zarządzania przerwami do hosta w EL1, który w tym celu działa jako niezaufana część hipernadzorcy.
pKVM oferuje pełną emulację Ogólnego kontrolera przerw w wersji 3 (GICv3) opartej na istniejącym kodzie KVM. Minutnik i IPI są obsługiwane w ramach tego niezaufanego kodu emulacji.
Obsługa GICv3
Interfejs między EL1 i EL2 musi zapewniać, że dla hosta EL1 widoczny jest pełny stan przerwy, w tym kopie rejestrów hipernadzorcy związanych z przerwami. Zwykle jest zapewniana z użyciem współdzielonych regionów pamięci, po jednym na procesor wirtualny (vCPU).
Kod pomocy do rejestru systemu w środowisku wykonawczym można uprościć, aby obsługiwał tylko rejestrowanie przerw w działaniu wygenerowanego przez oprogramowanie (SGIR) i rejestrowanie przerw w działaniu (DIR). Zgodnie z architekturą te rejestry zawsze przechwytują się na EL2, podczas gdy inne pułapki służyły dotychczas jedynie do ograniczania niedokładności. Pozostałe działania są obsługiwane przez sprzęt.
Po stronie MMIO wszystko jest emulowane w EL1, co pozwala wykorzystać całą bieżącą infrastrukturę KVM. Na koniec opcja Oczekiwanie na przerwanie (WFI) jest zawsze przekazywana do EL1, ponieważ jest to jeden z podstawowych podstawowych funkcji planowania używany przez KVM.
Obsługa licznika czasu
Wartość komparatora wirtualnego licznika czasu musi być dostępna dla EL1 w każdym pułapce WFI, tak aby EL1 mógł wstrzykiwać przerwy zegara, gdy procesor wirtualny jest zablokowany. Fizyczny minutnik jest w pełni emulowany, a wszystkie pułapki są przekazywane do EL1.
Obsługa MMIO
W celu komunikowania się z monitorem maszyn wirtualnych (VMM) i wykonywania emulacji GIC pułapki MMIO muszą być przekazywane z powrotem do hosta w EL1 w celu dalszej klasyfikacji. pKVM wymaga:
- IPA i rozmiar dostępu
- Dane w przypadku zapisu
- Endianność procesora w miejscu pułapki
Dodatkowo pułapki z rejestrem ogólnego przeznaczenia (GPR) jako źródło/miejsce docelowe są przekazywane przy użyciu abstrakcyjnego pseudorejestru związanego z transferem.
Interfejsy gościa
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. HiperWywołania są wyświetlane zgodnie ze standardem SMCKC, z zakresem zarezerwowanym dla alokacji dostawcy przez KVM. Poniższe hiperwywołania są szczególnie ważne dla gości pKVM.
Ogólne hiperwywołania
- PSCI udostępnia standardowy mechanizm kontrolowania cyklu życia procesorów wirtualnych przez gości, w tym włączania i wyłączania oraz wyłączania systemu.
- TRNG zapewnia standardowy mechanizm żądania entropii z pKVM, który przekazuje wywołanie do EL3. Ten mechanizm jest szczególnie przydatny, gdy nie można ufać hosta w celu wirtualizacji sprzętowego generatora liczb losowych.
hiperwywołania pKVM
- Udostępnianie pamięci hostowi. Cała pamięć gościa jest początkowo niedostępna dla hosta, ale dostęp do hosta jest niezbędny do komunikacji w pamięci współdzielonej i w przypadku parawirtualizowanych urządzeń, które korzystają ze współdzielonych buforów. HiperWywołania dotyczące udostępniania lub anulowania udostępniania stron z gospodarzem pozwalają gościom decydować, które części pamięci mają być dostępne dla reszty Androida bez potrzeby uzgadniania połączenia.
- Zrzeczenie się pamięci na hoście. Cała pamięć gościa zwykle należy
do gościa, dopóki nie zostanie zniszczona. Ten stan może być niewystarczający w przypadku długotrwałych maszyn wirtualnych z wymaganiami dotyczącymi pamięci, które zmieniają się z czasem. Hiperwywołanie
relinquish
umożliwia gościom jawne przeniesienie własności stron z powrotem na hosta bez konieczności zakończenia działania gościa. - Ograniczenie dostępu do pamięci na hoście. Tradycyjnie, jeśli gość KVM uzyskuje dostęp do adresu, który nie odpowiada prawidłowemu regionowi pamięci, wątek procesora wirtualnego jest wyjściem do hosta, a dostęp jest zwykle używany w przypadku MMIO i emulowany przez VMM w przestrzeni użytkownika. Aby ułatwić obsługę, pKVM musi reklamować szczegółowe informacje o poleceniu związanym z błędami, takie jak adres, rejestrowanie parametrów i potencjalnie ich zawartość z powrotem do hosta. Może to w sposób niezamierzony ujawnić dane wrażliwe chronionego gościa, jeśli pułapka nie była przewidywana. pKVM rozwiązuje ten problem, traktując te błędy jako poważne, chyba że użytkownik wcześniej dozwolony w celu umożliwienia hiperwywołania dostępu do instruktażu. To rozwiązanie jest nazywane zabezpieczeniem MMIO.
Wirtualne urządzenie I/O (virtio)
Virtio to popularny, przenośny i dojrzały standard służący do wdrażania urządzeń parawirtualizowanych i interakcji z nimi. Większość urządzeń udostępnianych chronionym gościom jest zaimplementowanych za pomocą virtio. Virtio opiera się też na implementacji interfejsu API w celu komunikacji między chronionym gościem a resztą Androida.
VMM zwykle wdraża w przestrzeni użytkownika hosta urządzenia Virtio, które przechwytują przechwycone uwięzione dane dostępu do pamięci z gościa do interfejsu MMIO urządzenia virtio i emulują oczekiwane działanie. Dostęp do MMIO jest stosunkowo kosztowny, ponieważ każdy dostęp do urządzenia wymaga przesyłania danych w obie strony do VMM i z powrotem, więc większość rzeczywistego przesyłania danych między urządzeniem a gościem odbywa się z wykorzystaniem zestawu wirtualnych kolejek w pamięci. Głównym założeniem w Virtio jest to, że host może dowolnie uzyskiwać dostęp do pamięci gościa. Założenie to jest wyraźne w projekcie wirtualnej kolejki, która może zawierać wskaźniki do buforów w trybie gościa, do których ma mieć bezpośredni dostęp emulacja urządzenia.
Choć opisane wcześniej hiperwywołania udostępniania pamięci można wykorzystać do udostępniania buforów danych virtio między gośćmi a hostem, udostępnianie to musi odbywać się z dokładnością do strony, przez co może zostać ujawnione więcej danych, niż jest to wymagane, jeśli rozmiar bufora będzie mniejszy niż strona. Zamiast tego konfiguracja gościa jest skonfigurowana tak, aby przydzielać zarówno wirtuały, jak i odpowiadające im bufory danych ze stałego okna współdzielonej pamięci, przy czym dane są kopiowane (odrzucane) do i z okna zgodnie z potrzebami.
Interakcja z TrustZone
Chociaż goście nie mogą wchodzić w bezpośrednią interakcję z TrustZone, gospodarz musi mieć możliwość wywoływania SMC w bezpiecznym świecie. Wywołania te mogą określać fizycznie adresowane bufory pamięci, które są niedostępne dla hosta. Jako że bezpieczne oprogramowanie jest zasadniczo nieświadome dostępności bufora, szkodliwy host może go wykorzystać do przeprowadzenia zdezorientowanego ataku typu „podstępny” (analogicznie do ataku DMA). Aby zapobiec takim atakom, pKVM przechwytuje wszystkie wywołania SMC hosta na EL2 i działa jako serwer proxy między hostem a bezpiecznym monitorem w EL3.
Wywołania PSCI z hosta są przekazywane do oprogramowania EL3 z niewielkimi zmianami. W szczególności punkt wejścia procesora przechodzącego w tryb online lub wznowienie zawieszenia jest przepisany w taki sposób, że tabela strony etapu 2 jest instalowana w EL2, zanim wróci do hosta w EL1. Podczas rozruchu ta ochrona jest egzekwowana przez pKVM.
Ta architektura opiera się na układzie SOC obsługującym PSCI, najlepiej dzięki użyciu aktualnej wersji TF-A jako oprogramowania EL3.
Oprogramowanie układowe Arm (FF-A) standaryzuje interakcje między światem normalnym a bezpiecznym, zwłaszcza w przypadku bezpiecznego hipernadzorcy. W dużej części specyfikacji definiuje się mechanizm udostępniania pamięci bezpiecznemu światu, wykorzystując zarówno popularny format wiadomości, jak i dobrze zdefiniowany model uprawnień dla stron bazowych. pKVM pośredniczy w wiadomościach FF-A, aby host nie próbował udostępniać pamięci bezpiecznej stronie, do której nie ma wystarczających uprawnień.
Ta architektura opiera się na oprogramowaniu zabezpieczeń w bezpiecznym świecie egzekwującym model dostępu do pamięci, aby zapewnić, że zaufane aplikacje i wszelkie inne oprogramowanie działające w bezpiecznym świecie mają dostęp do pamięci tylko wtedy, gdy należy ona wyłącznie do bezpiecznego świata lub została jej jawnie udostępniona za pomocą FF-A. W systemie z S-EL2 model dostępu do pamięci powinien być egzekwowany przez mechanizm SPMC (Secure Partition Manager Core), na przykład Hafnium, który obsługuje tabele z poziomem 2 dla bezpiecznego świata. W systemie bez S-EL2 TEE może zamiast tego wymusić model dostępu do pamięci za pomocą tabel na stronie etapu 1.
Jeśli wywołanie SMC do EL2 nie jest wywołaniem PSCI ani komunikatem zdefiniowanym w FF-A, nieobsłużone konta SMC są przekazywane do EL3. Zakładamy, że bezpieczne oprogramowanie układowe (niezbędnie zaufane) może bezpiecznie obsługiwać nieobsłużone urządzenia SMC, ponieważ rozumie ono środki ostrożności niezbędne do zachowania izolacji urządzeń pVM.
Monitor maszyny wirtualnej
crosvm to monitor maszyn wirtualnych, który uruchamia maszyny wirtualne przez interfejs KVM systemu Linux. Tym, co wyróżnia crosvm, jest bezpieczeństwo dzięki zastosowaniu języka programowania Rust i piaskownicy wokół urządzeń wirtualnych chroniących jądro hosta. Więcej informacji o crosvm znajdziesz w oficjalnej dokumentacji tutaj.
Deskryptory plików i ioctle
KVM udostępnia urządzenie znakowe /dev/kvm
w przestrzeni użytkownika za pomocą elementów ioctl, które składają się na interfejs KVM API. Ioctle należą do następujących kategorii:
- Systemowe odpytywanie i ustawianie atrybutów globalnych w podsystemie KVM oraz tworzenie maszyn wirtualnych.
- Ioctlsy maszyn wirtualnych wysyłają zapytania i ustawiają atrybuty, które tworzą wirtualne procesory wirtualne (vCPU) i urządzenia oraz wpływają na całą maszynę wirtualną, w tym na układ pamięci oraz liczbę procesorów wirtualnych (vCPU) i urządzeń.
- i ustawia atrybuty, które kontrolują działanie pojedynczego procesora wirtualnego.
- Odpytywanie ioctl urządzeń oraz ustawianie atrybutów, które kontrolują działanie pojedynczego urządzenia wirtualnego.
Każdy proces crosvm uruchamia dokładnie 1 instancję maszyny wirtualnej. Ten proces wykorzystuje ioctl systemu KVM_CREATE_VM
do utworzenia deskryptora pliku maszyny wirtualnej, którego można używać do wystawiania ioctl pVM. Ioctl KVM_CREATE_VCPU
lub KVM_CREATE_DEVICE
w FD maszyny wirtualnej tworzy vCPU/urządzenie i zwraca deskryptor pliku wskazujący nowy zasób. Ioctl na vCPU lub FD urządzenia może być używany do sterowania urządzeniem, które zostało utworzone przy użyciu ioctl w FD maszyny wirtualnej. W przypadku procesorów wirtualnych dotyczy to ważnego zadania uruchamiania kodu gościa.
Wewnętrznie crosvm rejestruje deskryptory plików maszyny wirtualnej w jądrze za pomocą interfejsu epoll
wyzwalanego przez krawędzie. Jądro powiadamia następnie crosvm za każdym razem, gdy w dowolnym deskryptorach plików pojawi się nowe zdarzenie.
pKVM dodaje nową funkcję KVM_CAP_ARM_PROTECTED_VM
, która pozwala uzyskać informacje o środowisku pVM i skonfigurować tryb chroniony maszyny wirtualnej. crosvm używa jej podczas tworzenia maszyny wirtualnej, jeśli zostanie przesłana flaga --protected-vm
, do wysyłania zapytań i zarezerwowania odpowiedniej ilości pamięci na potrzeby oprogramowania pVM, a następnie w celu włączenia trybu chronionego.
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 tabeli poniżej.
FDT w trybie normalnym | PHYS_MEMORY_END - 0x200000
|
Zwolnij miejsce | ...
|
Ramdysk | ALIGN_UP(KERNEL_END, 0x1000000)
|
Jądro | 0x80080000
|
Program rozruchowy | 0x80200000
|
FDT w trybie BIOS | 0x80000000
|
Baza pamięci fizycznej | 0x80000000
|
Oprogramowanie pVM | 0x7FE00000
|
Pamięć urządzenia | 0x10000 - 0x40000000
|
Pamięć fizyczna jest przydzielana za pomocą funkcji mmap
, a pamięć jest przekazywana do maszyny wirtualnej, aby zapełniać jej regiony pamięci, nazywane memslotami, wartością IOctl KVM_SET_USER_MEMORY_REGION
. Cała pamięć pVM gościa jest więc przypisywana do instancji crosvm, która nim zarządza, i może doprowadzić do zakończenia procesu (zakończenia działania maszyny wirtualnej), gdy host zacznie wyczerpywać wolną pamięć. Po zatrzymaniu maszyny wirtualnej pamięć jest automatycznie czyszczona przez hipernadzorcę i zwracana do jądra hosta.
W ramach standardowej maszyny wirtualnej VMM zachowuje dostęp do całej pamięci gościa. Dzięki pKVM pamięć gościa jest usuwana z fizycznej przestrzeni adresowej hosta, gdy jest przekazywana gościowi. Jedynym wyjątkiem jest pamięć współdzielona przez gościa, np. w przypadku urządzeń virtio.
Regiony MMIO w przestrzeni adresowej gościa nie są mapowane. Dostęp gościa do tych regionów jest ograniczony i powoduje wystąpienie zdarzenia wejścia-wyjścia w maszynie wirtualnej FD. Ten mechanizm służy do wdrażania urządzeń wirtualnych. W trybie chronionym gość musi potwierdzić za pomocą hiperwywołania, że region jego przestrzeni adresowej jest używany na potrzeby MMIO, co zmniejsza ryzyko przypadkowego wycieku informacji.
Godziny otwarcia
Każdy procesor wirtualny jest reprezentowany przez wątek POSIX i zaplanowany przez algorytm szeregowania hosta z systemem Linux. Wątek wywołuje element początkowy KVM_RUN
w FD procesora wirtualnego, co powoduje przełączenie hipernadzorcy na kontekst vCPU gościa. Algorytm szeregowania hosta zlicza czas spędzony w kontekście gościa jako czas wykorzystany przez odpowiedni wątek procesorów wirtualnych. Funkcja KVM_RUN
jest zwracana, gdy wystąpi zdarzenie, które musi być obsługiwane przez VMM, takie jak I/O, koniec przerwy lub zatrzymany procesor wirtualny. VMM obsługuje zdarzenie i ponownie wywołuje KVM_RUN
.
W czasie KVM_RUN
wątek pozostaje możliwy do wywłaszczania przez algorytm szeregowania hosta, z wyjątkiem wykonania kodu hipernadzorcy EL2, którego nie można wywłaszczać. Sama maszyna wirtualna gościa nie ma mechanizmu kontrolowania tego zachowania.
Ponieważ wszystkie wątki procesorów wirtualnych są planowane, podobnie jak inne zadania w przestrzeni użytkownika, podlegają one wszystkim standardowym mechanizmom QoS. Każdy wątek procesora wirtualnego może być przypięty do procesorów fizycznych, umieszczony w procesorach, wzmacniany lub ograniczany przez ograniczanie wykorzystania wykorzystania, a także mieć zmieniony priorytet/zasady harmonogramu i nie tylko.
Urządzenia wirtualne
crosvm obsługuje wiele urządzeń, w tym:
- virtio-blk w przypadku obrazów dysków kompozytowych, tylko do odczytu lub do odczytu i zapisu
- vhost-vsock do komunikacji z hostem.
- virtio-pci jako transport virtio
- zegar czasu rzeczywistego pl030 (RTC)
- 16550a UART do komunikacji szeregowej
Oprogramowanie pVM
Oprogramowanie pvmfw (pvmfw) to pierwszy kod wykonywany przez pVM, podobnie jak w przypadku rozruchowej pamięci ROM urządzeń fizycznych. Głównym celem pvmfw jest bezpieczne uruchamianie i wyciąganie unikalnego klucza tajnego dla pvmfw. Plik pvmfw nie jest ograniczony do użycia z żadnym konkretnym systemem operacyjnym, takim jak o ile stworzone przez Microvs są podpisane i podpisane.
Plik binarny pvmfw jest przechowywany w partycji Flash o tej samej nazwie i jest aktualizowany przy użyciu OTA.
Uruchamianie urządzenia
Do procedury rozruchu urządzenia obsługującego pKVM jest dodawana ta sekwencja:
- Program rozruchowy Androida (ABL) wczytuje do pamięci plik pvmfw ze swojej partycji i weryfikuje obraz.
- ABL pobiera obiekty tajne DICE (identyfikatory urządzeń złożonych (CDI) i łańcuch certyfikatów DICE) z katalogu Root of Trust.
- Narzędzie ABL pobiera dane CDI wymagane dla pvmfw i dodaje je do pliku binarnego pvmfw.
- Funkcja ABL dodaje do pliku DT węzeł zarezerwowanego regionu pamięci
linux,pkvm-guest-firmware-memory
opisujący lokalizację i rozmiar pliku binarnego pvmfw oraz obiekty tajne utworzone w poprzednim kroku. - Kontrola ABL nad systemem Linux i Linux inicjuje pKVM.
- pKVM usuwa mapowanie regionu pamięci pvmfw z tabel na etapie 2 hosta i chroni go przed hostem (i gośćmi) przez cały czas działania urządzenia.
Po uruchomieniu urządzenia mikrodroid jest uruchamiany zgodnie z instrukcjami w sekcji Sekwencja uruchamiania w dokumencie Microdroid.
Uruchamianie pVM
Podczas tworzenia maszyny wirtualnej crosvm (lub inny VMM) musi utworzyć odpowiednio duży memslot, aby hipernadzorca mógł wypełnić obraz pvmfw. VMM jest też ograniczone na liście rejestrów, których wartość początkową można ustawić (x0–x14 w przypadku podstawowego procesora wirtualnego, brak w przypadku dodatkowych procesorów wirtualnych). Pozostałe rejestry są zarezerwowane i są częścią interfejsu hipervisor-pvmfw ABI.
Po uruchomieniu maszyny wirtualnej hipernadzorca najpierw kontroluje podstawowe procesory wirtualne, a następnie pvmfw. Oprogramowanie crosvm oczekuje, że wczyta ono jądro podpisane przez AVB, które może być programem rozruchowym lub dowolnym innym obrazem, oraz niepodpisanym FDT do pamięci w znanych przesunięciach. pvmfw weryfikuje podpis AVB, a jeśli operacja się uda, generuje drzewo zaufanego urządzenia z odebranego FDT, usuwa jego obiekty tajne z pamięci punktowej do gałęzi. Jeśli jeden z kroków weryfikacji się nie powiedzie, oprogramowanie układowe wyśle hiperwywołanie PSCI SYSTEM_RESET
.
Między rozruchami informacje o instancji pVM są przechowywane na partycji (urządzenie virtio-blk) i zaszyfrowane za pomocą obiektu tajnego pvmfw, aby po ponownym uruchomieniu udostępnić obiekt tajny do właściwej instancji.