aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorChristoffer Dall <christoffer.dall@linaro.org>2013-11-15 16:14:12 -0500
committerChristoffer Dall <christoffer.dall@linaro.org>2013-11-16 21:54:45 -0500
commit40c2729bab48e2832b17c1fa8af9db60e776131b (patch)
treea87b795e3d512d059c099beb1c1af8b28e4ba90f /arch
parent5e01dc7b26d9f24f39abace5da98ccbd6a5ceb52 (diff)
arm/arm64: KVM: Fix hyp mappings of vmalloc regions
Using virt_to_phys on percpu mappings is horribly wrong as it may be backed by vmalloc. Introduce kvm_kaddr_to_phys which translates both types of valid kernel addresses to the corresponding physical address. At the same time resolves a typing issue where we were storing the physical address as a 32 bit unsigned long (on arm), truncating the physical address for addresses above the 4GB limit. This caused breakage on Keystone. Cc: <stable@vger.kernel.org> [3.10+] Reported-by: Santosh Shilimkar <santosh.shilimkar@ti.com> Tested-by: Santosh Shilimkar <santosh.shilimkar@ti.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/kvm/mmu.c34
1 files changed, 28 insertions, 6 deletions
diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
index b0de86b56c13..cb79a5dd6d96 100644
--- a/arch/arm/kvm/mmu.c
+++ b/arch/arm/kvm/mmu.c
@@ -307,6 +307,17 @@ out:
307 return err; 307 return err;
308} 308}
309 309
310static phys_addr_t kvm_kaddr_to_phys(void *kaddr)
311{
312 if (!is_vmalloc_addr(kaddr)) {
313 BUG_ON(!virt_addr_valid(kaddr));
314 return __pa(kaddr);
315 } else {
316 return page_to_phys(vmalloc_to_page(kaddr)) +
317 offset_in_page(kaddr);
318 }
319}
320
310/** 321/**
311 * create_hyp_mappings - duplicate a kernel virtual address range in Hyp mode 322 * create_hyp_mappings - duplicate a kernel virtual address range in Hyp mode
312 * @from: The virtual kernel start address of the range 323 * @from: The virtual kernel start address of the range
@@ -318,16 +329,27 @@ out:
318 */ 329 */
319int create_hyp_mappings(void *from, void *to) 330int create_hyp_mappings(void *from, void *to)
320{ 331{
321 unsigned long phys_addr = virt_to_phys(from); 332 phys_addr_t phys_addr;
333 unsigned long virt_addr;
322 unsigned long start = KERN_TO_HYP((unsigned long)from); 334 unsigned long start = KERN_TO_HYP((unsigned long)from);
323 unsigned long end = KERN_TO_HYP((unsigned long)to); 335 unsigned long end = KERN_TO_HYP((unsigned long)to);
324 336
325 /* Check for a valid kernel memory mapping */ 337 start = start & PAGE_MASK;
326 if (!virt_addr_valid(from) || !virt_addr_valid(to - 1)) 338 end = PAGE_ALIGN(end);
327 return -EINVAL;
328 339
329 return __create_hyp_mappings(hyp_pgd, start, end, 340 for (virt_addr = start; virt_addr < end; virt_addr += PAGE_SIZE) {
330 __phys_to_pfn(phys_addr), PAGE_HYP); 341 int err;
342
343 phys_addr = kvm_kaddr_to_phys(from + virt_addr - start);
344 err = __create_hyp_mappings(hyp_pgd, virt_addr,
345 virt_addr + PAGE_SIZE,
346 __phys_to_pfn(phys_addr),
347 PAGE_HYP);
348 if (err)
349 return err;
350 }
351
352 return 0;
331} 353}
332 354
333/** 355/**