Skip to content

Commit 34fa9de

Browse files
author
Marc Zyngier
committed
KVM: arm64: nv: Extract translation helper from the AT code
The address translation infrastructure is currently pretty tied to the AT emulation. However, we also need to features that require the use of VAs, such as VNCR_EL2 (and maybe one of these days SPE), meaning that we need a slightly more generic infrastructure. Start this by introducing a new helper (__kvm_translate_va()) that performs a S1 walk for a given translation regime, EL and PAN settings. Reviewed-by: Oliver Upton <oliver.upton@linux.dev> Link: https://lore.kernel.org/r/20250514103501.2225951-4-maz@kernel.org Signed-off-by: Marc Zyngier <maz@kernel.org>
1 parent 469c471 commit 34fa9de

File tree

2 files changed

+91
-59
lines changed

2 files changed

+91
-59
lines changed

arch/arm64/include/asm/kvm_nested.h

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,4 +245,58 @@ static inline unsigned int ps_to_output_size(unsigned int ps)
245245
}
246246
}
247247

248+
enum trans_regime {
249+
TR_EL10,
250+
TR_EL20,
251+
TR_EL2,
252+
};
253+
254+
struct s1_walk_info {
255+
u64 baddr;
256+
enum trans_regime regime;
257+
unsigned int max_oa_bits;
258+
unsigned int pgshift;
259+
unsigned int txsz;
260+
int sl;
261+
bool as_el0;
262+
bool hpd;
263+
bool e0poe;
264+
bool poe;
265+
bool pan;
266+
bool be;
267+
bool s2;
268+
};
269+
270+
struct s1_walk_result {
271+
union {
272+
struct {
273+
u64 desc;
274+
u64 pa;
275+
s8 level;
276+
u8 APTable;
277+
bool UXNTable;
278+
bool PXNTable;
279+
bool uwxn;
280+
bool uov;
281+
bool ur;
282+
bool uw;
283+
bool ux;
284+
bool pwxn;
285+
bool pov;
286+
bool pr;
287+
bool pw;
288+
bool px;
289+
};
290+
struct {
291+
u8 fst;
292+
bool ptw;
293+
bool s2;
294+
};
295+
};
296+
bool failed;
297+
};
298+
299+
int __kvm_translate_va(struct kvm_vcpu *vcpu, struct s1_walk_info *wi,
300+
struct s1_walk_result *wr, u64 va);
301+
248302
#endif /* __ARM64_KVM_NESTED_H */

arch/arm64/kvm/at.c

Lines changed: 37 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -10,56 +10,6 @@
1010
#include <asm/kvm_hyp.h>
1111
#include <asm/kvm_mmu.h>
1212

13-
enum trans_regime {
14-
TR_EL10,
15-
TR_EL20,
16-
TR_EL2,
17-
};
18-
19-
struct s1_walk_info {
20-
u64 baddr;
21-
enum trans_regime regime;
22-
unsigned int max_oa_bits;
23-
unsigned int pgshift;
24-
unsigned int txsz;
25-
int sl;
26-
bool hpd;
27-
bool e0poe;
28-
bool poe;
29-
bool pan;
30-
bool be;
31-
bool s2;
32-
};
33-
34-
struct s1_walk_result {
35-
union {
36-
struct {
37-
u64 desc;
38-
u64 pa;
39-
s8 level;
40-
u8 APTable;
41-
bool UXNTable;
42-
bool PXNTable;
43-
bool uwxn;
44-
bool uov;
45-
bool ur;
46-
bool uw;
47-
bool ux;
48-
bool pwxn;
49-
bool pov;
50-
bool pr;
51-
bool pw;
52-
bool px;
53-
};
54-
struct {
55-
u8 fst;
56-
bool ptw;
57-
bool s2;
58-
};
59-
};
60-
bool failed;
61-
};
62-
6313
static void fail_s1_walk(struct s1_walk_result *wr, u8 fst, bool s1ptw)
6414
{
6515
wr->fst = fst;
@@ -145,20 +95,15 @@ static void compute_s1poe(struct kvm_vcpu *vcpu, struct s1_walk_info *wi)
14595
}
14696
}
14797

