Skip to content

Commit 419edf4

Browse files
ryanhrobMarc Zyngier
authored andcommitted
KVM: arm64: Convert translation level parameter to s8
With the introduction of FEAT_LPA2, the Arm ARM adds a new level of translation, level -1, so levels can now be in the range [-1;3]. 3 is always the last level and the first level is determined based on the number of VA bits in use. Convert level variables to use a signed type in preparation for supporting this new level -1. Since the last level is always anchored at 3, and the first level varies to suit the number of VA/IPA bits, take the opportunity to replace KVM_PGTABLE_MAX_LEVELS with the 2 macros KVM_PGTABLE_FIRST_LEVEL and KVM_PGTABLE_LAST_LEVEL. This removes the assumption from the code that levels run from 0 to KVM_PGTABLE_MAX_LEVELS - 1, which will soon no longer be true. Reviewed-by: Oliver Upton <oliver.upton@linux.dev> Signed-off-by: Ryan Roberts <ryan.roberts@arm.com> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20231127111737.1897081-9-ryan.roberts@arm.com
1 parent bd412e2 commit 419edf4

8 files changed

Lines changed: 71 additions & 61 deletions

File tree

arch/arm64/include/asm/kvm_emulate.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ static __always_inline u8 kvm_vcpu_trap_get_fault_type(const struct kvm_vcpu *vc
409409
return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC_TYPE;
410410
}
411411

412-
static __always_inline u8 kvm_vcpu_trap_get_fault_level(const struct kvm_vcpu *vcpu)
412+
static __always_inline s8 kvm_vcpu_trap_get_fault_level(const struct kvm_vcpu *vcpu)
413413
{
414414
return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC_LEVEL;
415415
}

arch/arm64/include/asm/kvm_pgtable.h

Lines changed: 16 additions & 15 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 0
15+
#define KVM_PGTABLE_LAST_LEVEL 3
1516

1617
/*
1718
* The largest supported block sizes for KVM (no 52-bit PA support):
@@ -20,9 +21,9 @@
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

2829
#define kvm_lpa2_is_enabled() system_supports_lpa2()
@@ -103,28 +104,28 @@ static inline kvm_pfn_t kvm_pte_to_pfn(kvm_pte_t pte)
103104
return __phys_to_pfn(kvm_pte_to_phys(pte));
104105
}
105106

106-
static inline u64 kvm_granule_shift(u32 level)
107+
static inline u64 kvm_granule_shift(s8 level)
107108
{
108-
/* Assumes KVM_PGTABLE_MAX_LEVELS is 4 */
109+
/* Assumes KVM_PGTABLE_LAST_LEVEL is 3 */
109110
return ARM64_HW_PGTABLE_LEVEL_SHIFT(level);
110111
}
111112

112-
static inline u64 kvm_granule_size(u32 level)
113+
static inline u64 kvm_granule_size(s8 level)
113114
{
114115
return BIT(kvm_granule_shift(level));
115116
}
116117

117-
static inline bool kvm_level_supports_block_mapping(u32 level)
118+
static inline bool kvm_level_supports_block_mapping(s8 level)
118119
{
119120
return level >= KVM_PGTABLE_MIN_BLOCK_LEVEL;
120121
}
121122

