1
2
3
4
5
6
7#include <linux/irqflags.h>
8
9#include <asm/kvm_hyp.h>
10#include <asm/kvm_mmu.h>
11#include <asm/tlbflush.h>
12
13struct tlb_inv_context {
14 unsigned long flags;
15 u64 tcr;
16 u64 sctlr;
17};
18
19static void __tlb_switch_to_guest(struct kvm_s2_mmu *mmu,
20 struct tlb_inv_context *cxt)
21{
22 u64 val;
23
24 local_irq_save(cxt->flags);
25
26 if (cpus_have_final_cap(ARM64_WORKAROUND_SPECULATIVE_AT)) {
27
28
29
30
31
32
33
34
35
36 val = cxt->tcr = read_sysreg_el1(SYS_TCR);
37 val |= TCR_EPD1_MASK | TCR_EPD0_MASK;
38 write_sysreg_el1(val, SYS_TCR);
39 val = cxt->sctlr = read_sysreg_el1(SYS_SCTLR);
40 val |= SCTLR_ELx_M;
41 write_sysreg_el1(val, SYS_SCTLR);
42 }
43
44
45
46
47
48
49
50
51
52
53
54
55
56 __load_stage2(mmu, mmu->arch);
57 val = read_sysreg(hcr_el2);
58 val &= ~HCR_TGE;
59 write_sysreg(val, hcr_el2);
60 isb();
61}
62
63static void __tlb_switch_to_host(struct tlb_inv_context *cxt)
64{
65
66
67
68
69 write_sysreg(0, vttbr_el2);
70 write_sysreg(HCR_HOST_VHE_FLAGS, hcr_el2);
71 isb();
72
73 if (cpus_have_final_cap(ARM64_WORKAROUND_SPECULATIVE_AT)) {
74
75 write_sysreg_el1(cxt->tcr, SYS_TCR);
76 write_sysreg_el1(cxt->sctlr, SYS_SCTLR);
77 }
78
79 local_irq_restore(cxt->flags);
80}
81
82void __kvm_tlb_flush_vmid_ipa(struct kvm_s2_mmu *mmu,
83 phys_addr_t ipa, int level)
84{
85 struct tlb_inv_context cxt;
86
87 dsb(ishst);
88
89
90 __tlb_switch_to_guest(mmu, &cxt);
91
92
93
94
95
96
97 ipa >>= 12;
98 __tlbi_level(ipas2e1is, ipa, level);
99
100
101
102
103
104
105
106 dsb(ish);
107 __tlbi(vmalle1is);
108 dsb(ish);
109 isb();
110
111 __tlb_switch_to_host(&cxt);
112}
113
114void __kvm_tlb_flush_vmid(struct kvm_s2_mmu *mmu)
115{
116 struct tlb_inv_context cxt;
117
118 dsb(ishst);
119
120
121 __tlb_switch_to_guest(mmu, &cxt);
122
123 __tlbi(vmalls12e1is);
124 dsb(ish);
125 isb();
126
127 __tlb_switch_to_host(&cxt);
128}
129
130void __kvm_flush_cpu_context(struct kvm_s2_mmu *mmu)
131{
132 struct tlb_inv_context cxt;
133
134
135 __tlb_switch_to_guest(mmu, &cxt);
136
137 __tlbi(vmalle1);
138 asm volatile("ic iallu");
139 dsb(nsh);
140 isb();
141
142 __tlb_switch_to_host(&cxt);
143}
144
145void __kvm_flush_vm_context(void)
146{
147 dsb(ishst);
148 __tlbi(alle1is);
149
150
151
152
153
154
155
156
157
158
159 if (icache_is_vpipt())
160 asm volatile("ic ialluis");
161
162 dsb(ish);
163}
164