Skip to content

Commit 189f2c8

Browse files
author
Marc Zyngier
committed
Merge branch kvm-arm64/lpa2 into kvmarm-master/next
* kvm-arm64/lpa2: : . : Support FEAT_LPA2 at EL2 S1 and S2, courtesy of Ryan Roberts : : From the cover letter: : : "This adds support for FEAT_LPA2 to KVM for both hypervisor stage 1 (for the : nvhe/protected modes) and the vm stage 2 translation tables (for all modes). : FEAT_LPA2 enables 52 bit PAs and VAs for 4KB and 16KB granules (note this is : already supported for 64KB granules via the FEAT_LPA and FEAT_LVA extensions)." : . KVM: arm64: Use helpers to classify exception types reported via ESR KVM: selftests: arm64: Support P52V48 4K and 16K guest_modes KVM: selftests: arm64: Determine max ipa size per-page size KVM: arm64: Allow guests with >48-bit IPA size on FEAT_LPA2 systems KVM: arm64: Support up to 5 levels of translation in kvm_pgtable KVM: arm64: Convert translation level parameter to s8 KVM: arm64: Use LPA2 page-tables for stage2 and hyp stage1 KVM: arm64: Add new (V)TCR_EL2 field definitions for FEAT_LPA2 arm64: Add ARM64_HAS_LPA2 CPU capability arm64/mm: Add FEAT_LPA2 specific ID_AA64MMFR0.TGRAN[2] arm64/mm: Update tlb invalidation routines for FEAT_LPA2 arm64/mm: Add lpa2_is_enabled() kvm_lpa2_is_enabled() stubs arm64/mm: Modify range-based tlbi to decrement scale Signed-off-by: Marc Zyngier <maz@kernel.org>
2 parents 2cc14f5 + 11e5ea5 commit 189f2c8

28 files changed

Lines changed: 400 additions & 199 deletions

File tree

arch/arm64/include/asm/cpufeature.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,11 @@ static inline bool system_supports_tlb_range(void)
819819
return alternative_has_cap_unlikely(ARM64_HAS_TLB_RANGE);
820820
}
821821

822+
static inline bool system_supports_lpa2(void)
823+
{
824+
return cpus_have_final_cap(ARM64_HAS_LPA2);
825+
}
826+
822827
int do_emulate_mrs(struct pt_regs *regs, u32 sys_reg, u32 rt);
823828
bool try_emulate_mrs(struct pt_regs *regs, u32 isn);
824829

arch/arm64/include/asm/esr.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,21 @@ static inline bool esr_is_data_abort(unsigned long esr)
392392
return ec == ESR_ELx_EC_DABT_LOW || ec == ESR_ELx_EC_DABT_CUR;
393393
}
394394

395+
static inline bool esr_fsc_is_translation_fault(unsigned long esr)
396+
{
397+
return (esr & ESR_ELx_FSC_TYPE) == ESR_ELx_FSC_FAULT;
398+
}
399+
400+
static inline bool esr_fsc_is_permission_fault(unsigned long esr)
401+
{
402+
return (esr & ESR_ELx_FSC_TYPE) == ESR_ELx_FSC_PERM;
403+
}
404+
405+
static inline bool esr_fsc_is_access_flag_fault(unsigned long esr)
406+
{
407+
return (esr & ESR_ELx_FSC_TYPE) == ESR_ELx_FSC_ACCESS;
408+
}
409+
395410
const char *esr_get_class_string(unsigned long esr);
396411
#endif /* __ASSEMBLY */
397412

arch/arm64/include/asm/kvm_arm.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@
108108
#define HCRX_HOST_FLAGS (HCRX_EL2_MSCEn | HCRX_EL2_TCR2En)
109109

110110
/* TCR_EL2 Registers bits */
111+
#define TCR_EL2_DS (1UL << 32)
111112
#define TCR_EL2_RES1 ((1U << 31) | (1 << 23))
112113
#define TCR_EL2_TBI (1 << 20)
113114
#define TCR_EL2_PS_SHIFT 16
@@ -122,6 +123,7 @@
122123
TCR_EL2_ORGN0_MASK | TCR_EL2_IRGN0_MASK | TCR_EL2_T0SZ_MASK)
123124

124125
/* VTCR_EL2 Registers bits */
126+
#define VTCR_EL2_DS TCR_EL2_DS
125127
#define VTCR_EL2_RES1 (1U << 31)
126128
#define VTCR_EL2_HD (1 << 22)
127129
#define VTCR_EL2_HA (1 << 21)

