diff mbox series

[v2,12/12] KVM: selftests: arm64: Support P52V48 4K and 16K guest_modes

Message ID 20230306195438.1557851-13-ryan.roberts@arm.com (mailing list archive)
State New, archived
Headers show
Series KVM: arm64: Support FEAT_LPA2 at hyp s1 and vm s2 | expand

Commit Message

Ryan Roberts March 6, 2023, 7:54 p.m. UTC
Add support for VM_MODE_P52V48_4K and VM_MODE_P52V48_16K guest modes by
using the FEAT_LPA2 pte format for stage1, when FEAT_LPA2 is available.

Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
---
 .../selftests/kvm/include/kvm_util_base.h     |  1 +
 .../selftests/kvm/lib/aarch64/processor.c     | 39 ++++++++++++++-----
 tools/testing/selftests/kvm/lib/guest_modes.c |  2 +
 tools/testing/selftests/kvm/lib/kvm_util.c    |  3 ++
 4 files changed, 36 insertions(+), 9 deletions(-)

Comments

Ryan Roberts March 6, 2023, 8:04 p.m. UTC | #1
On 06/03/2023 19:54, Ryan Roberts wrote:
> Add support for VM_MODE_P52V48_4K and VM_MODE_P52V48_16K guest modes by
> using the FEAT_LPA2 pte format for stage1, when FEAT_LPA2 is available.
> 
> Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
> ---
>  .../selftests/kvm/include/kvm_util_base.h     |  1 +
>  .../selftests/kvm/lib/aarch64/processor.c     | 39 ++++++++++++++-----
>  tools/testing/selftests/kvm/lib/guest_modes.c |  2 +
>  tools/testing/selftests/kvm/lib/kvm_util.c    |  3 ++
>  4 files changed, 36 insertions(+), 9 deletions(-)
> 
> diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h
> index fbc2a79369b8..b8678bf4a980 100644
> --- a/tools/testing/selftests/kvm/include/kvm_util_base.h
> +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h
> @@ -150,6 +150,7 @@ static inline struct userspace_mem_region *vm_get_mem_region(struct kvm_vm *vm,
>  
>  enum vm_guest_mode {
>  	VM_MODE_P52V48_4K,
> +	VM_MODE_P52V48_16K,

I wasn't sure whether it was best to add this here in its "natural" position, or
at the end. These enum values are exposed through the command line interface, so
by putting it here, perhaps I could break people's scripts because everything
below gets renumbered. Happy to move we care about compat for these tests.

>  	VM_MODE_P52V48_64K,
>  	VM_MODE_P48V48_4K,
>  	VM_MODE_P48V48_16K,
> diff --git a/tools/testing/selftests/kvm/lib/aarch64/processor.c b/tools/testing/selftests/kvm/lib/aarch64/processor.c
> index b2d80396b8f8..934f8baa7d0e 100644
> --- a/tools/testing/selftests/kvm/lib/aarch64/processor.c
> +++ b/tools/testing/selftests/kvm/lib/aarch64/processor.c
> @@ -12,6 +12,7 @@
>  #include "kvm_util.h"
>  #include "processor.h"
>  #include <linux/bitfield.h>
> +#include <linux/sizes.h>
>  
>  #define DEFAULT_ARM64_GUEST_STACK_VADDR_MIN	0xac0000
>  
> @@ -58,13 +59,25 @@ static uint64_t pte_index(struct kvm_vm *vm, vm_vaddr_t gva)
>  	return (gva >> vm->page_shift) & mask;
>  }
>  
> +static inline bool use_lpa2_pte_format(struct kvm_vm *vm)
> +{
> +	return (vm->page_size == SZ_4K || vm->page_size == SZ_16K) &&
> +	    (vm->pa_bits > 48 || vm->va_bits > 48);
> +}
> +
>  static uint64_t addr_pte(struct kvm_vm *vm, uint64_t pa, uint64_t attrs)
>  {
>  	uint64_t pte;
>  
> -	pte = pa & GENMASK(47, vm->page_shift);
> -	if (vm->page_shift == 16)
> -		pte |= (pa & GENMASK(51, 48)) >> (48 - 12);
> +	if (use_lpa2_pte_format(vm)) {
> +		pte = pa & GENMASK(49, vm->page_shift);
> +		pte |= (pa & GENMASK(51, 50)) >> (50 - 8);
> +		attrs &= ~GENMASK(9, 8);
> +	} else {
> +		pte = pa & GENMASK(47, vm->page_shift);
> +		if (vm->page_shift == 16)
> +			pte |= (pa & GENMASK(51, 48)) >> (48 - 12);
> +	}
>  	pte |= attrs;
>  
>  	return pte;
> @@ -74,9 +87,14 @@ static uint64_t pte_addr(struct kvm_vm *vm, uint64_t pte)
>  {
>  	uint64_t pa;
>  
> -	pa = pte & GENMASK(47, vm->page_shift);
> -	if (vm->page_shift == 16)
> -		pa |= (pte & GENMASK(15, 12)) << (48 - 12);
> +	if (use_lpa2_pte_format(vm)) {
> +		pa = pte & GENMASK(49, vm->page_shift);
> +		pa |= (pte & GENMASK(9, 8)) << (50 - 8);
> +	} else {
> +		pa = pte & GENMASK(47, vm->page_shift);
> +		if (vm->page_shift == 16)
> +			pa |= (pte & GENMASK(15, 12)) << (48 - 12);
> +	}
>  
>  	return pa;
>  }
> @@ -266,9 +284,6 @@ void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init)
>  
>  	/* Configure base granule size */
>  	switch (vm->mode) {
> -	case VM_MODE_P52V48_4K:
> -		TEST_FAIL("AArch64 does not support 4K sized pages "
> -			  "with 52-bit physical address ranges");
>  	case VM_MODE_PXXV48_4K:
>  		TEST_FAIL("AArch64 does not support 4K sized pages "
>  			  "with ANY-bit physical address ranges");
> @@ -278,12 +293,14 @@ void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init)
>  	case VM_MODE_P36V48_64K:
>  		tcr_el1 |= 1ul << 14; /* TG0 = 64KB */
>  		break;
> +	case VM_MODE_P52V48_16K:
>  	case VM_MODE_P48V48_16K:
>  	case VM_MODE_P40V48_16K:
>  	case VM_MODE_P36V48_16K:
>  	case VM_MODE_P36V47_16K:
>  		tcr_el1 |= 2ul << 14; /* TG0 = 16KB */
>  		break;
> +	case VM_MODE_P52V48_4K:
>  	case VM_MODE_P48V48_4K:
>  	case VM_MODE_P40V48_4K:
>  	case VM_MODE_P36V48_4K:
> @@ -297,6 +314,8 @@ void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init)
>  
>  	/* Configure output size */
>  	switch (vm->mode) {
> +	case VM_MODE_P52V48_4K:
> +	case VM_MODE_P52V48_16K:
>  	case VM_MODE_P52V48_64K:
>  		tcr_el1 |= 6ul << 32; /* IPS = 52 bits */
>  		ttbr0_el1 |= (vm->pgd & GENMASK(51, 48)) >> (48 - 2);
> @@ -325,6 +344,8 @@ void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init)
>  	/* TCR_EL1 |= IRGN0:WBWA | ORGN0:WBWA | SH0:Inner-Shareable */;
>  	tcr_el1 |= (1 << 8) | (1 << 10) | (3 << 12);
>  	tcr_el1 |= (64 - vm->va_bits) /* T0SZ */;
> +	if (use_lpa2_pte_format(vm))
> +		tcr_el1 |= (1ul << 59) /* DS */;
>  
>  	vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_SCTLR_EL1), sctlr_el1);
>  	vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_TCR_EL1), tcr_el1);
> diff --git a/tools/testing/selftests/kvm/lib/guest_modes.c b/tools/testing/selftests/kvm/lib/guest_modes.c
> index c64c5cf49942..6634afc22137 100644
> --- a/tools/testing/selftests/kvm/lib/guest_modes.c
> +++ b/tools/testing/selftests/kvm/lib/guest_modes.c
> @@ -23,6 +23,8 @@ void guest_modes_append_default(void)
>  
>  		aarch64_get_supported_page_sizes(limit, &ipa4k, &ipa16k, &ipa64k);
>  
> +		guest_mode_append(VM_MODE_P52V48_4K, ipa4k >= 52, ipa4k >= 52);
> +		guest_mode_append(VM_MODE_P52V48_16K, ipa16k >= 52, ipa16k >= 52);
>  		guest_mode_append(VM_MODE_P52V48_64K, ipa64k >= 52, ipa64k >= 52);
>  
>  		guest_mode_append(VM_MODE_P48V48_4K, ipa4k >= 48, ipa4k >= 48);
> diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
> index 3ea24a5f4c43..0e4905b75825 100644
> --- a/tools/testing/selftests/kvm/lib/kvm_util.c
> +++ b/tools/testing/selftests/kvm/lib/kvm_util.c
> @@ -143,6 +143,7 @@ const char *vm_guest_mode_string(uint32_t i)
>  {
>  	static const char * const strings[] = {
>  		[VM_MODE_P52V48_4K]	= "PA-bits:52,  VA-bits:48,  4K pages",
> +		[VM_MODE_P52V48_16K]	= "PA-bits:52,  VA-bits:48, 16K pages",
>  		[VM_MODE_P52V48_64K]	= "PA-bits:52,  VA-bits:48, 64K pages",
>  		[VM_MODE_P48V48_4K]	= "PA-bits:48,  VA-bits:48,  4K pages",
>  		[VM_MODE_P48V48_16K]	= "PA-bits:48,  VA-bits:48, 16K pages",
> @@ -168,6 +169,7 @@ const char *vm_guest_mode_string(uint32_t i)
>  
>  const struct vm_guest_mode_params vm_guest_mode_params[] = {
>  	[VM_MODE_P52V48_4K]	= { 52, 48,  0x1000, 12 },
> +	[VM_MODE_P52V48_16K]	= { 52, 48,  0x4000, 14 },
>  	[VM_MODE_P52V48_64K]	= { 52, 48, 0x10000, 16 },
>  	[VM_MODE_P48V48_4K]	= { 48, 48,  0x1000, 12 },
>  	[VM_MODE_P48V48_16K]	= { 48, 48,  0x4000, 14 },
> @@ -246,6 +248,7 @@ struct kvm_vm *____vm_create(enum vm_guest_mode mode)
>  	case VM_MODE_P36V48_64K:
>  		vm->pgtable_levels = 3;
>  		break;
> +	case VM_MODE_P52V48_16K:
>  	case VM_MODE_P48V48_16K:
>  	case VM_MODE_P40V48_16K:
>  	case VM_MODE_P36V48_16K:
diff mbox series

Patch

diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h
index fbc2a79369b8..b8678bf4a980 100644
--- a/tools/testing/selftests/kvm/include/kvm_util_base.h
+++ b/tools/testing/selftests/kvm/include/kvm_util_base.h
@@ -150,6 +150,7 @@  static inline struct userspace_mem_region *vm_get_mem_region(struct kvm_vm *vm,
 
 enum vm_guest_mode {
 	VM_MODE_P52V48_4K,
+	VM_MODE_P52V48_16K,
 	VM_MODE_P52V48_64K,
 	VM_MODE_P48V48_4K,
 	VM_MODE_P48V48_16K,
diff --git a/tools/testing/selftests/kvm/lib/aarch64/processor.c b/tools/testing/selftests/kvm/lib/aarch64/processor.c
index b2d80396b8f8..934f8baa7d0e 100644
--- a/tools/testing/selftests/kvm/lib/aarch64/processor.c
+++ b/tools/testing/selftests/kvm/lib/aarch64/processor.c
@@ -12,6 +12,7 @@ 
 #include "kvm_util.h"
 #include "processor.h"
 #include <linux/bitfield.h>
+#include <linux/sizes.h>
 
 #define DEFAULT_ARM64_GUEST_STACK_VADDR_MIN	0xac0000
 
@@ -58,13 +59,25 @@  static uint64_t pte_index(struct kvm_vm *vm, vm_vaddr_t gva)
 	return (gva >> vm->page_shift) & mask;
 }
 
+static inline bool use_lpa2_pte_format(struct kvm_vm *vm)
+{
+	return (vm->page_size == SZ_4K || vm->page_size == SZ_16K) &&
+	    (vm->pa_bits > 48 || vm->va_bits > 48);
+}
+
 static uint64_t addr_pte(struct kvm_vm *vm, uint64_t pa, uint64_t attrs)
 {
 	uint64_t pte;
 
-	pte = pa & GENMASK(47, vm->page_shift);
-	if (vm->page_shift == 16)
-		pte |= (pa & GENMASK(51, 48)) >> (48 - 12);
+	if (use_lpa2_pte_format(vm)) {
+		pte = pa & GENMASK(49, vm->page_shift);
+		pte |= (pa & GENMASK(51, 50)) >> (50 - 8);
+		attrs &= ~GENMASK(9, 8);
+	} else {
+		pte = pa & GENMASK(47, vm->page_shift);
+		if (vm->page_shift == 16)
+			pte |= (pa & GENMASK(51, 48)) >> (48 - 12);
+	}
 	pte |= attrs;
 
 	return pte;
@@ -74,9 +87,14 @@  static uint64_t pte_addr(struct kvm_vm *vm, uint64_t pte)
 {
 	uint64_t pa;
 
-	pa = pte & GENMASK(47, vm->page_shift);
-	if (vm->page_shift == 16)
-		pa |= (pte & GENMASK(15, 12)) << (48 - 12);
+	if (use_lpa2_pte_format(vm)) {
+		pa = pte & GENMASK(49, vm->page_shift);
+		pa |= (pte & GENMASK(9, 8)) << (50 - 8);
+	} else {
+		pa = pte & GENMASK(47, vm->page_shift);
+		if (vm->page_shift == 16)
+			pa |= (pte & GENMASK(15, 12)) << (48 - 12);
+	}
 
 	return pa;
 }
@@ -266,9 +284,6 @@  void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init)
 
 	/* Configure base granule size */
 	switch (vm->mode) {
-	case VM_MODE_P52V48_4K:
-		TEST_FAIL("AArch64 does not support 4K sized pages "
-			  "with 52-bit physical address ranges");
 	case VM_MODE_PXXV48_4K:
 		TEST_FAIL("AArch64 does not support 4K sized pages "
 			  "with ANY-bit physical address ranges");
@@ -278,12 +293,14 @@  void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init)
 	case VM_MODE_P36V48_64K:
 		tcr_el1 |= 1ul << 14; /* TG0 = 64KB */
 		break;
+	case VM_MODE_P52V48_16K:
 	case VM_MODE_P48V48_16K:
 	case VM_MODE_P40V48_16K:
 	case VM_MODE_P36V48_16K:
 	case VM_MODE_P36V47_16K:
 		tcr_el1 |= 2ul << 14; /* TG0 = 16KB */
 		break;
+	case VM_MODE_P52V48_4K:
 	case VM_MODE_P48V48_4K:
 	case VM_MODE_P40V48_4K:
 	case VM_MODE_P36V48_4K:
@@ -297,6 +314,8 @@  void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init)
 
 	/* Configure output size */
 	switch (vm->mode) {
+	case VM_MODE_P52V48_4K:
+	case VM_MODE_P52V48_16K:
 	case VM_MODE_P52V48_64K:
 		tcr_el1 |= 6ul << 32; /* IPS = 52 bits */
 		ttbr0_el1 |= (vm->pgd & GENMASK(51, 48)) >> (48 - 2);
@@ -325,6 +344,8 @@  void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init)
 	/* TCR_EL1 |= IRGN0:WBWA | ORGN0:WBWA | SH0:Inner-Shareable */;
 	tcr_el1 |= (1 << 8) | (1 << 10) | (3 << 12);
 	tcr_el1 |= (64 - vm->va_bits) /* T0SZ */;
+	if (use_lpa2_pte_format(vm))
+		tcr_el1 |= (1ul << 59) /* DS */;
 
 	vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_SCTLR_EL1), sctlr_el1);
 	vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_TCR_EL1), tcr_el1);
