Message ID | 20200904160018.29481-3-steven.price@arm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | MTE support for KVM guest | expand |
On Fri, Sep 04, 2020 at 05:00:18PM +0100, Steven Price wrote: > Add a new VCPU features 'KVM_ARM_VCPU_MTE' which enables memory tagging > on a VCPU. When enabled on any VCPU in the virtual machine this causes > all pages that are faulted into the VM to have the PG_mte_tagged flag > set (and the tag storage cleared if this is the first use). > > Signed-off-by: Steven Price <steven.price@arm.com> > --- > arch/arm64/include/asm/kvm_emulate.h | 3 +++ > arch/arm64/include/asm/kvm_host.h | 5 ++++- > arch/arm64/include/uapi/asm/kvm.h | 1 + > arch/arm64/kvm/mmu.c | 15 +++++++++++++++ > arch/arm64/kvm/reset.c | 8 ++++++++ > arch/arm64/kvm/sys_regs.c | 6 +++++- > 6 files changed, 36 insertions(+), 2 deletions(-) > > diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h > index 49a55be2b9a2..0042323a4b7f 100644 > --- a/arch/arm64/include/asm/kvm_emulate.h > +++ b/arch/arm64/include/asm/kvm_emulate.h > @@ -79,6 +79,9 @@ static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu) > if (cpus_have_const_cap(ARM64_MISMATCHED_CACHE_TYPE) || > vcpu_el1_is_32bit(vcpu)) > vcpu->arch.hcr_el2 |= HCR_TID2; > + > + if (test_bit(KVM_ARM_VCPU_MTE, vcpu->arch.features)) > + vcpu->arch.hcr_el2 |= HCR_ATA; > } > > static inline unsigned long *vcpu_hcr(struct kvm_vcpu *vcpu) > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h > index 4f4360dd149e..b1190366242b 100644 > --- a/arch/arm64/include/asm/kvm_host.h > +++ b/arch/arm64/include/asm/kvm_host.h > @@ -37,7 +37,7 @@ > > #define KVM_MAX_VCPUS VGIC_V3_MAX_CPUS > > -#define KVM_VCPU_MAX_FEATURES 7 > +#define KVM_VCPU_MAX_FEATURES 8 > > #define KVM_REQ_SLEEP \ > KVM_ARCH_REQ_FLAGS(0, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP) > @@ -110,6 +110,9 @@ struct kvm_arch { > * supported. > */ > bool return_nisv_io_abort_to_user; > + > + /* If any VCPU has MTE enabled then all memory must be MTE enabled */ > + bool vcpu_has_mte; It looks like this is unnecessary as it's only used once, where a feature check could be used. > }; > > struct kvm_vcpu_fault_info { > diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h > index ba85bb23f060..2677e1ab8c16 100644 > --- a/arch/arm64/include/uapi/asm/kvm.h > +++ b/arch/arm64/include/uapi/asm/kvm.h > @@ -106,6 +106,7 @@ struct kvm_regs { > #define KVM_ARM_VCPU_SVE 4 /* enable SVE for this CPU */ > #define KVM_ARM_VCPU_PTRAUTH_ADDRESS 5 /* VCPU uses address authentication */ > #define KVM_ARM_VCPU_PTRAUTH_GENERIC 6 /* VCPU uses generic authentication */ > +#define KVM_ARM_VCPU_MTE 7 /* VCPU supports Memory Tagging */ > > struct kvm_vcpu_init { > __u32 target; > diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c > index ba00bcc0c884..e8891bacd76f 100644 > --- a/arch/arm64/kvm/mmu.c > +++ b/arch/arm64/kvm/mmu.c > @@ -1949,6 +1949,21 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, > if (vma_pagesize == PAGE_SIZE && !force_pte) > vma_pagesize = transparent_hugepage_adjust(memslot, hva, > &pfn, &fault_ipa); > + if (system_supports_mte() && kvm->arch.vcpu_has_mte && pfn_valid(pfn)) { > + /* > + * VM will be able to see the page's tags, so we must ensure > + * they have been initialised. > + */ > + struct page *page = pfn_to_page(pfn); > + long i, nr_pages = compound_nr(page); > + > + /* if PG_mte_tagged is set, tags have already been initialised */ > + for (i = 0; i < nr_pages; i++, page++) { > + if (!test_and_set_bit(PG_mte_tagged, &page->flags)) > + mte_clear_page_tags(page_address(page)); > + } > + } > + > if (writable) > kvm_set_pfn_dirty(pfn); > > diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c > index ee33875c5c2a..82f3883d717f 100644 > --- a/arch/arm64/kvm/reset.c > +++ b/arch/arm64/kvm/reset.c > @@ -274,6 +274,14 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu) > } > } > > + if (test_bit(KVM_ARM_VCPU_MTE, vcpu->arch.features)) { > + if (!system_supports_mte()) { > + ret = -EINVAL; > + goto out; > + } > + vcpu->kvm->arch.vcpu_has_mte = true; > + } We either need a KVM cap or a new CPU feature probing interface to avoid making userspace try features one at a time. It's too bad that VCPU_INIT doesn't clear all offending features from the feature set when returning EINVAL, because then userspace could create a scratch VCPU with everything it supports in order to see what KVM also supports in one go. > + > switch (vcpu->arch.target) { > default: > if (test_bit(KVM_ARM_VCPU_EL1_32BIT, vcpu->arch.features)) { > diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c > index a655f172b5ad..6a971b201e81 100644 > --- a/arch/arm64/kvm/sys_regs.c > +++ b/arch/arm64/kvm/sys_regs.c > @@ -1132,7 +1132,8 @@ static u64 read_id_reg(const struct kvm_vcpu *vcpu, > val &= ~(0xfUL << ID_AA64PFR0_SVE_SHIFT); > val &= ~(0xfUL << ID_AA64PFR0_AMU_SHIFT); > } else if (id == SYS_ID_AA64PFR1_EL1) { > - val &= ~(0xfUL << ID_AA64PFR1_MTE_SHIFT); > + if (!test_bit(KVM_ARM_VCPU_MTE, vcpu->arch.features)) > + val &= ~(0xfUL << ID_AA64PFR1_MTE_SHIFT); > } else if (id == SYS_ID_AA64ISAR1_EL1 && !vcpu_has_ptrauth(vcpu)) { > val &= ~((0xfUL << ID_AA64ISAR1_APA_SHIFT) | > (0xfUL << ID_AA64ISAR1_API_SHIFT) | > @@ -1394,6 +1395,9 @@ static bool access_mte_regs(struct kvm_vcpu *vcpu, struct sys_reg_params *p, > static unsigned int mte_visibility(const struct kvm_vcpu *vcpu, > const struct sys_reg_desc *rd) > { > + if (test_bit(KVM_ARM_VCPU_MTE, vcpu->arch.features)) > + return 0; > + > return REG_HIDDEN_USER | REG_HIDDEN_GUEST; > } > > -- > 2.20.1 > > _______________________________________________ > kvmarm mailing list > kvmarm@lists.cs.columbia.edu > https://lists.cs.columbia.edu/mailman/listinfo/kvmarm > Thanks, drew
On Wed, 9 Sep 2020 at 16:48, Andrew Jones <drjones@redhat.com> wrote: > We either need a KVM cap or a new CPU feature probing interface to avoid > making userspace try features one at a time. It's too bad that VCPU_INIT > doesn't clear all offending features from the feature set when returning > EINVAL, because then userspace could create a scratch VCPU with everything > it supports in order to see what KVM also supports in one go. You could add one if you wanted -- add a new feature bit TELL_ME_WHAT_YOU_HAVE. If the kernel sees that then on filure it clears out feature bits it doesn't support and also clears TELL_ME_WHAT_YOU_HAVE. If QEMU sees EINVAL and TELL_ME_WHAT_YOU_HAVE is still set, then it knows it's dealing with an old kernel and has to do one-at-a-time probing. If it sees EINVAL but not TELL_ME_WHAT_YOU_HAVE then it knows it has a new kernel and has just got all the info. -- PMM
On Wed, Sep 09, 2020 at 04:53:02PM +0100, Peter Maydell wrote: > On Wed, 9 Sep 2020 at 16:48, Andrew Jones <drjones@redhat.com> wrote: > > We either need a KVM cap or a new CPU feature probing interface to avoid > > making userspace try features one at a time. It's too bad that VCPU_INIT > > doesn't clear all offending features from the feature set when returning > > EINVAL, because then userspace could create a scratch VCPU with everything > > it supports in order to see what KVM also supports in one go. > > You could add one if you wanted -- add a new feature bit > TELL_ME_WHAT_YOU_HAVE. If the kernel sees that then on filure > it clears out feature bits it doesn't support and also clears > TELL_ME_WHAT_YOU_HAVE. If QEMU sees EINVAL and TELL_ME_WHAT_YOU_HAVE > is still set, then it knows it's dealing with an old kernel > and has to do one-at-a-time probing. If it sees EINVAL but not > TELL_ME_WHAT_YOU_HAVE then it knows it has a new kernel and > has just got all the info. > That's a great proposal. I'll try to find time to send the patches. Thanks, drew
On 09/09/2020 16:48, Andrew Jones wrote: > On Fri, Sep 04, 2020 at 05:00:18PM +0100, Steven Price wrote: >> Add a new VCPU features 'KVM_ARM_VCPU_MTE' which enables memory tagging >> on a VCPU. When enabled on any VCPU in the virtual machine this causes >> all pages that are faulted into the VM to have the PG_mte_tagged flag >> set (and the tag storage cleared if this is the first use). >> >> Signed-off-by: Steven Price <steven.price@arm.com> >> --- >> arch/arm64/include/asm/kvm_emulate.h | 3 +++ >> arch/arm64/include/asm/kvm_host.h | 5 ++++- >> arch/arm64/include/uapi/asm/kvm.h | 1 + >> arch/arm64/kvm/mmu.c | 15 +++++++++++++++ >> arch/arm64/kvm/reset.c | 8 ++++++++ >> arch/arm64/kvm/sys_regs.c | 6 +++++- >> 6 files changed, 36 insertions(+), 2 deletions(-) >> >> diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h >> index 49a55be2b9a2..0042323a4b7f 100644 >> --- a/arch/arm64/include/asm/kvm_emulate.h >> +++ b/arch/arm64/include/asm/kvm_emulate.h >> @@ -79,6 +79,9 @@ static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu) >> if (cpus_have_const_cap(ARM64_MISMATCHED_CACHE_TYPE) || >> vcpu_el1_is_32bit(vcpu)) >> vcpu->arch.hcr_el2 |= HCR_TID2; >> + >> + if (test_bit(KVM_ARM_VCPU_MTE, vcpu->arch.features)) >> + vcpu->arch.hcr_el2 |= HCR_ATA; >> } >> >> static inline unsigned long *vcpu_hcr(struct kvm_vcpu *vcpu) >> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h >> index 4f4360dd149e..b1190366242b 100644 >> --- a/arch/arm64/include/asm/kvm_host.h >> +++ b/arch/arm64/include/asm/kvm_host.h >> @@ -37,7 +37,7 @@ >> >> #define KVM_MAX_VCPUS VGIC_V3_MAX_CPUS >> >> -#define KVM_VCPU_MAX_FEATURES 7 >> +#define KVM_VCPU_MAX_FEATURES 8 >> >> #define KVM_REQ_SLEEP \ >> KVM_ARCH_REQ_FLAGS(0, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP) >> @@ -110,6 +110,9 @@ struct kvm_arch { >> * supported. >> */ >> bool return_nisv_io_abort_to_user; >> + >> + /* If any VCPU has MTE enabled then all memory must be MTE enabled */ >> + bool vcpu_has_mte; > > It looks like this is unnecessary as it's only used once, where a feature > check could be used. It's used in user_mem_abort(), so every time we fault a page into the VM - so having to iterate over all VCPUs to check if any have the feature bit set seems too expensive. Although perhaps I should just accept that this is realistically a VM setting and move it out of the VCPU. >> }; >> >> struct kvm_vcpu_fault_info { >> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h >> index ba85bb23f060..2677e1ab8c16 100644 >> --- a/arch/arm64/include/uapi/asm/kvm.h >> +++ b/arch/arm64/include/uapi/asm/kvm.h >> @@ -106,6 +106,7 @@ struct kvm_regs { >> #define KVM_ARM_VCPU_SVE 4 /* enable SVE for this CPU */ >> #define KVM_ARM_VCPU_PTRAUTH_ADDRESS 5 /* VCPU uses address authentication */ >> #define KVM_ARM_VCPU_PTRAUTH_GENERIC 6 /* VCPU uses generic authentication */ >> +#define KVM_ARM_VCPU_MTE 7 /* VCPU supports Memory Tagging */ >> >> struct kvm_vcpu_init { >> __u32 target; >> diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c >> index ba00bcc0c884..e8891bacd76f 100644 >> --- a/arch/arm64/kvm/mmu.c >> +++ b/arch/arm64/kvm/mmu.c >> @@ -1949,6 +1949,21 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, >> if (vma_pagesize == PAGE_SIZE && !force_pte) >> vma_pagesize = transparent_hugepage_adjust(memslot, hva, >> &pfn, &fault_ipa); >> + if (system_supports_mte() && kvm->arch.vcpu_has_mte && pfn_valid(pfn)) { >> + /* >> + * VM will be able to see the page's tags, so we must ensure >> + * they have been initialised. >> + */ >> + struct page *page = pfn_to_page(pfn); >> + long i, nr_pages = compound_nr(page); >> + >> + /* if PG_mte_tagged is set, tags have already been initialised */ >> + for (i = 0; i < nr_pages; i++, page++) { >> + if (!test_and_set_bit(PG_mte_tagged, &page->flags)) >> + mte_clear_page_tags(page_address(page)); >> + } >> + } >> + >> if (writable) >> kvm_set_pfn_dirty(pfn); >> >> diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c >> index ee33875c5c2a..82f3883d717f 100644 >> --- a/arch/arm64/kvm/reset.c >> +++ b/arch/arm64/kvm/reset.c >> @@ -274,6 +274,14 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu) >> } >> } >> >> + if (test_bit(KVM_ARM_VCPU_MTE, vcpu->arch.features)) { >> + if (!system_supports_mte()) { >> + ret = -EINVAL; >> + goto out; >> + } >> + vcpu->kvm->arch.vcpu_has_mte = true; >> + } > > We either need a KVM cap or a new CPU feature probing interface to avoid > making userspace try features one at a time. It's too bad that VCPU_INIT > doesn't clear all offending features from the feature set when returning > EINVAL, because then userspace could create a scratch VCPU with everything > it supports in order to see what KVM also supports in one go. If Peter's TELL_ME_WHAT_YOU_HAVE idea works out then perhaps we don't need the cap? Or would it still be useful? Thanks, Steve >> + >> switch (vcpu->arch.target) { >> default: >> if (test_bit(KVM_ARM_VCPU_EL1_32BIT, vcpu->arch.features)) { >> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c >> index a655f172b5ad..6a971b201e81 100644 >> --- a/arch/arm64/kvm/sys_regs.c >> +++ b/arch/arm64/kvm/sys_regs.c >> @@ -1132,7 +1132,8 @@ static u64 read_id_reg(const struct kvm_vcpu *vcpu, >> val &= ~(0xfUL << ID_AA64PFR0_SVE_SHIFT); >> val &= ~(0xfUL << ID_AA64PFR0_AMU_SHIFT); >> } else if (id == SYS_ID_AA64PFR1_EL1) { >> - val &= ~(0xfUL << ID_AA64PFR1_MTE_SHIFT); >> + if (!test_bit(KVM_ARM_VCPU_MTE, vcpu->arch.features)) >> + val &= ~(0xfUL << ID_AA64PFR1_MTE_SHIFT); >> } else if (id == SYS_ID_AA64ISAR1_EL1 && !vcpu_has_ptrauth(vcpu)) { >> val &= ~((0xfUL << ID_AA64ISAR1_APA_SHIFT) | >> (0xfUL << ID_AA64ISAR1_API_SHIFT) | >> @@ -1394,6 +1395,9 @@ static bool access_mte_regs(struct kvm_vcpu *vcpu, struct sys_reg_params *p, >> static unsigned int mte_visibility(const struct kvm_vcpu *vcpu, >> const struct sys_reg_desc *rd) >> { >> + if (test_bit(KVM_ARM_VCPU_MTE, vcpu->arch.features)) >> + return 0; >> + >> return REG_HIDDEN_USER | REG_HIDDEN_GUEST; >> } >> >> -- >> 2.20.1 >> >> _______________________________________________ >> kvmarm mailing list >> kvmarm@lists.cs.columbia.edu >> https://lists.cs.columbia.edu/mailman/listinfo/kvmarm >> > > Thanks, > drew >
On Thu, Sep 10, 2020 at 08:38:54AM +0200, Andrew Jones wrote: > On Wed, Sep 09, 2020 at 04:53:02PM +0100, Peter Maydell wrote: > > On Wed, 9 Sep 2020 at 16:48, Andrew Jones <drjones@redhat.com> wrote: > > > We either need a KVM cap or a new CPU feature probing interface to avoid > > > making userspace try features one at a time. It's too bad that VCPU_INIT > > > doesn't clear all offending features from the feature set when returning > > > EINVAL, because then userspace could create a scratch VCPU with everything > > > it supports in order to see what KVM also supports in one go. > > > > You could add one if you wanted -- add a new feature bit > > TELL_ME_WHAT_YOU_HAVE. If the kernel sees that then on filure > > it clears out feature bits it doesn't support and also clears > > TELL_ME_WHAT_YOU_HAVE. If QEMU sees EINVAL and TELL_ME_WHAT_YOU_HAVE > > is still set, then it knows it's dealing with an old kernel > > and has to do one-at-a-time probing. If it sees EINVAL but not > > TELL_ME_WHAT_YOU_HAVE then it knows it has a new kernel and > > has just got all the info. > > > > That's a great proposal. I'll try to find time to send the patches. > We also have KVM_ARM_PREFERRED_TARGET, which is documented as """ ... The ioctl returns struct kvm_vcpu_init instance containing information about preferred CPU target type and recommended features for it. The kvm_vcpu_init->features bitmap returned will have feature bits set if the preferred target recommends setting these features, but this is not mandatory. ... """ But, it says "recommended" features, not "all supported" features, and the current implementation of KVM_ARM_PREFERRED_TARGET only zeros out features. So, I think we should just leave KVM_ARM_PREFERRED_TARGET as is and stick to the plan of extending VCPU_INIT. Thanks, drew
On Thu, Sep 10, 2020 at 10:21:07AM +0100, Steven Price wrote: > > We either need a KVM cap or a new CPU feature probing interface to avoid > > making userspace try features one at a time. It's too bad that VCPU_INIT > > doesn't clear all offending features from the feature set when returning > > EINVAL, because then userspace could create a scratch VCPU with everything > > it supports in order to see what KVM also supports in one go. > > If Peter's TELL_ME_WHAT_YOU_HAVE idea works out then perhaps we don't need > the cap? Or would it still be useful? > We wouldn't need it, but we don't _need_ it now either. It's not very convenient to probe vcpu features with scratch vcpus, especially if we must probe one at a time, but it works. The TELL_ME_WHAT_YOU_HAVE idea will only fix the one at a time issue, but still require a vcpu fd. If this feature becomes a VM feature then a cap or VM level API would help reduce the userspace probing work. Thanks, drew
diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h index 49a55be2b9a2..0042323a4b7f 100644 --- a/arch/arm64/include/asm/kvm_emulate.h +++ b/arch/arm64/include/asm/kvm_emulate.h @@ -79,6 +79,9 @@ static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu) if (cpus_have_const_cap(ARM64_MISMATCHED_CACHE_TYPE) || vcpu_el1_is_32bit(vcpu)) vcpu->arch.hcr_el2 |= HCR_TID2; + + if (test_bit(KVM_ARM_VCPU_MTE, vcpu->arch.features)) + vcpu->arch.hcr_el2 |= HCR_ATA; } static inline unsigned long *vcpu_hcr(struct kvm_vcpu *vcpu) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 4f4360dd149e..b1190366242b 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -37,7 +37,7 @@ #define KVM_MAX_VCPUS VGIC_V3_MAX_CPUS -#define KVM_VCPU_MAX_FEATURES 7 +#define KVM_VCPU_MAX_FEATURES 8 #define KVM_REQ_SLEEP \ KVM_ARCH_REQ_FLAGS(0, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP) @@ -110,6 +110,9 @@ struct kvm_arch { * supported. */ bool return_nisv_io_abort_to_user; + + /* If any VCPU has MTE enabled then all memory must be MTE enabled */ + bool vcpu_has_mte; }; struct kvm_vcpu_fault_info { diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h index ba85bb23f060..2677e1ab8c16 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h @@ -106,6 +106,7 @@ struct kvm_regs { #define KVM_ARM_VCPU_SVE 4 /* enable SVE for this CPU */ #define KVM_ARM_VCPU_PTRAUTH_ADDRESS 5 /* VCPU uses address authentication */ #define KVM_ARM_VCPU_PTRAUTH_GENERIC 6 /* VCPU uses generic authentication */ +#define KVM_ARM_VCPU_MTE 7 /* VCPU supports Memory Tagging */ struct kvm_vcpu_init { __u32 target; diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index ba00bcc0c884..e8891bacd76f 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -1949,6 +1949,21 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, if (vma_pagesize == PAGE_SIZE && !force_pte) vma_pagesize = transparent_hugepage_adjust(memslot, hva, &pfn, &fault_ipa); + if (system_supports_mte() && kvm->arch.vcpu_has_mte && pfn_valid(pfn)) { + /* + * VM will be able to see the page's tags, so we must ensure + * they have been initialised. + */ + struct page *page = pfn_to_page(pfn); + long i, nr_pages = compound_nr(page); + + /* if PG_mte_tagged is set, tags have already been initialised */ + for (i = 0; i < nr_pages; i++, page++) { + if (!test_and_set_bit(PG_mte_tagged, &page->flags)) + mte_clear_page_tags(page_address(page)); + } + } + if (writable) kvm_set_pfn_dirty(pfn); diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c index ee33875c5c2a..82f3883d717f 100644 --- a/arch/arm64/kvm/reset.c +++ b/arch/arm64/kvm/reset.c @@ -274,6 +274,14 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu) } } + if (test_bit(KVM_ARM_VCPU_MTE, vcpu->arch.features)) { + if (!system_supports_mte()) { + ret = -EINVAL; + goto out; + } + vcpu->kvm->arch.vcpu_has_mte = true; + } + switch (vcpu->arch.target) { default: if (test_bit(KVM_ARM_VCPU_EL1_32BIT, vcpu->arch.features)) { diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index a655f172b5ad..6a971b201e81 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -1132,7 +1132,8 @@ static u64 read_id_reg(const struct kvm_vcpu *vcpu, val &= ~(0xfUL << ID_AA64PFR0_SVE_SHIFT); val &= ~(0xfUL << ID_AA64PFR0_AMU_SHIFT); } else if (id == SYS_ID_AA64PFR1_EL1) { - val &= ~(0xfUL << ID_AA64PFR1_MTE_SHIFT); + if (!test_bit(KVM_ARM_VCPU_MTE, vcpu->arch.features)) + val &= ~(0xfUL << ID_AA64PFR1_MTE_SHIFT); } else if (id == SYS_ID_AA64ISAR1_EL1 && !vcpu_has_ptrauth(vcpu)) { val &= ~((0xfUL << ID_AA64ISAR1_APA_SHIFT) | (0xfUL << ID_AA64ISAR1_API_SHIFT) | @@ -1394,6 +1395,9 @@ static bool access_mte_regs(struct kvm_vcpu *vcpu, struct sys_reg_params *p, static unsigned int mte_visibility(const struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd) { + if (test_bit(KVM_ARM_VCPU_MTE, vcpu->arch.features)) + return 0; + return REG_HIDDEN_USER | REG_HIDDEN_GUEST; }
Add a new VCPU features 'KVM_ARM_VCPU_MTE' which enables memory tagging on a VCPU. When enabled on any VCPU in the virtual machine this causes all pages that are faulted into the VM to have the PG_mte_tagged flag set (and the tag storage cleared if this is the first use). Signed-off-by: Steven Price <steven.price@arm.com> --- arch/arm64/include/asm/kvm_emulate.h | 3 +++ arch/arm64/include/asm/kvm_host.h | 5 ++++- arch/arm64/include/uapi/asm/kvm.h | 1 + arch/arm64/kvm/mmu.c | 15 +++++++++++++++ arch/arm64/kvm/reset.c | 8 ++++++++ arch/arm64/kvm/sys_regs.c | 6 +++++- 6 files changed, 36 insertions(+), 2 deletions(-)