diff --git a/course/02-KVM.md b/course/02-KVM.md index 855fd01563ab88aba7e89364b71845e873d80936..6c24187d34ea555118322c2e48be0ae538e0293e 100644 --- a/course/02-KVM.md +++ b/course/02-KVM.md @@ -457,7 +457,7 @@ while (!done) { ## Example of MMIO driver code: write to UART ```{.tiny .c} -// Base UART register +// Base UART register (MMIO) #define UART_BASE 0x10009000 // Data register @@ -491,23 +491,23 @@ The following code reads a sector from the first IDE[^10] disk (on the first bus // A sector has a size of 512 bytes #define SECTOR_SIZE 512 -// IDE status register (on first bus) -#define STATUS_PORT 0x1F7 +// Status register on the primary bus (read-only) +#define STATUS_REG 0x1F7 -// IDE base port (on first bus) -#define DATA_PORT 0x1F0 +// Command register on the primary bus (write-only) +#define CMD_REG 0x1F7 -// IDE control register (on first bus) -#define CONTROL_PORT 0x3F6 +// Base data register on primary bus (write-only) +#define DATA_BASE_REG 0x1F0 -// Assembly function that writes 8-bits data to address port -extern void outb(uint16_t port, uint8_t data) +// Assembly function that writes 8-bits data to address port (PMIO) +void outb(uint16_t port, uint8_t data) -// Assembly function that reads 8-bits from address port -extern uint8_t inb(uint16 port) +// Assembly function that reads 8-bits from address port (PMIO) +uint8_t inb(uint16 port) -// Assembly function that reads 16-bits from address port -extern uint16_t inb(uint16 port) +// Assembly function that reads 16-bits from address port (PMIO) +uint16_t inw(uint16 port) ``` [^10]:\scriptsize IDE is the grandfather of the SATA protocol @@ -519,24 +519,24 @@ extern uint16_t inb(uint16 port) This function reads a sector in LBA[^11] mode: ```{.tiny .c} -// Read sector n into buffer data (512 bytes and already allocated). +// Read sector n into data (allocated by the caller). void read_sector(int n, uint8_t *data) { - while ((inb(STATUS_PORT) & 0xC0) != 0x40); // Wait for drive to be ready + while ((inb(STATUS_REG) & 0xC0) != 0x40); // Wait for drive to be ready // Prepare disk for read or write at specified sector in 28-bit LBA mode - outb(0x1F2, 1); // Set sector count - outb(0x1F3, n & 0xff); // Set bits 00-07 of LBA - outb(0x1F4, (n >> 8) & 0xff); // Set bits 08-15 of LBA - outb(0x1F5, (n >> 16) & 0xff); // Set bits 16-23 of LBA - outb(0x1F6, ((n >> 24) & 0x0f) | 0xe0); // Set bits 24-27 of LBA - // + set LBA mode - outb(STATUS_PORT, 0x20); // Command: read sector with retry + outb(DATA_BASE_REG+2, 1); // Set sector count + outb(DATA_BASE_REG+3, n & 0xff); // Set bits 00-07 of LBA + outb(DATA_BASE_REG+4, (n >> 8) & 0xff); // Set bits 08-15 of LBA + outb(DATA_BASE_REG+5, (n >> 16) & 0xff); // Set bits 16-23 of LBA + outb(DATA_BASE_REG+6, ((n >> 24) & 0x0f) | 0xe0); // Set bits 24-27 of LBA + // + set LBA mode + outb(CMD_REG, 0x20); // Command: read sector with retry - while ((inb(STATUS_PORT) & 0xC0) != 0x40); // Wait for drive to be ready + while ((inb(STATUS_REG) & 0xC0) != 0x40); // Wait for drive to be ready uint16_t *data = (uint16_t *)src; - for (int i = 0; i < SECTOR_SIZE/2; i++) { // Read the sector, - *data = inw(DATA_PORT); // 16-bits at a time + for (int i = 0; i < SECTOR_SIZE/2; i++) { // Read sector content, + *data = inw(DATA_BASE_REG); // 16-bits at a time data++; } } @@ -600,14 +600,18 @@ void read_sector(int n, uint8_t *data) { ::: incremental -- The idea behind paravirtualization is simple: the guest OS sends a service request to the VMM -- Conceptually very similar to a user app requesting a service from the OS +- In a OS, a user app can request a service from the OS - this mechanism is called a **syscall** -- \textcolor{myblue}{In paravirtualization, guest requests a service from the VMM} - - \textcolor{myblue}{this mechanism is called an \textbf{hypercall}} -- Device paravirtualization is simpler and much easier to implement than emulation, hence we describe it first + +\vspace{.2cm} + +- The idea behind paravirtualization is very similar: + - \textcolor{myblue}{the guest OS \textbf{requests a service} from the VMM} + - this mechanism is called an **hypercall** + \vspace{.3cm} -- **\textcolor{mygreen}{How to implement paravirtualization?}** + +- { width=70% } ::: @@ -622,13 +626,6 @@ void read_sector(int n, uint8_t *data) { - guest OS requests to display something - guest OS requests to send a network packet -[//]: # ---------------------------------------------------------------- -## Hypercalls vs system calls - -- Mechanism similar to a system call between an application and an OS:\ - \vspace{1cm} - \centering { width=80% } - [//]: # ---------------------------------------------------------------- ## Benefits of hypercalls @@ -645,10 +642,14 @@ void read_sector(int n, uint8_t *data) { [//]: # ---------------------------------------------------------------- ## Hypercall principle +::: incremental + - How does the guest OS request an hypercall to the VMM? - An hypercall is simply a **specific `VMexit`** triggered by the guest OS, associated to a function **number** - Hypercalls arguments (parameters) are stored in an area of **shared memory** between VMM and guest OS +::: + [//]: # ---------------------------------------------------------------- ## Hypercalls: PMIO or MMIO?