lguest: add infrastructure to check mappings.
authorRusty Russell <rusty@rustcorp.com.au>
Wed, 11 Feb 2015 04:45:09 +0000 (15:15 +1030)
committerRusty Russell <rusty@rustcorp.com.au>
Wed, 11 Feb 2015 06:17:31 +0000 (16:47 +1030)
We normally abort the guest unconditionally when it gives us a bad address,
but in the next patch we want to copy some bytes which may not be mapped.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
drivers/lguest/lg.h
drivers/lguest/page_tables.c

index 020fec5bb072035b4dad81fcdcf80e1777caa0f0..9da4f351e07794565386099e24757f1afceedc93 100644 (file)
@@ -202,6 +202,7 @@ void guest_set_pte(struct lg_cpu *cpu, unsigned long gpgdir,
 void map_switcher_in_guest(struct lg_cpu *cpu, struct lguest_pages *pages);
 bool demand_page(struct lg_cpu *cpu, unsigned long cr2, int errcode);
 void pin_page(struct lg_cpu *cpu, unsigned long vaddr);
+bool __guest_pa(struct lg_cpu *cpu, unsigned long vaddr, unsigned long *paddr);
 unsigned long guest_pa(struct lg_cpu *cpu, unsigned long vaddr);
 void page_table_guest_data_init(struct lg_cpu *cpu);
 
index e8b55c3a617042e91c2936c5576b45b6387f9fc4..69c35caa955aab097f24a050218753fb92d123f0 100644 (file)
@@ -647,7 +647,7 @@ void guest_pagetable_flush_user(struct lg_cpu *cpu)
 /*:*/
 
 /* We walk down the guest page tables to get a guest-physical address */
-unsigned long guest_pa(struct lg_cpu *cpu, unsigned long vaddr)
+bool __guest_pa(struct lg_cpu *cpu, unsigned long vaddr, unsigned long *paddr)
 {
        pgd_t gpgd;
        pte_t gpte;
@@ -656,31 +656,47 @@ unsigned long guest_pa(struct lg_cpu *cpu, unsigned long vaddr)
 #endif
 
        /* Still not set up?  Just map 1:1. */
-       if (unlikely(cpu->linear_pages))
-               return vaddr;
+       if (unlikely(cpu->linear_pages)) {
+               *paddr = vaddr;
+               return true;
+       }
 
        /* First step: get the top-level Guest page table entry. */
        gpgd = lgread(cpu, gpgd_addr(cpu, vaddr), pgd_t);
        /* Toplevel not present?  We can't map it in. */
-       if (!(pgd_flags(gpgd) & _PAGE_PRESENT)) {
-               kill_guest(cpu, "Bad address %#lx", vaddr);
-               return -1UL;
-       }
+       if (!(pgd_flags(gpgd) & _PAGE_PRESENT))
+               goto fail;
 
 #ifdef CONFIG_X86_PAE
        gpmd = lgread(cpu, gpmd_addr(gpgd, vaddr), pmd_t);
-       if (!(pmd_flags(gpmd) & _PAGE_PRESENT)) {
-               kill_guest(cpu, "Bad address %#lx", vaddr);
-               return -1UL;
-       }
+       if (!(pmd_flags(gpmd) & _PAGE_PRESENT))
+               goto fail;
        gpte = lgread(cpu, gpte_addr(cpu, gpmd, vaddr), pte_t);
 #else
        gpte = lgread(cpu, gpte_addr(cpu, gpgd, vaddr), pte_t);
 #endif
        if (!(pte_flags(gpte) & _PAGE_PRESENT))
-               kill_guest(cpu, "Bad address %#lx", vaddr);
+               goto fail;
+
+       *paddr = pte_pfn(gpte) * PAGE_SIZE | (vaddr & ~PAGE_MASK);
+       return true;
+
+fail:
+       *paddr = -1UL;
+       return false;
+}
 
-       return pte_pfn(gpte) * PAGE_SIZE | (vaddr & ~PAGE_MASK);
+/*
+ * This is the version we normally use: kills the Guest if it uses a
+ * bad address
+ */
+unsigned long guest_pa(struct lg_cpu *cpu, unsigned long vaddr)
+{
+       unsigned long paddr;
+
+       if (!__guest_pa(cpu, vaddr, &paddr))
+               kill_guest(cpu, "Bad address %#lx", vaddr);
+       return paddr;
 }
 
 /*