diff --git a/course/02-KVM.md b/course/02-KVM.md
index 0349bf906aa347d730faedccda9c27eb2b824e6b..5ab71fae88a257f1fe5251fb6e72765ca791ce7e 100644
--- a/course/02-KVM.md
+++ b/course/02-KVM.md
@@ -1111,9 +1111,9 @@ outb(0x3C5, 0x0F);
 - Each device generates a different interrupt
 - Whenever the CPU receives an interrupt, it must handle it, i.e. execute some particular code, e.g.:
   - keyboard: read the pressed key and store it in an internal buffer
-  - mouse: read the new position and display the cursor at the new position
+  - mouse: read the mouse position and display the cursor at the new position
   - etc.
-- When the CPU finishes handling the interrupt, it must send a specific command (EOI = End Of Interrupts) to the interrupt controller to indicate it has finished handling the interrupt
+- When the CPU finishes handling the interrupt, it must send a specific command (EOI = End Of Interrupts) to the Programmable Interrupt Controller (PIC) to indicate it has finished handling the interrupt
   - otherwise that interrupt will never be fired again!
 
 [//]: # ----------------------------------------------------------------
@@ -1148,19 +1148,18 @@ outb(0x3C5, 0x0F);
    - \textcolor{myred}{important: must be created \textbf{before} creating any vCPU!}
 1. Configure the PIC to automatically issue End Of Interrupts (EOI)
    - allow to simplify the guest OS code
-1. Create a file descriptor for event notification
-1. Link this file descriptor to a KVM interrupt request object, specifying the hardware interrupt number
-1. Then, **to trigger a hardware interrupt in the guest, simply write to this file descriptor**
+1. Trigger a hardware interrupt in the guest by using the `KVM_IRQ_LINE` ioctl on the VM file descriptor
+   - emulate a *level-triggered* interrupt by writing to the interrupt line twice, first up, then down
 
 [//]: # ----------------------------------------------------------------
 ## Injection VMM side: (1) create virtual PIC
 
-A PIC is created using the following `ioctl` call on the VM file descriptor:
+A Programmable Interrupt Controller (PIC) is created by using the following `ioctl` call on the VM file descriptor:
 \vspace{.3cm}
 
 ```{.verysmall .c}
 if (ioctl(vmfd, KVM_CREATE_IRQCHIP, 0) < 0) {
-    err(1, "KVM_CREATE_IRQCHIP failed");
+    // Error...
 }
 ```
 
@@ -1176,16 +1175,52 @@ struct kvm_irqchip irqchip =  {
 };
 
 // Retrieve the PIC registers
-ioctl(vmfd, KVM_GET_IRQCHIP, &irqchip);
+if (ioctl(vmfd, KVM_GET_IRQCHIP, &irqchip) < 0) {
+    // Error...
+}
 
-// Configure the PIC registers so that the Guest OS doesn't need
-// to acknowledge the hardware interrupt by issuing an EOI.
+// Configure the PIC so that the Guest doesn't need to
+// acknowledge the hardware interrupt by issuing an EOI
 irqchip.chip.pic.auto_eoi = 1;
 
 // Set the PIC registers
-ioctl(vmfd, KVM_SET_IRQCHIP, &irqchip);
+if (ioctl(vmfd, KVM_SET_IRQCHIP, &irqchip) < 0) {
+    // Error...
+}
+```
+
+[//]: # ----------------------------------------------------------------
+## Injection VMM side: (3) trigger hardware interrupt
+
+Example that triggers a *level-triggered* interrupt, here hardware interrupt 5:
+
+```{.verysmall .c}
+struct kvm_irq_level irq_level;
+irq_level.irq = 5;
+
+// Drive the signal to the active level (1)
+irq_level.level = 1;
+if (ioctl(vmfd, KVM_IRQ_LINE, &irq_level) < 0) {
+    // Error...
+}
+
+// Drive the signal down (0)
+irq_level.level = 0;
+if (ioctl(vmfd, KVM_IRQ_LINE, &irq_level) < 0) {
+    // Error...
+}
 ```
 
+<!--
+[//]: # ----------------------------------------------------------------
+## Hardware interrupts injection - alternative VMM side
+
+Alternative way of triggering a hardware interrupt in the guest:
+
+1. Create a file descriptor for event notification
+1. Link this file descriptor to a KVM interrupt request object, specifying the hardware interrupt number
+1. Then, **to trigger a hardware interrupt in the guest, write to this file descriptor**
+
 [//]: # ----------------------------------------------------------------
 ## Injection VMM side: (3) fd for even notification
 
@@ -1229,6 +1264,7 @@ To trigger a hardware interrupt in the guest, simply write any 64 bits value to
 uint64_t dummy_val = 0;
 write(fd, &dummy_val, sizeof(uint64_t));
 ```
+-->
 
 [//]: # ----------------------------------------------------------------
 ## Hardware interrupts injection - guest OS side
@@ -1240,10 +1276,27 @@ Perform the same steps as on a real physical system[^4]:
    - implement ISRs for all potential hardware interrupts that may be triggered
 1. Unmask hardware interrupts so that they will be received
 
-\textcolor{myred}{Receiving a hardware interrupts for which there is no properly initialized IVT entry will result in a shutdown/reboot of the guest (as would on a physical machine)}
+\textcolor{myred}{Receiving a hardware interrupts for which there is no properly initialized IVT entry will result in a shutdown/reboot of the guest (as it would on a physical machine)}
 
 [^4]: \scriptsize With one exception: in the ISR, no need to send an EOI command to the PIC
 
+[//]: # ----------------------------------------------------------------
+## Guest OS, masking/unmasking hardware interrupts
+
+On x86, hardware interrupts are masked (disabled) using the `cli` machine instruction:
+```{.verysmall .c}
+static inline void cli() {
+    asm volatile("cli");
+}
+```
+
+Conversely, `sti` unmasks (enables) hardware interrupts:
+```{.verysmall .c}
+static inline void sti() {
+    asm volatile("sti");
+}
+```
+
 [//]: # ----------------------------------------------------------------
 # Miscellaneous