arch/arm64/include/asm/kvm_emulate.h

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -404,14 +404,25 @@ static __always_inline u8 kvm_vcpu_trap_get_fault(const struct kvm_vcpu *vcpu)
404404
return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC;
405405
}
406406

407-
static __always_inline u8 kvm_vcpu_trap_get_fault_type(const struct kvm_vcpu *vcpu)
407+
static inline
408+
bool kvm_vcpu_trap_is_permission_fault(const struct kvm_vcpu *vcpu)
408409
{
409-
return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC_TYPE;
410+
return esr_fsc_is_permission_fault(kvm_vcpu_get_esr(vcpu));
410411
}
411412

412-
static __always_inline u8 kvm_vcpu_trap_get_fault_level(const struct kvm_vcpu *vcpu)
413+
static inline
414+
bool kvm_vcpu_trap_is_translation_fault(const struct kvm_vcpu *vcpu)
413415
{
414-
return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC_LEVEL;
416+
return esr_fsc_is_translation_fault(kvm_vcpu_get_esr(vcpu));
417+
}
418+
419+
static inline
420+
u64 kvm_vcpu_trap_get_perm_fault_granule(const struct kvm_vcpu *vcpu)
421+
{
422+
unsigned long esr = kvm_vcpu_get_esr(vcpu);
423+
424+
BUG_ON(!esr_fsc_is_permission_fault(esr));
425+
return BIT(ARM64_HW_PGTABLE_LEVEL_SHIFT(esr & ESR_ELx_FSC_LEVEL));
415426
}
416427

417428
static __always_inline bool kvm_vcpu_abt_issea(const struct kvm_vcpu *vcpu)
@@ -454,12 +465,7 @@ static inline bool kvm_is_write_fault(struct kvm_vcpu *vcpu)
454465
* first), then a permission fault to allow the flags
455466
* to be set.
456467
*/
457-
switch (kvm_vcpu_trap_get_fault_type(vcpu)) {
458-
case ESR_ELx_FSC_PERM:
459-
return true;
460-
default:
461-
return false;
462-
}
468+
return kvm_vcpu_trap_is_permission_fault(vcpu);
463469
}
464470

465471
if (kvm_vcpu_trap_is_iabt(vcpu))

arch/arm64/include/asm/kvm_pgtable.h

Lines changed: 54 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
#include <linux/kvm_host.h>
1212
#include <linux/types.h>
1313

14-
#define KVM_PGTABLE_MAX_LEVELS 4U
14+
#define KVM_PGTABLE_FIRST_LEVEL -1
15+
#define KVM_PGTABLE_LAST_LEVEL 3
1516

1617
/*
1718
* The largest supported block sizes for KVM (no 52-bit PA support):
@@ -20,17 +21,29 @@
2021
* - 64K (level 2): 512MB
2122
*/
2223
#ifdef CONFIG_ARM64_4K_PAGES
23-
#define KVM_PGTABLE_MIN_BLOCK_LEVEL 1U
24+
#define KVM_PGTABLE_MIN_BLOCK_LEVEL 1
2425
#else
25-
#define KVM_PGTABLE_MIN_BLOCK_LEVEL 2U
26+
#define KVM_PGTABLE_MIN_BLOCK_LEVEL 2
2627
#endif
2728

29+
#define kvm_lpa2_is_enabled() system_supports_lpa2()
30+
31+
static inline u64 kvm_get_parange_max(void)
32+
{
33+
if (kvm_lpa2_is_enabled() ||
34+
(IS_ENABLED(CONFIG_ARM64_PA_BITS_52) && PAGE_SHIFT == 16))
35+
return ID_AA64MMFR0_EL1_PARANGE_52;
36+
else
37+
return ID_AA64MMFR0_EL1_PARANGE_48;
38+
}
39+
2840
static inline u64 kvm_get_parange(u64 mmfr0)
2941
{
42+
u64 parange_max = kvm_get_parange_max();
3043
u64 parange = cpuid_feature_extract_unsigned_field(mmfr0,
3144
ID_AA64MMFR0_EL1_PARANGE_SHIFT);
32-
if (parange > ID_AA64MMFR0_EL1_PARANGE_MAX)
33-
parange = ID_AA64MMFR0_EL1_PARANGE_MAX;
45+
if (parange > parange_max)
46+
parange = parange_max;
3447

3548
return parange;
3649
}
@@ -41,6 +54,8 @@ typedef u64 kvm_pte_t;
4154

