Message ID | 20231116142931.1675485-12-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 |
On Thu, Nov 16, 2023 at 02:29:30PM +0000, Ryan Roberts wrote: > We are about to add 52 bit PA guest modes for 4K and 16K pages when the > system supports LPA2. In preparation beef up the logic that parses mmfr0 > to also tell us what the maximum supported PA size is for each page > size. Max PA size = 0 implies the page size is not supported at all. > > Signed-off-by: Ryan Roberts <ryan.roberts@arm.com> > --- > .../selftests/kvm/include/aarch64/processor.h | 4 +- > .../selftests/kvm/lib/aarch64/processor.c | 27 ++++++++++--- > tools/testing/selftests/kvm/lib/guest_modes.c | 40 ++++++++----------- > 3 files changed, 41 insertions(+), 30 deletions(-) > > diff --git a/tools/testing/selftests/kvm/include/aarch64/processor.h b/tools/testing/selftests/kvm/include/aarch64/processor.h > index c42d683102c7..cf20e44e86f2 100644 > --- a/tools/testing/selftests/kvm/include/aarch64/processor.h > +++ b/tools/testing/selftests/kvm/include/aarch64/processor.h > @@ -119,8 +119,8 @@ enum { > /* Access flag update enable/disable */ > #define TCR_EL1_HA (1ULL << 39) > > -void aarch64_get_supported_page_sizes(uint32_t ipa, > - bool *ps4k, bool *ps16k, bool *ps64k); > +void aarch64_get_supported_page_sizes(uint32_t ipa, uint32_t *ipa4k, > + uint32_t *ipa16k, uint32_t *ipa64k); > > void vm_init_descriptor_tables(struct kvm_vm *vm); > void vcpu_init_descriptor_tables(struct kvm_vcpu *vcpu); > diff --git a/tools/testing/selftests/kvm/lib/aarch64/processor.c b/tools/testing/selftests/kvm/lib/aarch64/processor.c > index 6fe12e985ba5..917cfeddb6b4 100644 > --- a/tools/testing/selftests/kvm/lib/aarch64/processor.c > +++ b/tools/testing/selftests/kvm/lib/aarch64/processor.c > @@ -492,12 +492,24 @@ uint32_t guest_get_vcpuid(void) > return read_sysreg(tpidr_el1); > } > > -void aarch64_get_supported_page_sizes(uint32_t ipa, > - bool *ps4k, bool *ps16k, bool *ps64k) > +static uint32_t max_ipa_for_page_size(uint32_t vm_ipa, uint32_t gran, > + uint32_t not_sup_val, uint32_t ipa52_min_val) > +{ > + if (gran == not_sup_val) > + return 0; > + else if (gran >= ipa52_min_val && vm_ipa >= 52) > + return 52; > + else > + return min(vm_ipa, 48U); > +} > + > +void aarch64_get_supported_page_sizes(uint32_t ipa, uint32_t *ipa4k, > + uint32_t *ipa16k, uint32_t *ipa64k) > { > struct kvm_vcpu_init preferred_init; > int kvm_fd, vm_fd, vcpu_fd, err; > uint64_t val; > + uint32_t gran; > struct kvm_one_reg reg = { > .id = KVM_ARM64_SYS_REG(SYS_ID_AA64MMFR0_EL1), > .addr = (uint64_t)&val, > @@ -518,9 +530,14 @@ void aarch64_get_supported_page_sizes(uint32_t ipa, > err = ioctl(vcpu_fd, KVM_GET_ONE_REG, ®); > TEST_ASSERT(err == 0, KVM_IOCTL_ERROR(KVM_GET_ONE_REG, vcpu_fd)); > > - *ps4k = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN4), val) != 0xf; > - *ps64k = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN64), val) == 0; > - *ps16k = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN16), val) != 0; > + gran = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN4), val); > + *ipa4k = max_ipa_for_page_size(ipa, gran, 0xf, 1); > + > + gran = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN64), val); > + *ipa64k = max_ipa_for_page_size(ipa, gran, 0xf, 0); > + > + gran = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN16), val); > + *ipa16k = max_ipa_for_page_size(ipa, gran, 0, 2); > > close(vcpu_fd); > close(vm_fd); > diff --git a/tools/testing/selftests/kvm/lib/guest_modes.c b/tools/testing/selftests/kvm/lib/guest_modes.c > index 1df3ce4b16fd..c64c5cf49942 100644 > --- a/tools/testing/selftests/kvm/lib/guest_modes.c > +++ b/tools/testing/selftests/kvm/lib/guest_modes.c > @@ -18,33 +18,27 @@ void guest_modes_append_default(void) > #else > { > unsigned int limit = kvm_check_cap(KVM_CAP_ARM_VM_IPA_SIZE); > - bool ps4k, ps16k, ps64k; > + uint32_t ipa4k, ipa16k, ipa64k; > int i; > > - aarch64_get_supported_page_sizes(limit, &ps4k, &ps16k, &ps64k); > + aarch64_get_supported_page_sizes(limit, &ipa4k, &ipa16k, &ipa64k); > > - vm_mode_default = NUM_VM_MODES; > + guest_mode_append(VM_MODE_P52V48_64K, ipa64k >= 52, ipa64k >= 52); Can we just change guest_mode_append() to take a single bool argument and initialize both ::supported and ::enabled to its value?
On Thu, Nov 16, 2023 at 02:29:30PM +0000, Ryan Roberts wrote: [...] > @@ -518,9 +530,14 @@ void aarch64_get_supported_page_sizes(uint32_t ipa, > err = ioctl(vcpu_fd, KVM_GET_ONE_REG, ®); > TEST_ASSERT(err == 0, KVM_IOCTL_ERROR(KVM_GET_ONE_REG, vcpu_fd)); > > - *ps4k = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN4), val) != 0xf; > - *ps64k = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN64), val) == 0; > - *ps16k = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN16), val) != 0; > + gran = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN4), val); > + *ipa4k = max_ipa_for_page_size(ipa, gran, 0xf, 1); > + > + gran = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN64), val); > + *ipa64k = max_ipa_for_page_size(ipa, gran, 0xf, 0); > + > + gran = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN16), val); > + *ipa16k = max_ipa_for_page_size(ipa, gran, 0, 2); Oh, also: we have the generated system register definitions available in KVM selftests at this point. It'd be a good idea to move away from 'magic' values and use the enumerations instead.
On 21/11/2023 23:27, Oliver Upton wrote: > On Thu, Nov 16, 2023 at 02:29:30PM +0000, Ryan Roberts wrote: >> We are about to add 52 bit PA guest modes for 4K and 16K pages when the >> system supports LPA2. In preparation beef up the logic that parses mmfr0 >> to also tell us what the maximum supported PA size is for each page >> size. Max PA size = 0 implies the page size is not supported at all. >> >> Signed-off-by: Ryan Roberts <ryan.roberts@arm.com> >> --- >> .../selftests/kvm/include/aarch64/processor.h | 4 +- >> .../selftests/kvm/lib/aarch64/processor.c | 27 ++++++++++--- >> tools/testing/selftests/kvm/lib/guest_modes.c | 40 ++++++++----------- >> 3 files changed, 41 insertions(+), 30 deletions(-) >> >> diff --git a/tools/testing/selftests/kvm/include/aarch64/processor.h b/tools/testing/selftests/kvm/include/aarch64/processor.h >> index c42d683102c7..cf20e44e86f2 100644 >> --- a/tools/testing/selftests/kvm/include/aarch64/processor.h >> +++ b/tools/testing/selftests/kvm/include/aarch64/processor.h >> @@ -119,8 +119,8 @@ enum { >> /* Access flag update enable/disable */ >> #define TCR_EL1_HA (1ULL << 39) >> >> -void aarch64_get_supported_page_sizes(uint32_t ipa, >> - bool *ps4k, bool *ps16k, bool *ps64k); >> +void aarch64_get_supported_page_sizes(uint32_t ipa, uint32_t *ipa4k, >> + uint32_t *ipa16k, uint32_t *ipa64k); >> >> void vm_init_descriptor_tables(struct kvm_vm *vm); >> void vcpu_init_descriptor_tables(struct kvm_vcpu *vcpu); >> diff --git a/tools/testing/selftests/kvm/lib/aarch64/processor.c b/tools/testing/selftests/kvm/lib/aarch64/processor.c >> index 6fe12e985ba5..917cfeddb6b4 100644 >> --- a/tools/testing/selftests/kvm/lib/aarch64/processor.c >> +++ b/tools/testing/selftests/kvm/lib/aarch64/processor.c >> @@ -492,12 +492,24 @@ uint32_t guest_get_vcpuid(void) >> return read_sysreg(tpidr_el1); >> } >> >> -void aarch64_get_supported_page_sizes(uint32_t ipa, >> - bool *ps4k, bool *ps16k, bool *ps64k) >> +static uint32_t max_ipa_for_page_size(uint32_t vm_ipa, uint32_t gran, >> + uint32_t not_sup_val, uint32_t ipa52_min_val) >> +{ >> + if (gran == not_sup_val) >> + return 0; >> + else if (gran >= ipa52_min_val && vm_ipa >= 52) >> + return 52; >> + else >> + return min(vm_ipa, 48U); >> +} >> + >> +void aarch64_get_supported_page_sizes(uint32_t ipa, uint32_t *ipa4k, >> + uint32_t *ipa16k, uint32_t *ipa64k) >> { >> struct kvm_vcpu_init preferred_init; >> int kvm_fd, vm_fd, vcpu_fd, err; >> uint64_t val; >> + uint32_t gran; >> struct kvm_one_reg reg = { >> .id = KVM_ARM64_SYS_REG(SYS_ID_AA64MMFR0_EL1), >> .addr = (uint64_t)&val, >> @@ -518,9 +530,14 @@ void aarch64_get_supported_page_sizes(uint32_t ipa, >> err = ioctl(vcpu_fd, KVM_GET_ONE_REG, ®); >> TEST_ASSERT(err == 0, KVM_IOCTL_ERROR(KVM_GET_ONE_REG, vcpu_fd)); >> >> - *ps4k = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN4), val) != 0xf; >> - *ps64k = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN64), val) == 0; >> - *ps16k = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN16), val) != 0; >> + gran = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN4), val); >> + *ipa4k = max_ipa_for_page_size(ipa, gran, 0xf, 1); >> + >> + gran = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN64), val); >> + *ipa64k = max_ipa_for_page_size(ipa, gran, 0xf, 0); >> + >> + gran = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN16), val); >> + *ipa16k = max_ipa_for_page_size(ipa, gran, 0, 2); >> >> close(vcpu_fd); >> close(vm_fd); >> diff --git a/tools/testing/selftests/kvm/lib/guest_modes.c b/tools/testing/selftests/kvm/lib/guest_modes.c >> index 1df3ce4b16fd..c64c5cf49942 100644 >> --- a/tools/testing/selftests/kvm/lib/guest_modes.c >> +++ b/tools/testing/selftests/kvm/lib/guest_modes.c >> @@ -18,33 +18,27 @@ void guest_modes_append_default(void) >> #else >> { >> unsigned int limit = kvm_check_cap(KVM_CAP_ARM_VM_IPA_SIZE); >> - bool ps4k, ps16k, ps64k; >> + uint32_t ipa4k, ipa16k, ipa64k; >> int i; >> >> - aarch64_get_supported_page_sizes(limit, &ps4k, &ps16k, &ps64k); >> + aarch64_get_supported_page_sizes(limit, &ipa4k, &ipa16k, &ipa64k); >> >> - vm_mode_default = NUM_VM_MODES; >> + guest_mode_append(VM_MODE_P52V48_64K, ipa64k >= 52, ipa64k >= 52); > > Can we just change guest_mode_append() to take a single bool argument and > initialize both ::supported and ::enabled to its value? Works for me; I'll fix it up and re-post next week. >
On 21/11/2023 23:34, Oliver Upton wrote: > On Thu, Nov 16, 2023 at 02:29:30PM +0000, Ryan Roberts wrote: > > [...] > >> @@ -518,9 +530,14 @@ void aarch64_get_supported_page_sizes(uint32_t ipa, >> err = ioctl(vcpu_fd, KVM_GET_ONE_REG, ®); >> TEST_ASSERT(err == 0, KVM_IOCTL_ERROR(KVM_GET_ONE_REG, vcpu_fd)); >> >> - *ps4k = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN4), val) != 0xf; >> - *ps64k = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN64), val) == 0; >> - *ps16k = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN16), val) != 0; >> + gran = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN4), val); >> + *ipa4k = max_ipa_for_page_size(ipa, gran, 0xf, 1); >> + >> + gran = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN64), val); >> + *ipa64k = max_ipa_for_page_size(ipa, gran, 0xf, 0); >> + >> + gran = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN16), val); >> + *ipa16k = max_ipa_for_page_size(ipa, gran, 0, 2); > > Oh, also: we have the generated system register definitions available in > KVM selftests at this point. It'd be a good idea to move away from > 'magic' values and use the enumerations instead. > OK will do!
diff --git a/tools/testing/selftests/kvm/include/aarch64/processor.h b/tools/testing/selftests/kvm/include/aarch64/processor.h index c42d683102c7..cf20e44e86f2 100644 --- a/tools/testing/selftests/kvm/include/aarch64/processor.h +++ b/tools/testing/selftests/kvm/include/aarch64/processor.h @@ -119,8 +119,8 @@ enum { /* Access flag update enable/disable */ #define TCR_EL1_HA (1ULL << 39) -void aarch64_get_supported_page_sizes(uint32_t ipa, - bool *ps4k, bool *ps16k, bool *ps64k); +void aarch64_get_supported_page_sizes(uint32_t ipa, uint32_t *ipa4k, + uint32_t *ipa16k, uint32_t *ipa64k); void vm_init_descriptor_tables(struct kvm_vm *vm); void vcpu_init_descriptor_tables(struct kvm_vcpu *vcpu); diff --git a/tools/testing/selftests/kvm/lib/aarch64/processor.c b/tools/testing/selftests/kvm/lib/aarch64/processor.c index 6fe12e985ba5..917cfeddb6b4 100644 --- a/tools/testing/selftests/kvm/lib/aarch64/processor.c +++ b/tools/testing/selftests/kvm/lib/aarch64/processor.c @@ -492,12 +492,24 @@ uint32_t guest_get_vcpuid(void) return read_sysreg(tpidr_el1); } -void aarch64_get_supported_page_sizes(uint32_t ipa, - bool *ps4k, bool *ps16k, bool *ps64k) +static uint32_t max_ipa_for_page_size(uint32_t vm_ipa, uint32_t gran, + uint32_t not_sup_val, uint32_t ipa52_min_val) +{ + if (gran == not_sup_val) + return 0; + else if (gran >= ipa52_min_val && vm_ipa >= 52) + return 52; + else + return min(vm_ipa, 48U); +} + +void aarch64_get_supported_page_sizes(uint32_t ipa, uint32_t *ipa4k, + uint32_t *ipa16k, uint32_t *ipa64k) { struct kvm_vcpu_init preferred_init; int kvm_fd, vm_fd, vcpu_fd, err; uint64_t val; + uint32_t gran; struct kvm_one_reg reg = { .id = KVM_ARM64_SYS_REG(SYS_ID_AA64MMFR0_EL1), .addr = (uint64_t)&val, @@ -518,9 +530,14 @@ void aarch64_get_supported_page_sizes(uint32_t ipa, err = ioctl(vcpu_fd, KVM_GET_ONE_REG, ®); TEST_ASSERT(err == 0, KVM_IOCTL_ERROR(KVM_GET_ONE_REG, vcpu_fd)); - *ps4k = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN4), val) != 0xf; - *ps64k = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN64), val) == 0; - *ps16k = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN16), val) != 0; + gran = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN4), val); + *ipa4k = max_ipa_for_page_size(ipa, gran, 0xf, 1); + + gran = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN64), val); + *ipa64k = max_ipa_for_page_size(ipa, gran, 0xf, 0); + + gran = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN16), val); + *ipa16k = max_ipa_for_page_size(ipa, gran, 0, 2); close(vcpu_fd); close(vm_fd); diff --git a/tools/testing/selftests/kvm/lib/guest_modes.c b/tools/testing/selftests/kvm/lib/guest_modes.c index 1df3ce4b16fd..c64c5cf49942 100644 --- a/tools/testing/selftests/kvm/lib/guest_modes.c +++ b/tools/testing/selftests/kvm/lib/guest_modes.c @@ -18,33 +18,27 @@ void guest_modes_append_default(void) #else { unsigned int limit = kvm_check_cap(KVM_CAP_ARM_VM_IPA_SIZE); - bool ps4k, ps16k, ps64k; + uint32_t ipa4k, ipa16k, ipa64k; int i; - aarch64_get_supported_page_sizes(limit, &ps4k, &ps16k, &ps64k); + aarch64_get_supported_page_sizes(limit, &ipa4k, &ipa16k, &ipa64k); - vm_mode_default = NUM_VM_MODES; + guest_mode_append(VM_MODE_P52V48_64K, ipa64k >= 52, ipa64k >= 52); - if (limit >= 52) - guest_mode_append(VM_MODE_P52V48_64K, ps64k, ps64k); - if (limit >= 48) { - guest_mode_append(VM_MODE_P48V48_4K, ps4k, ps4k); - guest_mode_append(VM_MODE_P48V48_16K, ps16k, ps16k); - guest_mode_append(VM_MODE_P48V48_64K, ps64k, ps64k); - } - if (limit >= 40) { - guest_mode_append(VM_MODE_P40V48_4K, ps4k, ps4k); - guest_mode_append(VM_MODE_P40V48_16K, ps16k, ps16k); - guest_mode_append(VM_MODE_P40V48_64K, ps64k, ps64k); - if (ps4k) - vm_mode_default = VM_MODE_P40V48_4K; - } - if (limit >= 36) { - guest_mode_append(VM_MODE_P36V48_4K, ps4k, ps4k); - guest_mode_append(VM_MODE_P36V48_16K, ps16k, ps16k); - guest_mode_append(VM_MODE_P36V48_64K, ps64k, ps64k); - guest_mode_append(VM_MODE_P36V47_16K, ps16k, ps16k); - } + guest_mode_append(VM_MODE_P48V48_4K, ipa4k >= 48, ipa4k >= 48); + guest_mode_append(VM_MODE_P48V48_16K, ipa16k >= 48, ipa16k >= 48); + guest_mode_append(VM_MODE_P48V48_64K, ipa64k >= 48, ipa16k >= 48); + + guest_mode_append(VM_MODE_P40V48_4K, ipa4k >= 40, ipa4k >= 40); + guest_mode_append(VM_MODE_P40V48_16K, ipa16k >= 40, ipa16k >= 40); + guest_mode_append(VM_MODE_P40V48_64K, ipa64k >= 40, ipa64k >= 40); + + guest_mode_append(VM_MODE_P36V48_4K, ipa4k >= 36, ipa4k >= 36); + guest_mode_append(VM_MODE_P36V48_16K, ipa16k >= 36, ipa16k >= 36); + guest_mode_append(VM_MODE_P36V48_64K, ipa64k >= 36, ipa64k >= 36); + guest_mode_append(VM_MODE_P36V47_16K, ipa16k >= 36, ipa16k >= 36); + + vm_mode_default = ipa4k >= 40 ? VM_MODE_P40V48_4K : NUM_VM_MODES; /* * Pick the first supported IPA size if the default
We are about to add 52 bit PA guest modes for 4K and 16K pages when the system supports LPA2. In preparation beef up the logic that parses mmfr0 to also tell us what the maximum supported PA size is for each page size. Max PA size = 0 implies the page size is not supported at all. Signed-off-by: Ryan Roberts <ryan.roberts@arm.com> --- .../selftests/kvm/include/aarch64/processor.h | 4 +- .../selftests/kvm/lib/aarch64/processor.c | 27 ++++++++++--- tools/testing/selftests/kvm/lib/guest_modes.c | 40 ++++++++----------- 3 files changed, 41 insertions(+), 30 deletions(-)