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 aa2574ca94c7..f2dbbf3bdeab 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) | |||
481 | /* We return the initrd size. */ | 481 | /* We return the initrd size. */ |
482 | return len; | 482 | return len; |
483 | } | 483 | } |
484 | |||
485 | /* Once we know how much memory we have we can construct simple linear page | ||
486 | * tables which set virtual == physical which will get the Guest far enough | ||
487 | * into the boot to create its own. | ||
488 | * | ||
489 | * We lay them out of the way, just below the initrd (which is why we need to | ||
490 | * know its size here). */ | ||
491 | static unsigned long setup_pagetables(unsigned long mem, | ||
492 | unsigned long initrd_size) | ||
493 | { | ||
494 | unsigned long *pgdir, *linear; | ||
495 | unsigned int mapped_pages, i, linear_pages; | ||
496 | unsigned int ptes_per_page = getpagesize()/sizeof(void *); | ||
497 | |||
498 | mapped_pages = mem/getpagesize(); | ||
499 | |||
500 | /* Each PTE page can map ptes_per_page pages: how many do we need? */ | ||
501 | linear_pages = (mapped_pages + ptes_per_page-1)/ptes_per_page; | ||
502 | |||
503 | /* We put the toplevel page directory page at the top of memory. */ | ||
504 | pgdir = from_guest_phys(mem) - initrd_size - getpagesize(); | ||
505 | |||
506 | /* Now we use the next linear_pages pages as pte pages */ | ||
507 | linear = (void *)pgdir - linear_pages*getpagesize(); | ||
508 | |||
509 | /* Linear mapping is easy: put every page's address into the mapping in | ||
510 | * order. PAGE_PRESENT contains the flags Present, Writable and | ||
511 | * Executable. */ | ||
512 | for (i = 0; i < mapped_pages; i++) | ||
513 | linear[i] = ((i * getpagesize()) | PAGE_PRESENT); | ||
514 | |||
515 | /* The top level points to the linear page table pages above. */ | ||
516 | for (i = 0; i < mapped_pages; i += ptes_per_page) { | ||
517 | pgdir[i/ptes_per_page] | ||
518 | = ((to_guest_phys(linear) + i*sizeof(void *)) | ||
519 | | PAGE_PRESENT); | ||
520 | } | ||
521 | |||
522 | verbose("Linear mapping of %u pages in %u pte pages at %#lx\n", | ||
523 | mapped_pages, linear_pages, to_guest_phys(linear)); | ||
524 | |||
525 | /* We return the top level (guest-physical) address: the kernel needs | ||
526 | * to know where it is. */ | ||
527 | return to_guest_phys(pgdir); | ||
528 | } | ||
529 | /*:*/ | 484 | /*:*/ |
530 | 485 | ||
531 | /* Simple routine to roll all the commandline arguments together with spaces | 486 | /* Simple routine to roll all the commandline arguments together with spaces |
@@ -548,13 +503,13 @@ static void concat(char *dst, char *args[]) | |||
548 | 503 | ||
549 | /*L:185 This is where we actually tell the kernel to initialize the Guest. We | 504 | /*L:185 This is where we actually tell the kernel to initialize the Guest. We |
550 | * saw the arguments it expects when we looked at initialize() in lguest_user.c: | 505 | * saw the arguments it expects when we looked at initialize() in lguest_user.c: |
551 | * the base of Guest "physical" memory, the top physical page to allow, the | 506 | * the base of Guest "physical" memory, the top physical page to allow and the |
552 | * top level pagetable and the entry point for the Guest. */ | 507 | * entry point for the Guest. */ |
553 | static int tell_kernel(unsigned long pgdir, unsigned long start) | 508 | static int tell_kernel(unsigned long start) |
554 | { | 509 | { |
555 | unsigned long args[] = { LHREQ_INITIALIZE, | 510 | unsigned long args[] = { LHREQ_INITIALIZE, |
556 | (unsigned long)guest_base, | 511 | (unsigned long)guest_base, |
557 | guest_limit / getpagesize(), pgdir, start }; | 512 | guest_limit / getpagesize(), start }; |
558 | int fd; | 513 | int fd; |
559 | 514 | ||
560 | verbose("Guest: %p - %p (%#lx)\n", | 515 | verbose("Guest: %p - %p (%#lx)\n", |
@@ -1941,7 +1896,7 @@ int main(int argc, char *argv[]) | |||
1941 | { | 1896 | { |
1942 | /* Memory, top-level pagetable, code startpoint and size of the | 1897 | /* Memory, top-level pagetable, code startpoint and size of the |
1943 | * (optional) initrd. */ | 1898 | * (optional) initrd. */ |
1944 | unsigned long mem = 0, pgdir, start, initrd_size = 0; | 1899 | unsigned long mem = 0, start, initrd_size = 0; |
1945 | /* Two temporaries and the /dev/lguest file descriptor. */ | 1900 | /* Two temporaries and the /dev/lguest file descriptor. */ |
1946 | int i, c, lguest_fd; | 1901 | int i, c, lguest_fd; |
1947 | /* The boot information for the Guest. */ | 1902 | /* The boot information for the Guest. */ |
@@ -2040,9 +1995,6 @@ int main(int argc, char *argv[]) | |||
2040 | boot->hdr.type_of_loader = 0xFF; | 1995 | boot->hdr.type_of_loader = 0xFF; |
2041 | } | 1996 | } |
2042 | 1997 | ||
2043 | /* Set up the initial linear pagetables, starting below the initrd. */ | ||
2044 | pgdir = setup_pagetables(mem, initrd_size); | ||
2045 | |||
2046 | /* The Linux boot header contains an "E820" memory map: ours is a | 1998 | /* The Linux boot header contains an "E820" memory map: ours is a |
2047 | * simple, single region. */ | 1999 | * simple, single region. */ |
2048 | boot->e820_entries = 1; | 2000 | boot->e820_entries = 1; |
@@ -2064,7 +2016,7 @@ int main(int argc, char *argv[]) | |||
2064 | 2016 | ||
2065 | /* We tell the kernel to initialize the Guest: this returns the open | 2017 | /* We tell the kernel to initialize the Guest: this returns the open |
2066 | * /dev/lguest file descriptor. */ | 2018 | * /dev/lguest file descriptor. */ |
2067 | lguest_fd = tell_kernel(pgdir, start); | 2019 | lguest_fd = tell_kernel(start); |
2068 | 2020 | ||
2069 | /* We clone off a thread, which wakes the Launcher whenever one of the | 2021 | /* We clone off a thread, which wakes the Launcher whenever one of the |
2070 | * input file descriptors needs attention. We call this the Waker, and | 2022 | * 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 5c7cef34c9e7..10b9bd35a8ff 100644 --- a/arch/x86/lguest/i386_head.S +++ b/arch/x86/lguest/i386_head.S | |||
@@ -30,21 +30,6 @@ ENTRY(lguest_entry) | |||
30 | movl $lguest_data - __PAGE_OFFSET, %edx | 30 | movl $lguest_data - __PAGE_OFFSET, %edx |
31 | int $LGUEST_TRAP_ENTRY | 31 | int $LGUEST_TRAP_ENTRY |
32 | 32 | ||
33 | /* The Host put the toplevel pagetable in lguest_data.pgdir. The movsl | ||
34 | * instruction uses %esi implicitly as the source for the copy we're | ||
35 | * about to do. */ | ||
36 | movl lguest_data - __PAGE_OFFSET + LGUEST_DATA_pgdir, %esi | ||
37 | |||
38 | /* Copy first 32 entries of page directory to __PAGE_OFFSET entries. | ||
39 | * This means the first 128M of kernel memory will be mapped at | ||
40 | * PAGE_OFFSET where the kernel expects to run. This will get it far | ||
41 | * enough through boot to switch to its own pagetables. */ | ||
42 | movl $32, %ecx | ||
43 | movl %esi, %edi | ||
44 | addl $((__PAGE_OFFSET >> 22) * 4), %edi | ||
45 | rep | ||
46 | movsl | ||
47 | |||
48 | /* Set up the initial stack so we can run C code. */ | 33 | /* Set up the initial stack so we can run C code. */ |
49 | movl $(init_thread_union+THREAD_SIZE),%esp | 34 | movl $(init_thread_union+THREAD_SIZE),%esp |
50 | 35 | ||
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; |
diff --git a/include/linux/lguest_launcher.h b/include/linux/lguest_launcher.h index bd0eba760522..a53407a4165c 100644 --- a/include/linux/lguest_launcher.h +++ b/include/linux/lguest_launcher.h | |||
@@ -54,7 +54,7 @@ struct lguest_vqconfig { | |||
54 | /* Write command first word is a request. */ | 54 | /* Write command first word is a request. */ |
55 | enum lguest_req | 55 | enum lguest_req |
56 | { | 56 | { |
57 | LHREQ_INITIALIZE, /* + base, pfnlimit, pgdir, start */ | 57 | LHREQ_INITIALIZE, /* + base, pfnlimit, start */ |
58 | LHREQ_GETDMA, /* No longer used */ | 58 | LHREQ_GETDMA, /* No longer used */ |
59 | LHREQ_IRQ, /* + irq */ | 59 | LHREQ_IRQ, /* + irq */ |
60 | LHREQ_BREAK, /* + on/off flag (on blocks until someone does off) */ | 60 | LHREQ_BREAK, /* + on/off flag (on blocks until someone does off) */ |