summaryrefslogtreecommitdiffstats
path: root/arch/x86/lguest
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/lguest')
-rw-r--r--arch/x86/lguest/boot.c7
-rw-r--r--arch/x86/lguest/i386_head.S41
2 files changed, 38 insertions, 10 deletions
diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c
index 3a06b51c98ad..090f30cbf24c 100644
--- a/arch/x86/lguest/boot.c
+++ b/arch/x86/lguest/boot.c
@@ -86,6 +86,7 @@ struct lguest_data lguest_data = {
.hcall_status = { [0 ... LHCALL_RING_SIZE-1] = 0xFF },
.noirq_start = (u32)lguest_noirq_start,
.noirq_end = (u32)lguest_noirq_end,
+ .kernel_address = PAGE_OFFSET,
.blocked_interrupts = { 1 }, /* Block timer interrupts */
.syscall_vec = SYSCALL_VECTOR,
};
@@ -1033,11 +1034,7 @@ __init void lguest_init(void *boot)
/*G:070 Now we've seen all the paravirt_ops, we return to
* lguest_init() where the rest of the fairly chaotic boot setup
- * occurs.
- *
- * The Host expects our first hypercall to tell it where our "struct
- * lguest_data" is, so we do that first. */
- hcall(LHCALL_LGUEST_INIT, __pa(&lguest_data), 0, 0);
+ * occurs. */
/* The native boot code sets up initial page tables immediately after
* the kernel itself, and sets init_pg_tables_end so they're not
diff --git a/arch/x86/lguest/i386_head.S b/arch/x86/lguest/i386_head.S
index 6d7a74f07c41..ba4282eba5bf 100644
--- a/arch/x86/lguest/i386_head.S
+++ b/arch/x86/lguest/i386_head.S
@@ -1,5 +1,6 @@
#include <linux/linkage.h>
#include <linux/lguest.h>
+#include <asm/lguest_hcall.h>
#include <asm/asm-offsets.h>
#include <asm/thread_info.h>
#include <asm/processor-flags.h>
@@ -8,18 +9,48 @@
* looks for. The plan is that the Linux boot protocol will be extended with a
* "platform type" field which will guide us here from the normal entry point,
* but for the moment this suffices. The normal boot code uses %esi for the
- * boot header, so we do too. We convert it to a virtual address by adding
- * PAGE_OFFSET, and hand it to lguest_init() as its argument (ie. %eax).
+ * boot header, so we do too.
+ *
+ * WARNING: be very careful here! We're running at addresses equal to physical
+ * addesses (around 0), not above PAGE_OFFSET as most code expectes
+ * (eg. 0xC0000000). Jumps are relative, so they're OK, but we can't touch any
+ * data.
*
* The .section line puts this code in .init.text so it will be discarded after
* boot. */
.section .init.text, "ax", @progbits
.ascii "GenuineLguest"
- /* Set up initial stack. */
- movl $(init_thread_union+THREAD_SIZE),%esp
+ /* Make initial hypercall now, so we can set up the pagetables. */
+ movl $LHCALL_LGUEST_INIT, %eax
+ movl $lguest_data - __PAGE_OFFSET, %edx
+ int $LGUEST_TRAP_ENTRY
+
+ /* Set up boot information pointer to hand to lguest_init(): it wants
+ * a virtual address. */
movl %esi, %eax
addl $__PAGE_OFFSET, %eax
- jmp lguest_init
+
+ /* The Host put the toplevel pagetable in lguest_data.pgdir. The movsl
+ * instruction uses %esi, so we needed to save it above. */
+ movl lguest_data - __PAGE_OFFSET + LGUEST_DATA_pgdir, %esi
+
+ /* Copy first 32 entries of page directory to __PAGE_OFFSET entries.
+ * This means the first 128M of kernel memory will be mapped at
+ * PAGE_OFFSET where the kernel expects to run. This will get it far
+ * enough through boot to switch to its own pagetables. */
+ movl $32, %ecx
+ movl %esi, %edi
+ addl $((__PAGE_OFFSET >> 22) * 4), %edi
+ rep
+ movsl
+
+ /* Set up the initial stack so we can run C code. */
+ movl $(init_thread_union+THREAD_SIZE),%esp
+
+
+ /* Jumps are relative, and we're running __PAGE_OFFSET too low at the
+ * moment. */
+ jmp lguest_init+__PAGE_OFFSET
/*G:055 We create a macro which puts the assembler code between lgstart_ and
* lgend_ markers. These templates are put in the .text section: they can't be