diff --git a/Documentation/lguest/Makefile b/Documentation/lguest/Makefile index 31e794e..60136d8 100644 --- a/Documentation/lguest/Makefile +++ b/Documentation/lguest/Makefile @@ -13,7 +13,7 @@ LGUEST_GUEST_TOP := ($(CONFIG_PAGE_OFFSET) - 0x08000000) CFLAGS:=-Wall -Wmissing-declarations -Wmissing-prototypes -O3 -Wl,-T,lguest.lds LDLIBS:=-lz - +LDFLAGS+=-static all: lguest.lds lguest # The linker script on x86 is so complex the only way of creating one diff --git a/Documentation/lguest/lguest.c b/Documentation/lguest/lguest.c index f791840..bb33ae9 100644 --- a/Documentation/lguest/lguest.c +++ b/Documentation/lguest/lguest.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -235,15 +236,36 @@ static unsigned long map_elf(int elf_fd, const Elf32_Ehdr *ehdr, * * MAP_PRIVATE means that the page won't be copied until a * write is done to it. This allows us to share much of the - * kernel memory between Guests. */ + * kernel memory between Guests. + * Also, another gratuitous use of getpageize :-) as we round + * up the section file size. + */ addr = mmap((void *)phdr[i].p_paddr, - phdr[i].p_filesz, + roundup(phdr[i].p_filesz, getpagesize()), PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, elf_fd, phdr[i].p_offset); - if (addr != (void *)phdr[i].p_paddr) - err(1, "Mmaping vmlinux seg %i gave %p not %p", - i, addr, (void *)phdr[i].p_paddr); + /* There is no requirement or guarantee that an ELF file + * be appropriately laid out for mmap. In fact, it's + * not possible to know for sure beforehand: what if the + * file is linked on a machine running with 4K pages and + * we end up on a machine with much bigger pages? So we + * let the kernel tell us that it can or can not map + * the file. If it fails, we read the loader section in and + * lose the benefit of the mmap + */ + if (addr != (void *)phdr[i].p_paddr){ + ssize_t rsize; + warn("Mmaping vmlinux seg %i gave %p not %p", + i, addr, (void *)phdr[i].p_paddr); + addr = (void *) phdr[i].p_paddr; + /* read it in ... */ + if ((rsize = pread(elf_fd, addr, phdr[i].p_filesz, + phdr[i].p_offset)) < phdr[i].p_filesz) + err(1, + "Reading in ELF file gave %i not %d\n", rsize, + phdr[i].p_filesz); + } } return entry_point((void *)start, (void *)end, *page_offset); diff --git a/drivers/lguest/Kconfig b/drivers/lguest/Kconfig index 888205c..736e1e3 100644 --- a/drivers/lguest/Kconfig +++ b/drivers/lguest/Kconfig @@ -3,6 +3,9 @@ config LGUEST depends on X86 && PARAVIRT && EXPERIMENTAL && !X86_PAE select LGUEST_GUEST select HVC_DRIVER + select LGUEST_PLAN9_SYSCALL + select LGUEST_NET + select LGUEST_BLOCK ---help--- This is a very simple module which allows you to run multiple instances of the same Linux kernel, using the @@ -19,6 +22,11 @@ config LGUEST_GUEST support as a module. The drivers are tiny, so we build them in too. +config LGUEST_PLAN9_SYSCALL + bool + help + Support for Plan 9 system calls. + config LGUEST_NET tristate depends on LGUEST_GUEST && NET diff --git a/drivers/lguest/interrupts_and_traps.c b/drivers/lguest/interrupts_and_traps.c index 49787e9..4f83224 100644 --- a/drivers/lguest/interrupts_and_traps.c +++ b/drivers/lguest/interrupts_and_traps.c @@ -222,7 +222,11 @@ static int direct_trap(const struct lguest *lg, { /* Hardware interrupts don't go to the Guest at all (except system * call). */ - if (num >= FIRST_EXTERNAL_VECTOR && num != SYSCALL_VECTOR) + if (num >= FIRST_EXTERNAL_VECTOR && +#ifdef CONFIG_LGUEST_PLAN9_SYSCALL + num != PLAN9_SYSCALL_VECTOR && +#endif + num != SYSCALL_VECTOR) return 0; /* The Host needs to see page faults (for shadow paging and to save the @@ -351,6 +355,10 @@ void load_guest_idt_entry(struct lguest *lg, unsigned int num, u32 lo, u32 hi) set_trap(lg, &lg->idt[num], num, lo, hi); else if (num == SYSCALL_VECTOR) set_trap(lg, &lg->syscall_idt, num, lo, hi); +#ifdef CONFIG_LGUEST_PLAN9_SYSCALL + else if (num == PLAN9_SYSCALL_VECTOR) + set_trap(lg, &lg->syscall_idt, num, lo, hi); +#endif } /* The default entry for each interrupt points into the Switcher routines which @@ -407,6 +415,13 @@ void copy_traps(const struct lguest *lg, struct desc_struct *idt, idt[i] = lg->syscall_idt; else default_idt_entry(&idt[i], i, def[i]); +#ifdef CONFIG_LGUEST_PLAN9_SYSCALL + i = PLAN9_SYSCALL_VECTOR; + if (direct_trap(lg, &lg->syscall_idt, i)) + idt[i] = lg->syscall_idt; + else + default_idt_entry(&idt[i], i, def[i]); +#endif } void guest_set_clockevent(struct lguest *lg, unsigned long delta) diff --git a/include/linux/lguest.h b/include/linux/lguest.h index 157ad64..08d5474 100644 --- a/include/linux/lguest.h +++ b/include/linux/lguest.h @@ -26,6 +26,7 @@ #define LG_CLOCK_MIN_DELTA 100UL #define LG_CLOCK_MAX_DELTA ULONG_MAX +#define PLAN9_SYSCALL_VECTOR 0x40 /*G:031 First, how does our Guest contact the Host to ask for privileged * operations? There are two ways: the direct way is to make a "hypercall", * to make requests of the Host Itself.