aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/lguest/page_tables.c
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/page_tables.c
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/page_tables.c')
-rw-r--r--drivers/lguest/page_tables.c72
1 files changed, 70 insertions, 2 deletions
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;