ARM: KVM: sanitize freeing of HYP page tables
authorMarc Zyngier <marc.zyngier@arm.com>
Tue, 5 Mar 2013 02:43:17 +0000 (02:43 +0000)
committerChristoffer Dall <cdall@cs.columbia.edu>
Wed, 6 Mar 2013 23:59:20 +0000 (15:59 -0800)
Instead of trying to free everything from PAGE_OFFSET to the
top of memory, use the virt_addr_valid macro to check the
upper limit.

Also do the same for the vmalloc region where the IO mappings
are allocated.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <cdall@cs.columbia.edu>
arch/arm/kvm/mmu.c

index 0bf2c8551f75086261b50d6b0e649def4881f940..2f12e4056408e93c43976bd24d6a4109ac27753b 100644 (file)
@@ -85,34 +85,42 @@ static void free_ptes(pmd_t *pmd, unsigned long addr)
        }
 }
 
+static void free_hyp_pgd_entry(unsigned long addr)
+{
+       pgd_t *pgd;
+       pud_t *pud;
+       pmd_t *pmd;
+       unsigned long hyp_addr = KERN_TO_HYP(addr);
+
+       pgd = hyp_pgd + pgd_index(hyp_addr);
+       pud = pud_offset(pgd, hyp_addr);
+
+       if (pud_none(*pud))
+               return;
+       BUG_ON(pud_bad(*pud));
+
+       pmd = pmd_offset(pud, hyp_addr);
+       free_ptes(pmd, addr);
+       pmd_free(NULL, pmd);
+       pud_clear(pud);
+}
+
 /**
  * free_hyp_pmds - free a Hyp-mode level-2 tables and child level-3 tables
  *
  * Assumes this is a page table used strictly in Hyp-mode and therefore contains
- * only mappings in the kernel memory area, which is above PAGE_OFFSET.
+ * either mappings in the kernel memory area (above PAGE_OFFSET), or
+ * device mappings in the vmalloc range (from VMALLOC_START to VMALLOC_END).
  */
 void free_hyp_pmds(void)
 {
-       pgd_t *pgd;
-       pud_t *pud;
-       pmd_t *pmd;
        unsigned long addr;
 
        mutex_lock(&kvm_hyp_pgd_mutex);
-       for (addr = PAGE_OFFSET; addr != 0; addr += PGDIR_SIZE) {
-               unsigned long hyp_addr = KERN_TO_HYP(addr);
-               pgd = hyp_pgd + pgd_index(hyp_addr);
-               pud = pud_offset(pgd, hyp_addr);
-
-               if (pud_none(*pud))
-                       continue;
-               BUG_ON(pud_bad(*pud));
-
-               pmd = pmd_offset(pud, hyp_addr);
-               free_ptes(pmd, addr);
-               pmd_free(NULL, pmd);
-               pud_clear(pud);
-       }
+       for (addr = PAGE_OFFSET; virt_addr_valid(addr); addr += PGDIR_SIZE)
+               free_hyp_pgd_entry(addr);
+       for (addr = VMALLOC_START; is_vmalloc_addr((void*)addr); addr += PGDIR_SIZE)
+               free_hyp_pgd_entry(addr);
        mutex_unlock(&kvm_hyp_pgd_mutex);
 }