4255
#define KVM_PTE_ADDR_MASK GENMASK(47, PAGE_SHIFT)
4356
#define KVM_PTE_ADDR_51_48 GENMASK(15, 12)
57+
#define KVM_PTE_ADDR_MASK_LPA2 GENMASK(49, PAGE_SHIFT)
58+
#define KVM_PTE_ADDR_51_50_LPA2 GENMASK(9, 8)
4459

4560
#define KVM_PHYS_INVALID (-1ULL)
4661

@@ -51,21 +66,34 @@ static inline bool kvm_pte_valid(kvm_pte_t pte)
5166

5267
static inline u64 kvm_pte_to_phys(kvm_pte_t pte)
5368
{
54-
u64 pa = pte & KVM_PTE_ADDR_MASK;
55-
56-
if (PAGE_SHIFT == 16)
57-
pa |= FIELD_GET(KVM_PTE_ADDR_51_48, pte) << 48;
69+
u64 pa;
70+
71+
if (kvm_lpa2_is_enabled()) {
72+
pa = pte & KVM_PTE_ADDR_MASK_LPA2;
73+
pa |= FIELD_GET(KVM_PTE_ADDR_51_50_LPA2, pte) << 50;
74+
} else {
75+
pa = pte & KVM_PTE_ADDR_MASK;
76+
if (PAGE_SHIFT == 16)
77+
pa |= FIELD_GET(KVM_PTE_ADDR_51_48, pte) << 48;
78+
}
5879

5980
return pa;
6081
}
6182

