Skip to content

Commit 91c703e

Browse files
Marc Zyngierchazy
authored andcommitted
arm: KVM: Add optimized PIPT icache flushing
Calling __cpuc_coherent_user_range to invalidate the icache on a PIPT icache machine has some pointless overhead, as it starts by cleaning the dcache to the PoU, while we're guaranteed to have already cleaned it to the PoC. As KVM is the only user of such a feature, let's implement some ad-hoc cache flushing in kvm_mmu.h. Should it become useful to other subsystems, it can be moved to a more global location. Reviewed-by: Christoffer Dall <[email protected]> Signed-off-by: Marc Zyngier <[email protected]> Signed-off-by: Christoffer Dall <[email protected]>
1 parent 4fee947 commit 91c703e

File tree

2 files changed

+31
-3
lines changed

2 files changed

+31
-3
lines changed

arch/arm/include/asm/kvm_hyp.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@
6868
#define HIFAR __ACCESS_CP15(c6, 4, c0, 2)
6969
#define HPFAR __ACCESS_CP15(c6, 4, c0, 4)
7070
#define ICIALLUIS __ACCESS_CP15(c7, 0, c1, 0)
71+
#define BPIALLIS __ACCESS_CP15(c7, 0, c1, 6)
72+
#define ICIMVAU __ACCESS_CP15(c7, 0, c5, 1)
7173
#define ATS1CPR __ACCESS_CP15(c7, 0, c8, 0)
7274
#define TLBIALLIS __ACCESS_CP15(c8, 0, c3, 0)
7375
#define TLBIALL __ACCESS_CP15(c8, 0, c7, 0)

arch/arm/include/asm/kvm_mmu.h

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737

3838
#include <linux/highmem.h>
3939
#include <asm/cacheflush.h>
40+
#include <asm/cputype.h>
41+
#include <asm/kvm_hyp.h>
4042
#include <asm/pgalloc.h>
4143
#include <asm/stage2_pgtable.h>
4244

@@ -157,6 +159,8 @@ static inline void __invalidate_icache_guest_page(struct kvm_vcpu *vcpu,
157159
kvm_pfn_t pfn,
158160
unsigned long size)
159161
{
162+
u32 iclsz;
163+
160164
/*
161165
* If we are going to insert an instruction page and the icache is
162166
* either VIPT or PIPT, there is a potential problem where the host
@@ -181,18 +185,40 @@ static inline void __invalidate_icache_guest_page(struct kvm_vcpu *vcpu,
181185
return;
182186
}
183187

184-
/* PIPT cache. As for the d-side, use a temporary kernel mapping. */
188+
/*
189+
* CTR IminLine contains Log2 of the number of words in the
190+
* cache line, so we can get the number of words as
191+
* 2 << (IminLine - 1). To get the number of bytes, we
192+
* multiply by 4 (the number of bytes in a 32-bit word), and
193+
* get 4 << (IminLine).
194+
*/
195+
iclsz = 4 << (read_cpuid(CPUID_CACHETYPE) & 0xf);
196+
185197
while (size) {
186198
void *va = kmap_atomic_pfn(pfn);
199+
void *end = va + PAGE_SIZE;
200+
void *addr = va;
187201

188-
__cpuc_coherent_user_range((unsigned long)va,
189-
(unsigned long)va + PAGE_SIZE);
202+
do {
203+
write_sysreg(addr, ICIMVAU);
204+
addr += iclsz;
205+
} while (addr < end);
206+
207+
dsb(ishst);
208+
isb();
190209

191210
size -= PAGE_SIZE;
192211
pfn++;
193212

194213
kunmap_atomic(va);
195214
}
215+
216+
/* Check if we need to invalidate the BTB */
217+
if ((read_cpuid_ext(CPUID_EXT_MMFR1) >> 28) != 4) {
218+
write_sysreg(0, BPIALLIS);
219+
dsb(ishst);
220+
isb();
221+
}
196222
}
197223

198224
static inline void __kvm_flush_dcache_pte(pte_t pte)

0 commit comments

Comments
 (0)