Because of legacy-induced blindness, I insisted on separately building
the hypervisor.S switcher code (which is mapped at 0xFFC0000 in host
and guest).  However, the lguest64 patches showed the error of my
ways: it has no relocations, so it can be linked into the module like
normal then remapped.

The only downside is that we can no longer use sizeof(hypervisor_blob),
so we need to allocate our page-array dynamically.

Signed-off-by: Rusty Russell <[EMAIL PROTECTED]>

diff -r 9d462a93e1fa arch/i386/lguest/Makefile
--- a/arch/i386/lguest/Makefile Wed Mar 21 08:56:52 2007 +1100
+++ b/arch/i386/lguest/Makefile Thu Mar 22 11:43:20 2007 +1100
@@ -4,19 +4,4 @@ obj-$(CONFIG_LGUEST_GUEST) += lguest.o l
 # Host requires the other files, which can be a module.
 obj-$(CONFIG_LGUEST)   += lg.o
 lg-objs := core.o hypercalls.o page_tables.o interrupts_and_traps.o \
-       segments.o io.o lguest_user.o
-
-# We use top 4MB for hypervisor. */
-HYPE_ADDR := 0xFFC00000
-# The data is only 1k (256 interrupt handler pointers)
-HYPE_DATA_SIZE := 1024
-CFLAGS += -DHYPE_ADDR="$(HYPE_ADDR)" -DHYPE_DATA_SIZE="$(HYPE_DATA_SIZE)"
-
-$(obj)/core.o: $(obj)/hypervisor-blob.c
-# This links the hypervisor in the right place and turns it into a C array.
-$(obj)/hypervisor-raw: $(obj)/hypervisor.o
-       @$(LD) -static -Tdata=`printf %#x $$(($(HYPE_ADDR)))` -Ttext=`printf 
%#x $$(($(HYPE_ADDR)+$(HYPE_DATA_SIZE)))` -o $@ $< && $(OBJCOPY) -O binary $@
-$(obj)/hypervisor-blob.c: $(obj)/hypervisor-raw
-       @od -tx1 -An -v $< | sed -e 's/^ /0x/' -e 's/$$/,/' -e 's/ /,0x/g' > $@
-
-clean-files := hypervisor-blob.c hypervisor-raw
+       segments.o io.o lguest_user.o hypervisor.o
diff -r 9d462a93e1fa arch/i386/lguest/core.c
--- a/arch/i386/lguest/core.c   Wed Mar 21 08:56:52 2007 +1100
+++ b/arch/i386/lguest/core.c   Thu Mar 22 11:44:17 2007 +1100
@@ -19,17 +19,21 @@
 #include <asm/i387.h>
 #include "lg.h"
 
-/* This is our hypervisor, compiled from hypervisor.S. */
-static char __initdata hypervisor_blob[] = {
-#include "hypervisor-blob.c"
-};
+/* Found in hypervisor.S */
+extern char start_hyper_text[], end_hyper_text[], switch_to_guest[];
+extern unsigned long default_idt_entries[];
 
 /* Every guest maps the core hypervisor blob. */
-#define SHARED_HYPERVISOR_PAGES DIV_ROUND_UP(sizeof(hypervisor_blob),PAGE_SIZE)
+#define SHARED_HYPERVISOR_PAGES \
+       DIV_ROUND_UP(end_hyper_text - start_hyper_text, PAGE_SIZE)
+/* Pages for hypervisor itself, then two pages per cpu */
+#define TOTAL_HYPE_PAGES (SHARED_HYPERVISOR_PAGES + 2 * NR_CPUS)
+
+/* We map at -4M for ease of mapping into the guest (one PTE page). */
+#define HYPE_ADDR 0xFFC00000
 
 static struct vm_struct *hypervisor_vma;
