diff --git a/arch/arm64/include/asm/kvm_pkvm.h b/arch/arm64/include/asm/kvm_pkvm.h index 2c7652bfe362..983997757037 100644 --- a/arch/arm64/include/asm/kvm_pkvm.h +++ b/arch/arm64/include/asm/kvm_pkvm.h @@ -385,4 +385,10 @@ 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 unsigned long hyp_host_fp_pages(unsigned long nr_cpus) +{ + return PAGE_ALIGN(nr_cpus * sizeof(struct user_fpsimd_state)) >> + PAGE_SHIFT; +} + #endif /* __ARM64_KVM_PKVM_H__ */ diff --git a/arch/arm64/kvm/hyp/include/nvhe/pkvm.h b/arch/arm64/kvm/hyp/include/nvhe/pkvm.h index 32a77d17761f..c56db3d918ab 100644 --- a/arch/arm64/kvm/hyp/include/nvhe/pkvm.h +++ b/arch/arm64/kvm/hyp/include/nvhe/pkvm.h @@ -82,7 +82,7 @@ struct pkvm_hyp_vm { struct pkvm_hyp_vcpu *vcpus[]; }; -DECLARE_PER_CPU(struct user_fpsimd_state, loaded_host_fpsimd_state); +extern void *host_fp_state; static inline struct pkvm_hyp_vm * pkvm_hyp_vcpu_to_hyp_vm(struct pkvm_hyp_vcpu *hyp_vcpu) @@ -107,6 +107,7 @@ extern phys_addr_t pvmfw_base; extern phys_addr_t pvmfw_size; void pkvm_hyp_vm_table_init(void *tbl); +void pkvm_hyp_host_fp_init(void *host_fp); int __pkvm_init_vm(struct kvm *host_kvm, unsigned long vm_hva, unsigned long pgd_hva, unsigned long last_ran_hva); diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c index f217c4af956a..06c94f8dde96 100644 --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c @@ -413,7 +413,10 @@ static const hyp_entry_exit_handler_fn exit_hyp_vm_handlers[] = { static struct user_fpsimd_state *get_host_fpsimd_state(void) { - return this_cpu_ptr(&loaded_host_fpsimd_state); + char *state = (char *) host_fp_state + + sizeof(struct user_fpsimd_state) * hyp_smp_processor_id(); + + return (struct user_fpsimd_state *) state; } static void flush_hyp_vgic_state(struct pkvm_hyp_vcpu *hyp_vcpu) diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c index 5774fc4c5a70..c6e2c426c451 100644 --- a/arch/arm64/kvm/hyp/nvhe/pkvm.c +++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c @@ -32,12 +32,14 @@ unsigned int kvm_arm_vmid_bits; static DEFINE_PER_CPU(struct pkvm_hyp_vcpu *, loaded_hyp_vcpu); /* - * Host FPSIMD state. Written to when the guest accesses its own FPSIMD state, - * and read when the guest state is live and we need to switch back to the host. + * Host fp state for all cpus. This could include the host simd state, as well + * as the sve and sme states if supported. Written to when the guest accesses + * its own FPSIMD state, and read when the guest state is live and we need to + * switch back to the host. * * Only valid when (fp_state == FP_STATE_GUEST_OWNED) in the hyp vCPU structure. */ -DEFINE_PER_CPU(struct user_fpsimd_state, loaded_host_fpsimd_state); +void *host_fp_state; /* * Set trap register values based on features in ID_AA64PFR0. @@ -264,6 +266,12 @@ void pkvm_hyp_vm_table_init(void *tbl) vm_table = tbl; } +void pkvm_hyp_host_fp_init(void *host_fp) +{ + WARN_ON(host_fp_state); + host_fp_state = host_fp; +} + /* * Return the hyp vm structure corresponding to the handle. */ diff --git a/arch/arm64/kvm/hyp/nvhe/setup.c b/arch/arm64/kvm/hyp/nvhe/setup.c index a3f787859fa5..4255846108e7 100644 --- a/arch/arm64/kvm/hyp/nvhe/setup.c +++ b/arch/arm64/kvm/hyp/nvhe/setup.c @@ -34,6 +34,7 @@ static void *vm_table_base; static void *hyp_pgt_base; static void *host_s2_pgt_base; static void *ffa_proxy_pages; +static void *hyp_host_fp_base; static struct kvm_pgtable_mm_ops pkvm_pgtable_mm_ops; static struct hyp_pool hpool; @@ -68,6 +69,11 @@ static int divide_memory_pool(void *virt, unsigned long size) if (!ffa_proxy_pages) return -ENOMEM; + nr_pages = hyp_host_fp_pages(hyp_nr_cpus); + hyp_host_fp_base = hyp_early_alloc_contig(nr_pages); + if (!hyp_host_fp_base) + return -ENOMEM; + return 0; } @@ -370,6 +376,7 @@ void __noreturn __pkvm_init_finalise(void) goto out; pkvm_hyp_vm_table_init(vm_table_base); + pkvm_hyp_host_fp_init(hyp_host_fp_base); out: /* * We tail-called to here from handle___pkvm_init() and will not return, diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c index ae3077f1a07d..ec613347f116 100644 --- a/arch/arm64/kvm/pkvm.c +++ b/arch/arm64/kvm/pkvm.c @@ -173,6 +173,7 @@ void __init kvm_hyp_reserve(void) hyp_mem_pages += hyp_vm_table_pages(); hyp_mem_pages += hyp_vmemmap_pages(STRUCT_HYP_PAGE_SIZE); hyp_mem_pages += hyp_ffa_proxy_pages(); + hyp_mem_pages += hyp_host_fp_pages(num_possible_cpus()); /* * Try to allocate a PMD-aligned region to reduce TLB pressure once