diff options
Diffstat (limited to 'drivers')
-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 |
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); | |||
164 | void copy_gdt_tls(const struct lg_cpu *cpu, struct desc_struct *gdt); | 164 | void copy_gdt_tls(const struct lg_cpu *cpu, struct desc_struct *gdt); |
165 | 165 | ||
166 | /* page_tables.c: */ | 166 | /* page_tables.c: */ |
167 | int init_guest_pagetable(struct lguest *lg, unsigned long pgtable); | 167 | int init_guest_pagetable(struct lguest *lg); |
168 | void free_guest_pagetable(struct lguest *lg); | 168 | void free_guest_pagetable(struct lguest *lg); |
169 | void guest_new_pagetable(struct lg_cpu *cpu, unsigned long pgtable); | 169 | void guest_new_pagetable(struct lg_cpu *cpu, unsigned long pgtable); |
170 | void guest_set_pmd(struct lguest *lg, unsigned long gpgdir, u32 i); | 170 | 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 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 | */ |
163 | static int initialize(struct file *file, const unsigned long __user *input) | 160 | 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) | |||
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). */ | ||
591 | static 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: */ |
588 | int init_guest_pagetable(struct lguest *lg, unsigned long pgtable) | 644 | int 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; |