-/* Pages for hypervisor itself, then two pages per cpu */
-static struct page *hype_page[SHARED_HYPERVISOR_PAGES+2*NR_CPUS];
+static struct page **hype_page;
 
 static int cpu_had_pge;
 static struct {
@@ -43,16 +47,10 @@ static DEFINE_PER_CPU(struct lguest *, l
 #define MAX_LGUEST_GUESTS 16
 struct lguest lguests[MAX_LGUEST_GUESTS];
 
-/* IDT entries are at start of hypervisor. */
-static const unsigned long *lguest_default_idt_entries(void)
-{
-       return (void *)HYPE_ADDR;
-}
-
-/* Next is switch_to_guest */
-static void *__lguest_switch_to_guest(void)
-{
-       return (void *)HYPE_ADDR + HYPE_DATA_SIZE;
+/* Offset from where hypervisor.S was compiled to where we've copied it */
+static unsigned long hype_offset(void)
+{
+       return HYPE_ADDR - (unsigned long)start_hyper_text;
 }
 
 /* This cpu's struct lguest_pages. */
@@ -65,9 +63,15 @@ static __init int map_hypervisor(void)
 static __init int map_hypervisor(void)
 {
        int i, err;
-       struct page **pagep = hype_page;
-
-       for (i = 0; i < ARRAY_SIZE(hype_page); i++) {
+       struct page **pagep;
+
+       hype_page = kmalloc(sizeof(hype_page[0])*TOTAL_HYPE_PAGES, GFP_KERNEL);
+       if (!hype_page) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       for (i = 0; i < TOTAL_HYPE_PAGES; i++) {
                unsigned long addr = get_zeroed_page(GFP_KERNEL);
                if (!addr) {
                        err = -ENOMEM;
@@ -76,7 +80,7 @@ static __init int map_hypervisor(void)
                hype_page[i] = virt_to_page(addr);
        }
 
-       hypervisor_vma = __get_vm_area(ARRAY_SIZE(hype_page) * PAGE_SIZE,
+       hypervisor_vma = __get_vm_area(TOTAL_HYPE_PAGES * PAGE_SIZE,
                                       VM_ALLOC, HYPE_ADDR, VMALLOC_END);
        if (!hypervisor_vma) {
                err = -ENOMEM;
@@ -84,12 +88,18 @@ static __init int map_hypervisor(void)
                goto free_pages;
        }
 
+       pagep = hype_page;
        err = map_vm_area(hypervisor_vma, PAGE_KERNEL, &pagep);
        if (err) {
                printk("lguest: map_vm_area failed: %i\n", err);
                goto free_vma;
        }
-       memcpy(hypervisor_vma->addr, hypervisor_blob, sizeof(hypervisor_blob));
+       memcpy(hypervisor_vma->addr, start_hyper_text,
+              end_hyper_text - start_hyper_text);
+
+       /* Fix up IDT entries to point into copied text. */
+       for (i = 0; i < IDT_ENTRIES; i++)
+               default_idt_entries[i] += hype_offset();
 
        for_each_possible_cpu(i) {
                struct lguest_pages *pages = lguest_pages(i);
@@ -107,7 +117,7 @@ static __init int map_hypervisor(void)
                /* No I/O for you! */
                state->guest_tss.io_bitmap_base = sizeof(state->guest_tss);
                setup_default_gdt_entries(state);
-               setup_default_idt_entries(state, lguest_default_idt_entries());
+               setup_default_idt_entries(state, default_idt_entries);
 
                /* Setup LGUEST segments on all cpus */
                get_cpu_gdt_table(i)[GDT_ENTRY_LGUEST_CS] = FULL_EXEC_SEGMENT;
@@ -115,7 +125,7 @@ static __init int map_hypervisor(void)
        }
 
        /* Initialize entry point into hypervisor. */
-       lguest_entry.offset = (long)__lguest_switch_to_guest();
+       lguest_entry.offset = (long)switch_to_guest + hype_offset();
        lguest_entry.segment = LGUEST_CS;
 
        printk("lguest: mapped hypervisor at %p\n", hypervisor_vma->addr);
@@ -124,10 +134,12 @@ free_vma:
 free_vma:
        vunmap(hypervisor_vma->addr);
 free_pages:
-       i = ARRAY_SIZE(hype_page);
+       i = TOTAL_HYPE_PAGES;
 free_some_pages:
        for (--i; i >= 0; i--)
                __free_pages(hype_page[i], 0);
+       kfree(hype_page);
+out:
        return err;
 }
 
@@ -136,7 +148,7 @@ static __exit void unmap_hypervisor(void
        unsigned int i;
 
        vunmap(hypervisor_vma->addr);
-       for (i = 0; i < ARRAY_SIZE(hype_page); i++)
+       for (i = 0; i < TOTAL_HYPE_PAGES; i++)
                __free_pages(hype_page[i], 0);
 }
 
@@ -277,8 +289,7 @@ static void copy_in_guest_info(struct lg
 
        /* Copy direct trap entries. */
        if (lg->changed & CHANGED_IDT)
-               copy_traps(lg, pages->state.guest_idt,
-                          lguest_default_idt_entries());
+               copy_traps(lg, pages->state.guest_idt, default_idt_entries);
 
        /* Copy all GDT entries but the TSS. */
        if (lg->changed & CHANGED_GDT)
diff -r 9d462a93e1fa arch/i386/lguest/hypervisor.S
--- a/arch/i386/lguest/hypervisor.S     Wed Mar 21 08:56:52 2007 +1100
+++ b/arch/i386/lguest/hypervisor.S     Thu Mar 22 11:43:20 2007 +1100
@@ -10,11 +10,11 @@
 #include "lg.h"
 
 .text
-ENTRY(_start) /* ld complains unless _start is defined. */
+ENTRY(start_hyper_text)
 
 /* %eax points to lguest pages for this CPU.  %ebx contains cr3 value.
    All normal registers can be clobbered! */
-switch_to_guest:
+ENTRY(switch_to_guest)
        /* Save host segments on host stack. */
        pushl   %es
        pushl   %ds
@@ -148,8 +148,8 @@ handle_nmi:
  * host.  Unfortunately we can't tell them apart except by entry
  * point, so we need 256 entry points.
  */
-irq_stubs:
 .data
+.global default_idt_entries
 default_idt_entries:
 .text
        IRQ_STUBS 0 1 return_to_host            /* First two traps */
@@ -159,5 +159,5 @@ default_idt_entries:
        IRQ_STUB 128 return_to_host             /* System call (overridden) */
        IRQ_STUBS 129 255 deliver_to_host       /* Other real interrupts */
 
-/* Everything after this is used for the lguest_state structs. */
-ALIGN
+.text
+ENTRY(end_hyper_text)


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to