diff options
Diffstat (limited to 'drivers/lguest/interrupts_and_traps.c')
-rw-r--r-- | drivers/lguest/interrupts_and_traps.c | 49 |
1 files changed, 19 insertions, 30 deletions
diff --git a/drivers/lguest/interrupts_and_traps.c b/drivers/lguest/interrupts_and_traps.c index 39731232d827..0dfb0903aa69 100644 --- a/drivers/lguest/interrupts_and_traps.c +++ b/drivers/lguest/interrupts_and_traps.c | |||
@@ -218,10 +218,9 @@ int deliver_trap(struct lguest *lg, unsigned int num) | |||
218 | * system calls down from 1750ns to 270ns. Plus, if lguest didn't do it, all | 218 | * system calls down from 1750ns to 270ns. Plus, if lguest didn't do it, all |
219 | * the other hypervisors would tease it. | 219 | * the other hypervisors would tease it. |
220 | * | 220 | * |
221 | * This routine determines if a trap can be delivered directly. */ | 221 | * This routine indicates if a particular trap number could be delivered |
222 | static int direct_trap(const struct lguest *lg, | 222 | * directly. */ |
223 | const struct desc_struct *trap, | 223 | static int direct_trap(unsigned int num) |
224 | unsigned int num) | ||
225 | { | 224 | { |
226 | /* Hardware interrupts don't go to the Guest at all (except system | 225 | /* Hardware interrupts don't go to the Guest at all (except system |
227 | * call). */ | 226 | * call). */ |
@@ -232,14 +231,7 @@ static int direct_trap(const struct lguest *lg, | |||
232 | * fault address), general protection faults (in/out emulation) and | 231 | * fault address), general protection faults (in/out emulation) and |
233 | * device not available (TS handling), and of course, the hypercall | 232 | * device not available (TS handling), and of course, the hypercall |
234 | * trap. */ | 233 | * trap. */ |
235 | if (num == 14 || num == 13 || num == 7 || num == LGUEST_TRAP_ENTRY) | 234 | return num != 14 && num != 13 && num != 7 && num != LGUEST_TRAP_ENTRY; |
236 | return 0; | ||
237 | |||
238 | /* Only trap gates (type 15) can go direct to the Guest. Interrupt | ||
239 | * gates (type 14) disable interrupts as they are entered, which we | ||
240 | * never let the Guest do. Not present entries (type 0x0) also can't | ||
241 | * go direct, of course 8) */ | ||
242 | return idt_type(trap->a, trap->b) == 0xF; | ||
243 | } | 235 | } |
244 | /*:*/ | 236 | /*:*/ |
245 | 237 | ||
@@ -348,15 +340,11 @@ void load_guest_idt_entry(struct lguest *lg, unsigned int num, u32 lo, u32 hi) | |||
348 | * to copy this again. */ | 340 | * to copy this again. */ |
349 | lg->changed |= CHANGED_IDT; | 341 | lg->changed |= CHANGED_IDT; |
350 | 342 | ||
351 | /* The IDT which we keep in "struct lguest" only contains 32 entries | 343 | /* Check that the Guest doesn't try to step outside the bounds. */ |
352 | * for the traps and LGUEST_IRQS (32) entries for interrupts. We | 344 | if (num >= ARRAY_SIZE(lg->idt)) |
353 | * ignore attempts to set handlers for higher interrupt numbers, except | 345 | kill_guest(lg, "Setting idt entry %u", num); |
354 | * for the system call "interrupt" at 128: we have a special IDT entry | 346 | else |
355 | * for that. */ | ||
356 | if (num < ARRAY_SIZE(lg->idt)) | ||
357 | set_trap(lg, &lg->idt[num], num, lo, hi); | 347 | set_trap(lg, &lg->idt[num], num, lo, hi); |
358 | else if (num == SYSCALL_VECTOR) | ||
359 | set_trap(lg, &lg->syscall_idt, num, lo, hi); | ||
360 | } | 348 | } |
361 | 349 | ||
362 | /* The default entry for each interrupt points into the Switcher routines which | 350 | /* The default entry for each interrupt points into the Switcher routines which |
@@ -399,20 +387,21 @@ void copy_traps(const struct lguest *lg, struct desc_struct *idt, | |||
399 | 387 | ||
400 | /* We can simply copy the direct traps, otherwise we use the default | 388 | /* We can simply copy the direct traps, otherwise we use the default |
401 | * ones in the Switcher: they will return to the Host. */ | 389 | * ones in the Switcher: they will return to the Host. */ |
402 | for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++) { | 390 | for (i = 0; i < ARRAY_SIZE(lg->idt); i++) { |
403 | if (direct_trap(lg, &lg->idt[i], i)) | 391 | /* If no Guest can ever override this trap, leave it alone. */ |
392 | if (!direct_trap(i)) | ||
393 | continue; | ||
394 | |||
395 | /* Only trap gates (type 15) can go direct to the Guest. | ||
396 | * Interrupt gates (type 14) disable interrupts as they are | ||
397 | * entered, which we never let the Guest do. Not present | ||
398 | * entries (type 0x0) also can't go direct, of course. */ | ||
399 | if (idt_type(lg->idt[i].a, lg->idt[i].b) == 0xF) | ||
404 | idt[i] = lg->idt[i]; | 400 | idt[i] = lg->idt[i]; |
405 | else | 401 | else |
402 | /* Reset it to the default. */ | ||
406 | default_idt_entry(&idt[i], i, def[i]); | 403 | default_idt_entry(&idt[i], i, def[i]); |
407 | } | 404 | } |
408 | |||
409 | /* Don't forget the system call trap! The IDT entries for other | ||
410 | * interupts never change, so no need to copy them. */ | ||
411 | i = SYSCALL_VECTOR; | ||
412 | if (direct_trap(lg, &lg->syscall_idt, i)) | ||
413 | idt[i] = lg->syscall_idt; | ||
414 | else | ||
415 | default_idt_entry(&idt[i], i, def[i]); | ||
416 | } | 405 | } |
417 | 406 | ||
418 | void guest_set_clockevent(struct lguest *lg, unsigned long delta) | 407 | void guest_set_clockevent(struct lguest *lg, unsigned long delta) |