Skip to content

Commit 9f073ac

Browse files
committed
KVM: selftests: Add "struct kvm_mmu" to track a given MMU instance
Add a "struct kvm_mmu" to track a given MMU instance, e.g. a VM's stage-1 MMU versus a VM's stage-2 MMU, so that x86 can share MMU functionality for both stage-1 and stage-2 MMUs, without creating the potential for subtle bugs, e.g. due to consuming on vm->pgtable_levels when operating a stage-2 MMU. Encapsulate the existing de facto MMU in "struct kvm_vm", e.g instead of burying the MMU details in "struct kvm_vm_arch", to avoid more #ifdefs in ____vm_create(), and in the hopes that other architectures can utilize the formalized MMU structure if/when they too support stage-2 page tables. No functional change intended. Reviewed-by: Yosry Ahmed <yosry.ahmed@linux.dev> Link: https://patch.msgid.link/20251230230150.4150236-7-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
1 parent 3cd5002 commit 9f073ac

8 files changed

Lines changed: 94 additions & 88 deletions

File tree

tools/testing/selftests/kvm/include/kvm_util.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,17 @@ enum kvm_mem_region_type {
8888
NR_MEM_REGIONS,
8989
};
9090

91+
struct kvm_mmu {
92+
bool pgd_created;
93+
uint64_t pgd;
94+
int pgtable_levels;
95+
};
96+
9197
struct kvm_vm {
9298
int mode;
9399
unsigned long type;
94100
int kvm_fd;
95101
int fd;
96-
unsigned int pgtable_levels;
97102
unsigned int page_size;
98103
unsigned int page_shift;
99104
unsigned int pa_bits;
@@ -104,13 +109,13 @@ struct kvm_vm {
104109
struct sparsebit *vpages_valid;
105110
struct sparsebit *vpages_mapped;
106111
bool has_irqchip;
107-
bool pgd_created;
108112
vm_paddr_t ucall_mmio_addr;
109-
vm_paddr_t pgd;
110113
vm_vaddr_t handlers;
111114
uint32_t dirty_ring_size;
112115
uint64_t gpa_tag_mask;
113116

117+
struct kvm_mmu mmu;
118+
114119
struct kvm_vm_arch arch;
115120

116121
struct kvm_binary_stats stats;

tools/testing/selftests/kvm/lib/arm64/processor.c

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ static uint64_t page_align(struct kvm_vm *vm, uint64_t v)
2828

2929
static uint64_t pgd_index(struct kvm_vm *vm, vm_vaddr_t gva)
3030
{
31-
unsigned int shift = (vm->pgtable_levels - 1) * (vm->page_shift - 3) + vm->page_shift;
31+
unsigned int shift = (vm->mmu.pgtable_levels - 1) * (vm->page_shift - 3) + vm->page_shift;
3232
uint64_t mask = (1UL << (vm->va_bits - shift)) - 1;
3333

3434
return (gva >> shift) & mask;
@@ -39,7 +39,7 @@ static uint64_t pud_index(struct kvm_vm *vm, vm_vaddr_t gva)
3939
unsigned int shift = 2 * (vm->page_shift - 3) + vm->page_shift;
4040
uint64_t mask = (1UL << (vm->page_shift - 3)) - 1;
4141

42-
TEST_ASSERT(vm->pgtable_levels == 4,
42+
TEST_ASSERT(vm->mmu.pgtable_levels == 4,
4343
"Mode %d does not have 4 page table levels", vm->mode);
4444

4545
return (gva >> shift) & mask;
@@ -50,7 +50,7 @@ static uint64_t pmd_index(struct kvm_vm *vm, vm_vaddr_t gva)
5050
unsigned int shift = (vm->page_shift - 3) + vm->page_shift;
5151
uint64_t mask = (1UL << (vm->page_shift - 3)) - 1;
5252

53-
TEST_ASSERT(vm->pgtable_levels >= 3,
53+
TEST_ASSERT(vm->mmu.pgtable_levels >= 3,
5454
"Mode %d does not have >= 3 page table levels", vm->mode);
5555

5656
return (gva >> shift) & mask;
@@ -104,7 +104,7 @@ static uint64_t pte_addr(struct kvm_vm *vm, uint64_t pte)
104104

105105
static uint64_t ptrs_per_pgd(struct kvm_vm *vm)
106106
{
107-
unsigned int shift = (vm->pgtable_levels - 1) * (vm->page_shift - 3) + vm->page_shift;
107+
unsigned int shift = (vm->mmu.pgtable_levels - 1) * (vm->page_shift - 3) + vm->page_shift;
108108
return 1 << (vm->va_bits - shift);
109109
}
110110

@@ -117,13 +117,13 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm)
117117
{
118118
size_t nr_pages = page_align(vm, ptrs_per_pgd(vm) * 8) / vm->page_size;
119119

120-
if (vm->pgd_created)
120+
if (vm->mmu.pgd_created)
121121
return;
122122

123-
vm->pgd = vm_phy_pages_alloc(vm, nr_pages,
124-
KVM_GUEST_PAGE_TABLE_MIN_PADDR,
125-
vm->memslots[MEM_REGION_PT]);
126-
vm->pgd_created = true;
123+
vm->mmu.pgd = vm_phy_pages_alloc(vm, nr_pages,
124+
KVM_GUEST_PAGE_TABLE_MIN_PADDR,
125+
vm->memslots[MEM_REGION_PT]);
126+
vm->mmu.pgd_created = true;
127127
}
128128

129129
static void _virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
@@ -147,12 +147,12 @@ static void _virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
147147
" paddr: 0x%lx vm->max_gfn: 0x%lx vm->page_size: 0x%x",
148148
paddr, vm->max_gfn, vm->page_size);
149149

150-
ptep = addr_gpa2hva(vm, vm->pgd) + pgd_index(vm, vaddr) * 8;
150+
ptep = addr_gpa2hva(vm, vm->mmu.pgd) + pgd_index(vm, vaddr) * 8;
151151
if (!*ptep)
152152
*ptep = addr_pte(vm, vm_alloc_page_table(vm),
153153
PGD_TYPE_TABLE | PTE_VALID);
154154

155-
switch (vm->pgtable_levels) {
155+
switch (vm->mmu.pgtable_levels) {
156156
case 4:
157157
ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pud_index(vm, vaddr) * 8;
158158
if (!*ptep)
@@ -190,16 +190,16 @@ uint64_t *virt_get_pte_hva_at_level(struct kvm_vm *vm, vm_vaddr_t gva, int level
190190
{
191191
uint64_t *ptep;
192192

193-
if (!vm->pgd_created)
193+
if (!vm->mmu.pgd_created)
194194
goto unmapped_gva;
195195

196-
ptep = addr_gpa2hva(vm, vm->pgd) + pgd_index(vm, gva) * 8;
196+
ptep = addr_gpa2hva(vm, vm->mmu.pgd) + pgd_index(vm, gva) * 8;
197197
if (!ptep)
198198
goto unmapped_gva;
199199
if (level == 0)
200200
return ptep;
201201

202-
switch (vm->pgtable_levels) {
202+
switch (vm->mmu.pgtable_levels) {
203203
case 4:
204204
ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pud_index(vm, gva) * 8;
205205
if (!ptep)
@@ -263,13 +263,13 @@ static void pte_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent, uint64_t p
263263

264264
void virt_arch_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent)
265265
{
266-
int level = 4 - (vm->pgtable_levels - 1);
266+
int level = 4 - (vm->mmu.pgtable_levels - 1);
267267
uint64_t pgd, *ptep;
268268

269-
if (!vm->pgd_created)
269+
if (!vm->mmu.pgd_created)
270270
return;
271271

272-
for (pgd = vm->pgd; pgd < vm->pgd + ptrs_per_pgd(vm) * 8; pgd += 8) {
272+
for (pgd = vm->mmu.pgd; pgd < vm->mmu.pgd + ptrs_per_pgd(vm) * 8; pgd += 8) {
273273
ptep = addr_gpa2hva(vm, pgd);
274274
if (!*ptep)
275275
continue;
@@ -350,15 +350,15 @@ void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init)
350350
TEST_FAIL("Unknown guest mode, mode: 0x%x", vm->mode);
351351
}
352352

353-
ttbr0_el1 = vm->pgd & GENMASK(47, vm->page_shift);
353+
ttbr0_el1 = vm->mmu.pgd & GENMASK(47, vm->page_shift);
354354

355355
/* Configure output size */
356356
switch (vm->mode) {
357357
case VM_MODE_P52V48_4K:
358358
case VM_MODE_P52V48_16K:
359359
case VM_MODE_P52V48_64K:
360360
tcr_el1 |= TCR_IPS_52_BITS;
361-
ttbr0_el1 |= FIELD_GET(GENMASK(51, 48), vm->pgd) << 2;
361+
ttbr0_el1 |= FIELD_GET(GENMASK(51, 48), vm->mmu.pgd) << 2;
362362
break;
363363
case VM_MODE_P48V48_4K:
364364
case VM_MODE_P48V48_16K:

tools/testing/selftests/kvm/lib/kvm_util.c

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -281,34 +281,34 @@ struct kvm_vm *____vm_create(struct vm_shape shape)
281281
/* Setup mode specific traits. */
282282
switch (vm->mode) {
283283
case VM_MODE_P52V48_4K:
284-
vm->pgtable_levels = 4;
284+
vm->mmu.pgtable_levels = 4;
285285
break;
286286
case VM_MODE_P52V48_64K:
287-
vm->pgtable_levels = 3;
287+
vm->mmu.pgtable_levels = 3;
288288
break;
289289
case VM_MODE_P48V48_4K:
290-
vm->pgtable_levels = 4;
290+
vm->mmu.pgtable_levels = 4;
291291
break;
292292
case VM_MODE_P48V48_64K:
293-
vm->pgtable_levels = 3;
293+
vm->mmu.pgtable_levels = 3;
294294
break;
295295
case VM_MODE_P40V48_4K:
296296
case VM_MODE_P36V48_4K:
297-
vm->pgtable_levels = 4;
297+
vm->mmu.pgtable_levels = 4;
298298
break;
299299
case VM_MODE_P40V48_64K:
300300
case VM_MODE_P36V48_64K:
301-
vm->pgtable_levels = 3;
301+
vm->mmu.pgtable_levels = 3;
302302
break;
303303
case VM_MODE_P52V48_16K:
304304
case VM_MODE_P48V48_16K:
305305
case VM_MODE_P40V48_16K:
306306
case VM_MODE_P36V48_16K:
307-
vm->pgtable_levels = 4;
307+
vm->mmu.pgtable_levels = 4;
308308
break;
309309
case VM_MODE_P47V47_16K:
310310
case VM_MODE_P36V47_16K:
311-
vm->pgtable_levels = 3;
311+
vm->mmu.pgtable_levels = 3;
312312
break;
313313
case VM_MODE_PXXVYY_4K:
314314
#ifdef __x86_64__
@@ -321,22 +321,22 @@ struct kvm_vm *____vm_create(struct vm_shape shape)
321321
vm->va_bits);
322322

323323
if (vm->va_bits == 57) {
324-
vm->pgtable_levels = 5;
324+
vm->mmu.pgtable_levels = 5;
325325
} else {
326326
TEST_ASSERT(vm->va_bits == 48,
327327
"Unexpected guest virtual address width: %d",
328328
vm->va_bits);
329-
vm->pgtable_levels = 4;
329+
vm->mmu.pgtable_levels = 4;
330330
}
331331
#else
332332
TEST_FAIL("VM_MODE_PXXVYY_4K not supported on non-x86 platforms");
333333
#endif
334334
break;
335335
case VM_MODE_P47V64_4K:
336-
vm->pgtable_levels = 5;
336+
vm->mmu.pgtable_levels = 5;
337337
break;
338338
case VM_MODE_P44V64_4K:
339-
vm->pgtable_levels = 5;
339+
vm->mmu.pgtable_levels = 5;
340340
break;
341341
default:
342342
TEST_FAIL("Unknown guest mode: 0x%x", vm->mode);
@@ -1956,8 +1956,8 @@ void vm_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent)
19561956
fprintf(stream, "%*sMapped Virtual Pages:\n", indent, "");
19571957
sparsebit_dump(stream, vm->vpages_mapped, indent + 2);
19581958
fprintf(stream, "%*spgd_created: %u\n", indent, "",
1959-
vm->pgd_created);
1960-
if (vm->pgd_created) {
1959+
vm->mmu.pgd_created);
1960+
if (vm->mmu.pgd_created) {
19611961
fprintf(stream, "%*sVirtual Translation Tables:\n",
19621962
indent + 2, "");
19631963
virt_dump(stream, vm, indent + 4);

tools/testing/selftests/kvm/lib/loongarch/processor.c

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -50,20 +50,20 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm)
5050
int i;
5151
vm_paddr_t child, table;
5252

53-
if (vm->pgd_created)
53+
if (vm->mmu.pgd_created)
5454
return;
5555

5656
child = table = 0;
57-
for (i = 0; i < vm->pgtable_levels; i++) {
57+
for (i = 0; i < vm->mmu.pgtable_levels; i++) {
5858
invalid_pgtable[i] = child;
5959
table = vm_phy_page_alloc(vm, LOONGARCH_PAGE_TABLE_PHYS_MIN,
6060
vm->memslots[MEM_REGION_PT]);
6161
TEST_ASSERT(table, "Fail to allocate page tale at level %d\n", i);
6262
virt_set_pgtable(vm, table, child);
6363
child = table;
6464
}
65-
vm->pgd = table;
66-
vm->pgd_created = true;
65+
vm->mmu.pgd = table;
66+
vm->mmu.pgd_created = true;
6767
}
6868

6969
static int virt_pte_none(uint64_t *ptep, int level)
@@ -77,11 +77,11 @@ static uint64_t *virt_populate_pte(struct kvm_vm *vm, vm_vaddr_t gva, int alloc)
7777
uint64_t *ptep;
7878
vm_paddr_t child;
7979

80-
if (!vm->pgd_created)
80+
if (!vm->mmu.pgd_created)
8181
goto unmapped_gva;
8282

83-
child = vm->pgd;
84-
level = vm->pgtable_levels - 1;
83+
child = vm->mmu.pgd;
84+
level = vm->mmu.pgtable_levels - 1;
8585
while (level > 0) {
8686
ptep = addr_gpa2hva(vm, child) + virt_pte_index(vm, gva, level) * 8;
8787
if (virt_pte_none(ptep, level)) {
@@ -161,11 +161,11 @@ void virt_arch_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent)
161161
{
162162
int level;
163163

164-
if (!vm->pgd_created)
164+
if (!vm->mmu.pgd_created)
165165
return;
166166

167-
level = vm->pgtable_levels - 1;
168-
pte_dump(stream, vm, indent, vm->pgd, level);
167+
level = vm->mmu.pgtable_levels - 1;
168+
pte_dump(stream, vm, indent, vm->mmu.pgd, level);
169169
}
170170

171171
void vcpu_arch_dump(FILE *stream, struct kvm_vcpu *vcpu, uint8_t indent)
@@ -297,7 +297,7 @@ static void loongarch_vcpu_setup(struct kvm_vcpu *vcpu)
297297

298298
width = vm->page_shift - 3;
299299

300-
switch (vm->pgtable_levels) {
300+
switch (vm->mmu.pgtable_levels) {
301301
case 4:
302302
/* pud page shift and width */
303303
val = (vm->page_shift + width * 2) << 20 | (width << 25);
@@ -309,15 +309,15 @@ static void loongarch_vcpu_setup(struct kvm_vcpu *vcpu)
309309
val |= vm->page_shift | width << 5;
310310
break;
311311
default:
312-
TEST_FAIL("Got %u page table levels, expected 3 or 4", vm->pgtable_levels);
312+
TEST_FAIL("Got %u page table levels, expected 3 or 4", vm->mmu.pgtable_levels);
313313
}
314314

315315
loongarch_set_csr(vcpu, LOONGARCH_CSR_PWCTL0, val);
316316

317317
/* PGD page shift and width */
318-
val = (vm->page_shift + width * (vm->pgtable_levels - 1)) | width << 6;
318+
val = (vm->page_shift + width * (vm->mmu.pgtable_levels - 1)) | width << 6;
319319
loongarch_set_csr(vcpu, LOONGARCH_CSR_PWCTL1, val);
320-
loongarch_set_csr(vcpu, LOONGARCH_CSR_PGDL, vm->pgd);
320+
loongarch_set_csr(vcpu, LOONGARCH_CSR_PGDL, vm->mmu.pgd);
321321

322322
/*
323323
* Refill exception runs on real mode

0 commit comments

Comments
 (0)