https://chacker.pl/
Nawiązanie komunikacji z jednym z oferowanych urządzeń obejmuje dwa kroki. Po pierwsze, wysyłamy listę numerów ramek stron gościa (GPFN) opisujących zakres(y) pamięci, które będziemy udostępniać hostowi. Po drugie, dzielimy ten region na dwa bufory pierścieniowe: jeden do odbioru, a drugi do transmisji. Udostępnianie pamięci między gościem a hostem (lub dokładniej między partycją podrzędną a partycją nadrzędną) odbywa się poprzez utworzenie listy deskryptorów adresów fizycznych gościa (GPADL). Jeśli kiedykolwiek pracowałeś z listami deskryptorów pamięci systemu Windows (MDL),11 zasada jest taka sama: utwórz ciągły bufor z nieciągłej pamięci fizycznej. W przypadku GPADL wysyłamy GPFN (host przetłumaczy je na odpowiednie SPFN). Tworzymy GPADL z sekwencji „zakresów GPA”, a każdy zakres jest kodowany w następujący sposób:

Zakres GPA to struktura o zmiennej wielkości, zaczynająca się od rozmiaru zakresu w bajtach (1), po którym następuje przesunięcie (2) (w bajtach, względem pierwszej strony pamięci). Pozostała część struktury to lista GPFN (3) reprezentująca zakres pamięci. Liczba elementów listy powinna odpowiadać liczbie wymaganych stron, biorąc pod uwagę rozmiar zakresu i przesunięcie początkowe. Ponieważ nasza struktura używa modelu mapowania pamięci 1:1, będziemy po prostu używać fizycznie ciągłych stron. Biorąc pod uwagę adres bazowy i argumenty rozmiaru, funkcja gpa_range (4) zwraca zakres GPA. Aby utworzyć GPADL, wysyłamy żądanie „nagłówka GPADL” (msgtype 8) z listą zakresów GPA. Kodujemy tę wiadomość w następujący sposób:

Po nagłówku wiadomości mamy pole child_relid (1). Podajemy wartość uzyskaną z tego samego pola wiadomości oferty urządzenia, z którym chcemy się komunikować. Pole gpadl (2) jest ustawione na wybraną przez nas wartość; zostanie ona użyta do zidentyfikowania GPADL. Na końcu wiadomości mamy sekwencję zakresów GPA (3). Liczba elementów w tej sekwencji jest ustawiona w rangecount (4), a całkowity rozmiar (w bajtach) tej sekwencji w range_buflen (5). Funkcja gpa_range_size (6) oblicza ten rozmiar, kodując listę zakresów. Gdy bufor, który chcemy utworzyć, jest wystarczająco mały, zmieści się w pojedynczej wiadomości „nagłówek GPADL”; jednak może się zdarzyć, że liczba PFN i/lub zakresów wymaganych do reprezentowania większych buforów nie zmieści się w pojedynczej wiadomości (rozmiar wiadomości używany przez HvCallPostMessage jest ograniczony do 240 bajtów). W takich przypadkach dzielimy zawartość pola „range” na fragmenty, aby dopasować je do tego rozmiaru. Pierwszy fragment jest wysyłany z „GPADL header”, a pozostałe w serii wiadomości „GPADL body” (msgtype 9). Wiadomość „GPADL body” zawiera nagłówek, po którym następuje fragment. Kodowanie nagłówka jest następujące:

Pole msgnumber (1) identyfikuje wysyłany fragment (zwiększamy tę wartość dla każdego wysyłanego fragmentu), a pole gpadl (2) jest ustawione na tę samą wartość, której użyliśmy w wiadomości nagłówka GPADL. Po wysłaniu nagłówka GPADL i (opcjonalnie) jednej lub więcej wiadomości treści GPADL, jesteśmy powiadamiani o utworzeniu GPADL za pomocą odpowiedzi „GPADL created” (msgtype 10). Układ tej wiadomości jest następujący:

Pola child_relid (1) i gpadl (2) zawierają te same wartości, które podaliśmy, a creation_status (3) powinno wynosić zero. Na koniec, aby skonfigurować bufory pierścieniowe, wysyłamy żądanie „open channel” (msgtype 5). Układ tej wiadomości jest następujący:

Jak zwykle, child_relid (1) jest ustawione na tę samą wartość, co pole child_relid oferty. Ustawiamy openid (2) na wartość naszego wyboru i przekazujemy identyfikator naszego nowo utworzonego GPADL do ringbuffer_gpadl (3). W downstream_offset (4) przekazujemy przesunięcie (w stronach), które podzieli ten bufor na dwa bufory pierścieniowe. Ustawimy docelowy procesor wirtualny (5) i user_data (6) na zero. Jeśli żądanie się powiedzie, otrzymamy odpowiedź „open channel result” (msgtype 6):

Pola child_relid (1) i openid (2) zawierają te same wartości, które podaliśmy, a status (3) powinien wynosić zero. W tym momencie możemy komunikować się z urządzeniem za pośrednictwem dwóch buforów pierścieniowych.