6283
static inline kvm_pte_t kvm_phys_to_pte(u64 pa)
6384
{
64-
kvm_pte_t pte = pa & KVM_PTE_ADDR_MASK;
65-
66-
if (PAGE_SHIFT == 16) {
67-
pa &= GENMASK(51, 48);
68-
pte |= FIELD_PREP(KVM_PTE_ADDR_51_48, pa >> 48);
85+
kvm_pte_t pte;
86+
87+
if (kvm_lpa2_is_enabled()) {
88+
pte = pa & KVM_PTE_ADDR_MASK_LPA2;
89+
pa &= GENMASK(51, 50);
90+
pte |= FIELD_PREP(KVM_PTE_ADDR_51_50_LPA2, pa >> 50);
91+
} else {
92+
pte = pa & KVM_PTE_ADDR_MASK;
93+
if (PAGE_SHIFT == 16) {
94+
pa &= GENMASK(51, 48);
95+
pte |= FIELD_PREP(KVM_PTE_ADDR_51_48, pa >> 48);
96+
}
6997
}
7098

7199
return pte;
@@ -76,28 +104,28 @@ static inline kvm_pfn_t kvm_pte_to_pfn(kvm_pte_t pte)
76104
return __phys_to_pfn(kvm_pte_to_phys(pte));
77105
}
78106

79-
static inline u64 kvm_granule_shift(u32 level)
107+
static inline u64 kvm_granule_shift(s8 level)
80108
{
81-
/* Assumes KVM_PGTABLE_MAX_LEVELS is 4 */
109+
/* Assumes KVM_PGTABLE_LAST_LEVEL is 3 */
82110
return ARM64_HW_PGTABLE_LEVEL_SHIFT(level);
83111
}
84112

85-
static inline u64 kvm_granule_size(u32 level)
113+
static inline u64 kvm_granule_size(s8 level)
86114
{
87115
return BIT(kvm_granule_shift(level));
88116
}
89117

90-
static inline bool kvm_level_supports_block_mapping(u32 level)
118+
static inline bool kvm_level_supports_block_mapping(s8 level)
91119
{
92120
return level >= KVM_PGTABLE_MIN_BLOCK_LEVEL;
93121
}
94122

95123
static inline u32 kvm_supported_block_sizes(void)
96124
{
97-
u32 level = KVM_PGTABLE_MIN_BLOCK_LEVEL;
125+
s8 level = KVM_PGTABLE_MIN_BLOCK_LEVEL;
98126
u32 r = 0;
99127

100-
for (; level < KVM_PGTABLE_MAX_LEVELS; level++)
128+
for (; level <= KVM_PGTABLE_LAST_LEVEL; level++)
101129
r |= BIT(kvm_granule_shift(level));
102130

103131
return r;
@@ -142,7 +170,7 @@ struct kvm_pgtable_mm_ops {
142170
void* (*zalloc_page)(void *arg);
143171
void* (*zalloc_pages_exact)(size_t size);
144172
void (*free_pages_exact)(void *addr, size_t size);
145-
void (*free_unlinked_table)(void *addr, u32 level);
173+
void (*free_unlinked_table)(void *addr, s8 level);
146174
void (*get_page)(void *addr);
147175
void (*put_page)(void *addr);
148176
int (*page_count)(void *addr);
@@ -238,7 +266,7 @@ struct kvm_pgtable_visit_ctx {
238266
u64 start;
239267
u64 addr;
240268
u64 end;
241-
u32 level;
269+
s8 level;
242270
enum kvm_pgtable_walk_flags flags;
243271
};
244272

@@ -341,7 +369,7 @@ static inline bool kvm_pgtable_walk_lock_held(void)
341369
*/
342370
struct kvm_pgtable {
343371
u32 ia_bits;
344-
u32 start_level;
372+
s8 start_level;
345373
kvm_pteref_t pgd;
346374
struct kvm_pgtable_mm_ops *mm_ops;
347375

@@ -475,7 +503,7 @@ void kvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt);
475503
* The page-table is assumed to be unreachable by any hardware walkers prior to
476504
* freeing and therefore no TLB invalidation is performed.
477505
*/
478-
void kvm_pgtable_stage2_free_unlinked(struct kvm_pgtable_mm_ops *mm_ops, void *pgtable, u32 level);
506+
void kvm_pgtable_stage2_free_unlinked(struct kvm_pgtable_mm_ops *mm_ops, void *pgtable, s8 level);
479507

480508
/**
481509
* kvm_pgtable_stage2_create_unlinked() - Create an unlinked stage-2 paging structure.
@@ -499,7 +527,7 @@ void kvm_pgtable_stage2_free_unlinked(struct kvm_pgtable_mm_ops *mm_ops, void *p
499527
* an ERR_PTR(error) on failure.
500528
*/
501529
kvm_pte_t *kvm_pgtable_stage2_create_unlinked(struct kvm_pgtable *pgt,
502-
u64 phys, u32 level,
530+
u64 phys, s8 level,
503531
enum kvm_pgtable_prot prot,
504532
void *mc, bool force_pte);
505533

@@ -725,7 +753,7 @@ int kvm_pgtable_walk(struct kvm_pgtable *pgt, u64 addr, u64 size,
725753
* Return: 0 on success, negative error code on failure.
726754
*/
727755
int kvm_pgtable_get_leaf(struct kvm_pgtable *pgt, u64 addr,
728-
kvm_pte_t *ptep, u32 *level);
756+
kvm_pte_t *ptep, s8 *level);
729757

730758
/**
731759
* kvm_pgtable_stage2_pte_prot() - Retrieve the protection attributes of a

arch/arm64/include/asm/kvm_pkvm.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,11 @@ static inline unsigned long hyp_vm_table_pages(void)
5656

5757
static inline unsigned long __hyp_pgtable_max_pages(unsigned long nr_pages)
5858
{
59-
unsigned long total = 0, i;
59+
unsigned long total = 0;
60+
int i;
6061

6162
/* Provision the worst case scenario */
62-
for (i = 0; i < KVM_PGTABLE_MAX_LEVELS; i++) {
63+
for (i = KVM_PGTABLE_FIRST_LEVEL; i <= KVM_PGTABLE_LAST_LEVEL; i++) {
6364
nr_pages = DIV_ROUND_UP(nr_pages, PTRS_PER_PTE);
6465
total += nr_pages;
6566
}

arch/arm64/include/asm/pgtable-prot.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ extern bool arm64_use_ng_mappings;
7171
#define PTE_MAYBE_NG (arm64_use_ng_mappings ? PTE_NG : 0)
7272
#define PMD_MAYBE_NG (arm64_use_ng_mappings ? PMD_SECT_NG : 0)
7373

74+
#define lpa2_is_enabled() false
75+
7476
/*
7577
* If we have userspace only BTI we don't want to mark kernel pages
7678
* guarded even if the system does support BTI.

arch/arm64/include/asm/sysreg.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -871,17 +871,20 @@
871871

872872
/* id_aa64mmfr0 */
873873
#define ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED_MIN 0x0
874+
#define ID_AA64MMFR0_EL1_TGRAN4_LPA2 ID_AA64MMFR0_EL1_TGRAN4_52_BIT
874875
#define ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED_MAX 0x7
875876
#define ID_AA64MMFR0_EL1_TGRAN64_SUPPORTED_MIN 0x0
876877
#define ID_AA64MMFR0_EL1_TGRAN64_SUPPORTED_MAX 0x7
877878
#define ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED_MIN 0x1
879+
#define ID_AA64MMFR0_EL1_TGRAN16_LPA2 ID_AA64MMFR0_EL1_TGRAN16_52_BIT
878880
#define ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED_MAX 0xf
879881

880882
#define ARM64_MIN_PARANGE_BITS 32
881883

882884
#define ID_AA64MMFR0_EL1_TGRAN_2_SUPPORTED_DEFAULT 0x0
883885
#define ID_AA64MMFR0_EL1_TGRAN_2_SUPPORTED_NONE 0x1
884886
#define ID_AA64MMFR0_EL1_TGRAN_2_SUPPORTED_MIN 0x2
887+
#define ID_AA64MMFR0_EL1_TGRAN_2_SUPPORTED_LPA2 0x3
885888
#define ID_AA64MMFR0_EL1_TGRAN_2_SUPPORTED_MAX 0x7
886889

887890
#ifdef CONFIG_ARM64_PA_BITS_52
@@ -892,11 +895,13 @@
892895

893896
#if defined(CONFIG_ARM64_4K_PAGES)
894897
#define ID_AA64MMFR0_EL1_TGRAN_SHIFT ID_AA64MMFR0_EL1_TGRAN4_SHIFT
898+
#define ID_AA64MMFR0_EL1_TGRAN_LPA2 ID_AA64MMFR0_EL1_TGRAN4_52_BIT
895899
#define ID_AA64MMFR0_EL1_TGRAN_SUPPORTED_MIN ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED_MIN
896900
#define ID_AA64MMFR0_EL1_TGRAN_SUPPORTED_MAX ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED_MAX
897901
#define ID_AA64MMFR0_EL1_TGRAN_2_SHIFT ID_AA64MMFR0_EL1_TGRAN4_2_SHIFT
898902
#elif defined(CONFIG_ARM64_16K_PAGES)
899903
#define ID_AA64MMFR0_EL1_TGRAN_SHIFT ID_AA64MMFR0_EL1_TGRAN16_SHIFT
904+
#define ID_AA64MMFR0_EL1_TGRAN_LPA2 ID_AA64MMFR0_EL1_TGRAN16_52_BIT
900905
#define ID_AA64MMFR0_EL1_TGRAN_SUPPORTED_MIN ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED_MIN
901906
#define ID_AA64MMFR0_EL1_TGRAN_SUPPORTED_MAX ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED_MAX
902907
#define ID_AA64MMFR0_EL1_TGRAN_2_SHIFT ID_AA64MMFR0_EL1_TGRAN16_2_SHIFT

arch/arm64/include/asm/tlb.h

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,15 @@ static void tlb_flush(struct mmu_gather *tlb);
2222
#include <asm-generic/tlb.h>
2323

2424
/*
25-
* get the tlbi levels in arm64. Default value is 0 if more than one
26-
* of cleared_* is set or neither is set.
27-
* Arm64 doesn't support p4ds now.
25+
* get the tlbi levels in arm64. Default value is TLBI_TTL_UNKNOWN if more than
26+
* one of cleared_* is set or neither is set - this elides the level hinting to
27+
* the hardware.
2828
*/
2929
static inline int tlb_get_level(struct mmu_gather *tlb)
3030
{
3131
/* The TTL field is only valid for the leaf entry. */
3232
if (tlb->freed_tables)
33-
return 0;
33+
return TLBI_TTL_UNKNOWN;
3434

3535
if (tlb->cleared_ptes && !(tlb->cleared_pmds ||
3636
tlb->cleared_puds ||
@@ -47,7 +47,12 @@ static inline int tlb_get_level(struct mmu_gather *tlb)
4747
tlb->cleared_p4ds))
4848
return 1;
4949

50-
return 0;
50+
if (tlb->cleared_p4ds && !(tlb->cleared_ptes ||
51+
tlb->cleared_pmds ||
52+
tlb->cleared_puds))
53+
return 0;
54+
55+
return TLBI_TTL_UNKNOWN;
5156
}
5257

5358
static inline void tlb_flush(struct mmu_gather *tlb)

0 commit comments

Comments
 (0)