diff options
Diffstat (limited to 'virt')
-rw-r--r-- | virt/kvm/arm/mmu.c | 19 |
1 files changed, 15 insertions, 4 deletions
diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c index 2174244f6317..0417c8e2a81c 100644 --- a/virt/kvm/arm/mmu.c +++ b/virt/kvm/arm/mmu.c | |||
@@ -1292,7 +1292,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, | |||
1292 | unsigned long fault_status) | 1292 | unsigned long fault_status) |
1293 | { | 1293 | { |
1294 | int ret; | 1294 | int ret; |
1295 | bool write_fault, writable, hugetlb = false, force_pte = false; | 1295 | bool write_fault, exec_fault, writable, hugetlb = false, force_pte = false; |
1296 | unsigned long mmu_seq; | 1296 | unsigned long mmu_seq; |
1297 | gfn_t gfn = fault_ipa >> PAGE_SHIFT; | 1297 | gfn_t gfn = fault_ipa >> PAGE_SHIFT; |
1298 | struct kvm *kvm = vcpu->kvm; | 1298 | struct kvm *kvm = vcpu->kvm; |
@@ -1304,7 +1304,10 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, | |||
1304 | unsigned long flags = 0; | 1304 | unsigned long flags = 0; |
1305 | 1305 | ||
1306 | write_fault = kvm_is_write_fault(vcpu); | 1306 | write_fault = kvm_is_write_fault(vcpu); |
1307 | if (fault_status == FSC_PERM && !write_fault) { | 1307 | exec_fault = kvm_vcpu_trap_is_iabt(vcpu); |
1308 | VM_BUG_ON(write_fault && exec_fault); | ||
1309 | |||
1310 | if (fault_status == FSC_PERM && !write_fault && !exec_fault) { | ||
1308 | kvm_err("Unexpected L2 read permission error\n"); | 1311 | kvm_err("Unexpected L2 read permission error\n"); |
1309 | return -EFAULT; | 1312 | return -EFAULT; |
1310 | } | 1313 | } |
@@ -1398,7 +1401,11 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, | |||
1398 | kvm_set_pfn_dirty(pfn); | 1401 | kvm_set_pfn_dirty(pfn); |
1399 | } | 1402 | } |
1400 | clean_dcache_guest_page(vcpu, pfn, PMD_SIZE); | 1403 | clean_dcache_guest_page(vcpu, pfn, PMD_SIZE); |
1401 | invalidate_icache_guest_page(vcpu, pfn, PMD_SIZE); | 1404 | |
1405 | if (exec_fault) { | ||
1406 | new_pmd = kvm_s2pmd_mkexec(new_pmd); | ||
1407 | invalidate_icache_guest_page(vcpu, pfn, PMD_SIZE); | ||
1408 | } | ||
1402 | 1409 | ||
1403 | ret = stage2_set_pmd_huge(kvm, memcache, fault_ipa, &new_pmd); | 1410 | ret = stage2_set_pmd_huge(kvm, memcache, fault_ipa, &new_pmd); |
1404 | } else { | 1411 | } else { |
@@ -1410,7 +1417,11 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, | |||
1410 | mark_page_dirty(kvm, gfn); | 1417 | mark_page_dirty(kvm, gfn); |
1411 | } | 1418 | } |
1412 | clean_dcache_guest_page(vcpu, pfn, PAGE_SIZE); | 1419 | clean_dcache_guest_page(vcpu, pfn, PAGE_SIZE); |
1413 | invalidate_icache_guest_page(vcpu, pfn, PAGE_SIZE); | 1420 | |
1421 | if (exec_fault) { | ||
1422 | new_pte = kvm_s2pte_mkexec(new_pte); | ||
1423 | invalidate_icache_guest_page(vcpu, pfn, PAGE_SIZE); | ||
1424 | } | ||
1414 | 1425 | ||
1415 | ret = stage2_set_pte(kvm, memcache, fault_ipa, &new_pte, flags); | 1426 | ret = stage2_set_pte(kvm, memcache, fault_ipa, &new_pte, flags); |
1416 | } | 1427 | } |