Skip to content

Commit 19cffd1

Browse files
willdeaconOliver Upton
authored andcommitted
KVM: arm64: Invert KVM_PGTABLE_WALK_HANDLE_FAULT to fix pKVM walkers
Commit ddcadb2 ("KVM: arm64: Ignore EAGAIN for walks outside of a fault") introduced a new walker flag ('KVM_PGTABLE_WALK_HANDLE_FAULT') to KVM's page-table code. When set, the walk logic maintains its previous behaviour of terminating a walk as soon as the visitor callback returns an error. However, when the flag is clear, the walk will continue if the visitor returns -EAGAIN and the error is then suppressed and returned as zero to the caller. Clearing the flag is beneficial when write-protecting a range of IPAs with kvm_pgtable_stage2_wrprotect() but is not useful in any other cases, either because we are operating on a single page (e.g. kvm_pgtable_stage2_mkyoung() or kvm_phys_addr_ioremap()) or because the early termination is desirable (e.g. when mapping pages from a fault in user_mem_abort()). Subsequently, commit e912efe ("KVM: arm64: Introduce the EL1 pKVM MMU") hooked up pKVM's hypercall interface to the MMU code at EL1 but failed to propagate any of the walker flags. As a result, page-table walks at EL2 fail to set KVM_PGTABLE_WALK_HANDLE_FAULT even when the early termination semantics are desirable on the fault handling path. Rather than complicate the pKVM hypercall interface, invert the flag so that the whole thing can be simplified and only pass the new flag ('KVM_PGTABLE_WALK_IGNORE_EAGAIN') from the wrprotect code. Cc: Fuad Tabba <tabba@google.com> Cc: Quentin Perret <qperret@google.com> Cc: Marc Zyngier <maz@kernel.org> Cc: Oliver Upton <oupton@kernel.org> Reviewed-by: Marc Zyngier <maz@kernel.org> Fixes: fce886a ("KVM: arm64: Plumb the pKVM MMU in KVM") Signed-off-by: Will Deacon <will@kernel.org> Reviewed-by: Quentin Perret <qperret@google.com> Link: https://msgid.link/20260105154939.11041-2-will@kernel.org Signed-off-by: Oliver Upton <oupton@kernel.org>
1 parent 8636483 commit 19cffd1

File tree

3 files changed

+9
-10
lines changed

3 files changed

+9
-10
lines changed

arch/arm64/include/asm/kvm_pgtable.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -301,8 +301,8 @@ typedef bool (*kvm_pgtable_force_pte_cb_t)(u64 addr, u64 end,
301301
* children.
302302
* @KVM_PGTABLE_WALK_SHARED: Indicates the page-tables may be shared
303303
* with other software walkers.
304-
* @KVM_PGTABLE_WALK_HANDLE_FAULT: Indicates the page-table walk was
305-
* invoked from a fault handler.
304+
* @KVM_PGTABLE_WALK_IGNORE_EAGAIN: Don't terminate the walk early if
305+
* the walker returns -EAGAIN.
306306
* @KVM_PGTABLE_WALK_SKIP_BBM_TLBI: Visit and update table entries
307307
* without Break-before-make's
308308
* TLB invalidation.
@@ -315,7 +315,7 @@ enum kvm_pgtable_walk_flags {
315315
KVM_PGTABLE_WALK_TABLE_PRE = BIT(1),
316316
KVM_PGTABLE_WALK_TABLE_POST = BIT(2),
317317
KVM_PGTABLE_WALK_SHARED = BIT(3),
318-
KVM_PGTABLE_WALK_HANDLE_FAULT = BIT(4),
318+
KVM_PGTABLE_WALK_IGNORE_EAGAIN = BIT(4),
319319
KVM_PGTABLE_WALK_SKIP_BBM_TLBI = BIT(5),
320320
KVM_PGTABLE_WALK_SKIP_CMO = BIT(6),
321321
};

arch/arm64/kvm/hyp/pgtable.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ static bool kvm_pgtable_walk_continue(const struct kvm_pgtable_walker *walker,
144144
* page table walk.
145145
*/
146146
if (r == -EAGAIN)
147-
return !(walker->flags & KVM_PGTABLE_WALK_HANDLE_FAULT);
147+
return walker->flags & KVM_PGTABLE_WALK_IGNORE_EAGAIN;
148148

149149
return !r;
150150
}
@@ -1262,7 +1262,8 @@ int kvm_pgtable_stage2_wrprotect(struct kvm_pgtable *pgt, u64 addr, u64 size)
12621262
{
12631263
return stage2_update_leaf_attrs(pgt, addr, size, 0,
12641264
KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W,
1265-
NULL, NULL, 0);
1265+
NULL, NULL,
1266+
KVM_PGTABLE_WALK_IGNORE_EAGAIN);
12661267
}
12671268

12681269
void kvm_pgtable_stage2_mkyoung(struct kvm_pgtable *pgt, u64 addr,

arch/arm64/kvm/mmu.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1563,14 +1563,12 @@ static void adjust_nested_exec_perms(struct kvm *kvm,
15631563
*prot &= ~KVM_PGTABLE_PROT_PX;
15641564
}
15651565

1566-
#define KVM_PGTABLE_WALK_MEMABORT_FLAGS (KVM_PGTABLE_WALK_HANDLE_FAULT | KVM_PGTABLE_WALK_SHARED)
1567-
15681566
static int gmem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
15691567
struct kvm_s2_trans *nested,
15701568
struct kvm_memory_slot *memslot, bool is_perm)
15711569
{
15721570
bool write_fault, exec_fault, writable;
1573-
enum kvm_pgtable_walk_flags flags = KVM_PGTABLE_WALK_MEMABORT_FLAGS;
1571+
enum kvm_pgtable_walk_flags flags = KVM_PGTABLE_WALK_SHARED;
15741572
enum kvm_pgtable_prot prot = KVM_PGTABLE_PROT_R;
15751573
struct kvm_pgtable *pgt = vcpu->arch.hw_mmu->pgt;
15761574
unsigned long mmu_seq;
@@ -1665,7 +1663,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
16651663
struct kvm_pgtable *pgt;
16661664
struct page *page;
16671665
vm_flags_t vm_flags;
1668-
enum kvm_pgtable_walk_flags flags = KVM_PGTABLE_WALK_MEMABORT_FLAGS;
1666+
enum kvm_pgtable_walk_flags flags = KVM_PGTABLE_WALK_SHARED;
16691667

16701668
if (fault_is_perm)
16711669
fault_granule = kvm_vcpu_trap_get_perm_fault_granule(vcpu);
@@ -1933,7 +1931,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
19331931
/* Resolve the access fault by making the page young again. */
19341932
static void handle_access_fault(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa)
19351933
{
1936-
enum kvm_pgtable_walk_flags flags = KVM_PGTABLE_WALK_HANDLE_FAULT | KVM_PGTABLE_WALK_SHARED;
1934+
enum kvm_pgtable_walk_flags flags = KVM_PGTABLE_WALK_SHARED;
19371935
struct kvm_s2_mmu *mmu;
19381936

19391937
trace_kvm_access_fault(fault_ipa);

0 commit comments

Comments
 (0)