aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kvm
diff options
context:
space:
mode:
authorCatalin Marinas <catalin.marinas@arm.com>2016-04-13 12:57:37 -0400
committerChristoffer Dall <christoffer.dall@linaro.org>2016-05-09 16:23:08 -0400
commit06485053244480f5f403d8f89b8617bd7d549113 (patch)
tree4f1ef376aae6b679b941230953e8be8f801bed06 /arch/arm/kvm
parenta53d892dfb6f14f77c508e1027f5e1bdb400fd23 (diff)
kvm: arm64: Enable hardware updates of the Access Flag for Stage 2 page tables
The ARMv8.1 architecture extensions introduce support for hardware updates of the access and dirty information in page table entries. With VTCR_EL2.HA enabled (bit 21), when the CPU accesses an IPA with the PTE_AF bit cleared in the stage 2 page table, instead of raising an Access Flag fault to EL2 the CPU sets the actual page table entry bit (10). To ensure that kernel modifications to the page table do not inadvertently revert a bit set by hardware updates, certain Stage 2 software pte/pmd operations must be performed atomically. The main user of the AF bit is the kvm_age_hva() mechanism. The kvm_age_hva_handler() function performs a "test and clear young" action on the pte/pmd. This needs to be atomic in respect of automatic hardware updates of the AF bit. Since the AF bit is in the same position for both Stage 1 and Stage 2, the patch reuses the existing ptep_test_and_clear_young() functionality if __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG is defined. Otherwise, the existing pte_young/pte_mkold mechanism is preserved. The kvm_set_s2pte_readonly() (and the corresponding pmd equivalent) have to perform atomic modifications in order to avoid a race with updates of the AF bit. The arm64 implementation has been re-written using exclusives. Currently, kvm_set_s2pte_writable() (and pmd equivalent) take a pointer argument and modify the pte/pmd in place. However, these functions are only used on local variables rather than actual page table entries, so it makes more sense to follow the pte_mkwrite() approach for stage 1 attributes. The change to kvm_s2pte_mkwrite() makes it clear that these functions do not modify the actual page table entries. The (pte|pmd)_mkyoung() uses on Stage 2 entries (setting the AF bit explicitly) do not need to be modified since hardware updates of the dirty status are not supported by KVM, so there is no possibility of losing such information. Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> Cc: Paolo Bonzini <pbonzini@redhat.com> Acked-by: Marc Zyngier <marc.zyngier@arm.com> Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Diffstat (limited to 'arch/arm/kvm')
-rw-r--r--arch/arm/kvm/mmu.c46
1 files changed, 29 insertions, 17 deletions
diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
index 74b5d199f6b7..783e5ff0b32e 100644
--- a/arch/arm/kvm/mmu.c
+++ b/arch/arm/kvm/mmu.c
@@ -977,6 +977,27 @@ static int stage2_set_pte(struct kvm *kvm, struct kvm_mmu_memory_cache *cache,
977 return 0; 977 return 0;
978} 978}
979 979
980#ifndef __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
981static int stage2_ptep_test_and_clear_young(pte_t *pte)
982{
983 if (pte_young(*pte)) {
984 *pte = pte_mkold(*pte);
985 return 1;
986 }
987 return 0;
988}
989#else
990static int stage2_ptep_test_and_clear_young(pte_t *pte)
991{
992 return __ptep_test_and_clear_young(pte);
993}
994#endif
995
996static int stage2_pmdp_test_and_clear_young(pmd_t *pmd)
997{
998 return stage2_ptep_test_and_clear_young((pte_t *)pmd);
999}
1000
980/** 1001/**
981 * kvm_phys_addr_ioremap - map a device range to guest IPA 1002 * kvm_phys_addr_ioremap - map a device range to guest IPA
982 * 1003 *
@@ -1000,7 +1021,7 @@ int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa,
1000 pte_t pte = pfn_pte(pfn, PAGE_S2_DEVICE); 1021 pte_t pte = pfn_pte(pfn, PAGE_S2_DEVICE);
1001 1022
1002 if (writable) 1023 if (writable)
1003 kvm_set_s2pte_writable(&pte); 1024 pte = kvm_s2pte_mkwrite(pte);
1004 1025
1005 ret = mmu_topup_memory_cache(&cache, KVM_MMU_CACHE_MIN_PAGES, 1026 ret = mmu_topup_memory_cache(&cache, KVM_MMU_CACHE_MIN_PAGES,
1006 KVM_NR_MEM_OBJS); 1027 KVM_NR_MEM_OBJS);
@@ -1342,7 +1363,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
1342 pmd_t new_pmd = pfn_pmd(pfn, mem_type); 1363 pmd_t new_pmd = pfn_pmd(pfn, mem_type);
1343 new_pmd = pmd_mkhuge(new_pmd); 1364 new_pmd = pmd_mkhuge(new_pmd);
1344 if (writable) { 1365 if (writable) {
1345 kvm_set_s2pmd_writable(&new_pmd); 1366 new_pmd = kvm_s2pmd_mkwrite(new_pmd);
1346 kvm_set_pfn_dirty(pfn); 1367 kvm_set_pfn_dirty(pfn);
1347 } 1368 }
1348 coherent_cache_guest_page(vcpu, pfn, PMD_SIZE, fault_ipa_uncached); 1369 coherent_cache_guest_page(vcpu, pfn, PMD_SIZE, fault_ipa_uncached);
@@ -1351,7 +1372,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
1351 pte_t new_pte = pfn_pte(pfn, mem_type); 1372 pte_t new_pte = pfn_pte(pfn, mem_type);
1352 1373
1353 if (writable) { 1374 if (writable) {
1354 kvm_set_s2pte_writable(&new_pte); 1375 new_pte = kvm_s2pte_mkwrite(new_pte);
1355 kvm_set_pfn_dirty(pfn); 1376 kvm_set_pfn_dirty(pfn);
1356 mark_page_dirty(kvm, gfn); 1377 mark_page_dirty(kvm, gfn);
1357 } 1378 }
@@ -1370,6 +1391,8 @@ out_unlock:
1370 * Resolve the access fault by making the page young again. 1391 * Resolve the access fault by making the page young again.
1371 * Note that because the faulting entry is guaranteed not to be 1392 * Note that because the faulting entry is guaranteed not to be
1372 * cached in the TLB, we don't need to invalidate anything. 1393 * cached in the TLB, we don't need to invalidate anything.
1394 * Only the HW Access Flag updates are supported for Stage 2 (no DBM),
1395 * so there is no need for atomic (pte|pmd)_mkyoung operations.
1373 */ 1396 */
1374static void handle_access_fault(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa) 1397static void handle_access_fault(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa)
1375{ 1398{
@@ -1610,25 +1633,14 @@ static int kvm_age_hva_handler(struct kvm *kvm, gpa_t gpa, void *data)
1610 if (!pmd || pmd_none(*pmd)) /* Nothing there */ 1633 if (!pmd || pmd_none(*pmd)) /* Nothing there */
1611 return 0; 1634 return 0;
1612 1635
1613 if (pmd_thp_or_huge(*pmd)) { /* THP, HugeTLB */ 1636 if (pmd_thp_or_huge(*pmd)) /* THP, HugeTLB */
1614 if (pmd_young(*pmd)) { 1637 return stage2_pmdp_test_and_clear_young(pmd);
1615 *pmd = pmd_mkold(*pmd);
1616 return 1;
1617 }
1618
1619 return 0;
1620 }
1621 1638
1622 pte = pte_offset_kernel(pmd, gpa); 1639 pte = pte_offset_kernel(pmd, gpa);
1623 if (pte_none(*pte)) 1640 if (pte_none(*pte))
1624 return 0; 1641 return 0;
1625 1642
1626 if (pte_young(*pte)) { 1643 return stage2_ptep_test_and_clear_young(pte);
1627 *pte = pte_mkold(*pte); /* Just a page... */
1628 return 1;
1629 }
1630
1631 return 0;
1632} 1644}
1633 1645
1634static int kvm_test_age_hva_handler(struct kvm *kvm, gpa_t gpa, void *data) 1646static int kvm_test_age_hva_handler(struct kvm *kvm, gpa_t gpa, void *data)