Skip to content

Commit 089606c

Browse files
author
Marc Zyngier
committed
Merge branch kvm-arm64/selftest/ipa into kvmarm-master/next
* kvm-arm64/selftest/ipa: : . : Expand the KVM/arm64 selftest infrastructure to discover : supported page sizes at runtime, support 16kB pages, and : find out about the original M1 stupidly small IPA space. : . KVM: selftests: arm64: Add support for various modes with 16kB page size KVM: selftests: arm64: Add support for VM_MODE_P36V48_{4K,64K} KVM: selftests: arm64: Rework TCR_EL1 configuration KVM: selftests: arm64: Check for supported page sizes KVM: selftests: arm64: Introduce a variable default IPA size KVM: selftests: arm64: Initialise default guest mode at test startup time Signed-off-by: Marc Zyngier <[email protected]>
2 parents 43d8ac2 + aa674de commit 089606c

File tree

5 files changed

+152
-14
lines changed

5 files changed

+152
-14
lines changed

tools/testing/selftests/kvm/include/aarch64/processor.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@ enum {
113113
#define ESR_EC_WP_CURRENT 0x35
114114
#define ESR_EC_BRK_INS 0x3c
115115

116+
void aarch64_get_supported_page_sizes(uint32_t ipa,
117+
bool *ps4k, bool *ps16k, bool *ps64k);
118+
116119
void vm_init_descriptor_tables(struct kvm_vm *vm);
117120
void vcpu_init_descriptor_tables(struct kvm_vm *vm, uint32_t vcpuid);
118121

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,18 +42,26 @@ enum vm_guest_mode {
4242
VM_MODE_P52V48_4K,
4343
VM_MODE_P52V48_64K,
4444
VM_MODE_P48V48_4K,
45+
VM_MODE_P48V48_16K,
4546
VM_MODE_P48V48_64K,
4647
VM_MODE_P40V48_4K,
48+
VM_MODE_P40V48_16K,
4749
VM_MODE_P40V48_64K,
4850
VM_MODE_PXXV48_4K, /* For 48bits VA but ANY bits PA */
4951
VM_MODE_P47V64_4K,
5052
VM_MODE_P44V64_4K,
53+
VM_MODE_P36V48_4K,
54+
VM_MODE_P36V48_16K,
55+
VM_MODE_P36V48_64K,
56+
VM_MODE_P36V47_16K,
5157
NUM_VM_MODES,
5258
};
5359

5460
#if defined(__aarch64__)
5561

56-
#define VM_MODE_DEFAULT VM_MODE_P40V48_4K
62+
extern enum vm_guest_mode vm_mode_default;
63+
64+
#define VM_MODE_DEFAULT vm_mode_default
5765
#define MIN_PAGE_SHIFT 12U
5866
#define ptes_per_page(page_size) ((page_size) / 8)
5967

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

Lines changed: 75 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <linux/compiler.h>
99
#include <assert.h>
1010

11+
#include "guest_modes.h"
1112
#include "kvm_util.h"
1213
#include "../kvm_util_internal.h"
1314
#include "processor.h"
@@ -237,6 +238,7 @@ void aarch64_vcpu_setup(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_vcpu_init
237238
get_reg(vm, vcpuid, KVM_ARM64_SYS_REG(SYS_SCTLR_EL1), &sctlr_el1);
238239
get_reg(vm, vcpuid, KVM_ARM64_SYS_REG(SYS_TCR_EL1), &tcr_el1);
239240

241+
/* Configure base granule size */
240242
switch (vm->mode) {
241243
case VM_MODE_P52V48_4K:
242244
TEST_FAIL("AArch64 does not support 4K sized pages "
@@ -245,25 +247,47 @@ void aarch64_vcpu_setup(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_vcpu_init
245247
TEST_FAIL("AArch64 does not support 4K sized pages "
246248
"with ANY-bit physical address ranges");
247249
case VM_MODE_P52V48_64K:
250+
case VM_MODE_P48V48_64K:
251+
case VM_MODE_P40V48_64K:
252+
case VM_MODE_P36V48_64K:
248253
tcr_el1 |= 1ul << 14; /* TG0 = 64KB */
249-
tcr_el1 |= 6ul << 32; /* IPS = 52 bits */
254+
break;
255+
case VM_MODE_P48V48_16K:
256+
case VM_MODE_P40V48_16K:
257+
case VM_MODE_P36V48_16K:
258+
case VM_MODE_P36V47_16K:
259+
tcr_el1 |= 2ul << 14; /* TG0 = 16KB */
250260
break;
251261
case VM_MODE_P48V48_4K:
262+
case VM_MODE_P40V48_4K:
263+
case VM_MODE_P36V48_4K:
252264
tcr_el1 |= 0ul << 14; /* TG0 = 4KB */
253-
tcr_el1 |= 5ul << 32; /* IPS = 48 bits */
254265
break;
266+
default:
267+
TEST_FAIL("Unknown guest mode, mode: 0x%x", vm->mode);
268+
}
269+
270+
/* Configure output size */
271+
switch (vm->mode) {
272+
case VM_MODE_P52V48_64K:
273+
tcr_el1 |= 6ul << 32; /* IPS = 52 bits */
274+
break;
275+
case VM_MODE_P48V48_4K:
276+
case VM_MODE_P48V48_16K:
255277
case VM_MODE_P48V48_64K:
256-
tcr_el1 |= 1ul << 14; /* TG0 = 64KB */
257278
tcr_el1 |= 5ul << 32; /* IPS = 48 bits */
258279
break;
259280
case VM_MODE_P40V48_4K:
260-
tcr_el1 |= 0ul << 14; /* TG0 = 4KB */
261-
tcr_el1 |= 2ul << 32; /* IPS = 40 bits */
262-
break;
281+
case VM_MODE_P40V48_16K:
263282
case VM_MODE_P40V48_64K:
264-
tcr_el1 |= 1ul << 14; /* TG0 = 64KB */
265283
tcr_el1 |= 2ul << 32; /* IPS = 40 bits */
266284
break;
285+
case VM_MODE_P36V48_4K:
286+
case VM_MODE_P36V48_16K:
287+
case VM_MODE_P36V48_64K:
288+
case VM_MODE_P36V47_16K:
289+
tcr_el1 |= 1ul << 32; /* IPS = 36 bits */
290+
break;
267291
default:
268292
TEST_FAIL("Unknown guest mode, mode: 0x%x", vm->mode);
269293
}
@@ -432,3 +456,47 @@ uint32_t guest_get_vcpuid(void)
432456
{
433457
return read_sysreg(tpidr_el1);
434458
}
459+
460+
void aarch64_get_supported_page_sizes(uint32_t ipa,
461+
bool *ps4k, bool *ps16k, bool *ps64k)
462+
{
463+
struct kvm_vcpu_init preferred_init;
464+
int kvm_fd, vm_fd, vcpu_fd, err;
465+
uint64_t val;
466+
struct kvm_one_reg reg = {
467+
.id = KVM_ARM64_SYS_REG(SYS_ID_AA64MMFR0_EL1),
468+
.addr = (uint64_t)&val,
469+
};
470+
471+
kvm_fd = open_kvm_dev_path_or_exit();
472+
vm_fd = ioctl(kvm_fd, KVM_CREATE_VM, ipa);
473+
TEST_ASSERT(vm_fd >= 0, "Can't create VM");
474+
475+
vcpu_fd = ioctl(vm_fd, KVM_CREATE_VCPU, 0);
476+
TEST_ASSERT(vcpu_fd >= 0, "Can't create vcpu");
477+
478+
err = ioctl(vm_fd, KVM_ARM_PREFERRED_TARGET, &preferred_init);
479+
TEST_ASSERT(err == 0, "Can't get target");
480+
err = ioctl(vcpu_fd, KVM_ARM_VCPU_INIT, &preferred_init);
481+
TEST_ASSERT(err == 0, "Can't get init vcpu");
482+
483+
err = ioctl(vcpu_fd, KVM_GET_ONE_REG, &reg);
484+
TEST_ASSERT(err == 0, "Can't get MMFR0");
485+
486+
*ps4k = ((val >> 28) & 0xf) != 0xf;
487+
*ps64k = ((val >> 24) & 0xf) == 0;
488+
*ps16k = ((val >> 20) & 0xf) != 0;
489+
490+
close(vcpu_fd);
491+
close(vm_fd);
492+
close(kvm_fd);
493+
}
494+
495+
/*
496+
* arm64 doesn't have a true default mode, so start by computing the
497+
* available IPA space and page sizes early.
498+
*/
499+
void __attribute__((constructor)) init_guest_modes(void)
500+
{
501+
guest_modes_append_default();
502+
}

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

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,59 @@
44
*/
55
#include "guest_modes.h"
66

7+
#ifdef __aarch64__
8+
#include "processor.h"
9+
enum vm_guest_mode vm_mode_default;
10+
#endif
11+
712
struct guest_mode guest_modes[NUM_VM_MODES];
813

914
void guest_modes_append_default(void)
1015
{
16+
#ifndef __aarch64__
1117
guest_mode_append(VM_MODE_DEFAULT, true, true);
12-
13-
#ifdef __aarch64__
14-
guest_mode_append(VM_MODE_P40V48_64K, true, true);
18+
#else
1519
{
1620
unsigned int limit = kvm_check_cap(KVM_CAP_ARM_VM_IPA_SIZE);
21+
bool ps4k, ps16k, ps64k;
22+
int i;
23+
24+
aarch64_get_supported_page_sizes(limit, &ps4k, &ps16k, &ps64k);
25+
26+
vm_mode_default = NUM_VM_MODES;
27+
1728
if (limit >= 52)
18-
guest_mode_append(VM_MODE_P52V48_64K, true, true);
29+
guest_mode_append(VM_MODE_P52V48_64K, ps64k, ps64k);
1930
if (limit >= 48) {
20-
guest_mode_append(VM_MODE_P48V48_4K, true, true);
21-
guest_mode_append(VM_MODE_P48V48_64K, true, true);
31+
guest_mode_append(VM_MODE_P48V48_4K, ps4k, ps4k);
32+
guest_mode_append(VM_MODE_P48V48_16K, ps16k, ps16k);
33+
guest_mode_append(VM_MODE_P48V48_64K, ps64k, ps64k);
34+
}
35+
if (limit >= 40) {
36+
guest_mode_append(VM_MODE_P40V48_4K, ps4k, ps4k);
37+
guest_mode_append(VM_MODE_P40V48_16K, ps16k, ps16k);
38+
guest_mode_append(VM_MODE_P40V48_64K, ps64k, ps64k);
39+
if (ps4k)
40+
vm_mode_default = VM_MODE_P40V48_4K;
41+
}
42+
if (limit >= 36) {
43+
guest_mode_append(VM_MODE_P36V48_4K, ps4k, ps4k);
44+
guest_mode_append(VM_MODE_P36V48_16K, ps16k, ps16k);
45+
guest_mode_append(VM_MODE_P36V48_64K, ps64k, ps64k);
46+
guest_mode_append(VM_MODE_P36V47_16K, ps16k, ps16k);
2247
}
48+
49+
/*
50+
* Pick the first supported IPA size if the default
51+
* isn't available.
52+
*/
53+
for (i = 0; vm_mode_default == NUM_VM_MODES && i < NUM_VM_MODES; i++) {
54+
if (guest_modes[i].supported && guest_modes[i].enabled)
55+
vm_mode_default = i;
56+
}
57+
58+
TEST_ASSERT(vm_mode_default != NUM_VM_MODES,
59+
"No supported mode!");
2360
}
2461
#endif
2562
#ifdef __s390x__

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,12 +166,18 @@ const char *vm_guest_mode_string(uint32_t i)
166166
[VM_MODE_P52V48_4K] = "PA-bits:52, VA-bits:48, 4K pages",
167167
[VM_MODE_P52V48_64K] = "PA-bits:52, VA-bits:48, 64K pages",
168168
[VM_MODE_P48V48_4K] = "PA-bits:48, VA-bits:48, 4K pages",
169+
[VM_MODE_P48V48_16K] = "PA-bits:48, VA-bits:48, 16K pages",
169170
[VM_MODE_P48V48_64K] = "PA-bits:48, VA-bits:48, 64K pages",
170171
[VM_MODE_P40V48_4K] = "PA-bits:40, VA-bits:48, 4K pages",
172+
[VM_MODE_P40V48_16K] = "PA-bits:40, VA-bits:48, 16K pages",
171173
[VM_MODE_P40V48_64K] = "PA-bits:40, VA-bits:48, 64K pages",
172174
[VM_MODE_PXXV48_4K] = "PA-bits:ANY, VA-bits:48, 4K pages",
173175
[VM_MODE_P47V64_4K] = "PA-bits:47, VA-bits:64, 4K pages",
174176
[VM_MODE_P44V64_4K] = "PA-bits:44, VA-bits:64, 4K pages",
177+
[VM_MODE_P36V48_4K] = "PA-bits:36, VA-bits:48, 4K pages",
178+
[VM_MODE_P36V48_16K] = "PA-bits:36, VA-bits:48, 16K pages",
179+
[VM_MODE_P36V48_64K] = "PA-bits:36, VA-bits:48, 64K pages",
180+
[VM_MODE_P36V47_16K] = "PA-bits:36, VA-bits:47, 16K pages",
175181
};
176182
_Static_assert(sizeof(strings)/sizeof(char *) == NUM_VM_MODES,
177183
"Missing new mode strings?");
@@ -185,12 +191,18 @@ const struct vm_guest_mode_params vm_guest_mode_params[] = {
185191
[VM_MODE_P52V48_4K] = { 52, 48, 0x1000, 12 },
186192
[VM_MODE_P52V48_64K] = { 52, 48, 0x10000, 16 },
187193
[VM_MODE_P48V48_4K] = { 48, 48, 0x1000, 12 },
194+
[VM_MODE_P48V48_16K] = { 48, 48, 0x4000, 14 },
188195
[VM_MODE_P48V48_64K] = { 48, 48, 0x10000, 16 },
189196
[VM_MODE_P40V48_4K] = { 40, 48, 0x1000, 12 },
197+
[VM_MODE_P40V48_16K] = { 40, 48, 0x4000, 14 },
190198
[VM_MODE_P40V48_64K] = { 40, 48, 0x10000, 16 },
191199
[VM_MODE_PXXV48_4K] = { 0, 0, 0x1000, 12 },
192200
[VM_MODE_P47V64_4K] = { 47, 64, 0x1000, 12 },
193201
[VM_MODE_P44V64_4K] = { 44, 64, 0x1000, 12 },
202+
[VM_MODE_P36V48_4K] = { 36, 48, 0x1000, 12 },
203+
[VM_MODE_P36V48_16K] = { 36, 48, 0x4000, 14 },
204+
[VM_MODE_P36V48_64K] = { 36, 48, 0x10000, 16 },
205+
[VM_MODE_P36V47_16K] = { 36, 47, 0x4000, 14 },
194206
};
195207
_Static_assert(sizeof(vm_guest_mode_params)/sizeof(struct vm_guest_mode_params) == NUM_VM_MODES,
196208
"Missing new mode params?");
@@ -252,9 +264,19 @@ struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm)
252264
vm->pgtable_levels = 3;
253265
break;
254266
case VM_MODE_P40V48_4K:
267+
case VM_MODE_P36V48_4K:
255268
vm->pgtable_levels = 4;
256269
break;
257270
case VM_MODE_P40V48_64K:
271+
case VM_MODE_P36V48_64K:
272+
vm->pgtable_levels = 3;
273+
break;
274+
case VM_MODE_P48V48_16K:
275+
case VM_MODE_P40V48_16K:
276+
case VM_MODE_P36V48_16K:
277+
vm->pgtable_levels = 4;
278+
break;
279+
case VM_MODE_P36V47_16K:
258280
vm->pgtable_levels = 3;
259281
break;
260282
case VM_MODE_PXXV48_4K:

0 commit comments

Comments
 (0)