Skip to content

Commit b8e6251

Browse files
author
Marc Zyngier
committed
KVM: arm64: Add S1 IPA to page table level walker
Use the filtering hook infrastructure to implement a new walker that, for a given VA and an IPA, returns the level of the first occurence of this IPA in the walk from that VA. This will be used to improve our SEA syndrome reporting. Reviewed-by: Oliver Upton <[email protected]> Signed-off-by: Marc Zyngier <[email protected]>
1 parent 0c54714 commit b8e6251

File tree

2 files changed

+67
-0
lines changed

2 files changed

+67
-0
lines changed

arch/arm64/include/asm/kvm_nested.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,8 @@ struct s1_walk_result {
353353

354354
int __kvm_translate_va(struct kvm_vcpu *vcpu, struct s1_walk_info *wi,
355355
struct s1_walk_result *wr, u64 va);
356+
int __kvm_find_s1_desc_level(struct kvm_vcpu *vcpu, u64 va, u64 ipa,
357+
int *level);
356358

357359
/* VNCR management */
358360
int kvm_vcpu_allocate_vncr_tlb(struct kvm_vcpu *vcpu);

arch/arm64/kvm/at.c

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1569,3 +1569,68 @@ int __kvm_translate_va(struct kvm_vcpu *vcpu, struct s1_walk_info *wi,
15691569

15701570
return 0;
15711571
}
1572+
1573+
struct desc_match {
1574+
u64 ipa;
1575+
int level;
1576+
};
1577+
1578+
static int match_s1_desc(struct s1_walk_context *ctxt, void *priv)
1579+
{
1580+
struct desc_match *dm = priv;
1581+
u64 ipa = dm->ipa;
1582+
1583+
/* Use S1 granule alignment */
1584+
ipa &= GENMASK(51, ctxt->wi->pgshift);
1585+
1586+
/* Not the IPA we're looking for? Continue. */
1587+
if (ipa != ctxt->table_ipa)
1588+
return 0;
1589+
1590+
/* Note the level and interrupt the walk */
1591+
dm->level = ctxt->level;
1592+
return -EINTR;
1593+
}
1594+
1595+
int __kvm_find_s1_desc_level(struct kvm_vcpu *vcpu, u64 va, u64 ipa, int *level)
1596+
{
1597+
struct desc_match dm = {
1598+
.ipa = ipa,
1599+
};
1600+
struct s1_walk_info wi = {
1601+
.filter = &(struct s1_walk_filter){
1602+
.fn = match_s1_desc,
1603+
.priv = &dm,
1604+
},
1605+
.regime = TR_EL10,
1606+
.as_el0 = false,
1607+
.pan = false,
1608+
};
1609+
struct s1_walk_result wr = {};
1610+
int ret;
1611+
1612+
ret = setup_s1_walk(vcpu, &wi, &wr, va);
1613+
if (ret)
1614+
return ret;
1615+
1616+
/* We really expect the S1 MMU to be on here... */
1617+
if (WARN_ON_ONCE(wr.level == S1_MMU_DISABLED)) {
1618+
*level = 0;
1619+
return 0;
1620+
}
1621+
1622+
/* Walk the guest's PT, looking for a match along the way */
1623+
ret = walk_s1(vcpu, &wi, &wr, va);
1624+
switch (ret) {
1625+
case -EINTR:
1626+
/* We interrupted the walk on a match, return the level */
1627+
*level = dm.level;
1628+
return 0;
1629+
case 0:
1630+
/* The walk completed, we failed to find the entry */
1631+
return -ENOENT;
1632+
default:
1633+
/* Any other error... */
1634+
return ret;
1635+
}
1636+
}

0 commit comments

Comments
 (0)