diff options
Diffstat (limited to 'drivers/lguest/interrupts_and_traps.c')
-rw-r--r-- | drivers/lguest/interrupts_and_traps.c | 37 |
1 files changed, 29 insertions, 8 deletions
diff --git a/drivers/lguest/interrupts_and_traps.c b/drivers/lguest/interrupts_and_traps.c index 82966982cb38..2b66f79c208b 100644 --- a/drivers/lguest/interrupts_and_traps.c +++ b/drivers/lguest/interrupts_and_traps.c | |||
@@ -92,8 +92,8 @@ static void set_guest_interrupt(struct lguest *lg, u32 lo, u32 hi, int has_err) | |||
92 | 92 | ||
93 | /* Remember that we never let the Guest actually disable interrupts, so | 93 | /* Remember that we never let the Guest actually disable interrupts, so |
94 | * the "Interrupt Flag" bit is always set. We copy that bit from the | 94 | * the "Interrupt Flag" bit is always set. We copy that bit from the |
95 | * Guest's "irq_enabled" field into the eflags word: the Guest copies | 95 | * Guest's "irq_enabled" field into the eflags word: we saw the Guest |
96 | * it back in "lguest_iret". */ | 96 | * copy it back in "lguest_iret". */ |
97 | eflags = lg->regs->eflags; | 97 | eflags = lg->regs->eflags; |
98 | if (get_user(irq_enable, &lg->lguest_data->irq_enabled) == 0 | 98 | if (get_user(irq_enable, &lg->lguest_data->irq_enabled) == 0 |
99 | && !(irq_enable & X86_EFLAGS_IF)) | 99 | && !(irq_enable & X86_EFLAGS_IF)) |
@@ -124,7 +124,7 @@ static void set_guest_interrupt(struct lguest *lg, u32 lo, u32 hi, int has_err) | |||
124 | kill_guest(lg, "Disabling interrupts"); | 124 | kill_guest(lg, "Disabling interrupts"); |
125 | } | 125 | } |
126 | 126 | ||
127 | /*H:200 | 127 | /*H:205 |
128 | * Virtual Interrupts. | 128 | * Virtual Interrupts. |
129 | * | 129 | * |
130 | * maybe_do_interrupt() gets called before every entry to the Guest, to see if | 130 | * maybe_do_interrupt() gets called before every entry to the Guest, to see if |
@@ -256,19 +256,21 @@ int deliver_trap(struct lguest *lg, unsigned int num) | |||
256 | * bogus one in): if we fail here, the Guest will be killed. */ | 256 | * bogus one in): if we fail here, the Guest will be killed. */ |
257 | if (!idt_present(lg->arch.idt[num].a, lg->arch.idt[num].b)) | 257 | if (!idt_present(lg->arch.idt[num].a, lg->arch.idt[num].b)) |
258 | return 0; | 258 | return 0; |
259 | set_guest_interrupt(lg, lg->arch.idt[num].a, lg->arch.idt[num].b, has_err(num)); | 259 | set_guest_interrupt(lg, lg->arch.idt[num].a, lg->arch.idt[num].b, |
260 | has_err(num)); | ||
260 | return 1; | 261 | return 1; |
261 | } | 262 | } |
262 | 263 | ||
263 | /*H:250 Here's the hard part: returning to the Host every time a trap happens | 264 | /*H:250 Here's the hard part: returning to the Host every time a trap happens |
264 | * and then calling deliver_trap() and re-entering the Guest is slow. | 265 | * and then calling deliver_trap() and re-entering the Guest is slow. |
265 | * Particularly because Guest userspace system calls are traps (trap 128). | 266 | * Particularly because Guest userspace system calls are traps (usually trap |
267 | * 128). | ||
266 | * | 268 | * |
267 | * So we'd like to set up the IDT to tell the CPU to deliver traps directly | 269 | * So we'd like to set up the IDT to tell the CPU to deliver traps directly |
268 | * into the Guest. This is possible, but the complexities cause the size of | 270 | * into the Guest. This is possible, but the complexities cause the size of |
269 | * this file to double! However, 150 lines of code is worth writing for taking | 271 | * this file to double! However, 150 lines of code is worth writing for taking |
270 | * system calls down from 1750ns to 270ns. Plus, if lguest didn't do it, all | 272 | * system calls down from 1750ns to 270ns. Plus, if lguest didn't do it, all |
271 | * the other hypervisors would tease it. | 273 | * the other hypervisors would beat it up at lunchtime. |
272 | * | 274 | * |
273 | * This routine indicates if a particular trap number could be delivered | 275 | * This routine indicates if a particular trap number could be delivered |
274 | * directly. */ | 276 | * directly. */ |
@@ -331,7 +333,7 @@ void pin_stack_pages(struct lguest *lg) | |||
331 | * change stacks on each context switch. */ | 333 | * change stacks on each context switch. */ |
332 | void guest_set_stack(struct lguest *lg, u32 seg, u32 esp, unsigned int pages) | 334 | void guest_set_stack(struct lguest *lg, u32 seg, u32 esp, unsigned int pages) |
333 | { | 335 | { |
334 | /* You are not allowd have a stack segment with privilege level 0: bad | 336 | /* You are not allowed have a stack segment with privilege level 0: bad |
335 | * Guest! */ | 337 | * Guest! */ |
336 | if ((seg & 0x3) != GUEST_PL) | 338 | if ((seg & 0x3) != GUEST_PL) |
337 | kill_guest(lg, "bad stack segment %i", seg); | 339 | kill_guest(lg, "bad stack segment %i", seg); |
@@ -350,7 +352,7 @@ void guest_set_stack(struct lguest *lg, u32 seg, u32 esp, unsigned int pages) | |||
350 | * part of the Host: page table handling. */ | 352 | * part of the Host: page table handling. */ |
351 | 353 | ||
352 | /*H:235 This is the routine which actually checks the Guest's IDT entry and | 354 | /*H:235 This is the routine which actually checks the Guest's IDT entry and |
353 | * transfers it into our entry in "struct lguest": */ | 355 | * transfers it into the entry in "struct lguest": */ |
354 | static void set_trap(struct lguest *lg, struct desc_struct *trap, | 356 | static void set_trap(struct lguest *lg, struct desc_struct *trap, |
355 | unsigned int num, u32 lo, u32 hi) | 357 | unsigned int num, u32 lo, u32 hi) |
356 | { | 358 | { |
@@ -456,6 +458,18 @@ void copy_traps(const struct lguest *lg, struct desc_struct *idt, | |||
456 | } | 458 | } |
457 | } | 459 | } |
458 | 460 | ||
461 | /*H:200 | ||
462 | * The Guest Clock. | ||
463 | * | ||
464 | * There are two sources of virtual interrupts. We saw one in lguest_user.c: | ||
465 | * the Launcher sending interrupts for virtual devices. The other is the Guest | ||
466 | * timer interrupt. | ||
467 | * | ||
468 | * The Guest uses the LHCALL_SET_CLOCKEVENT hypercall to tell us how long to | ||
469 | * the next timer interrupt (in nanoseconds). We use the high-resolution timer | ||
470 | * infrastructure to set a callback at that time. | ||
471 | * | ||
472 | * 0 means "turn off the clock". */ | ||
459 | void guest_set_clockevent(struct lguest *lg, unsigned long delta) | 473 | void guest_set_clockevent(struct lguest *lg, unsigned long delta) |
460 | { | 474 | { |
461 | ktime_t expires; | 475 | ktime_t expires; |
@@ -466,20 +480,27 @@ void guest_set_clockevent(struct lguest *lg, unsigned long delta) | |||
466 | return; | 480 | return; |
467 | } | 481 | } |
468 | 482 | ||
483 | /* We use wallclock time here, so the Guest might not be running for | ||
484 | * all the time between now and the timer interrupt it asked for. This | ||
485 | * is almost always the right thing to do. */ | ||
469 | expires = ktime_add_ns(ktime_get_real(), delta); | 486 | expires = ktime_add_ns(ktime_get_real(), delta); |
470 | hrtimer_start(&lg->hrt, expires, HRTIMER_MODE_ABS); | 487 | hrtimer_start(&lg->hrt, expires, HRTIMER_MODE_ABS); |
471 | } | 488 | } |
472 | 489 | ||
490 | /* This is the function called when the Guest's timer expires. */ | ||
473 | static enum hrtimer_restart clockdev_fn(struct hrtimer *timer) | 491 | static enum hrtimer_restart clockdev_fn(struct hrtimer *timer) |
474 | { | 492 | { |
475 | struct lguest *lg = container_of(timer, struct lguest, hrt); | 493 | struct lguest *lg = container_of(timer, struct lguest, hrt); |
476 | 494 | ||
495 | /* Remember the first interrupt is the timer interrupt. */ | ||
477 | set_bit(0, lg->irqs_pending); | 496 | set_bit(0, lg->irqs_pending); |
497 | /* If the Guest is actually stopped, we need to wake it up. */ | ||
478 | if (lg->halted) | 498 | if (lg->halted) |
479 | wake_up_process(lg->tsk); | 499 | wake_up_process(lg->tsk); |
480 | return HRTIMER_NORESTART; | 500 | return HRTIMER_NORESTART; |
481 | } | 501 | } |
482 | 502 | ||
503 | /* This sets up the timer for this Guest. */ | ||
483 | void init_clockdev(struct lguest *lg) | 504 | void init_clockdev(struct lguest *lg) |
484 | { | 505 | { |
485 | hrtimer_init(&lg->hrt, CLOCK_REALTIME, HRTIMER_MODE_ABS); | 506 | hrtimer_init(&lg->hrt, CLOCK_REALTIME, HRTIMER_MODE_ABS); |