aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/lguest/page_tables.c
diff options
context:
space:
mode:
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;