Skip to content
Snippets Groups Projects
Commit 6720b056 authored by Florent Gluck's avatar Florent Gluck
Browse files

Updated 02-KVM.md with a simpler way of injecting hardware interrupts into the guest

parent ca11938e
No related branches found
No related tags found
No related merge requests found
...@@ -1111,9 +1111,9 @@ outb(0x3C5, 0x0F); ...@@ -1111,9 +1111,9 @@ outb(0x3C5, 0x0F);
- Each device generates a different interrupt - Each device generates a different interrupt
- Whenever the CPU receives an interrupt, it must handle it, i.e. execute some particular code, e.g.: - 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 - 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. - 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! - otherwise that interrupt will never be fired again!
[//]: # ---------------------------------------------------------------- [//]: # ----------------------------------------------------------------
...@@ -1148,19 +1148,18 @@ outb(0x3C5, 0x0F); ...@@ -1148,19 +1148,18 @@ outb(0x3C5, 0x0F);
- \textcolor{myred}{important: must be created \textbf{before} creating any vCPU!} - \textcolor{myred}{important: must be created \textbf{before} creating any vCPU!}
1. Configure the PIC to automatically issue End Of Interrupts (EOI) 1. Configure the PIC to automatically issue End Of Interrupts (EOI)
- allow to simplify the guest OS code - allow to simplify the guest OS code
1. Create a file descriptor for event notification 1. Trigger a hardware interrupt in the guest by using the `KVM_IRQ_LINE` ioctl on the VM file descriptor
1. Link this file descriptor to a KVM interrupt request object, specifying the hardware interrupt number - emulate a *level-triggered* interrupt by writing to the interrupt line twice, first up, then down
1. Then, **to trigger a hardware interrupt in the guest, simply write to this file descriptor**
[//]: # ---------------------------------------------------------------- [//]: # ----------------------------------------------------------------
## Injection VMM side: (1) create virtual PIC ## 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} \vspace{.3cm}
```{.verysmall .c} ```{.verysmall .c}
if (ioctl(vmfd, KVM_CREATE_IRQCHIP, 0) < 0) { if (ioctl(vmfd, KVM_CREATE_IRQCHIP, 0) < 0) {
err(1, "KVM_CREATE_IRQCHIP failed"); // Error...
} }
``` ```
...@@ -1176,16 +1175,52 @@ struct kvm_irqchip irqchip = { ...@@ -1176,16 +1175,52 @@ struct kvm_irqchip irqchip = {
}; };
// Retrieve the PIC registers // 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 // Configure the PIC so that the Guest doesn't need to
// to acknowledge the hardware interrupt by issuing an EOI. // acknowledge the hardware interrupt by issuing an EOI
irqchip.chip.pic.auto_eoi = 1; irqchip.chip.pic.auto_eoi = 1;
// Set the PIC registers // 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 ## 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 ...@@ -1229,6 +1264,7 @@ To trigger a hardware interrupt in the guest, simply write any 64 bits value to
uint64_t dummy_val = 0; uint64_t dummy_val = 0;
write(fd, &dummy_val, sizeof(uint64_t)); write(fd, &dummy_val, sizeof(uint64_t));
``` ```
-->
[//]: # ---------------------------------------------------------------- [//]: # ----------------------------------------------------------------
## Hardware interrupts injection - guest OS side ## Hardware interrupts injection - guest OS side
...@@ -1240,10 +1276,27 @@ Perform the same steps as on a real physical system[^4]: ...@@ -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 - implement ISRs for all potential hardware interrupts that may be triggered
1. Unmask hardware interrupts so that they will be received 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 [^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 # Miscellaneous
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment