diff --git a/course/02-KVM.md b/course/02-KVM.md
index ca9d8d6866b60b038e463238c0ddc7c4daffaa85..855fd01563ab88aba7e89364b71845e873d80936 100644
--- a/course/02-KVM.md
+++ b/course/02-KVM.md
@@ -389,16 +389,23 @@ while (!done) {
 [//]: # ----------------------------------------------------------------
 ## Memory-Mapped I/O devices (MMIO)
 
+\small
+
 - Device registers are **mapped** into the CPU **physical address space**
 - **RAM and devices registers share the same address space!**
 - Called **MMIO**: Memory-Mapped Input/Output
 - Read/write from/to these devices happen exactly like memory (RAM)
 - All CPU instructions dealing with memory operands can interact with these devices
-  - e.g. `mov` instruction (x86)
+  - \footnotesize e.g. `mov` instruction (x86)
     ```{.verysmall .assembler}
-    mov al,[42]  ; reads 8-bits at MMIO address 42
+    mov al,[42]  ; reads 32-bits at MMIO address 42
                  ; and stores it into al register
     ```
+    ```{.verysmall .assembler}
+    mov ebx,42        ; store 42 into ebx register
+    mov byte[ebx],17  ; writes 8-bits value 17
+                      ; to MMIO address 42
+    ```
 
 [//]: # ----------------------------------------------------------------
 ## Port-Mapped I/O devices (PMIO)
@@ -583,22 +590,24 @@ void read_sector(int n, uint8_t *data) {
 
 \definecolor{palechestnut}{rgb}{0.87, 0.68, 0.69}
 \setlength{\fboxsep}{6pt}
-\fcolorbox{black}{palechestnut!50}{\parbox{10cm}{How to use these VMexits, to either \textbf{paravirtualize} or \textbf{emulate} a device?}}              
+\fcolorbox{black}{palechestnut!50}{\parbox{10cm}{How to use these VMexits, to either \textbf{paravirtualize} or \textbf{emulate} a device?}}
 
 [//]: # ----------------------------------------------------------------
-# Device paravirtualisation
+# Device paravirtualization
 
 [//]: # ----------------------------------------------------------------
-## From device emulation to device paravirtualization
+## Paravirtualization
 
-::: incremental :::
+::: incremental
 
-- Device emulation can be complex and difficult to implement
-- Device drivers that trigger many `VMexits` have poor performance
-  - each `VMexit` triggers a context switch
-  - many context switches lead to poor performance
-- Paravirtualized devices designed to be simple and efficient with few `VMexits`
-- How?
+- 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
+  - 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{.3cm}
+- **\textcolor{mygreen}{How to implement paravirtualization?}**
 
 :::
 
@@ -607,11 +616,11 @@ void read_sector(int n, uint8_t *data) {
 
 - Mechanism for the guest OS to request the help of the VMM
 - The VMM exposes an "API" of what functions are available to the guest OS
-  - typically used to access devices
-- Examples of hypercalls:
-  - guest OS wants to read a disk sector
-  - guest OS wants to display something
-  - guest OS wants to send a network packet
+  - typically used to access and control devices
+- Hypercall examples:
+  - guest OS requests to read a disk sector
+  - guest OS requests to display something
+  - guest OS requests to send a network packet
 
 [//]: # ----------------------------------------------------------------
 ## Hypercalls vs system calls
@@ -680,22 +689,45 @@ void read_sector(int n, uint8_t *data) {
 [//]: # ----------------------------------------------------------------
 ## Hypercalls: parameters
 
-```{.verysmall}
-typedef struct {
-    uint8_t x;
-    int32_t val;
-    uint64_t msg;   // a pointer
-} __attribute__((packed)) params_t;
-```
+\small
+
+- **\textcolor{mygreen}{Idea}**: hypercall parameters are serialized/deserialized into a structure, e.g.
+  ```{.verysmall .c}
+  typedef struct {
+      uint8_t val;
+      uint64_t ptr;   // a pointer
+  } __attribute__((packed)) params_t;
+  ```
+- Fields can be used to store both inputs and/or outputs
+- Structure must be **`packed`** as it might be padded differently between VMM and guest (it depends on how code was compiled!)
+- Pointers must be declared as the **largest storage size** among VMM and guest
+  - \footnotesize otherwise risk of overflow if architectures are of different size (e.g. 32-bits guest and 64-bits VMM)
 
-IMPORTANT: if VMM and guest architecture are of different size, e.g. guest is 32-bits and VMM is 64, the above structure must use the **largest** data storage type!
+[//]: # ----------------------------------------------------------------
+## Hypercalls parameters: guest
+
+How does guest OS prepare an hypercall's parameters?
+
+- Initialize structure with required parameters
+- Copy (shallow) structure's content to shared hypercall buffer
+- Issue hypercall by writing the desired number to the dedicated hypercall address
+
+[//]: # ----------------------------------------------------------------
+## Hypercalls parameters: VMM
+
+How does VMM retrieve an hypercall's parameters?
+
+- Detect `VMExit` dedicated to an hypercall, then retrieve its number
+- Execute function corresponding to the retrieved hypercall number
 
 [//]: # ----------------------------------------------------------------
-## Writing/read to/from shared buffer
+## Hypercalls: rebasing pointers
 
-- Compiler optimization:
-  - use memcpy if VMM must write something that must be read back by the guest OS!
-  - otherwise, compiler won't read the value again (will use the existing value as it doesn't know the value was modified in another thread/process)
+- Remember that a pointer is just... an address
+- This address is relative to the process' address space
+- \textcolor{myred}{Guest OS address space $\neq$ VMM address space!}
+- VMM must convert every guest address into the address relative to the VMM's address space
+- This process is called **pointer rebasing**
 
 [//]: # ----------------------------------------------------------------
 # VMExits: retrieving values
@@ -969,6 +1001,18 @@ outb(0x3C5, 0x0F);
 :::
 ::::::
 
+<!--
+[//]: # ----------------------------------------------------------------
+## Performance consideration: emulation vs paravirtualization
+
+- Emulation typically triggers lots of `VMexits`
+- Device drivers that trigger many `VMexits` have poor performance
+  - each `VMexit` triggers a context switch
+  - many context switches lead to poor performance
+- Paravirtualized devices designed to be simple and efficient with only few `VMexits`
+  - leads to **much better performance** than emulation
+-->
+
 [//]: # ----------------------------------------------------------------
 # VMM software architecture
 
@@ -990,7 +1034,7 @@ outb(0x3C5, 0x0F);
 - Dedicate a thread for every vCPU
 - If using the SDL library to manage the display, **make sure** that only the main thread calls SDL functions[^8]
 - Dedicate a thread to interact with the user
-  - if using SDL, handle it in the same thread (main) as the one calling SDL functions
+  - if using SDL, handle it in the same thread (`main` function) as the one calling SDL functions
 - If VMM emulates a timer, have it run in a dedicated thread
 
 [^8]: \scriptsize [\textcolor{myblue}{https://documentation.help/SDL/thread.html}](https://documentation.help/SDL/thread.html)
diff --git a/labs/lab-virtual_game_machine/lab-virtual_game_machine.md b/labs/lab-virtual_game_machine/lab-virtual_game_machine.md
index 4f7b42e6f8facf6ae2c6ab3fd2f2596a7e75af63..6cc92654f7ea2cd02e1803adfdb2d17673846b0c 100644
--- a/labs/lab-virtual_game_machine/lab-virtual_game_machine.md
+++ b/labs/lab-virtual_game_machine/lab-virtual_game_machine.md
@@ -336,7 +336,7 @@ Le petit programme **`bin2array`**, dont le code source [se trouve ici](https://
 ## Consignes à propos de l'implémentation
 
 - Gérez toujours les erreurs potentielles\ : testez toujours le retour de fonctions qui peuvent échouer, en particulier celles qui dépendent de l'utilisateur (ex. `open`).
-- Assurez-vous que votre guest n'a aucun moyen de faire crasher[^1] votre VMM\ ; si c'est le cas, c'est que votre VMM n'est pas robuste (p.ex. exécuter un guest bidon ou volontairement buggé).
+- Assurez-vous que votre guest n'a aucun moyen de faire crasher[^1] votre VMM\ ; si c'est le cas, c'est que votre VMM n'est pas robuste (p.ex. exécuter un guest bidon ou volontairement buggé, n° d'hypercalls invalides, etc.).
 - Modularisez votre code afin de ne pas avoir tout le code dans un même fichier source.
 - Utilisez des noms de variables qui ont du sens et qui aident à la compréhension du code.
 - Ecrivez des fonctions courtes, lisibles et réutilisables.
diff --git a/labs/lab-virtual_game_machine/skeleton/guest/entrypoint_asm.s b/labs/lab-virtual_game_machine/skeleton/guest/entrypoint_asm.s
index f1e90a750305e094691e0da0b0642a83ad42d3b9..1c2ea58fadf03feb88df23a501cf56defbfcf8a0 100644
--- a/labs/lab-virtual_game_machine/skeleton/guest/entrypoint_asm.s
+++ b/labs/lab-virtual_game_machine/skeleton/guest/entrypoint_asm.s
@@ -25,7 +25,10 @@ mov     ss,ax
 mov     es,ax
 
 call    guest_main           ; call guest C code entrypoint
+
+@forever:
 hlt                          ; halt the CPU
+jmp @forever
 
 ; Setup a GDT table to identity map the full 4GB address space (32 bits)
 gdt_start:                   ; the GDT table starts here