]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/lguest/interrupts_and_traps.c
lguest: Guest int3 fix
[linux-2.6-omap-h63xx.git] / drivers / lguest / interrupts_and_traps.c
index 32e97c1858e571a2608c678e602755a7f3b7aa38..a1039068f95c378cd85b2d6ff2f0f6729c003db2 100644 (file)
@@ -144,7 +144,6 @@ void maybe_do_interrupt(struct lg_cpu *cpu)
        if (copy_from_user(&blk, cpu->lg->lguest_data->blocked_interrupts,
                           sizeof(blk)))
                return;
-
        bitmap_andnot(blk, cpu->irqs_pending, blk, LGUEST_IRQS);
 
        /* Find the first interrupt. */
@@ -237,9 +236,9 @@ void free_interrupts(void)
                clear_bit(syscall_vector, used_vectors);
 }
 
-/*H:220 Now we've got the routines to deliver interrupts, delivering traps
- * like page fault is easy.  The only trick is that Intel decided that some
- * traps should have error codes: */
+/*H:220 Now we've got the routines to deliver interrupts, delivering traps like
+ * page fault is easy.  The only trick is that Intel decided that some traps
+ * should have error codes: */
 static int has_err(unsigned int trap)
 {
        return (trap == 8 || (trap >= 10 && trap <= 14) || trap == 17);
@@ -407,7 +406,8 @@ void load_guest_idt_entry(struct lg_cpu *cpu, unsigned int num, u32 lo, u32 hi)
  * deliver_trap() to bounce it back into the Guest. */
 static void default_idt_entry(struct desc_struct *idt,
                              int trap,
-                             const unsigned long handler)
+                             const unsigned long handler,
+                             const struct desc_struct *base)
 {
        /* A present interrupt gate. */
        u32 flags = 0x8e00;
@@ -416,6 +416,10 @@ static void default_idt_entry(struct desc_struct *idt,
         * the Guest to use the "int" instruction to trigger it. */
        if (trap == LGUEST_TRAP_ENTRY)
                flags |= (GUEST_PL << 13);
+       else if (base)
+               /* Copy priv. level from what Guest asked for.  This allows
+                * debug (int 3) traps from Guest userspace, for example. */
+               flags |= (base->b & 0x6000);
 
        /* Now pack it into the IDT entry in its weird format. */
        idt->a = (LGUEST_CS<<16) | (handler&0x0000FFFF);
@@ -429,7 +433,7 @@ void setup_default_idt_entries(struct lguest_ro_state *state,
        unsigned int i;
 
        for (i = 0; i < ARRAY_SIZE(state->guest_idt); i++)
-               default_idt_entry(&state->guest_idt[i], i, def[i]);
+               default_idt_entry(&state->guest_idt[i], i, def[i], NULL);
 }
 
 /*H:240 We don't use the IDT entries in the "struct lguest" directly, instead
@@ -443,6 +447,8 @@ void copy_traps(const struct lg_cpu *cpu, struct desc_struct *idt,
        /* We can simply copy the direct traps, otherwise we use the default
         * ones in the Switcher: they will return to the Host. */
        for (i = 0; i < ARRAY_SIZE(cpu->arch.idt); i++) {
+               const struct desc_struct *gidt = &cpu->arch.idt[i];
+
                /* If no Guest can ever override this trap, leave it alone. */
                if (!direct_trap(i))
                        continue;
@@ -450,12 +456,15 @@ void copy_traps(const struct lg_cpu *cpu, struct desc_struct *idt,
                /* Only trap gates (type 15) can go direct to the Guest.
                 * Interrupt gates (type 14) disable interrupts as they are
                 * entered, which we never let the Guest do.  Not present
-                * entries (type 0x0) also can't go direct, of course. */
-               if (idt_type(cpu->arch.idt[i].a, cpu->arch.idt[i].b) == 0xF)
-                       idt[i] = cpu->arch.idt[i];
+                * entries (type 0x0) also can't go direct, of course.
+                *
+                * If it can't go direct, we still need to copy the priv. level:
+                * they might want to give userspace access to a software
+                * interrupt. */
+               if (idt_type(gidt->a, gidt->b) == 0xF)
+                       idt[i] = *gidt;
                else
-                       /* Reset it to the default. */
-                       default_idt_entry(&idt[i], i, def[i]);
+                       default_idt_entry(&idt[i], i, def[i], gidt);
        }
 }