Skip to content
Snippets Groups Projects
Commit 1cf380bd 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 08e21679
No related branches found
No related tags found
No related merge requests found
......@@ -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
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment