aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/lguest
diff options
context:
space:
mode:
authorMatias Zabaljauregui <zabaljauregui@gmail.com>2008-09-29 00:40:07 -0400
committerRusty Russell <rusty@rustcorp.com.au>2008-12-29 17:56:11 -0500
commit58a24566449892dda409b9ad92c2e56c76c5670c (patch)
tree4dfe2305dfd078c71d949ea8cc6c9cc6e2679494 /drivers/lguest
parentbe3c5832d51174ef7f21cefd6ad612dabdcb62fd (diff)
lguest: move the initial guest page table creation code to the host
This patch moves the initial guest page table creation code to the host, so the launcher keeps working with PAE enabled configs. Signed-off-by: Matias Zabaljauregui <zabaljauregui@gmail.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'drivers/lguest')
-rw-r--r--drivers/lguest/lg.h2
-rw-r--r--drivers/lguest/lguest_user.c13
-rw-r--r--drivers/lguest/page_tables.c72
3 files changed, 76 insertions, 11 deletions
diff --git a/drivers/lguest/lg.h b/drivers/lguest/lg.h
index 5faefeaf6790..f2c641e0bdde 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);
164void copy_gdt_tls(const struct lg_cpu *cpu, struct desc_struct *gdt); 164void copy_gdt_tls(const struct lg_cpu *cpu, struct desc_struct *gdt);
165 165
166/* page_tables.c: */ 166/* page_tables.c: */
167int init_guest_pagetable(struct lguest *lg, unsigned long pgtable); 167int init_guest_pagetable(struct lguest *lg);
168void free_guest_pagetable(struct lguest *lg); 168void free_guest_pagetable(struct lguest *lg);
169void guest_new_pagetable(struct lg_cpu *cpu, unsigned long pgtable); 169void guest_new_pagetable(struct lg_cpu *cpu, unsigned long pgtable);
170void guest_set_pmd(struct lguest *lg, unsigned long gpgdir, u32 i); 170void 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 e73a000473cc..34bc017b8b3c 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)
146 return 0; 146 return 0;
147} 147}
148 148
149/*L:020 The initialization write supplies 4 pointer sized (32 or 64 bit) 149/*L:020 The initialization write supplies 3 pointer sized (32 or 64 bit)
150 * values (in addition to the LHREQ_INITIALIZE value). These are: 150 * values (in addition to the LHREQ_INITIALIZE value). These are:
151 * 151 *
152 * base: The start of the Guest-physical memory inside the Launcher memory. 152 * 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)
155 * allowed to access. The Guest memory lives inside the Launcher, so it sets 155 * allowed to access. The Guest memory lives inside the Launcher, so it sets
156 * this to ensure the Guest can only reach its own memory. 156 * this to ensure the Guest can only reach its own memory.
157 * 157 *
158 * pgdir: The (Guest-physical) address of the top of the initial Guest
159 * pagetables (which are set up by the Launcher).
160 *
161 * start: The first instruction to execute ("eip" in x86-speak). 158 * start: The first instruction to execute ("eip" in x86-speak).
162 */ 159 */
163static int initialize(struct file *file, const unsigned long __user *input) 160static 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)
166 * Guest. */ 163 * Guest. */
167 struct lguest *lg; 164 struct lguest *lg;
168 int err; 165 int err;
169 unsigned long args[4]; 166 unsigned long args[3];
170 167
171 /* We grab the Big Lguest lock, which protects against multiple 168 /* We grab the Big Lguest lock, which protects against multiple
172 * simultaneous initializations. */ 169 * simultaneous initializations. */
@@ -192,14 +189,14 @@ static int initialize(struct file *file, const unsigned long __user *input)
192 lg->mem_base = (void __user *)args[0]; 189 lg->mem_base = (void __user *)args[0];
193 lg->pfn_limit = args[1]; 190 lg->pfn_limit = args[1];
194 191
195 /* This is the first cpu (cpu 0) and it will start booting at args[3] */ 192 /* This is the first cpu (cpu 0) and it will start booting at args[2] */
196 err = lg_cpu_start(&lg->cpus[0], 0, args[3]); 193 err = lg_cpu_start(&lg->cpus[0], 0, args[2]);
197 if (err) 194 if (err)
198 goto release_guest; 195 goto release_guest;
199 196
200 /* Initialize the Guest's shadow page tables, using the toplevel 197 /* Initialize the Guest's shadow page tables, using the toplevel
201 * address the Launcher gave us. This allocates memory, so can fail. */ 198 * address the Launcher gave us. This allocates memory, so can fail. */
202 err = init_guest_pagetable(lg, args[2]); 199 err = init_guest_pagetable(lg);
203 if (err) 200 if (err)
204 goto free_regs; 201 goto free_regs;
205 202
diff --git a/drivers/lguest/page_tables.c b/drivers/lguest/page_tables.c
index 81d0c6053447..576a8318221c 100644
--- a/drivers/lguest/page_tables.c
+++ b/drivers/lguest/page_tables.c
@@ -14,6 +14,7 @@
14#include <linux/percpu.h> 14#include <linux/percpu.h>
15#include <asm/tlbflush.h> 15#include <asm/tlbflush.h>
16#include <asm/uaccess.h> 16#include <asm/uaccess.h>
17#include <asm/bootparam.h>
17#include "lg.h" 18#include "lg.h"
18 19
19/*M:008 We hold reference to pages, which prevents them from being swapped. 20/*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)
581 release_pgd(lg, lg->pgdirs[pgdir].pgdir + idx); 582 release_pgd(lg, lg->pgdirs[pgdir].pgdir + idx);
582} 583}
583 584
585/* Once we know how much memory we have we can construct simple identity
586 * (which set virtual == physical) and linear mappings
587 * which will get the Guest far enough into the boot to create its own.
588 *
589 * We lay them out of the way, just below the initrd (which is why we need to
590 * know its size here). */
591static unsigned long setup_pagetables(struct lguest *lg,
592 unsigned long mem,
593 unsigned long initrd_size)
594{
595 pgd_t __user *pgdir;
596 pte_t __user *linear;
597 unsigned int mapped_pages, i, linear_pages, phys_linear;
598 unsigned long mem_base = (unsigned long)lg->mem_base;
599
600 /* We have mapped_pages frames to map, so we need
601 * linear_pages page tables to map them. */
602 mapped_pages = mem / PAGE_SIZE;
603 linear_pages = (mapped_pages + PTRS_PER_PTE - 1) / PTRS_PER_PTE;
604
605 /* We put the toplevel page directory page at the top of memory. */
606 pgdir = (pgd_t *)(mem + mem_base - initrd_size - PAGE_SIZE);
607
608 /* Now we use the next linear_pages pages as pte pages */
609 linear = (void *)pgdir - linear_pages * PAGE_SIZE;
610
611 /* Linear mapping is easy: put every page's address into the
612 * mapping in order. */
613 for (i = 0; i < mapped_pages; i++) {
614 pte_t pte;
615 pte = pfn_pte(i, __pgprot(_PAGE_PRESENT|_PAGE_RW|_PAGE_USER));
616 if (copy_to_user(&linear[i], &pte, sizeof(pte)) != 0)
617 return -EFAULT;
618 }
619
620 /* The top level points to the linear page table pages above.
621 * We setup the identity and linear mappings here. */
622 phys_linear = (unsigned long)linear - mem_base;
623 for (i = 0; i < mapped_pages; i += PTRS_PER_PTE) {
624 pgd_t pgd;
625 pgd = __pgd((phys_linear + i * sizeof(pte_t)) |
626 (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER));
627
628 if (copy_to_user(&pgdir[i / PTRS_PER_PTE], &pgd, sizeof(pgd))
629 || copy_to_user(&pgdir[pgd_index(PAGE_OFFSET)
630 + i / PTRS_PER_PTE],
631 &pgd, sizeof(pgd)))
632 return -EFAULT;
633 }
634
635 /* We return the top level (guest-physical) address: remember where
636 * this is. */
637 return (unsigned long)pgdir - mem_base;
638}
639
584/*H:500 (vii) Setting up the page tables initially. 640/*H:500 (vii) Setting up the page tables initially.
585 * 641 *
586 * When a Guest is first created, the Launcher tells us where the toplevel of 642 * When a Guest is first created, the Launcher tells us where the toplevel of
587 * its first page table is. We set some things up here: */ 643 * its first page table is. We set some things up here: */
588int init_guest_pagetable(struct lguest *lg, unsigned long pgtable) 644int init_guest_pagetable(struct lguest *lg)
589{ 645{
646 u64 mem;
647 u32 initrd_size;
648 struct boot_params __user *boot = (struct boot_params *)lg->mem_base;
649
650 /* Get the Guest memory size and the ramdisk size from the boot header
651 * located at lg->mem_base (Guest address 0). */
652 if (copy_from_user(&mem, &boot->e820_map[0].size, sizeof(mem))
653 || get_user(initrd_size, &boot->hdr.ramdisk_size))
654 return -EFAULT;
655
590 /* We start on the first shadow page table, and give it a blank PGD 656 /* We start on the first shadow page table, and give it a blank PGD
591 * page. */ 657 * page. */
592 lg->pgdirs[0].gpgdir = pgtable; 658 lg->pgdirs[0].gpgdir = setup_pagetables(lg, mem, initrd_size);
659 if (IS_ERR_VALUE(lg->pgdirs[0].gpgdir))
660 return lg->pgdirs[0].gpgdir;
593 lg->pgdirs[0].pgdir = (pgd_t *)get_zeroed_page(GFP_KERNEL); 661 lg->pgdirs[0].pgdir = (pgd_t *)get_zeroed_page(GFP_KERNEL);
594 if (!lg->pgdirs[0].pgdir) 662 if (!lg->pgdirs[0].pgdir)
595 return -ENOMEM; 663 return -ENOMEM;