diff options
author | Kristina Martsenko <kristina.martsenko@arm.com> | 2018-01-15 10:23:49 -0500 |
---|---|---|
committer | Catalin Marinas <catalin.marinas@arm.com> | 2018-01-15 13:20:26 -0500 |
commit | 98732d1b189b626a7593afd02dc3d2dc3f6c545a (patch) | |
tree | 480e6be8c4dd28aaf7d29ba8f5e6445fdd739737 /virt | |
parent | 6a205420758af5625429a2e77a2654abbf59ac09 (diff) |
KVM: arm/arm64: fix HYP ID map extension to 52 bits
Commit fa2a8445b1d3 incorrectly masks the index of the HYP ID map pgd
entry, causing a non-VHE kernel to hang during boot. This happens when
VA_BITS=48 and the ID map text is in 52-bit physical memory. In this
case we don't need an extra table level but need more entries in the
top-level table, so we need to map into hyp_pgd and need to use
__kvm_idmap_ptrs_per_pgd to mask in the extra bits. However,
__create_hyp_mappings currently masks by PTRS_PER_PGD instead.
Fix it so that we always use __kvm_idmap_ptrs_per_pgd for the HYP ID
map. This ensures that we use the larger mask for the top-level ID map
table when it has more entries. In all other cases, PTRS_PER_PGD is used
as normal.
Fixes: fa2a8445b1d3 ("arm64: allow ID map to be extended to 52 bits")
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Kristina Martsenko <kristina.martsenko@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Diffstat (limited to 'virt')
-rw-r--r-- | virt/kvm/arm/mmu.c | 18 |
1 files changed, 6 insertions, 12 deletions
diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c index 761787befd3b..876caf531d32 100644 --- a/virt/kvm/arm/mmu.c +++ b/virt/kvm/arm/mmu.c | |||
@@ -623,21 +623,15 @@ static int create_hyp_pud_mappings(pgd_t *pgd, unsigned long start, | |||
623 | return 0; | 623 | return 0; |
624 | } | 624 | } |
625 | 625 | ||
626 | static int __create_hyp_mappings(pgd_t *pgdp, | 626 | static int __create_hyp_mappings(pgd_t *pgdp, unsigned long ptrs_per_pgd, |
627 | unsigned long start, unsigned long end, | 627 | unsigned long start, unsigned long end, |
628 | unsigned long pfn, pgprot_t prot) | 628 | unsigned long pfn, pgprot_t prot) |
629 | { | 629 | { |
630 | pgd_t *pgd; | 630 | pgd_t *pgd; |
631 | pud_t *pud; | 631 | pud_t *pud; |
632 | unsigned long addr, next, ptrs_per_pgd = PTRS_PER_PGD; | 632 | unsigned long addr, next; |
633 | int err = 0; | 633 | int err = 0; |
634 | 634 | ||
635 | /* | ||
636 | * If it's not the hyp_pgd, fall back to the kvm idmap layout. | ||
637 | */ | ||
638 | if (pgdp != hyp_pgd) | ||
639 | ptrs_per_pgd = __kvm_idmap_ptrs_per_pgd(); | ||
640 | |||
641 | mutex_lock(&kvm_hyp_pgd_mutex); | 635 | mutex_lock(&kvm_hyp_pgd_mutex); |
642 | addr = start & PAGE_MASK; | 636 | addr = start & PAGE_MASK; |
643 | end = PAGE_ALIGN(end); | 637 | end = PAGE_ALIGN(end); |
@@ -705,8 +699,8 @@ int create_hyp_mappings(void *from, void *to, pgprot_t prot) | |||
705 | int err; | 699 | int err; |
706 | 700 | ||
707 | phys_addr = kvm_kaddr_to_phys(from + virt_addr - start); | 701 | phys_addr = kvm_kaddr_to_phys(from + virt_addr - start); |
708 | err = __create_hyp_mappings(hyp_pgd, virt_addr, | 702 | err = __create_hyp_mappings(hyp_pgd, PTRS_PER_PGD, |
709 | virt_addr + PAGE_SIZE, | 703 | virt_addr, virt_addr + PAGE_SIZE, |
710 | __phys_to_pfn(phys_addr), | 704 | __phys_to_pfn(phys_addr), |
711 | prot); | 705 | prot); |
712 | if (err) | 706 | if (err) |
@@ -737,7 +731,7 @@ int create_hyp_io_mappings(void *from, void *to, phys_addr_t phys_addr) | |||
737 | if (!is_vmalloc_addr(from) || !is_vmalloc_addr(to - 1)) | 731 | if (!is_vmalloc_addr(from) || !is_vmalloc_addr(to - 1)) |
738 | return -EINVAL; | 732 | return -EINVAL; |
739 | 733 | ||
740 | return __create_hyp_mappings(hyp_pgd, start, end, | 734 | return __create_hyp_mappings(hyp_pgd, PTRS_PER_PGD, start, end, |
741 | __phys_to_pfn(phys_addr), PAGE_HYP_DEVICE); | 735 | __phys_to_pfn(phys_addr), PAGE_HYP_DEVICE); |
742 | } | 736 | } |
743 | 737 | ||
@@ -1743,7 +1737,7 @@ static int kvm_map_idmap_text(pgd_t *pgd) | |||
1743 | int err; | 1737 | int err; |
1744 | 1738 | ||
1745 | /* Create the idmap in the boot page tables */ | 1739 | /* Create the idmap in the boot page tables */ |
1746 | err = __create_hyp_mappings(pgd, | 1740 | err = __create_hyp_mappings(pgd, __kvm_idmap_ptrs_per_pgd(), |
1747 | hyp_idmap_start, hyp_idmap_end, | 1741 | hyp_idmap_start, hyp_idmap_end, |
1748 | __phys_to_pfn(hyp_idmap_start), | 1742 | __phys_to_pfn(hyp_idmap_start), |
1749 | PAGE_HYP_EXEC); | 1743 | PAGE_HYP_EXEC); |