[Lguest] [patch] core.c i386 disentangle v3
Rusty Russell
rusty at rustcorp.com.au
Thu Aug 23 22:22:11 EST 2007
On Fri, 2007-08-17 at 11:28 +0200, Jes Sorensen wrote:
> Hi,
>
> Ok so here it is, this is the super uber deluxe version based on the
> input I have gotten so far and taking into account the 'minor' nits
> Muli pointed out yesterday.
OK, I committed this with some modifications. Diff is below:
1) Comment and "make Beer" fixes.
2) Made many arch functions return void: if they can fail later we need
to check the return value anyway.
3) Removed lguest_arch_map_switcher() and rolled it into
lguest_arch_host_init().
4) Similarly made lguest_arch_handle_trap(lg) deliver it if necessary as
well.
5) Took cr2 out of regs struct (that has to match hw & switcher.S), and
renamed it to "last_pagefault". Might eventually be in generic code,
but at least with that name it'll be easier for non-i386 people to
see.
6) static-ize lguest_emulate_insn and rename to emulate_insn again.
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/dontdiff --minimal tmp/drivers/lguest/core.c linux-2.6.23-rc3/drivers/lguest/core.c
--- tmp/drivers/lguest/core.c 2007-08-23 22:05:59.000000000 +1000
+++ linux-2.6.23-rc3/drivers/lguest/core.c 2007-08-23 22:06:17.000000000 +1000
@@ -35,9 +35,7 @@ DEFINE_MUTEX(lguest_lock);
* Host since it will be running as the switchover occurs.
*
* Trying to map memory at a particular address is an unusual thing to do, so
- * it's not a simple one-liner. We also set up the per-cpu parts of the
- * Switcher here.
- */
+ * it's not a simple one-liner. */
static __init int map_switcher(void)
{
int i, err;
@@ -94,14 +92,11 @@ static __init int map_switcher(void)
goto free_vma;
}
- /* Now the switcher is mapped at the right address, we can't fail!
- * Copy in the compiled-in Switcher code (from switcher.S). */
+ /* Now the Switcher is mapped at the right address, we can't fail!
+ * Copy in the compiled-in Switcher code (from <arch>_switcher.S). */
memcpy(switcher_vma->addr, start_switcher_text,
end_switcher_text - start_switcher_text);
- /* Call the architecture specific portion for mapping the switcher. */
- lguest_arch_map_switcher();
-
printk(KERN_INFO "lguest: mapped switcher at %p\n",
switcher_vma->addr);
/* And we succeeded... */
@@ -251,22 +246,20 @@ int run_guest(struct lguest *lg, unsigne
* the "Do Not Disturb" sign: */
local_irq_disable();
+ /* Actually run the Guest until something happens. */
lguest_arch_run_guest(lg);
/* Now we're ready to be interrupted or moved to other CPUs */
local_irq_enable();
- if (lguest_arch_handle_trap(lg))
- continue;
-
- lguest_arch_deliver_trap(lg);
+ /* Now we deal with whatever happened to the Guest. */
+ lguest_arch_handle_trap(lg);
}
/* The Guest is dead => "No such file or directory" */
return -ENOENT;
}
-
/*H:000
* Welcome to the Host!
*
@@ -308,11 +301,13 @@ static int __init init(void)
return err;
}
+ /* Finally we do some architecture-specific setup. */
lguest_arch_host_init();
/* All good! */
return 0;
}
+/*:*/
/* Cleaning up is just the same code, backwards. With a little French. */
static void __exit fini(void)
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/dontdiff --minimal tmp/drivers/lguest/i386_core.c linux-2.6.23-rc3/drivers/lguest/i386_core.c
--- tmp/drivers/lguest/i386_core.c 2007-08-23 22:05:59.000000000 +1000
+++ linux-2.6.23-rc3/drivers/lguest/i386_core.c 2007-08-23 22:06:17.000000000 +1000
@@ -63,92 +63,6 @@ static struct lguest_pages *lguest_pages
static DEFINE_PER_CPU(struct lguest *, last_guest);
-__init int lguest_arch_map_switcher(void)
-{
- int i;
-
- /* Most of the switcher.S doesn't care that it's been moved; on Intel,
- * jumps are relative, and it doesn't access any references to external
- * code or data.
- *
- * 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. */
- for (i = 0; i < IDT_ENTRIES; i++)
- default_idt_entries[i] += switcher_offset();
-
- /*
- * Set up the Switcher's per-cpu areas.
- *
- * Each CPU gets two pages of its own within the high-mapped region
- * (aka. "struct lguest_pages"). Much of this can be initialized now,
- * but some depends on what Guest we are running (which is set up in
- * copy_in_guest_info()).
- */
- for_each_possible_cpu(i) {
- /* lguest_pages() returns this CPU's two pages. */
- struct lguest_pages *pages = lguest_pages(i);
- /* This is a convenience pointer to make the code fit one
- * statement to a line. */
- struct lguest_ro_state *state = &pages->state;
-
- /* The Global Descriptor Table: the Host has a different one
- * for each CPU. We keep a descriptor for the GDT which says
- * where it is and how big it is (the size is actually the last
- * byte, not the size, hence the "-1"). */
- state->host_gdt_desc.size = GDT_SIZE-1;
- state->host_gdt_desc.address = (long)get_cpu_gdt_table(i);
-
- /* All CPUs on the Host use the same Interrupt Descriptor
- * Table, so we just use store_idt(), which gets this CPU's IDT
- * descriptor. */
- store_idt(&state->host_idt_desc);
-
- /* The descriptors for the Guest's GDT and IDT can be filled
- * out now, too. We copy the GDT & IDT into ->guest_gdt and
- * ->guest_idt before actually running the Guest. */
- state->guest_idt_desc.size = sizeof(state->guest_idt)-1;
- state->guest_idt_desc.address = (long)&state->guest_idt;
- state->guest_gdt_desc.size = sizeof(state->guest_gdt)-1;
- 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
- * we start it at the end of that structure. */
- state->guest_tss.esp0 = (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;
-
- /* x86 can have a finegrained bitmap which indicates what I/O
- * ports the process can use. We set it to the end of our
- * structure, meaning "none". */
- state->guest_tss.io_bitmap_base = sizeof(state->guest_tss);
-
- /* Some GDT entries are the same across all Guests, so we can
- * set them up now. */
- setup_default_gdt_entries(state);
- /* Most IDT entries are the same for all Guests, too.*/
- setup_default_idt_entries(state, default_idt_entries);
-
- /* The Host needs to be able to use the LGUEST segments on this
- * CPU, too, so put them in the Host GDT. */
- get_cpu_gdt_table(i)[GDT_ENTRY_LGUEST_CS] = FULL_EXEC_SEGMENT;
- get_cpu_gdt_table(i)[GDT_ENTRY_LGUEST_DS] = FULL_SEGMENT;
- }
-
- /* In the Switcher, we want the %cs segment register to use the
- * LGUEST_CS GDT entry: we've put that in the Host and Guest GDTs, so
- * it will be undisturbed when we switch. To change %cs and jump we
- * need this structure to feed to Intel's "lcall" instruction. */
- lguest_entry.offset = (long)switch_to_guest + switcher_offset();
- lguest_entry.segment = LGUEST_CS;
-
- return 0;
-}
-
/*S:010
* We are getting close to the Switcher.
*
@@ -160,7 +74,7 @@ __init int lguest_arch_map_switcher(void
* since it last ran. We saw this set in interrupts_and_traps.c and
* segments.c.
*/
-void copy_in_guest_info(struct lguest *lg, struct lguest_pages *pages)
+static void copy_in_guest_info(struct lguest *lg, struct lguest_pages *pages)
{
/* 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
@@ -236,11 +150,12 @@ static void run_guest_once(struct lguest
* the Switcher. */
: "memory", "%edx", "%ecx", "%edi", "%esi");
}
+/*:*/
-int lguest_arch_run_guest(struct lguest *lg)
+/*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 lguest *lg)
{
- lg->regs->cr2 = 0;
-
/* 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. */
@@ -272,7 +187,7 @@ int lguest_arch_run_guest(struct lguest
* fault and thus overwrite cr2, or we could even move off to a
* different CPU. */
if (lg->regs->trapnum == 14)
- lg->regs->cr2 = read_cr2();
+ lg->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 (lg->regs->trapnum == 7)
@@ -281,21 +196,92 @@ int lguest_arch_run_guest(struct lguest
/* Restore SYSENTER if it's supposed to be on. */
if (boot_cpu_has(X86_FEATURE_SEP))
wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0);
+}
- return 0;
+/*H:130 Our Guest is usually so well behaved; it never tries to do things it
+ * isn't allowed to. Unfortunately, "struct paravirt_ops" isn't quite
+ * complete, because it doesn't contain replacements for the Intel I/O
+ * instructions. As a result, the Guest sometimes fumbles across one during
+ * the boot process as it probes for various things which are usually attached
+ * to a PC.
+ *
+ * When the Guest uses one of these instructions, we get trap #13 (General
+ * Protection Fault) and come here. We see if it's one of those troublesome
+ * instructions and skip over it. We return true if we did. */
+static int emulate_insn(struct lguest *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, lg->regs->eip);
+
+ /* The guest_pa() function only works for Guest kernel addresses, but
+ * that's all we're trying to do anyway. */
+ if (lg->regs->eip < lg->page_offset)
+ return 0;
+
+ /* Decoding x86 instructions is icky. */
+ lgread(lg, &insn, physaddr, 1);
+
+ /* 0x66 is an "operand prefix". It means it's using the upper 16 bits
+ of the eax register. */
+ if (insn == 0x66) {
+ shift = 16;
+ /* The instruction is 1 byte so far, read the next byte. */
+ insnlen = 1;
+ lgread(lg, &insn, physaddr + insnlen, 1);
+ }
+
+ /* We can ignore the lower bit for the moment and decode the 4 opcodes
+ * we need to emulate. */
+ switch (insn & 0xFE) {
+ case 0xE4: /* in <next byte>,%al */
+ insnlen += 2;
+ in = 1;
+ break;
+ case 0xEC: /* in (%dx),%al */
+ insnlen += 1;
+ in = 1;
+ break;
+ case 0xE6: /* out %al,<next byte> */
+ insnlen += 2;
+ break;
+ case 0xEE: /* out %al,(%dx) */
+ insnlen += 1;
+ break;
+ default:
+ /* OK, we don't know what this is, can't emulate. */
+ return 0;
+ }
+
+ /* If it was an "IN" instruction, they expect the result to be read
+ * into %eax, so we change %eax. We always return all-ones, which
+ * traditionally means "there's nothing there". */
+ if (in) {
+ /* Lower bit tells is whether it's a 16 or 32 bit access */
+ if (insn & 0x1)
+ lg->regs->eax = 0xFFFFFFFF;
+ else
+ lg->regs->eax |= (0xFFFF << shift);
+ }
+ /* Finally, we've "done" the instruction, so move past it. */
+ lg->regs->eip += insnlen;
+ /* Success! */
+ return 1;
}
-int lguest_arch_handle_trap(struct lguest *lg)
+/*H:050 Once we've re-enabled interrupts, we look at why the Guest exited. */
+void lguest_arch_handle_trap(struct lguest *lg)
{
- /* 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 (lguest_emulate_insn(lg))
- return 1;
+ if (emulate_insn(lg))
+ return;
}
break;
case 14: /* We've intercepted a page fault. */
@@ -308,8 +294,8 @@ int lguest_arch_handle_trap(struct lgues
*
* The errcode tells whether this was a read or a
* write, and whether kernel or userspace code. */
- if (demand_page(lg, lg->regs->cr2, lg->regs->errcode))
- return 1;
+ if (demand_page(lg, lg->arch.last_pagefault, lg->regs->errcode))
+ return;
/* OK, it's really not there (or not OK): the Guest
* needs to know. We write out the cr2 value so it
@@ -319,7 +305,7 @@ int lguest_arch_handle_trap(struct lgues
* could happen before it's done the INITIALIZE
* hypercall, so lg->lguest_data will be NULL */
if (lg->lguest_data &&
- put_user(lg->regs->cr2, &lg->lguest_data->cr2))
+ put_user(lg->arch.last_pagefault, &lg->lguest_data->cr2))
kill_guest(lg, "Writing cr2");
break;
case 7: /* We've intercepted a Device Not Available fault. */
@@ -327,7 +313,7 @@ int lguest_arch_handle_trap(struct lgues
* restored the Floating Point Unit, so we just
* continue without telling it. */
if (!lg->ts)
- return 1;
+ return;
break;
case 32 ... 255:
/* These values mean a real interrupt occurred, in
@@ -336,28 +322,19 @@ int lguest_arch_handle_trap(struct lgues
* should now be run, then fall through to loop
* around: */
cond_resched();
- case LGUEST_TRAP_ENTRY: /* Handled at top of loop */
- return 1;
+ case LGUEST_TRAP_ENTRY: /* Handled before re-entering Guest */
+ return;
}
- return 0;
-}
-
-int lguest_arch_deliver_trap(struct lguest *lg)
-{
- /* If we get here, it's a trap the Guest wants to know
- * about. */
- if (deliver_trap(lg, lg->regs->trapnum))
- return 0;
-
- /* 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 ? lg->regs->cr2 : lg->regs->errcode);
-
- return 0;
+ /* We didn't handle the trap, so it needs to go to the Guest. */
+ if (!deliver_trap(lg, lg->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)",
+ lg->regs->trapnum, lg->regs->eip,
+ lg->regs->trapnum == 14 ? lg->arch.last_pagefault
+ : lg->regs->errcode);
}
/* Now we can look at each of the routines this calls, in increasing order of
@@ -373,8 +350,90 @@ static void adjust_pge(void *on)
write_cr4(read_cr4() & ~X86_CR4_PGE);
}
-int __init lguest_arch_host_init(void)
+/*H:020 Now the Switcher is mapped and every thing else is ready, we need to do
+ * some more i386-specific initialization. */
+void __init lguest_arch_host_init(void)
{
+ int i;
+
+ /* Most of the i386_switcher.S doesn't care that it's been moved; on
+ * Intel, jumps are relative, and it doesn't access any references to
+ * external code or data.
+ *
+ * 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. */
+ for (i = 0; i < IDT_ENTRIES; i++)
+ default_idt_entries[i] += switcher_offset();
+
+ /*
+ * Set up the Switcher's per-cpu areas.
+ *
+ * Each CPU gets two pages of its own within the high-mapped region
+ * (aka. "struct lguest_pages"). Much of this can be initialized now,
+ * but some depends on what Guest we are running (which is set up in
+ * copy_in_guest_info()).
+ */
+ for_each_possible_cpu(i) {
+ /* lguest_pages() returns this CPU's two pages. */
+ struct lguest_pages *pages = lguest_pages(i);
+ /* This is a convenience pointer to make the code fit one
+ * statement to a line. */
+ struct lguest_ro_state *state = &pages->state;
+
+ /* The Global Descriptor Table: the Host has a different one
+ * for each CPU. We keep a descriptor for the GDT which says
+ * where it is and how big it is (the size is actually the last
+ * byte, not the size, hence the "-1"). */
+ state->host_gdt_desc.size = GDT_SIZE-1;
+ state->host_gdt_desc.address = (long)get_cpu_gdt_table(i);
+
+ /* All CPUs on the Host use the same Interrupt Descriptor
+ * Table, so we just use store_idt(), which gets this CPU's IDT
+ * descriptor. */
+ store_idt(&state->host_idt_desc);
+
+ /* The descriptors for the Guest's GDT and IDT can be filled
+ * out now, too. We copy the GDT & IDT into ->guest_gdt and
+ * ->guest_idt before actually running the Guest. */
+ state->guest_idt_desc.size = sizeof(state->guest_idt)-1;
+ state->guest_idt_desc.address = (long)&state->guest_idt;
+ state->guest_gdt_desc.size = sizeof(state->guest_gdt)-1;
+ 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
+ * we start it at the end of that structure. */
+ state->guest_tss.esp0 = (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;
+
+ /* x86 can have a finegrained bitmap which indicates what I/O
+ * ports the process can use. We set it to the end of our
+ * structure, meaning "none". */
+ state->guest_tss.io_bitmap_base = sizeof(state->guest_tss);
+
+ /* Some GDT entries are the same across all Guests, so we can
+ * set them up now. */
+ setup_default_gdt_entries(state);
+ /* Most IDT entries are the same for all Guests, too.*/
+ setup_default_idt_entries(state, default_idt_entries);
+
+ /* The Host needs to be able to use the LGUEST segments on this
+ * CPU, too, so put them in the Host GDT. */
+ get_cpu_gdt_table(i)[GDT_ENTRY_LGUEST_CS] = FULL_EXEC_SEGMENT;
+ get_cpu_gdt_table(i)[GDT_ENTRY_LGUEST_DS] = FULL_SEGMENT;
+ }
+
+ /* In the Switcher, we want the %cs segment register to use the
+ * LGUEST_CS GDT entry: we've put that in the Host and Guest GDTs, so
+ * it will be undisturbed when we switch. To change %cs and jump we
+ * need this structure to feed to Intel's "lcall" instruction. */
+ lguest_entry.offset = (long)switch_to_guest + switcher_offset();
+ lguest_entry.segment = LGUEST_CS;
/* Finally, we need to turn off "Page Global Enable". PGE is an
* optimization where page table entries are specially marked to show
@@ -401,8 +460,8 @@ int __init lguest_arch_host_init(void)
clear_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability);
}
unlock_cpu_hotplug();
- return 0;
};
+/*:*/
void __exit lguest_arch_host_fini(void)
{
@@ -415,77 +474,3 @@ void __exit lguest_arch_host_fini(void)
}
unlock_cpu_hotplug();
}
-
-/*H:130 Our Guest is usually so well behaved; it never tries to do things it
- * isn't allowed to. Unfortunately, "struct paravirt_ops" isn't quite
- * complete, because it doesn't contain replacements for the Intel I/O
- * instructions. As a result, the Guest sometimes fumbles across one during
- * the boot process as it probes for various things which are usually attached
- * to a PC.
- *
- * When the Guest uses one of these instructions, we get trap #13 (General
- * Protection Fault) and come here. We see if it's one of those troublesome
- * instructions and skip over it. We return true if we did. */
-int lguest_emulate_insn(struct lguest *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, lg->regs->eip);
-
- /* The guest_pa() function only works for Guest kernel addresses, but
- * that's all we're trying to do anyway. */
- if (lg->regs->eip < lg->page_offset)
- return 0;
-
- /* Decoding x86 instructions is icky. */
- lgread(lg, &insn, physaddr, 1);
-
- /* 0x66 is an "operand prefix". It means it's using the upper 16 bits
- of the eax register. */
- if (insn == 0x66) {
- shift = 16;
- /* The instruction is 1 byte so far, read the next byte. */
- insnlen = 1;
- lgread(lg, &insn, physaddr + insnlen, 1);
- }
-
- /* We can ignore the lower bit for the moment and decode the 4 opcodes
- * we need to emulate. */
- switch (insn & 0xFE) {
- case 0xE4: /* in <next byte>,%al */
- insnlen += 2;
- in = 1;
- break;
- case 0xEC: /* in (%dx),%al */
- insnlen += 1;
- in = 1;
- break;
- case 0xE6: /* out %al,<next byte> */
- insnlen += 2;
- break;
- case 0xEE: /* out %al,(%dx) */
- insnlen += 1;
- break;
- default:
- /* OK, we don't know what this is, can't emulate. */
- return 0;
- }
-
- /* If it was an "IN" instruction, they expect the result to be read
- * into %eax, so we change %eax. We always return all-ones, which
- * traditionally means "there's nothing there". */
- if (in) {
- /* Lower bit tells is whether it's a 16 or 32 bit access */
- if (insn & 0x1)
- lg->regs->eax = 0xFFFFFFFF;
- else
- lg->regs->eax |= (0xFFFF << shift);
- }
- /* Finally, we've "done" the instruction, so move past it. */
- lg->regs->eip += insnlen;
- /* Success! */
- return 1;
-}
-/*:*/
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/dontdiff --minimal tmp/drivers/lguest/lg.h linux-2.6.23-rc3/drivers/lguest/lg.h
--- tmp/drivers/lguest/lg.h 2007-08-23 22:05:59.000000000 +1000
+++ linux-2.6.23-rc3/drivers/lguest/lg.h 2007-08-23 22:06:17.000000000 +1000
@@ -197,13 +197,10 @@ int demand_page(struct lguest *info, uns
void pin_page(struct lguest *lg, unsigned long vaddr);
/* <arch>_core.c: */
-int lguest_arch_map_switcher(void);
-int lguest_arch_host_init(void);
+void lguest_arch_host_init(void);
void lguest_arch_host_fini(void);
-int lguest_emulate_insn(struct lguest *lg);
-int lguest_arch_run_guest(struct lguest *lg);
-int lguest_arch_handle_trap(struct lguest *lg);
-int lguest_arch_deliver_trap(struct lguest *lg);
+void lguest_arch_run_guest(struct lguest *lg);
+void lguest_arch_handle_trap(struct lguest *lg);
/* <arch>_switcher.S: */
extern char start_switcher_text[], end_switcher_text[], switch_to_guest[];
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/dontdiff --minimal tmp/include/asm-i386/lguest.h linux-2.6.23-rc3/include/asm-i386/lguest.h
--- tmp/include/asm-i386/lguest.h 2007-08-23 22:05:59.000000000 +1000
+++ linux-2.6.23-rc3/include/asm-i386/lguest.h 2007-08-23 22:06:17.000000000 +1000
@@ -38,7 +38,6 @@ struct lguest_regs
unsigned long eflags;
unsigned long esp;
unsigned long ss;
- unsigned long cr2;
};
/* This is a guest-specific page (mapped ro) into the guest. */
@@ -65,6 +64,9 @@ struct lguest_arch
/* The IDT entries: some copied into lguest_ro_state when running. */
struct desc_struct idt[IDT_ENTRIES];
+
+ /* The address of the last guest-visible pagefault (ie. cr2). */
+ unsigned long last_pagefault;
};
static inline void lguest_set_ts(void)
More information about the Lguest
mailing list