|
10 | 10 | #include <asm/kvm_hyp.h>
|
11 | 11 | #include <asm/kvm_mmu.h>
|
12 | 12 |
|
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 |
| - |
63 | 13 | static void fail_s1_walk(struct s1_walk_result *wr, u8 fst, bool s1ptw)
|
64 | 14 | {
|
65 | 15 | wr->fst = fst;
|
@@ -145,20 +95,15 @@ static void compute_s1poe(struct kvm_vcpu *vcpu, struct s1_walk_info *wi)
|
145 | 95 | }
|
146 | 96 | }
|
147 | 97 |
|
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, |
149 | 99 | struct s1_walk_result *wr, u64 va)
|
150 | 100 | {
|
151 | 101 | u64 hcr, sctlr, tcr, tg, ps, ia_bits, ttbr;
|
152 | 102 | unsigned int stride, x;
|
153 |
| - bool va55, tbi, lva, as_el0; |
| 103 | + bool va55, tbi, lva; |
154 | 104 |
|
155 | 105 | hcr = __vcpu_sys_reg(vcpu, HCR_EL2);
|
156 | 106 |
|
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 |
| - |
162 | 107 | va55 = va & BIT(55);
|
163 | 108 |
|
164 | 109 | 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,
|
319 | 264 |
|
320 | 265 | /* R_BNDVG and following statements */
|
321 | 266 | 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))) |
323 | 268 | goto transfault_l0;
|
324 | 269 |
|
325 | 270 | /* AArch64.S1StartLevel() */
|
@@ -1155,7 +1100,12 @@ static u64 handle_at_slow(struct kvm_vcpu *vcpu, u32 op, u64 vaddr)
|
1155 | 1100 | bool perm_fail = false;
|
1156 | 1101 | int ret, idx;
|
1157 | 1102 |
|
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); |
1159 | 1109 | if (ret)
|
1160 | 1110 | goto compute_par;
|
1161 | 1111 |
|
@@ -1457,3 +1407,31 @@ void __kvm_at_s12(struct kvm_vcpu *vcpu, u32 op, u64 vaddr)
|
1457 | 1407 | par = compute_par_s12(vcpu, par, &out);
|
1458 | 1408 | vcpu_write_sys_reg(vcpu, par, PAR_EL1);
|
1459 | 1409 | }
|
| 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