diff --git a/tools/testing/selftests/kvm/lib/guest_modes.c b/tools/testing/selftests/kvm/lib/guest_modes.c
index c64c5cf49942..6634afc22137 100644
--- a/tools/testing/selftests/kvm/lib/guest_modes.c
+++ b/tools/testing/selftests/kvm/lib/guest_modes.c
@@ -23,6 +23,8 @@  void guest_modes_append_default(void)
 
 		aarch64_get_supported_page_sizes(limit, &ipa4k, &ipa16k, &ipa64k);
 
+		guest_mode_append(VM_MODE_P52V48_4K, ipa4k >= 52, ipa4k >= 52);
+		guest_mode_append(VM_MODE_P52V48_16K, ipa16k >= 52, ipa16k >= 52);
 		guest_mode_append(VM_MODE_P52V48_64K, ipa64k >= 52, ipa64k >= 52);
 
 		guest_mode_append(VM_MODE_P48V48_4K, ipa4k >= 48, ipa4k >= 48);
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index 3ea24a5f4c43..0e4905b75825 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -143,6 +143,7 @@  const char *vm_guest_mode_string(uint32_t i)
 {
 	static const char * const strings[] = {
 		[VM_MODE_P52V48_4K]	= "PA-bits:52,  VA-bits:48,  4K pages",
+		[VM_MODE_P52V48_16K]	= "PA-bits:52,  VA-bits:48, 16K pages",
 		[VM_MODE_P52V48_64K]	= "PA-bits:52,  VA-bits:48, 64K pages",
 		[VM_MODE_P48V48_4K]	= "PA-bits:48,  VA-bits:48,  4K pages",
 		[VM_MODE_P48V48_16K]	= "PA-bits:48,  VA-bits:48, 16K pages",
@@ -168,6 +169,7 @@  const char *vm_guest_mode_string(uint32_t i)
 
 const struct vm_guest_mode_params vm_guest_mode_params[] = {
 	[VM_MODE_P52V48_4K]	= { 52, 48,  0x1000, 12 },
+	[VM_MODE_P52V48_16K]	= { 52, 48,  0x4000, 14 },
 	[VM_MODE_P52V48_64K]	= { 52, 48, 0x10000, 16 },
 	[VM_MODE_P48V48_4K]	= { 48, 48,  0x1000, 12 },
 	[VM_MODE_P48V48_16K]	= { 48, 48,  0x4000, 14 },
@@ -246,6 +248,7 @@  struct kvm_vm *____vm_create(enum vm_guest_mode mode)
 	case VM_MODE_P36V48_64K:
 		vm->pgtable_levels = 3;
 		break;
+	case VM_MODE_P52V48_16K:
 	case VM_MODE_P48V48_16K:
 	case VM_MODE_P40V48_16K:
 	case VM_MODE_P36V48_16K: