aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2018-04-06 07:27:28 -0400
committerMarc Zyngier <marc.zyngier@arm.com>2018-07-09 06:37:41 -0400
commite48d53a91f6e90873e21a5ca5e8c0d7a9f8936a4 (patch)
tree8226aa3bd5ae8eefb39ad90d66fff26917bd747b
parent1e4b044d22517cae7047c99038abb444423243ca (diff)
arm64: KVM: Add support for Stage-2 control of memory types and cacheability
Up to ARMv8.3, the combinaison of Stage-1 and Stage-2 attributes results in the strongest attribute of the two stages. This means that the hypervisor has to perform quite a lot of cache maintenance just in case the guest has some non-cacheable mappings around. ARMv8.4 solves this problem by offering a different mode (FWB) where Stage-2 has total control over the memory attribute (this is limited to systems where both I/O and instruction fetches are coherent with the dcache). This is achieved by having a different set of memory attributes in the page tables, and a new bit set in HCR_EL2. On such a system, we can then safely sidestep any form of dcache management. Acked-by: Catalin Marinas <catalin.marinas@arm.com> Reviewed-by: Christoffer Dall <christoffer.dall@arm.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
-rw-r--r--arch/arm64/include/asm/cpucaps.h3
-rw-r--r--arch/arm64/include/asm/kvm_arm.h1
-rw-r--r--arch/arm64/include/asm/kvm_emulate.h2
-rw-r--r--arch/arm64/include/asm/kvm_mmu.h27
-rw-r--r--arch/arm64/include/asm/memory.h7
-rw-r--r--arch/arm64/include/asm/pgtable-prot.h14
-rw-r--r--arch/arm64/include/asm/sysreg.h1
-rw-r--r--arch/arm64/kernel/cpufeature.c20
-rw-r--r--virt/kvm/arm/mmu.c4
9 files changed, 70 insertions, 9 deletions
diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h
index 8a699c708fc9..ed84d6536830 100644
--- a/arch/arm64/include/asm/cpucaps.h
+++ b/arch/arm64/include/asm/cpucaps.h
@@ -49,7 +49,8 @@
49#define ARM64_HAS_CACHE_DIC 28 49#define ARM64_HAS_CACHE_DIC 28
50#define ARM64_HW_DBM 29 50#define ARM64_HW_DBM 29
51#define ARM64_SSBD 30 51#define ARM64_SSBD 30
52#define ARM64_HAS_STAGE2_FWB 31
52 53
53#define ARM64_NCAPS 31 54#define ARM64_NCAPS 32
54 55
55#endif /* __ASM_CPUCAPS_H */ 56#endif /* __ASM_CPUCAPS_H */
diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index 6dd285e979c9..aa45df752a16 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -23,6 +23,7 @@
23#include <asm/types.h> 23#include <asm/types.h>
24 24
25/* Hyp Configuration Register (HCR) bits */ 25/* Hyp Configuration Register (HCR) bits */
26#define HCR_FWB (UL(1) << 46)
26#define HCR_TEA (UL(1) << 37) 27#define HCR_TEA (UL(1) << 37)
27#define HCR_TERR (UL(1) << 36) 28#define HCR_TERR (UL(1) << 36)
28#define HCR_TLOR (UL(1) << 35) 29#define HCR_TLOR (UL(1) << 35)
diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 1dab3a984608..dd98fdf33d99 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -63,6 +63,8 @@ static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
63 /* trap error record accesses */ 63 /* trap error record accesses */
64 vcpu->arch.hcr_el2 |= HCR_TERR; 64 vcpu->arch.hcr_el2 |= HCR_TERR;
65 } 65 }
66 if (cpus_have_const_cap(ARM64_HAS_STAGE2_FWB))
67 vcpu->arch.hcr_el2 |= HCR_FWB;
66 68
67 if (test_bit(KVM_ARM_VCPU_EL1_32BIT, vcpu->arch.features)) 69 if (test_bit(KVM_ARM_VCPU_EL1_32BIT, vcpu->arch.features))
68 vcpu->arch.hcr_el2 &= ~HCR_RW; 70 vcpu->arch.hcr_el2 &= ~HCR_RW;
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index fb9a7127bb75..bac9f016736b 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -267,6 +267,15 @@ static inline void __clean_dcache_guest_page(kvm_pfn_t pfn, unsigned long size)
267{ 267{
268 void *va = page_address(pfn_to_page(pfn)); 268 void *va = page_address(pfn_to_page(pfn));
269 269
270 /*
271 * With FWB, we ensure that the guest always accesses memory using
272 * cacheable attributes, and we don't have to clean to PoC when
273 * faulting in pages. Furthermore, FWB implies IDC, so cleaning to
274 * PoU is not required either in this case.
275 */
276 if (cpus_have_const_cap(ARM64_HAS_STAGE2_FWB))
277 return;
278
270 kvm_flush_dcache_to_poc(va, size); 279 kvm_flush_dcache_to_poc(va, size);
271} 280}
272 281
@@ -287,20 +296,26 @@ static inline void __invalidate_icache_guest_page(kvm_pfn_t pfn,
287 296
288static inline void __kvm_flush_dcache_pte(pte_t pte) 297static inline void __kvm_flush_dcache_pte(pte_t pte)
289{ 298{
290 struct page *page = pte_page(pte); 299 if (!cpus_have_const_cap(ARM64_HAS_STAGE2_FWB)) {
291 kvm_flush_dcache_to_poc(page_address(page), PAGE_SIZE); 300 struct page *page = pte_page(pte);
301 kvm_flush_dcache_to_poc(page_address(page), PAGE_SIZE);
302 }
292} 303}
293 304
294static inline void __kvm_flush_dcache_pmd(pmd_t pmd) 305static inline void __kvm_flush_dcache_pmd(pmd_t pmd)
295{ 306{
296 struct page *page = pmd_page(pmd); 307 if (!cpus_have_const_cap(ARM64_HAS_STAGE2_FWB)) {
297 kvm_flush_dcache_to_poc(page_address(page), PMD_SIZE); 308 struct page *page = pmd_page(pmd);
309 kvm_flush_dcache_to_poc(page_address(page), PMD_SIZE);
310 }
298} 311}
299 312
300static inline void __kvm_flush_dcache_pud(pud_t pud) 313static inline void __kvm_flush_dcache_pud(pud_t pud)
301{ 314{
302 struct page *page = pud_page(pud); 315 if (!cpus_have_const_cap(ARM64_HAS_STAGE2_FWB)) {
303 kvm_flush_dcache_to_poc(page_address(page), PUD_SIZE); 316 struct page *page = pud_page(pud);
317 kvm_flush_dcache_to_poc(page_address(page), PUD_SIZE);
318 }
304} 319}
305 320
306#define kvm_virt_to_phys(x) __pa_symbol(x) 321#define kvm_virt_to_phys(x) __pa_symbol(x)
diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
index 49d99214f43c..b96442960aea 100644
--- a/arch/arm64/include/asm/memory.h
+++ b/arch/arm64/include/asm/memory.h
@@ -155,6 +155,13 @@
155#define MT_S2_NORMAL 0xf 155#define MT_S2_NORMAL 0xf
156#define MT_S2_DEVICE_nGnRE 0x1 156#define MT_S2_DEVICE_nGnRE 0x1
157 157
158/*
159 * Memory types for Stage-2 translation when ID_AA64MMFR2_EL1.FWB is 0001
160 * Stage-2 enforces Normal-WB and Device-nGnRE
161 */
162#define MT_S2_FWB_NORMAL 6
163#define MT_S2_FWB_DEVICE_nGnRE 1
164
158#ifdef CONFIG_ARM64_4K_PAGES 165#ifdef CONFIG_ARM64_4K_PAGES
159#define IOREMAP_MAX_ORDER (PUD_SHIFT) 166#define IOREMAP_MAX_ORDER (PUD_SHIFT)
160#else 167#else
diff --git a/arch/arm64/include/asm/pgtable-prot.h b/arch/arm64/include/asm/pgtable-prot.h
index 108ecad7acc5..c66c3047400e 100644
--- a/arch/arm64/include/asm/pgtable-prot.h
+++ b/arch/arm64/include/asm/pgtable-prot.h
@@ -67,8 +67,18 @@
67#define PAGE_HYP_RO __pgprot(_HYP_PAGE_DEFAULT | PTE_HYP | PTE_RDONLY | PTE_HYP_XN) 67#define PAGE_HYP_RO __pgprot(_HYP_PAGE_DEFAULT | PTE_HYP | PTE_RDONLY | PTE_HYP_XN)
68#define PAGE_HYP_DEVICE __pgprot(PROT_DEVICE_nGnRE | PTE_HYP) 68#define PAGE_HYP_DEVICE __pgprot(PROT_DEVICE_nGnRE | PTE_HYP)
69 69
70#define PAGE_S2 __pgprot(_PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_NORMAL) | PTE_S2_RDONLY | PTE_S2_XN) 70#define PAGE_S2_MEMATTR(attr) \
71#define PAGE_S2_DEVICE __pgprot(_PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_DEVICE_nGnRE) | PTE_S2_RDONLY | PTE_S2_XN) 71 ({ \
72 u64 __val; \
73 if (cpus_have_const_cap(ARM64_HAS_STAGE2_FWB)) \
74 __val = PTE_S2_MEMATTR(MT_S2_FWB_ ## attr); \
75 else \
76 __val = PTE_S2_MEMATTR(MT_S2_ ## attr); \
77 __val; \
78 })
79
80#define PAGE_S2 __pgprot(_PROT_DEFAULT | PAGE_S2_MEMATTR(NORMAL) | PTE_S2_RDONLY | PTE_S2_XN)
81#define PAGE_S2_DEVICE __pgprot(_PROT_DEFAULT | PAGE_S2_MEMATTR(DEVICE_nGnRE) | PTE_S2_RDONLY | PTE_S2_XN)
72 82
73#define PAGE_NONE __pgprot(((_PAGE_DEFAULT) & ~PTE_VALID) | PTE_PROT_NONE | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_UXN) 83#define PAGE_NONE __pgprot(((_PAGE_DEFAULT) & ~PTE_VALID) | PTE_PROT_NONE | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_UXN)
74#define PAGE_SHARED __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_WRITE) 84#define PAGE_SHARED __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_WRITE)
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index a8f84812c6e8..98af0b37fb31 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -576,6 +576,7 @@
576#define ID_AA64MMFR1_VMIDBITS_16 2 576#define ID_AA64MMFR1_VMIDBITS_16 2
577 577
578/* id_aa64mmfr2 */ 578/* id_aa64mmfr2 */
579#define ID_AA64MMFR2_FWB_SHIFT 40
579#define ID_AA64MMFR2_AT_SHIFT 32 580#define ID_AA64MMFR2_AT_SHIFT 32
580#define ID_AA64MMFR2_LVA_SHIFT 16 581#define ID_AA64MMFR2_LVA_SHIFT 16
581#define ID_AA64MMFR2_IESB_SHIFT 12 582#define ID_AA64MMFR2_IESB_SHIFT 12
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index f24892a40d2c..d58d1f0abe16 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -192,6 +192,7 @@ static const struct arm64_ftr_bits ftr_id_aa64mmfr1[] = {
192}; 192};
193 193
194static const struct arm64_ftr_bits ftr_id_aa64mmfr2[] = { 194static const struct arm64_ftr_bits ftr_id_aa64mmfr2[] = {
195 ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64MMFR2_FWB_SHIFT, 4, 0),
195 ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64MMFR2_AT_SHIFT, 4, 0), 196 ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64MMFR2_AT_SHIFT, 4, 0),
196 ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64MMFR2_LVA_SHIFT, 4, 0), 197 ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64MMFR2_LVA_SHIFT, 4, 0),
197 ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64MMFR2_IESB_SHIFT, 4, 0), 198 ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64MMFR2_IESB_SHIFT, 4, 0),
@@ -1026,6 +1027,14 @@ static void cpu_copy_el2regs(const struct arm64_cpu_capabilities *__unused)
1026} 1027}
1027#endif 1028#endif
1028 1029
1030static void cpu_has_fwb(const struct arm64_cpu_capabilities *__unused)
1031{
1032 u64 val = read_sysreg_s(SYS_CLIDR_EL1);
1033
1034 /* Check that CLIDR_EL1.LOU{U,IS} are both 0 */
1035 WARN_ON(val & (7 << 27 | 7 << 21));
1036}
1037
1029static const struct arm64_cpu_capabilities arm64_features[] = { 1038static const struct arm64_cpu_capabilities arm64_features[] = {
1030 { 1039 {
1031 .desc = "GIC system register CPU interface", 1040 .desc = "GIC system register CPU interface",
@@ -1182,6 +1191,17 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
1182 .type = ARM64_CPUCAP_SYSTEM_FEATURE, 1191 .type = ARM64_CPUCAP_SYSTEM_FEATURE,
1183 .matches = has_cache_dic, 1192 .matches = has_cache_dic,
1184 }, 1193 },
1194 {
1195 .desc = "Stage-2 Force Write-Back",
1196 .type = ARM64_CPUCAP_SYSTEM_FEATURE,
1197 .capability = ARM64_HAS_STAGE2_FWB,
1198 .sys_reg = SYS_ID_AA64MMFR2_EL1,
1199 .sign = FTR_UNSIGNED,
1200 .field_pos = ID_AA64MMFR2_FWB_SHIFT,
1201 .min_field_value = 1,
1202 .matches = has_cpuid_feature,
1203 .cpu_enable = cpu_has_fwb,
1204 },
1185#ifdef CONFIG_ARM64_HW_AFDBM 1205#ifdef CONFIG_ARM64_HW_AFDBM
1186 { 1206 {
1187 /* 1207 /*
diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c
index 1d90d79706bd..ea7314296ad1 100644
--- a/virt/kvm/arm/mmu.c
+++ b/virt/kvm/arm/mmu.c
@@ -196,6 +196,10 @@ static void clear_stage2_pmd_entry(struct kvm *kvm, pmd_t *pmd, phys_addr_t addr
196 * This is why right after unmapping a page/section and invalidating 196 * This is why right after unmapping a page/section and invalidating
197 * the corresponding TLBs, we call kvm_flush_dcache_p*() to make sure 197 * the corresponding TLBs, we call kvm_flush_dcache_p*() to make sure
198 * the IO subsystem will never hit in the cache. 198 * the IO subsystem will never hit in the cache.
199 *
200 * This is all avoided on systems that have ARM64_HAS_STAGE2_FWB, as
201 * we then fully enforce cacheability of RAM, no matter what the guest
202 * does.
199 */ 203 */
200static void unmap_stage2_ptes(struct kvm *kvm, pmd_t *pmd, 204static void unmap_stage2_ptes(struct kvm *kvm, pmd_t *pmd,
201 phys_addr_t addr, phys_addr_t end) 205 phys_addr_t addr, phys_addr_t end)