[Lguest] [patch] core.c i386 disentangle
Rusty Russell
rusty at rustcorp.com.au
Wed Aug 15 11:25:45 EST 2007
On Tue, 2007-08-14 at 14:54 +0200, Jes Sorensen wrote:
> Hi,
>
> Here's a patch to disentangle a lot of i386 specific gibberish :) from
> core.c. I've tried doing it in the right order etc. but it's possible
> you'll disagree with how I put some of it.
>
> I don't have an x86 build box handy so it's likely the patch needs a bit
> of work to build on i386, but at least it makes me compile core.c on
> ia64 without getting loads of warnings.
>
> The patch is against Rusty's hg patch queue as of this morning (my
> time).
>
> Builds for me<tm>!
>
> Rusty will you be able to mingle this to build on x86, or do you require
> me to try and track down an x86 box somewhere here and fix any breakage?
>
> Thanks,
> Jes
>
>
> plain text document attachment (lg-core-i386-seperate.diff)
> Seperate i368 architecture specific from core.c and move it to
> i386_guest.c and add header file entries to match.
>
> Signed-off-by: Jes Sorensen <jes at sgi.com>
>
> ---
> drivers/lguest/core.c | 497 ---------------------------------
> drivers/lguest/i386_guest.c | 510 ++++++++++++++++++++++++++++++++++
> drivers/lguest/interrupts_and_traps.c | 18 -
> drivers/lguest/lg.h | 55 ---
> drivers/lguest/segments.c | 26 -
> include/asm-i386/lguest.h | 54 +++
> 6 files changed, 600 insertions(+), 560 deletions(-)
Hi Jes,
I think you've misunderstood the role of "i386_guest.c". That's the
*guest* side of i386. We need a new file (i386.c? i386_core.c?) which
has all the host-side of i386. Some of this, of course, will be moved
to x86.c when we share with x86_64, but that's ok for later.
> +#ifdef CONFIG_HIGHMEM
> #include <asm/highmem.h>
> +#endif
Erk... change this to linux/highmem.h and I think everyone will be
happy.
> -/*H:030 Let's jump straight to the the main loop which runs the Guest.
> - * Remember, this is called by the Launcher reading /dev/lguest, and we keep
> - * going around and around until something interesting happens. */
> -int run_guest(struct lguest *lg, unsigned long __user *user)
> -{
I wonder if we want to move this whole function, or try to hook in arch
stuff in a sane way, eg:
> - /* We stop running once the Guest is dead. */
> - while (!lg->dead) {
> - /* We need to initialize this, otherwise gcc complains. It's
> - * not (yet) clever enough to see that it's initialized when we
> - * need it. */
> - unsigned int cr2 = 0; /* Damn gcc */
Obviously would need to get rid of that...
> -
> - /* First we run any hypercalls the Guest wants done: either in
> - * the hypercall ring in "struct lguest_data", or directly by
> - * using int 31 (LGUEST_TRAP_ENTRY). */
> - do_hypercalls(lg);
> - /* It's possible the Guest did a SEND_DMA hypercall to the
> - * Launcher, in which case we return from the read() now. */
> - if (lg->dma_is_pending) {
> - if (put_user(lg->pending_dma, user) ||
> - put_user(lg->pending_key, user+1))
> - return -EFAULT;
> - return sizeof(unsigned long)*2;
> - }
> -
> - /* Check for signals */
> - if (signal_pending(current))
> - return -ERESTARTSYS;
> -
> - /* If Waker set break_out, return to Launcher. */
> - if (lg->break_out)
> - return -EAGAIN;
> -
> - /* Check if there are any interrupts which can be delivered
> - * now: if so, this sets up the hander to be executed when we
> - * next run the Guest. */
> - maybe_do_interrupt(lg);
> -
> - /* All long-lived kernel loops need to check with this horrible
> - * thing called the freezer. If the Host is trying to suspend,
> - * it stops us. */
> - try_to_freeze();
> -
> - /* Just make absolutely sure the Guest is still alive. One of
> - * those hypercalls could have been fatal, for example. */
> - if (lg->dead)
> - break;
> -
> - /* If the Guest asked to be stopped, we sleep. The Guest's
> - * clock timer or LHCALL_BREAK from the Waker will wake us. */
> - if (lg->halted) {
> - set_current_state(TASK_INTERRUPTIBLE);
> - schedule();
> - continue;
> - }
> -
> - /* OK, now we're ready to jump into the Guest. First we put up
> - * the "Do Not Disturb" sign: */
> - local_irq_disable();
This is all generic.
> -
> - /* 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)
> - set_ts();
> -
> - /* SYSENTER is an optimized way of doing system calls. We
> - * can't allow it because it always jumps to privilege level 0.
> - * A normal Guest won't try it because we don't advertise it in
> - * CPUID, but a malicious Guest (or malicious Guest userspace
> - * program) could, so we tell the CPU to disable it before
> - * running the Guest. */
> - if (boot_cpu_has(X86_FEATURE_SEP))
> - wrmsr(MSR_IA32_SYSENTER_CS, 0, 0);
> -
> - /* Now we actually run the Guest. It will pop back out when
> - * something interesting happens, and we can examine its
> - * registers to see what it was doing. */
> - run_guest_once(lg, lguest_pages(raw_smp_processor_id()));
> -
> - /* The "regs" pointer 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. */
> -
> - /* If the Guest page faulted, then the cr2 register will tell
> - * us the bad virtual address. We have to grab this now,
> - * because once we re-enable interrupts an interrupt could
> - * fault and thus overwrite cr2, or we could even move off to a
> - * different CPU. */
> - if (lg->regs->trapnum == 14)
> - cr2 = 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 (lg->regs->trapnum == 7)
> - math_state_restore();
> -
> - /* Restore SYSENTER if it's supposed to be on. */
> - if (boot_cpu_has(X86_FEATURE_SEP))
> - wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0);
This could all be wrapped in lguest_arch_run_guest() (x86 will have to
have somewhere to stash the cr2, but that's easy).
> -
> - /* Now we're ready to be interrupted or moved to other CPUs */
> - local_irq_enable();
Generic.
> -
> - /* OK, so what happened? */
> - switch (lg->regs->trapnum) {
> - case 13: /* We've intercepted a GPF. */
> - /* Check if this was one of those annoying IN or OUT
> - * instructions which we need to emulate. If so, we
> - * just go back into the Guest after we've done it. */
> - if (lg->regs->errcode == 0) {
> - if (emulate_insn(lg))
> - continue;
> - }
> - 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.
> - *
> - * The errcode tells whether this was a read or a
> - * write, and whether kernel or userspace code. */
> - if (demand_page(lg, cr2, lg->regs->errcode))
> - continue;
> -
> - /* OK, it's really not there (or not OK): the Guest
> - * needs to know. We write out the cr2 value so it
> - * knows where the fault occurred.
> - *
> - * Note that if the Guest were really messed up, this
> - * could happen before it's done the INITIALIZE
> - * hypercall, so lg->lguest_data will be NULL */
> - if (lg->lguest_data
> - && put_user(cr2, &lg->lguest_data->cr2))
> - kill_guest(lg, "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)
> - continue;
> - break;
> - case 32 ... 255:
> - /* These values mean a real interrupt occurred, in
> - * which case the Host handler has already been run.
> - * We just do a friendly check if another process
> - * should now be run, then fall through to loop
> - * around: */
> - cond_resched();
> - case LGUEST_TRAP_ENTRY: /* Handled at top of loop */
> - continue;
> - }
if (lguest_arch_handle_trap(lg))
continue;
> -
> - /* If we get here, it's a trap the Guest wants to know
> - * about. */
> - if (deliver_trap(lg, lg->regs->trapnum))
> - continue;
> -
> - /* 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)",
> - lg->regs->trapnum, lg->regs->eip,
> - lg->regs->trapnum == 14 ? cr2 : lg->regs->errcode);
lguest_arch_deliver_trap(lg);
Rest looks fine...
Thanks,
Rusty.
More information about the Lguest
mailing list