diff options
| -rw-r--r-- | Documentation/lguest/lguest.c | 60 | ||||
| -rw-r--r-- | arch/x86/lguest/i386_head.S | 15 | ||||
| -rw-r--r-- | drivers/lguest/lg.h | 2 | ||||
| -rw-r--r-- | drivers/lguest/lguest_user.c | 13 | ||||
| -rw-r--r-- | drivers/lguest/page_tables.c | 72 | ||||
| -rw-r--r-- | include/linux/lguest_launcher.h | 2 | 
6 files changed, 83 insertions, 81 deletions
diff --git a/Documentation/lguest/lguest.c b/Documentation/lguest/lguest.c index aa2574ca94c..f2dbbf3bdea 100644 --- a/Documentation/lguest/lguest.c +++ b/Documentation/lguest/lguest.c @@ -481,51 +481,6 @@ static unsigned long load_initrd(const char *name, unsigned long mem)  	/* We return the initrd size. */  	return len;  } - -/* Once we know how much memory we have we can construct simple linear page - * tables which set virtual == physical which will get the Guest far enough - * into the boot to create its own. - * - * We lay them out of the way, just below the initrd (which is why we need to - * know its size here). */ -static unsigned long setup_pagetables(unsigned long mem, -				      unsigned long initrd_size) -{ -	unsigned long *pgdir, *linear; -	unsigned int mapped_pages, i, linear_pages; -	unsigned int ptes_per_page = getpagesize()/sizeof(void *); - -	mapped_pages = mem/getpagesize(); - -	/* Each PTE page can map ptes_per_page pages: how many do we need? */ -	linear_pages = (mapped_pages + ptes_per_page-1)/ptes_per_page; - -	/* We put the toplevel page directory page at the top of memory. */ -	pgdir = from_guest_phys(mem) - initrd_size - getpagesize(); - -	/* Now we use the next linear_pages pages as pte pages */ -	linear = (void *)pgdir - linear_pages*getpagesize(); - -	/* Linear mapping is easy: put every page's address into the mapping in -	 * order.  PAGE_PRESENT contains the flags Present, Writable and -	 * Executable. */ -	for (i = 0; i < mapped_pages; i++) -		linear[i] = ((i * getpagesize()) | PAGE_PRESENT); - -	/* The top level points to the linear page table pages above. */ -	for (i = 0; i < mapped_pages; i += ptes_per_page) { -		pgdir[i/ptes_per_page] -			= ((to_guest_phys(linear) + i*sizeof(void *)) -			   | PAGE_PRESENT); -	} - -	verbose("Linear mapping of %u pages in %u pte pages at %#lx\n", -		mapped_pages, linear_pages, to_guest_phys(linear)); - -	/* We return the top level (guest-physical) address: the kernel needs -	 * to know where it is. */ -	return to_guest_phys(pgdir); -}  /*:*/  /* Simple routine to roll all the commandline arguments together with spaces @@ -548,13 +503,13 @@ static void concat(char *dst, char *args[])  /*L:185 This is where we actually tell the kernel to initialize the Guest.  We   * saw the arguments it expects when we looked at initialize() in lguest_user.c: - * the base of Guest "physical" memory, the top physical page to allow, the - * top level pagetable and the entry point for the Guest. */ -static int tell_kernel(unsigned long pgdir, unsigned long start) + * the base of Guest "physical" memory, the top physical page to allow and the + * entry point for the Guest. */ +static int tell_kernel(unsigned long start)  {  	unsigned long args[] = { LHREQ_INITIALIZE,  				 (unsigned long)guest_base, -				 guest_limit / getpagesize(), pgdir, start }; +				 guest_limit / getpagesize(), start };  	int fd;  	verbose("Guest: %p - %p (%#lx)\n", @@ -1941,7 +1896,7 @@ int main(int argc, char *argv[])  {  	/* Memory, top-level pagetable, code startpoint and size of the  	 * (optional) initrd. */ -	unsigned long mem = 0, pgdir, start, initrd_size = 0; +	unsigned long mem = 0, start, initrd_size = 0;  	/* Two temporaries and the /dev/lguest file descriptor. */  	int i, c, lguest_fd;  	/* The boot information for the Guest. */ @@ -2040,9 +1995,6 @@ int main(int argc, char *argv[])  		boot->hdr.type_of_loader = 0xFF;  	} -	/* Set up the initial linear pagetables, starting below the initrd. */ -	pgdir = setup_pagetables(mem, initrd_size); -  	/* The Linux boot header contains an "E820" memory map: ours is a  	 * simple, single region. */  	boot->e820_entries = 1; @@ -2064,7 +2016,7 @@ int main(int argc, char *argv[])  	/* We tell the kernel to initialize the Guest: this returns the open  	 * /dev/lguest file descriptor. */ -	lguest_fd = tell_kernel(pgdir, start); +	lguest_fd = tell_kernel(start);  	/* We clone off a thread, which wakes the Launcher whenever one of the  	 * input file descriptors needs attention.  We call this the Waker, and diff --git a/arch/x86/lguest/i386_head.S b/arch/x86/lguest/i386_head.S index 5c7cef34c9e..10b9bd35a8f 100644 --- a/arch/x86/lguest/i386_head.S +++ b/arch/x86/lguest/i386_head.S @@ -30,21 +30,6 @@ ENTRY(lguest_entry)  	movl $lguest_data - __PAGE_OFFSET, %edx  	int $LGUEST_TRAP_ENTRY -	/* The Host put the toplevel pagetable in lguest_data.pgdir.  The movsl -	 * instruction uses %esi implicitly as the source for the copy we're -	 * about to do. */ -	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 diff --git a/drivers/lguest/lg.h b/drivers/lguest/lg.h index 5faefeaf679..f2c641e0bdd 100644 --- a/drivers/lguest/lg.h +++ b/drivers/lguest/lg.h @@ -164,7 +164,7 @@ void copy_gdt(const struct lg_cpu *cpu, struct desc_struct *gdt);  void copy_gdt_tls(const struct lg_cpu *cpu, struct desc_struct *gdt);  /* page_tables.c: */ -int init_guest_pagetable(struct lguest *lg, unsigned long pgtable); +int init_guest_pagetable(struct lguest *lg);  void free_guest_pagetable(struct lguest *lg);  void guest_new_pagetable(struct lg_cpu *cpu, unsigned long pgtable);  void guest_set_pmd(struct lguest *lg, unsigned long gpgdir, u32 i); diff --git a/drivers/lguest/lguest_user.c b/drivers/lguest/lguest_user.c index e73a000473c..34bc017b8b3 100644 --- a/drivers/lguest/lguest_user.c +++ b/drivers/lguest/lguest_user.c @@ -146,7 +146,7 @@ static int lg_cpu_start(struct lg_cpu *cpu, unsigned id, unsigned long start_ip)  	return 0;  } -/*L:020 The initialization write supplies 4 pointer sized (32 or 64 bit) +/*L:020 The initialization write supplies 3 pointer sized (32 or 64 bit)   * values (in addition to the LHREQ_INITIALIZE value).  These are:   *   * base: The start of the Guest-physical memory inside the Launcher memory. @@ -155,9 +155,6 @@ static int lg_cpu_start(struct lg_cpu *cpu, unsigned id, unsigned long start_ip)   * allowed to access.  The Guest memory lives inside the Launcher, so it sets   * this to ensure the Guest can only reach its own memory.   * - * pgdir: The (Guest-physical) address of the top of the initial Guest - * pagetables (which are set up by the Launcher). - *   * start: The first instruction to execute ("eip" in x86-speak).   */  static int initialize(struct file *file, const unsigned long __user *input) @@ -166,7 +163,7 @@ static int initialize(struct file *file, const unsigned long __user *input)  	 * Guest. */  	struct lguest *lg;  	int err; -	unsigned long args[4]; +	unsigned long args[3];  	/* We grab the Big Lguest lock, which protects against multiple  	 * simultaneous initializations. */ @@ -192,14 +189,14 @@ static int initialize(struct file *file, const unsigned long __user *input)  	lg->mem_base = (void __user *)args[0];  	lg->pfn_limit = args[1]; -	/* This is the first cpu (cpu 0) and it will start booting at args[3] */ -	err = lg_cpu_start(&lg->cpus[0], 0, args[3]); +	/* This is the first cpu (cpu 0) and it will start booting at args[2] */ +	err = lg_cpu_start(&lg->cpus[0], 0, args[2]);  	if (err)  		goto release_guest;  	/* Initialize the Guest's shadow page tables, using the toplevel  	 * address the Launcher gave us.  This allocates memory, so can fail. */ -	err = init_guest_pagetable(lg, args[2]); +	err = init_guest_pagetable(lg);  	if (err)  		goto free_regs; diff --git a/drivers/lguest/page_tables.c b/drivers/lguest/page_tables.c index 81d0c605344..576a8318221 100644 --- a/drivers/lguest/page_tables.c +++ b/drivers/lguest/page_tables.c @@ -14,6 +14,7 @@  #include <linux/percpu.h>  #include <asm/tlbflush.h>  #include <asm/uaccess.h> +#include <asm/bootparam.h>  #include "lg.h"  /*M:008 We hold reference to pages, which prevents them from being swapped. @@ -581,15 +582,82 @@ void guest_set_pmd(struct lguest *lg, unsigned long gpgdir, u32 idx)  		release_pgd(lg, lg->pgdirs[pgdir].pgdir + idx);  } +/* Once we know how much memory we have we can construct simple identity + * (which set virtual == physical) and linear mappings + * which will get the Guest far enough into the boot to create its own. + * + * We lay them out of the way, just below the initrd (which is why we need to + * know its size here). */ +static unsigned long setup_pagetables(struct lguest *lg, +				      unsigned long mem, +				      unsigned long initrd_size) +{ +	pgd_t __user *pgdir; +	pte_t __user *linear; +	unsigned int mapped_pages, i, linear_pages, phys_linear; +	unsigned long mem_base = (unsigned long)lg->mem_base; + +	/* We have mapped_pages frames to map, so we need +	 * linear_pages page tables to map them. */ +	mapped_pages = mem / PAGE_SIZE; +	linear_pages = (mapped_pages + PTRS_PER_PTE - 1) / PTRS_PER_PTE; + +	/* We put the toplevel page directory page at the top of memory. */ +	pgdir = (pgd_t *)(mem + mem_base - initrd_size - PAGE_SIZE); + +	/* Now we use the next linear_pages pages as pte pages */ +	linear = (void *)pgdir - linear_pages * PAGE_SIZE; + +	/* Linear mapping is easy: put every page's address into the +	 * mapping in order. */ +	for (i = 0; i < mapped_pages; i++) { +		pte_t pte; +		pte = pfn_pte(i, __pgprot(_PAGE_PRESENT|_PAGE_RW|_PAGE_USER)); +		if (copy_to_user(&linear[i], &pte, sizeof(pte)) != 0) +			return -EFAULT; +	} + +	/* The top level points to the linear page table pages above. +	 * We setup the identity and linear mappings here. */ +	phys_linear = (unsigned long)linear - mem_base; +	for (i = 0; i < mapped_pages; i += PTRS_PER_PTE) { +		pgd_t pgd; +		pgd = __pgd((phys_linear + i * sizeof(pte_t)) | +			    (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER)); + +		if (copy_to_user(&pgdir[i / PTRS_PER_PTE], &pgd, sizeof(pgd)) +		    || copy_to_user(&pgdir[pgd_index(PAGE_OFFSET) +					   + i / PTRS_PER_PTE], +				    &pgd, sizeof(pgd))) +			return -EFAULT; +	} + +	/* We return the top level (guest-physical) address: remember where +	 * this is. */ +	return (unsigned long)pgdir - mem_base; +} +  /*H:500 (vii) Setting up the page tables initially.   *   * When a Guest is first created, the Launcher tells us where the toplevel of   * its first page table is.  We set some things up here: */ -int init_guest_pagetable(struct lguest *lg, unsigned long pgtable) +int init_guest_pagetable(struct lguest *lg)  { +	u64 mem; +	u32 initrd_size; +	struct boot_params __user *boot = (struct boot_params *)lg->mem_base; + +	/* Get the Guest memory size and the ramdisk size from the boot header +	 * located at lg->mem_base (Guest address 0). */ +	if (copy_from_user(&mem, &boot->e820_map[0].size, sizeof(mem)) +	    || get_user(initrd_size, &boot->hdr.ramdisk_size)) +		return -EFAULT; +  	/* We start on the first shadow page table, and give it a blank PGD  	 * page. */ -	lg->pgdirs[0].gpgdir = pgtable; +	lg->pgdirs[0].gpgdir = setup_pagetables(lg, mem, initrd_size); +	if (IS_ERR_VALUE(lg->pgdirs[0].gpgdir)) +		return lg->pgdirs[0].gpgdir;  	lg->pgdirs[0].pgdir = (pgd_t *)get_zeroed_page(GFP_KERNEL);  	if (!lg->pgdirs[0].pgdir)  		return -ENOMEM; diff --git a/include/linux/lguest_launcher.h b/include/linux/lguest_launcher.h index bd0eba76052..a53407a4165 100644 --- a/include/linux/lguest_launcher.h +++ b/include/linux/lguest_launcher.h @@ -54,7 +54,7 @@ struct lguest_vqconfig {  /* Write command first word is a request. */  enum lguest_req  { -	LHREQ_INITIALIZE, /* + base, pfnlimit, pgdir, start */ +	LHREQ_INITIALIZE, /* + base, pfnlimit, start */  	LHREQ_GETDMA, /* No longer used */  	LHREQ_IRQ, /* + irq */  	LHREQ_BREAK, /* + on/off flag (on blocks until someone does off) */  |