122123
static inline u32 kvm_supported_block_sizes(void)
123124
{
124-
u32 level = KVM_PGTABLE_MIN_BLOCK_LEVEL;
125+
s8 level = KVM_PGTABLE_MIN_BLOCK_LEVEL;
125126
u32 r = 0;
126127

127-
for (; level < KVM_PGTABLE_MAX_LEVELS; level++)
128+
for (; level <= KVM_PGTABLE_LAST_LEVEL; level++)
128129
r |= BIT(kvm_granule_shift(level));
129130

130131
return r;
@@ -169,7 +170,7 @@ struct kvm_pgtable_mm_ops {
169170
void* (*zalloc_page)(void *arg);
170171
void* (*zalloc_pages_exact)(size_t size);
171172
void (*free_pages_exact)(void *addr, size_t size);
172-
void (*free_unlinked_table)(void *addr, u32 level);
173+
void (*free_unlinked_table)(void *addr, s8 level);
173174
void (*get_page)(void *addr);
174175
void (*put_page)(void *addr);
175176
int (*page_count)(void *addr);
@@ -265,7 +266,7 @@ struct kvm_pgtable_visit_ctx {
265266
u64 start;
266267
u64 addr;
267268
u64 end;
268-
u32 level;
269+
s8 level;
269270
enum kvm_pgtable_walk_flags flags;
270271
};
271272

@@ -368,7 +369,7 @@ static inline bool kvm_pgtable_walk_lock_held(void)
368369
*/
369370
struct kvm_pgtable {
370371
u32 ia_bits;
371-
u32 start_level;
372+
s8 start_level;
372373
kvm_pteref_t pgd;
373374
struct kvm_pgtable_mm_ops *mm_ops;
374375

@@ -502,7 +503,7 @@ void kvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt);
502503
* The page-table is assumed to be unreachable by any hardware walkers prior to
503504
* freeing and therefore no TLB invalidation is performed.
504505
*/
505-
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);
506507

507508
/**
508509
* kvm_pgtable_stage2_create_unlinked() - Create an unlinked stage-2 paging structure.
@@ -526,7 +527,7 @@ void kvm_pgtable_stage2_free_unlinked(struct kvm_pgtable_mm_ops *mm_ops, void *p
526527
* an ERR_PTR(error) on failure.
527528
*/
528529
kvm_pte_t *kvm_pgtable_stage2_create_unlinked(struct kvm_pgtable *pgt,
529-
u64 phys, u32 level,
530+
u64 phys, s8 level,
530531
enum kvm_pgtable_prot prot,
531532
void *mc, bool force_pte);
532533

@@ -752,7 +753,7 @@ int kvm_pgtable_walk(struct kvm_pgtable *pgt, u64 addr, u64 size,
752753
* Return: 0 on success, negative error code on failure.
753754
*/
754755
int kvm_pgtable_get_leaf(struct kvm_pgtable *pgt, u64 addr,
755-
kvm_pte_t *ptep, u32 *level);
756+
kvm_pte_t *ptep, s8 *level);
756757

757758
/**
758759
* 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/kvm/hyp/nvhe/mem_protect.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ static void host_s2_put_page(void *addr)
9191
hyp_put_page(&host_s2_pool, addr);
9292
}
9393

94-
static void host_s2_free_unlinked_table(void *addr, u32 level)
94+
static void host_s2_free_unlinked_table(void *addr, s8 level)
9595
{
9696
kvm_pgtable_stage2_free_unlinked(&host_mmu.mm_ops, addr, level);
9797
}
@@ -443,7 +443,7 @@ static int host_stage2_adjust_range(u64 addr, struct kvm_mem_range *range)
443443
{
444444
struct kvm_mem_range cur;
445445
kvm_pte_t pte;
446-
u32 level;
446+
s8 level;
447447
int ret;
448448

449449
hyp_assert_lock_held(&host_mmu.lock);
@@ -462,7 +462,7 @@ static int host_stage2_adjust_range(u64 addr, struct kvm_mem_range *range)
462462
cur.start = ALIGN_DOWN(addr, granule);
463463
cur.end = cur.start + granule;
464464
level++;
465-
} while ((level < KVM_PGTABLE_MAX_LEVELS) &&
465+
} while ((level <= KVM_PGTABLE_LAST_LEVEL) &&
466466
!(kvm_level_supports_block_mapping(level) &&
467467
range_included(&cur, range)));
468468

arch/arm64/kvm/hyp/nvhe/mm.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ static void fixmap_clear_slot(struct hyp_fixmap_slot *slot)
260260
* https://lore.kernel.org/kvm/20221017115209.2099-1-will@kernel.org/T/#mf10dfbaf1eaef9274c581b81c53758918c1d0f03
261261
*/
262262
dsb(ishst);
263-
__tlbi_level(vale2is, __TLBI_VADDR(addr, 0), (KVM_PGTABLE_MAX_LEVELS - 1));
263+
__tlbi_level(vale2is, __TLBI_VADDR(addr, 0), KVM_PGTABLE_LAST_LEVEL);
264264
dsb(ish);
265265
isb();
266266
}
@@ -275,7 +275,7 @@ static int __create_fixmap_slot_cb(const struct kvm_pgtable_visit_ctx *ctx,
275275
{
276276
struct hyp_fixmap_slot *slot = per_cpu_ptr(&fixmap_slots, (u64)ctx->arg);
277277

278-
if (!kvm_pte_valid(ctx->old) || ctx->level != KVM_PGTABLE_MAX_LEVELS - 1)
278+
if (!kvm_pte_valid(ctx->old) || ctx->level != KVM_PGTABLE_LAST_LEVEL)
279279
return -EINVAL;
280280

281281
slot->addr = ctx->addr;

arch/arm64/kvm/hyp/nvhe/setup.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ static int fix_host_ownership_walker(const struct kvm_pgtable_visit_ctx *ctx,
181181
if (!kvm_pte_valid(ctx->old))
182182
return 0;
183183

184-
if (ctx->level != (KVM_PGTABLE_MAX_LEVELS - 1))
184+
if (ctx->level != KVM_PGTABLE_LAST_LEVEL)
185185
return -EINVAL;
186186

187187
phys = kvm_pte_to_phys(ctx->old);

0 commit comments

Comments
 (0)