diff options
Diffstat (limited to 'drivers/lguest/core.c')
| -rw-r--r-- | drivers/lguest/core.c | 87 | 
1 files changed, 42 insertions, 45 deletions
diff --git a/drivers/lguest/core.c b/drivers/lguest/core.c index efa202499e3..0bf1e4edf04 100644 --- a/drivers/lguest/core.c +++ b/drivers/lguest/core.c @@ -20,9 +20,9 @@  #include <asm/asm-offsets.h>  #include "lg.h" - +unsigned long switcher_addr; +struct page **lg_switcher_pages;  static struct vm_struct *switcher_vma; -static struct page **switcher_page;  /* This One Big lock protects all inter-guest data structures. */  DEFINE_MUTEX(lguest_lock); @@ -52,13 +52,21 @@ static __init int map_switcher(void)  	 * easy.  	 */ +	/* We assume Switcher text fits into a single page. */ +	if (end_switcher_text - start_switcher_text > PAGE_SIZE) { +		printk(KERN_ERR "lguest: switcher text too large (%zu)\n", +		       end_switcher_text - start_switcher_text); +		return -EINVAL; +	} +  	/*  	 * We allocate an array of struct page pointers.  map_vm_area() wants  	 * this, rather than just an array of pages.  	 */ -	switcher_page = kmalloc(sizeof(switcher_page[0])*TOTAL_SWITCHER_PAGES, -				GFP_KERNEL); -	if (!switcher_page) { +	lg_switcher_pages = kmalloc(sizeof(lg_switcher_pages[0]) +				    * TOTAL_SWITCHER_PAGES, +				    GFP_KERNEL); +	if (!lg_switcher_pages) {  		err = -ENOMEM;  		goto out;  	} @@ -68,32 +76,29 @@ static __init int map_switcher(void)  	 * so we make sure they're zeroed.  	 */  	for (i = 0; i < TOTAL_SWITCHER_PAGES; i++) { -		switcher_page[i] = alloc_page(GFP_KERNEL|__GFP_ZERO); -		if (!switcher_page[i]) { +		lg_switcher_pages[i] = alloc_page(GFP_KERNEL|__GFP_ZERO); +		if (!lg_switcher_pages[i]) {  			err = -ENOMEM;  			goto free_some_pages;  		}  	}  	/* -	 * First we check that the Switcher won't overlap the fixmap area at -	 * the top of memory.  It's currently nowhere near, but it could have -	 * very strange effects if it ever happened. +	 * We place the Switcher underneath the fixmap area, which is the +	 * highest virtual address we can get.  This is important, since we +	 * tell the Guest it can't access this memory, so we want its ceiling +	 * as high as possible.  	 */ -	if (SWITCHER_ADDR + (TOTAL_SWITCHER_PAGES+1)*PAGE_SIZE > FIXADDR_START){ -		err = -ENOMEM; -		printk("lguest: mapping switcher would thwack fixmap\n"); -		goto free_pages; -	} +	switcher_addr = FIXADDR_START - (TOTAL_SWITCHER_PAGES+1)*PAGE_SIZE;  	/* -	 * Now we reserve the "virtual memory area" we want: 0xFFC00000 -	 * (SWITCHER_ADDR).  We might not get it in theory, but in practice -	 * it's worked so far.  The end address needs +1 because __get_vm_area -	 * allocates an extra guard page, so we need space for that. +	 * Now we reserve the "virtual memory area" we want.  We might +	 * not get it in theory, but in practice it's worked so far. +	 * The end address needs +1 because __get_vm_area allocates an +	 * extra guard page, so we need space for that.  	 */  	switcher_vma = __get_vm_area(TOTAL_SWITCHER_PAGES * PAGE_SIZE, -				     VM_ALLOC, SWITCHER_ADDR, SWITCHER_ADDR +				     VM_ALLOC, switcher_addr, switcher_addr  				     + (TOTAL_SWITCHER_PAGES+1) * PAGE_SIZE);  	if (!switcher_vma) {  		err = -ENOMEM; @@ -103,12 +108,12 @@ static __init int map_switcher(void)  	/*  	 * This code actually sets up the pages we've allocated to appear at -	 * SWITCHER_ADDR.  map_vm_area() takes the vma we allocated above, the +	 * switcher_addr.  map_vm_area() takes the vma we allocated above, the  	 * kind of pages we're mapping (kernel pages), and a pointer to our  	 * array of struct pages.  It increments that pointer, but we don't  	 * care.  	 */ -	pagep = switcher_page; +	pagep = lg_switcher_pages;  	err = map_vm_area(switcher_vma, PAGE_KERNEL_EXEC, &pagep);  	if (err) {  		printk("lguest: map_vm_area failed: %i\n", err); @@ -117,7 +122,7 @@ static __init int map_switcher(void)  	/*  	 * Now the Switcher is mapped at the right address, we can't fail! -	 * Copy in the compiled-in Switcher code (from <arch>_switcher.S). +	 * Copy in the compiled-in Switcher code (from x86/switcher_32.S).  	 */  	memcpy(switcher_vma->addr, start_switcher_text,  	       end_switcher_text - start_switcher_text); @@ -133,8 +138,8 @@ free_pages:  	i = TOTAL_SWITCHER_PAGES;  free_some_pages:  	for (--i; i >= 0; i--) -		__free_pages(switcher_page[i], 0); -	kfree(switcher_page); +		__free_pages(lg_switcher_pages[i], 0); +	kfree(lg_switcher_pages);  out:  	return err;  } @@ -149,8 +154,8 @@ static void unmap_switcher(void)  	vunmap(switcher_vma->addr);  	/* Now we just need to free the pages we copied the switcher into */  	for (i = 0; i < TOTAL_SWITCHER_PAGES; i++) -		__free_pages(switcher_page[i], 0); -	kfree(switcher_page); +		__free_pages(lg_switcher_pages[i], 0); +	kfree(lg_switcher_pages);  }  /*H:032 @@ -225,13 +230,20 @@ int run_guest(struct lg_cpu *cpu, unsigned long __user *user)  			 * eventfd (ie. the appropriate virtqueue thread)?  			 */  			if (!send_notify_to_eventfd(cpu)) { -				/* OK, we tell the main Laucher. */ +				/* OK, we tell the main Launcher. */  				if (put_user(cpu->pending_notify, user))  					return -EFAULT;  				return sizeof(cpu->pending_notify);  			}  		} +		/* +		 * All long-lived kernel loops need to check with this horrible +		 * thing called the freezer.  If the Host is trying to suspend, +		 * it stops us. +		 */ +		try_to_freeze(); +  		/* Check for signals */  		if (signal_pending(current))  			return -ERESTARTSYS; @@ -246,13 +258,6 @@ int run_guest(struct lg_cpu *cpu, unsigned long __user *user)  			try_deliver_interrupt(cpu, irq, more);  		/* -		 * All long-lived kernel loops need to check with this horrible -		 * thing called the freezer.  If the Host is trying to suspend, -		 * it stops us. -		 */ -		try_to_freeze(); - -		/*  		 * Just make absolutely sure the Guest is still alive.  One of  		 * those hypercalls could have been fatal, for example.  		 */ @@ -313,7 +318,7 @@ static int __init init(void)  	int err;  	/* Lguest can't run under Xen, VMI or itself.  It does Tricky Stuff. */ -	if (paravirt_enabled()) { +	if (get_kernel_rpl() != 0) {  		printk("lguest is afraid of being a guest\n");  		return -EPERM;  	} @@ -323,15 +328,10 @@ static int __init init(void)  	if (err)  		goto out; -	/* Now we set up the pagetable implementation for the Guests. */ -	err = init_pagetables(switcher_page, SHARED_SWITCHER_PAGES); -	if (err) -		goto unmap; -  	/* We might need to reserve an interrupt vector. */  	err = init_interrupts();  	if (err) -		goto free_pgtables; +		goto unmap;  	/* /dev/lguest needs to be registered. */  	err = lguest_device_init(); @@ -346,8 +346,6 @@ static int __init init(void)  free_interrupts:  	free_interrupts(); -free_pgtables: -	free_pagetables();  unmap:  	unmap_switcher();  out: @@ -359,7 +357,6 @@ static void __exit fini(void)  {  	lguest_device_remove();  	free_interrupts(); -	free_pagetables();  	unmap_switcher();  	lguest_arch_host_fini();  | 
