[PATCH v2 5/7] KVM: arm64: Allocate memory at hyp for host sve state in pKVM

Fuad Tabba tabba at google.com
Wed May 22 07:37:53 PDT 2024


Hi Marc,

On Tue, May 21, 2024 at 10:44 PM Marc Zyngier <maz at kernel.org> wrote:
>
> On Tue, 21 May 2024 17:37:18 +0100,
> Fuad Tabba <tabba at google.com> wrote:
> >
> > Protected mode needs to maintain (save/restore) the host's sve
> > state, rather than relying on the host kernel to do that. This is
> > to avoid leaking information to the host about guests and the
> > type of operations they are performing.
> >
> > As a first step towards that, allocate memory at hyp, per cpu, to
> > hold the host sve data. The following patch will use this memory
> > to save/restore the host state.
>
> What I read in the code contradicts this statement. The memory is
> definitely allocated on the *host*.

You're right. I should say memory mapped at hyp.

> >
> > Signed-off-by: Fuad Tabba <tabba at google.com>
> > ---
> > Note that the last patch in this series will consolidate the
> > setup of the host's fpsimd and sve states, which currently take
> > place in two different locations. Moreover, that last patch will
> > also place the host fpsimd and sve_state pointers in a union.
> > ---
> >  arch/arm64/include/asm/kvm_host.h    |  2 +
> >  arch/arm64/include/asm/kvm_pkvm.h    |  9 ++++
> >  arch/arm64/include/uapi/asm/ptrace.h | 14 ++++++
> >  arch/arm64/kvm/arm.c                 | 68 ++++++++++++++++++++++++++++
> >  arch/arm64/kvm/hyp/nvhe/setup.c      | 24 ++++++++++
> >  5 files changed, 117 insertions(+)
> >
> > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > index 0a5fceb20f3a..7b3745ef1d73 100644
> > --- a/arch/arm64/include/asm/kvm_host.h
> > +++ b/arch/arm64/include/asm/kvm_host.h
> > @@ -535,7 +535,9 @@ struct kvm_cpu_context {
> >   */
> >  struct kvm_host_data {
> >       struct kvm_cpu_context host_ctxt;
> > +
> >       struct user_fpsimd_state *fpsimd_state; /* hyp VA */
> > +     struct user_sve_state *sve_state;       /* hyp VA */
> >
> >       /* Ownership of the FP regs */
> >       enum {
> > diff --git a/arch/arm64/include/asm/kvm_pkvm.h b/arch/arm64/include/asm/kvm_pkvm.h
> > index ad9cfb5c1ff4..b9d12e123efb 100644
> > --- a/arch/arm64/include/asm/kvm_pkvm.h
> > +++ b/arch/arm64/include/asm/kvm_pkvm.h
> > @@ -128,4 +128,13 @@ static inline unsigned long hyp_ffa_proxy_pages(void)
> >       return (2 * KVM_FFA_MBOX_NR_PAGES) + DIV_ROUND_UP(desc_max, PAGE_SIZE);
> >  }
> >
> > +static inline size_t pkvm_host_sve_state_size(void)
> > +{
> > +     if (!system_supports_sve())
> > +             return 0;
> > +
> > +     return size_add(sizeof(struct user_sve_state),
> > +                     SVE_SIG_REGS_SIZE(sve_vq_from_vl(kvm_host_sve_max_vl)));
> > +}
> > +
> >  #endif       /* __ARM64_KVM_PKVM_H__ */
> > diff --git a/arch/arm64/include/uapi/asm/ptrace.h b/arch/arm64/include/uapi/asm/ptrace.h
> > index 7fa2f7036aa7..77aabf964071 100644
> > --- a/arch/arm64/include/uapi/asm/ptrace.h
> > +++ b/arch/arm64/include/uapi/asm/ptrace.h
> > @@ -120,6 +120,20 @@ struct user_sve_header {
> >       __u16 __reserved;
> >  };
> >
> > +struct user_sve_state {
> > +     __u64 zcr_el1;
> > +
> > +     /*
> > +      * Ordering is important since __sve_save_state/__sve_restore_state
> > +      * relies on it.
> > +      */
> > +     __u32 fpsr;
> > +     __u32 fpcr;
> > +
> > +     /* Must be SVE_VQ_BYTES (128 bit) aligned. */
> > +     __u8 sve_regs[];
> > +};
> > +
>
> Huh, why is this in uapi? Why should userspace even care about this at
> all? From what I can tell, this is purely internal to the kernel, and
> in any case, KVM isn't tied to that format if it doesn't dump stuff in
> the userspace thread context. Given the number of bugs this format has
> generated, I really wouldn't mind moving away from it.

I put it here since the sve_header is here, as well as other similar structures.

Should I move it to asm/kvm_pkvm.h?

> >  /* Definitions for user_sve_header.flags: */
> >  #define SVE_PT_REGS_MASK             (1 << 0)
> >
> > diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
> > index 9e565ea3d645..a9b1b0e9c319 100644
> > --- a/arch/arm64/kvm/arm.c
> > +++ b/arch/arm64/kvm/arm.c
> > @@ -1931,6 +1931,11 @@ static unsigned long nvhe_percpu_order(void)
> >       return size ? get_order(size) : 0;
> >  }
> >
> > +static size_t pkvm_host_sve_state_order(void)
> > +{
> > +     return get_order(pkvm_host_sve_state_size());
> > +}
> > +
> >  /* A lookup table holding the hypervisor VA for each vector slot */
> >  static void *hyp_spectre_vector_selector[BP_HARDEN_EL2_SLOTS];
> >
> > @@ -2316,7 +2321,15 @@ static void __init teardown_hyp_mode(void)
> >       for_each_possible_cpu(cpu) {
> >               free_page(per_cpu(kvm_arm_hyp_stack_page, cpu));
> >               free_pages(kvm_nvhe_sym(kvm_arm_hyp_percpu_base)[cpu], nvhe_percpu_order());
> > +
> > +             if (system_supports_sve() && is_protected_kvm_enabled()) {
> > +                     struct user_sve_state *sve_state;
> > +
> > +                     sve_state = per_cpu_ptr_nvhe_sym(kvm_host_data, cpu)->sve_state;
> > +                     free_pages((unsigned long) sve_state, pkvm_host_sve_state_order());
> > +             }
> >       }
> > +
> >  }
> >
> >  static int __init do_pkvm_init(u32 hyp_va_bits)
> > @@ -2399,6 +2412,50 @@ static int __init kvm_hyp_init_protection(u32 hyp_va_bits)
> >       return 0;
> >  }
> >
> > +static int init_pkvm_host_sve_state(void)
> > +{
> > +     int cpu;
> > +
> > +     if (!system_supports_sve())
> > +             return 0;
> > +
> > +     /* Allocate pages for host sve state in protected mode. */
> > +     for_each_possible_cpu(cpu) {
> > +             struct page *page = alloc_pages(GFP_KERNEL, pkvm_host_sve_state_order());
> > +
>
> See? That's definitely not a HYP allocation.

Nope :) I will fix the commit message and relevant comments in this patch.

Thanks,
/fuad



> Thanks,
>
>         M.
>
> --
> Without deviation from the norm, progress is not possible.
>



More information about the linux-arm-kernel mailing list