Make hypercalls arch-independent.
[safe/jmp/linux-2.6] / drivers / lguest / interrupts_and_traps.c
index bd0091b..fdefc0a 100644 (file)
@@ -165,7 +165,7 @@ void maybe_do_interrupt(struct lguest *lg)
        /* Look at the IDT entry the Guest gave us for this interrupt.  The
         * first 32 (FIRST_EXTERNAL_VECTOR) entries are for traps, so we skip
         * over them. */
-       idt = &lg->idt[FIRST_EXTERNAL_VECTOR+irq];
+       idt = &lg->arch.idt[FIRST_EXTERNAL_VECTOR+irq];
        /* If they don't have a handler (yet?), we just ignore it */
        if (idt_present(idt->a, idt->b)) {
                /* OK, mark it no longer pending and deliver it. */
@@ -175,6 +175,13 @@ void maybe_do_interrupt(struct lguest *lg)
                 * the stack as well: virtual interrupts never do. */
                set_guest_interrupt(lg, idt->a, idt->b, 0);
        }
+
+       /* Every time we deliver an interrupt, we update the timestamp in the
+        * Guest's lguest_data struct.  It would be better for the Guest if we
+        * did this more often, but it can actually be quite slow: doing it
+        * here is a compromise which means at least it gets updated every
+        * timer interrupt. */
+       write_timestamp(lg);
 }
 
 /*H:220 Now we've got the routines to deliver interrupts, delivering traps
@@ -188,13 +195,16 @@ static int has_err(unsigned int trap)
 /* deliver_trap() returns true if it could deliver the trap. */
 int deliver_trap(struct lguest *lg, unsigned int num)
 {
-       u32 lo = lg->idt[num].a, hi = lg->idt[num].b;
+       /* Trap numbers are always 8 bit, but we set an impossible trap number
+        * for traps inside the Switcher, so check that here. */
+       if (num >= ARRAY_SIZE(lg->arch.idt))
+               return 0;
 
        /* Early on the Guest hasn't set the IDT entries (or maybe it put a
         * bogus one in): if we fail here, the Guest will be killed. */
-       if (!idt_present(lo, hi))
+       if (!idt_present(lg->arch.idt[num].a, lg->arch.idt[num].b))
                return 0;
-       set_guest_interrupt(lg, lo, hi, has_err(num));
+       set_guest_interrupt(lg, lg->arch.idt[num].a, lg->arch.idt[num].b, has_err(num));
        return 1;
 }
 
@@ -208,10 +218,9 @@ int deliver_trap(struct lguest *lg, unsigned int num)
  * system calls down from 1750ns to 270ns.  Plus, if lguest didn't do it, all
  * the other hypervisors would tease it.
  *
- * This routine determines if a trap can be delivered directly. */
-static int direct_trap(const struct lguest *lg,
-                      const struct desc_struct *trap,
-                      unsigned int num)
+ * This routine indicates if a particular trap number could be delivered
+ * directly. */
+static int direct_trap(unsigned int num)
 {
        /* Hardware interrupts don't go to the Guest at all (except system
         * call). */
@@ -222,14 +231,7 @@ static int direct_trap(const struct lguest *lg,
         * fault address), general protection faults (in/out emulation) and
         * device not available (TS handling), and of course, the hypercall
         * trap. */
-       if (num == 14 || num == 13 || num == 7 || num == LGUEST_TRAP_ENTRY)
-               return 0;
-
-       /* 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 8) */
-       return idt_type(trap->a, trap->b) == 0xF;
+       return num != 14 && num != 13 && num != 7 && num != LGUEST_TRAP_ENTRY;
 }
 /*:*/
 
@@ -260,8 +262,11 @@ void pin_stack_pages(struct lguest *lg)
        /* Depending on the CONFIG_4KSTACKS option, the Guest can have one or
         * two pages of stack space. */
        for (i = 0; i < lg->stack_pages; i++)
-               /* The stack grows *upwards*, hence the subtraction */
-               pin_page(lg, lg->esp1 - i * PAGE_SIZE);
+               /* The stack grows *upwards*, so the address we're given is the
+                * start of the page after the kernel stack.  Subtract one to
+                * get back onto the first stack page, and keep subtracting to
+                * get to the rest of the stack pages. */
+               pin_page(lg, lg->esp1 - 1 - i * PAGE_SIZE);
 }
 
 /* Direct traps also mean that we need to know whenever the Guest wants to use
@@ -335,15 +340,11 @@ void load_guest_idt_entry(struct lguest *lg, unsigned int num, u32 lo, u32 hi)
         * to copy this again. */
        lg->changed |= CHANGED_IDT;
 
-       /* The IDT which we keep in "struct lguest" only contains 32 entries
-        * for the traps and LGUEST_IRQS (32) entries for interrupts.  We
-        * ignore attempts to set handlers for higher interrupt numbers, except
-        * for the system call "interrupt" at 128: we have a special IDT entry
-        * for that. */
-       if (num < ARRAY_SIZE(lg->idt))
-               set_trap(lg, &lg->idt[num], num, lo, hi);
-       else if (num == SYSCALL_VECTOR)
-               set_trap(lg, &lg->syscall_idt, num, lo, hi);
+       /* Check that the Guest doesn't try to step outside the bounds. */
+       if (num >= ARRAY_SIZE(lg->arch.idt))
+               kill_guest(lg, "Setting idt entry %u", num);
+       else
+               set_trap(lg, &lg->arch.idt[num], num, lo, hi);
 }
 
 /* The default entry for each interrupt points into the Switcher routines which
@@ -386,20 +387,21 @@ void copy_traps(const struct lguest *lg, 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 < FIRST_EXTERNAL_VECTOR; i++) {
-               if (direct_trap(lg, &lg->idt[i], i))
-                       idt[i] = lg->idt[i];
+       for (i = 0; i < ARRAY_SIZE(lg->arch.idt); i++) {
+               /* If no Guest can ever override this trap, leave it alone. */
+               if (!direct_trap(i))
+                       continue;
+
+               /* 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(lg->arch.idt[i].a, lg->arch.idt[i].b) == 0xF)
+                       idt[i] = lg->arch.idt[i];
                else
+                       /* Reset it to the default. */
                        default_idt_entry(&idt[i], i, def[i]);
        }
-
-       /* Don't forget the system call trap!  The IDT entries for other
-        * interupts never change, so no need to copy them. */
-       i = SYSCALL_VECTOR;
-       if (direct_trap(lg, &lg->syscall_idt, i))
-               idt[i] = lg->syscall_idt;
-       else
-               default_idt_entry(&idt[i], i, def[i]);
 }
 
 void guest_set_clockevent(struct lguest *lg, unsigned long delta)