X-Git-Url: http://pilppa.org/gitweb/?a=blobdiff_plain;f=drivers%2Flguest%2Fx86%2Fcore.c;h=5126d5d9ea0e8d8d97fa0eaf47ed22216329328b;hb=54ad64129cc166b9eec7151f3f9fc83589e33555;hp=e989b8358864289db0d3c0e71818bacb6ce7d7d3;hpb=fc708b3e407dfd2e12ba9a6cf35bd0bffad1796d;p=linux-2.6-omap-h63xx.git diff --git a/drivers/lguest/x86/core.c b/drivers/lguest/x86/core.c index e989b835886..5126d5d9ea0 100644 --- a/drivers/lguest/x86/core.c +++ b/drivers/lguest/x86/core.c @@ -17,6 +17,13 @@ * 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 #include #include @@ -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) + 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) + 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) + 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. */ @@ -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,cpu->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(cpu->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,8 +350,8 @@ 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 ? 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; @@ -516,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 @@ -528,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 @@ -541,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() *