]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/lguest/x86/core.c
lguest: comment documentation update.
[linux-2.6-omap-h63xx.git] / drivers / lguest / x86 / core.c
index d96a93d95aea588b020b199b940a7e984201245a..5126d5d9ea0e8d8d97fa0eaf47ed22216329328b 100644 (file)
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
+/*P:450 This file contains the x86-specific lguest code.  It used to be all
+ * mixed in with drivers/lguest/core.c but several foolhardy code slashers
+ * wrestled most of the dependencies out to here in preparation for porting
+ * lguest to other architectures (see what I mean by foolhardy?).
+ *
+ * This also contains a couple of non-obvious setup and teardown pieces which
+ * were implemented after days of debugging pain. :*/
 #include <linux/kernel.h>
 #include <linux/start_kernel.h>
 #include <linux/string.h>
@@ -60,7 +67,7 @@ static struct lguest_pages *lguest_pages(unsigned int cpu)
                  (SWITCHER_ADDR + SHARED_SWITCHER_PAGES*PAGE_SIZE))[cpu]);
 }
 
-static DEFINE_PER_CPU(struct lguest *, last_guest);
+static DEFINE_PER_CPU(struct lg_cpu *, last_cpu);
 
 /*S:010
  * We approach the Switcher.
@@ -75,15 +82,14 @@ static DEFINE_PER_CPU(struct lguest *, last_guest);
  */
 static void copy_in_guest_info(struct lg_cpu *cpu, struct lguest_pages *pages)
 {
-       struct lguest *lg = cpu->lg;
        /* Copying all this data can be quite expensive.  We usually run the
         * same Guest we ran last time (and that Guest hasn't run anywhere else
         * meanwhile).  If that's not the case, we pretend everything in the
         * Guest has changed. */
-       if (__get_cpu_var(last_guest) != lg || lg->last_pages != pages) {
-               __get_cpu_var(last_guest) = lg;
-               lg->last_pages = pages;
-               lg->changed = CHANGED_ALL;
+       if (__get_cpu_var(last_cpu) != cpu || cpu->last_pages != pages) {
+               __get_cpu_var(last_cpu) = cpu;
+               cpu->last_pages = pages;
+               cpu->changed = CHANGED_ALL;
        }
 
        /* These copies are pretty cheap, so we do them unconditionally: */
@@ -95,22 +101,22 @@ static void copy_in_guest_info(struct lg_cpu *cpu, struct lguest_pages *pages)
        /* Set up the two "TSS" members which tell the CPU what stack to use
         * for traps which do directly into the Guest (ie. traps at privilege
         * level 1). */
-       pages->state.guest_tss.esp1 = lg->esp1;
-       pages->state.guest_tss.ss1 = lg->ss1;
+       pages->state.guest_tss.sp1 = cpu->esp1;
+       pages->state.guest_tss.ss1 = cpu->ss1;
 
        /* Copy direct-to-Guest trap entries. */
-       if (lg->changed & CHANGED_IDT)
-               copy_traps(lg, pages->state.guest_idt, default_idt_entries);
+       if (cpu->changed & CHANGED_IDT)
+               copy_traps(cpu, pages->state.guest_idt, default_idt_entries);
 
        /* Copy all GDT entries which the Guest can change. */
-       if (lg->changed & CHANGED_GDT)
-               copy_gdt(lg, pages->state.guest_gdt);
+       if (cpu->changed & CHANGED_GDT)
+               copy_gdt(cpu, pages->state.guest_gdt);
        /* If only the TLS entries have changed, copy them. */
-       else if (lg->changed & CHANGED_GDT_TLS)
-               copy_gdt_tls(lg, pages->state.guest_gdt);
+       else if (cpu->changed & CHANGED_GDT_TLS)
+               copy_gdt_tls(cpu, pages->state.guest_gdt);
 
        /* Mark the Guest as unchanged for next time. */
-       lg->changed = 0;
+       cpu->changed = 0;
 }
 
 /* Finally: the code to actually call into the Switcher to run the Guest. */
@@ -118,7 +124,6 @@ static void run_guest_once(struct lg_cpu *cpu, struct lguest_pages *pages)
 {
        /* This is a dummy value we need for GCC's sake. */
        unsigned int clobber;
-       struct lguest *lg = cpu->lg;
 
        /* Copy the guest-specific information into this CPU's "struct
         * lguest_pages". */
@@ -145,7 +150,7 @@ static void run_guest_once(struct lg_cpu *cpu, struct lguest_pages *pages)
                      * 0-th argument above, ie "a").  %ebx contains the
                      * physical address of the Guest's top-level page
                      * directory. */
-                    : "0"(pages), "1"(__pa(lg->pgdirs[lg->pgdidx].pgdir))
+                    : "0"(pages), "1"(__pa(cpu->lg->pgdirs[cpu->cpu_pgd].pgdir))
                     /* We tell gcc that all these registers could change,
                      * which means we don't have to save and restore them in
                      * the Switcher. */
@@ -159,18 +164,18 @@ static void run_guest_once(struct lg_cpu *cpu, struct lguest_pages *pages)
  * also simplify copy_in_guest_info().  Note that we'd still need to restore
  * things when we exit to Launcher userspace, but that's fairly easy.
  *
+ * We could also try using this hooks for PGE, but that might be too expensive.
+ *
  * The hooks were designed for KVM, but we can also put them to good use. :*/
 
 /*H:040 This is the i386-specific code to setup and run the Guest.  Interrupts
  * are disabled: we own the CPU. */
 void lguest_arch_run_guest(struct lg_cpu *cpu)
 {
-       struct lguest *lg = cpu->lg;
-
        /* Remember the awfully-named TS bit?  If the Guest has asked to set it
         * we set it now, so we can trap and pass that trap to the Guest if it
         * uses the FPU. */
-       if (lg->ts)
+       if (cpu->ts)
                lguest_set_ts();
 
        /* SYSENTER is an optimized way of doing system calls.  We can't allow
@@ -186,7 +191,7 @@ void lguest_arch_run_guest(struct lg_cpu *cpu)
         * was doing. */
        run_guest_once(cpu, lguest_pages(raw_smp_processor_id()));
 
-       /* Note that the "regs" pointer contains two extra entries which are
+       /* Note that the "regs" structure contains two extra entries which are
         * not really registers: a trap number which says what interrupt or
         * trap made the switcher code come back, and an error code which some
         * traps set.  */
@@ -196,7 +201,7 @@ void lguest_arch_run_guest(struct lg_cpu *cpu)
         * re-enable interrupts an interrupt could fault and thus overwrite
         * cr2, or we could even move off to a different CPU. */
        if (cpu->regs->trapnum == 14)
-               lg->arch.last_pagefault = read_cr2();
+               cpu->arch.last_pagefault = read_cr2();
        /* Similarly, if we took a trap because the Guest used the FPU,
         * we have to restore the FPU it expects to see. */
        else if (cpu->regs->trapnum == 7)
@@ -220,12 +225,11 @@ void lguest_arch_run_guest(struct lg_cpu *cpu)
  * instructions and skip over it.  We return true if we did. */
 static int emulate_insn(struct lg_cpu *cpu)
 {
-       struct lguest *lg = cpu->lg;
        u8 insn;
        unsigned int insnlen = 0, in = 0, shift = 0;
        /* The eip contains the *virtual* address of the Guest's instruction:
         * guest_pa just subtracts the Guest's page_offset. */
-       unsigned long physaddr = guest_pa(lg, cpu->regs->eip);
+       unsigned long physaddr = guest_pa(cpu, cpu->regs->eip);
 
        /* This must be the Guest kernel trying to do something, not userspace!
         * The bottom two bits of the CS segment register are the privilege
@@ -234,7 +238,7 @@ static int emulate_insn(struct lg_cpu *cpu)
                return 0;
 
        /* Decoding x86 instructions is icky. */
-       insn = lgread(lg, physaddr, u8);
+       insn = lgread(cpu, physaddr, u8);
 
        /* 0x66 is an "operand prefix".  It means it's using the upper 16 bits
           of the eax register. */
@@ -242,7 +246,7 @@ static int emulate_insn(struct lg_cpu *cpu)
                shift = 16;
                /* The instruction is 1 byte so far, read the next byte. */
                insnlen = 1;
-               insn = lgread(lg, physaddr + insnlen, u8);
+               insn = lgread(cpu, physaddr + insnlen, u8);
        }
 
        /* We can ignore the lower bit for the moment and decode the 4 opcodes
@@ -286,7 +290,6 @@ static int emulate_insn(struct lg_cpu *cpu)
 /*H:050 Once we've re-enabled interrupts, we look at why the Guest exited. */
 void lguest_arch_handle_trap(struct lg_cpu *cpu)
 {
-       struct lguest *lg = cpu->lg;
        switch (cpu->regs->trapnum) {
        case 13: /* We've intercepted a General Protection Fault. */
                /* Check if this was one of those annoying IN or OUT
@@ -299,15 +302,15 @@ void lguest_arch_handle_trap(struct lg_cpu *cpu)
                break;
        case 14: /* We've intercepted a Page Fault. */
                /* The Guest accessed a virtual address that wasn't mapped.
-                * This happens a lot: we don't actually set up most of the
-                * page tables for the Guest at all when we start: as it runs
-                * it asks for more and more, and we set them up as
-                * required. In this case, we don't even tell the Guest that
-                * the fault happened.
+                * This happens a lot: we don't actually set up most of the page
+                * tables for the Guest at all when we start: as it runs it asks
+                * for more and more, and we set them up as required. In this
+                * case, we don't even tell the Guest that the fault happened.
                 *
                 * The errcode tells whether this was a read or a write, and
                 * whether kernel or userspace code. */
-               if (demand_page(lg, lg->arch.last_pagefault, cpu->regs->errcode))
+               if (demand_page(cpu, cpu->arch.last_pagefault,
+                               cpu->regs->errcode))
                        return;
 
                /* OK, it's really not there (or not OK): the Guest needs to
@@ -317,15 +320,16 @@ void lguest_arch_handle_trap(struct lg_cpu *cpu)
                 * Note that if the Guest were really messed up, this could
                 * happen before it's done the LHCALL_LGUEST_INIT hypercall, so
                 * lg->lguest_data could be NULL */
-               if (lg->lguest_data &&
-                   put_user(lg->arch.last_pagefault, &lg->lguest_data->cr2))
-                       kill_guest(lg, "Writing cr2");
+               if (cpu->lg->lguest_data &&
+                   put_user(cpu->arch.last_pagefault,
+                            &cpu->lg->lguest_data->cr2))
+                       kill_guest(cpu, "Writing cr2");
                break;
        case 7: /* We've intercepted a Device Not Available fault. */
                /* If the Guest doesn't want to know, we already restored the
                 * Floating Point Unit, so we just continue without telling
                 * it. */
-               if (!lg->ts)
+               if (!cpu->ts)
                        return;
                break;
        case 32 ... 255:
@@ -346,10 +350,10 @@ void lguest_arch_handle_trap(struct lg_cpu *cpu)
        if (!deliver_trap(cpu, cpu->regs->trapnum))
                /* If the Guest doesn't have a handler (either it hasn't
                 * registered any yet, or it's one of the faults we don't let
-                * it handle), it dies with a cryptic error message. */
-               kill_guest(lg, "unhandled trap %li at %#lx (%#lx)",
+                * it handle), it dies with this cryptic error message. */
+               kill_guest(cpu, "unhandled trap %li at %#lx (%#lx)",
                           cpu->regs->trapnum, cpu->regs->eip,
-                          cpu->regs->trapnum == 14 ? lg->arch.last_pagefault
+                          cpu->regs->trapnum == 14 ? cpu->arch.last_pagefault
                           : cpu->regs->errcode);
 }
 
@@ -379,8 +383,8 @@ void __init lguest_arch_host_init(void)
         * The only exception is the interrupt handlers in switcher.S: their
         * addresses are placed in a table (default_idt_entries), so we need to
         * update the table with the new addresses.  switcher_offset() is a
-        * convenience function which returns the distance between the builtin
-        * switcher code and the high-mapped copy we just made. */
+        * convenience function which returns the distance between the
+        * compiled-in switcher code and the high-mapped copy we just made. */
        for (i = 0; i < IDT_ENTRIES; i++)
                default_idt_entries[i] += switcher_offset();
 
@@ -420,9 +424,9 @@ void __init lguest_arch_host_init(void)
                state->guest_gdt_desc.address = (long)&state->guest_gdt;
 
                /* We know where we want the stack to be when the Guest enters
-                * the switcher: in pages->regs.  The stack grows upwards, so
+                * the Switcher: in pages->regs.  The stack grows upwards, so
                 * we start it at the end of that structure. */
-               state->guest_tss.esp0 = (long)(&pages->regs + 1);
+               state->guest_tss.sp0 = (long)(&pages->regs + 1);
                /* And this is the GDT entry to use for the stack: we keep a
                 * couple of special LGUEST entries. */
                state->guest_tss.ss0 = LGUEST_DS;
@@ -495,17 +499,15 @@ void __exit lguest_arch_host_fini(void)
 /*H:122 The i386-specific hypercalls simply farm out to the right functions. */
 int lguest_arch_do_hcall(struct lg_cpu *cpu, struct hcall_args *args)
 {
-       struct lguest *lg = cpu->lg;
-
        switch (args->arg0) {
        case LHCALL_LOAD_GDT:
-               load_guest_gdt(lg, args->arg1, args->arg2);
+               load_guest_gdt(cpu, args->arg1, args->arg2);
                break;
        case LHCALL_LOAD_IDT_ENTRY:
-               load_guest_idt_entry(lg, args->arg1, args->arg2, args->arg3);
+               load_guest_idt_entry(cpu, args->arg1, args->arg2, args->arg3);
                break;
        case LHCALL_LOAD_TLS:
-               guest_load_tls(lg, args->arg1);
+               guest_load_tls(cpu, args->arg1);
                break;
        default:
                /* Bad Guest.  Bad! */
@@ -518,11 +520,11 @@ int lguest_arch_do_hcall(struct lg_cpu *cpu, struct hcall_args *args)
 int lguest_arch_init_hypercalls(struct lg_cpu *cpu)
 {
        u32 tsc_speed;
-       struct lguest *lg = cpu->lg;
 
-       /* The pointer to the Guest's "struct lguest_data" is the only
-        * argument.  We check that address now. */
-       if (!lguest_address_ok(lg, cpu->hcall->arg1, sizeof(*lg->lguest_data)))
+       /* The pointer to the Guest's "struct lguest_data" is the only argument.
+        * We check that address now. */
+       if (!lguest_address_ok(cpu->lg, cpu->hcall->arg1,
+                              sizeof(*cpu->lg->lguest_data)))
                return -EFAULT;
 
        /* Having checked it, we simply set lg->lguest_data to point straight
@@ -530,7 +532,7 @@ int lguest_arch_init_hypercalls(struct lg_cpu *cpu)
         * copy_to_user/from_user from now on, instead of lgread/write.  I put
         * this in to show that I'm not immune to writing stupid
         * optimizations. */
-       lg->lguest_data = lg->mem_base + cpu->hcall->arg1;
+       cpu->lg->lguest_data = cpu->lg->mem_base + cpu->hcall->arg1;
 
        /* We insist that the Time Stamp Counter exist and doesn't change with
         * cpu frequency.  Some devious chip manufacturers decided that TSC
@@ -543,15 +545,16 @@ int lguest_arch_init_hypercalls(struct lg_cpu *cpu)
                tsc_speed = tsc_khz;
        else
                tsc_speed = 0;
-       if (put_user(tsc_speed, &lg->lguest_data->tsc_khz))
+       if (put_user(tsc_speed, &cpu->lg->lguest_data->tsc_khz))
                return -EFAULT;
 
        /* The interrupt code might not like the system call vector. */
-       if (!check_syscall_vector(lg))
-               kill_guest(lg, "bad syscall vector");
+       if (!check_syscall_vector(cpu->lg))
+               kill_guest(cpu, "bad syscall vector");
 
        return 0;
 }
+/*:*/
 
 /*L:030 lguest_arch_setup_regs()
  *
@@ -586,5 +589,5 @@ void lguest_arch_setup_regs(struct lg_cpu *cpu, unsigned long start)
 
        /* There are a couple of GDT entries the Guest expects when first
         * booting. */
-       setup_guest_gdt(cpu->lg);
+       setup_guest_gdt(cpu);
 }