148-
static int setup_s1_walk(struct kvm_vcpu *vcpu, u32 op, struct s1_walk_info *wi,
98+
static int setup_s1_walk(struct kvm_vcpu *vcpu, struct s1_walk_info *wi,
14999
struct s1_walk_result *wr, u64 va)
150100
{
151101
u64 hcr, sctlr, tcr, tg, ps, ia_bits, ttbr;
152102
unsigned int stride, x;
153-
bool va55, tbi, lva, as_el0;
103+
bool va55, tbi, lva;
154104

155105
hcr = __vcpu_sys_reg(vcpu, HCR_EL2);
156106

157-
wi->regime = compute_translation_regime(vcpu, op);
158-
as_el0 = (op == OP_AT_S1E0R || op == OP_AT_S1E0W);
159-
wi->pan = (op == OP_AT_S1E1RP || op == OP_AT_S1E1WP) &&
160-
(*vcpu_cpsr(vcpu) & PSR_PAN_BIT);
161-
162107
va55 = va & BIT(55);
163108

164109
if (wi->regime == TR_EL2 && va55)
@@ -319,7 +264,7 @@ static int setup_s1_walk(struct kvm_vcpu *vcpu, u32 op, struct s1_walk_info *wi,
319264

320265
/* R_BNDVG and following statements */
321266
if (kvm_has_feat(vcpu->kvm, ID_AA64MMFR2_EL1, E0PD, IMP) &&
322-
as_el0 && (tcr & (va55 ? TCR_E0PD1 : TCR_E0PD0)))
267+
wi->as_el0 && (tcr & (va55 ? TCR_E0PD1 : TCR_E0PD0)))
323268
goto transfault_l0;
324269

325270
/* AArch64.S1StartLevel() */
@@ -1155,7 +1100,12 @@ static u64 handle_at_slow(struct kvm_vcpu *vcpu, u32 op, u64 vaddr)
11551100
bool perm_fail = false;
11561101
int ret, idx;
11571102

1158-
ret = setup_s1_walk(vcpu, op, &wi, &wr, vaddr);
1103+
wi.regime = compute_translation_regime(vcpu, op);
1104+
wi.as_el0 = (op == OP_AT_S1E0R || op == OP_AT_S1E0W);
1105+
wi.pan = (op == OP_AT_S1E1RP || op == OP_AT_S1E1WP) &&
1106+
(*vcpu_cpsr(vcpu) & PSR_PAN_BIT);
1107+
1108+
ret = setup_s1_walk(vcpu, &wi, &wr, vaddr);
11591109
if (ret)
11601110
goto compute_par;
11611111

@@ -1457,3 +1407,31 @@ void __kvm_at_s12(struct kvm_vcpu *vcpu, u32 op, u64 vaddr)
14571407
par = compute_par_s12(vcpu, par, &out);
14581408
vcpu_write_sys_reg(vcpu, par, PAR_EL1);
14591409
}
1410+
1411+
/*
1412+
* Translate a VA for a given EL in a given translation regime, with
1413+
* or without PAN. This requires wi->{regime, as_el0, pan} to be
1414+
* set. The rest of the wi and wr should be 0-initialised.
1415+
*/
1416+
int __kvm_translate_va(struct kvm_vcpu *vcpu, struct s1_walk_info *wi,
1417+
struct s1_walk_result *wr, u64 va)
1418+
{
1419+
int ret;
1420+
1421+
ret = setup_s1_walk(vcpu, wi, wr, va);
1422+
if (ret)
1423+
return ret;
1424+
1425+
if (wr->level == S1_MMU_DISABLED) {
1426+
wr->ur = wr->uw = wr->ux = true;
1427+
wr->pr = wr->pw = wr->px = true;
1428+
} else {
1429+
ret = walk_s1(vcpu, wi, wr, va);
1430+
if (ret)
1431+
return ret;
1432+
1433+
compute_s1_permissions(vcpu, wi, wr);
1434+
}
1435+
1436+
return 0;
1437+
}

0 commit comments

Comments
 (0)