fpsimd.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * arch/arm64/kvm/fpsimd.c: Guest/host FPSIMD context coordination helpers
  4. *
  5. * Copyright 2018 Arm Limited
  6. * Author: Dave Martin <Dave.Martin@arm.com>
  7. */
  8. #include <linux/irqflags.h>
  9. #include <linux/sched.h>
  10. #include <linux/kvm_host.h>
  11. #include <asm/fpsimd.h>
  12. #include <asm/kvm_asm.h>
  13. #include <asm/kvm_hyp.h>
  14. #include <asm/kvm_mmu.h>
  15. #include <asm/sysreg.h>
  16. /*
  17. * Prepare vcpu for saving the host's FPSIMD state and loading the guest's.
  18. * The actual loading is done by the FPSIMD access trap taken to hyp.
  19. *
  20. * Here, we just set the correct metadata to indicate that the FPSIMD
  21. * state in the cpu regs (if any) belongs to current on the host.
  22. */
  23. void kvm_arch_vcpu_load_fp(struct kvm_vcpu *vcpu)
  24. {
  25. BUG_ON(!current->mm);
  26. if (!system_supports_fpsimd())
  27. return;
  28. /*
  29. * Ensure that any host FPSIMD/SVE/SME state is saved and unbound such
  30. * that the host kernel is responsible for restoring this state upon
  31. * return to userspace, and the hyp code doesn't need to save anything.
  32. *
  33. * When the host may use SME, fpsimd_save_and_flush_cpu_state() ensures
  34. * that PSTATE.{SM,ZA} == {0,0}.
  35. */
  36. fpsimd_save_and_flush_cpu_state();
  37. *host_data_ptr(fp_owner) = FP_STATE_FREE;
  38. WARN_ON_ONCE(system_supports_sme() && read_sysreg_s(SYS_SVCR));
  39. }
  40. /*
  41. * Called just before entering the guest once we are no longer preemptible
  42. * and interrupts are disabled. If we have managed to run anything using
  43. * FP while we were preemptible (such as off the back of an interrupt),
  44. * then neither the host nor the guest own the FP hardware (and it was the
  45. * responsibility of the code that used FP to save the existing state).
  46. */
  47. void kvm_arch_vcpu_ctxflush_fp(struct kvm_vcpu *vcpu)
  48. {
  49. if (test_thread_flag(TIF_FOREIGN_FPSTATE))
  50. *host_data_ptr(fp_owner) = FP_STATE_FREE;
  51. }
  52. /*
  53. * Called just after exiting the guest. If the guest FPSIMD state
  54. * was loaded, update the host's context tracking data mark the CPU
  55. * FPSIMD regs as dirty and belonging to vcpu so that they will be
  56. * written back if the kernel clobbers them due to kernel-mode NEON
  57. * before re-entry into the guest.
  58. */
  59. void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu)
  60. {
  61. struct cpu_fp_state fp_state;
  62. WARN_ON_ONCE(!irqs_disabled());
  63. if (guest_owns_fp_regs()) {
  64. /*
  65. * Currently we do not support SME guests so SVCR is
  66. * always 0 and we just need a variable to point to.
  67. */
  68. fp_state.st = &vcpu->arch.ctxt.fp_regs;
  69. fp_state.sve_state = vcpu->arch.sve_state;
  70. fp_state.sve_vl = vcpu->arch.sve_max_vl;
  71. fp_state.sme_state = NULL;
  72. fp_state.svcr = __ctxt_sys_reg(&vcpu->arch.ctxt, SVCR);
  73. fp_state.fpmr = __ctxt_sys_reg(&vcpu->arch.ctxt, FPMR);
  74. fp_state.fp_type = &vcpu->arch.fp_type;
  75. if (vcpu_has_sve(vcpu))
  76. fp_state.to_save = FP_STATE_SVE;
  77. else
  78. fp_state.to_save = FP_STATE_FPSIMD;
  79. fpsimd_bind_state_to_cpu(&fp_state);
  80. clear_thread_flag(TIF_FOREIGN_FPSTATE);
  81. }
  82. }
  83. /*
  84. * Write back the vcpu FPSIMD regs if they are dirty, and invalidate the
  85. * cpu FPSIMD regs so that they can't be spuriously reused if this vcpu
  86. * disappears and another task or vcpu appears that recycles the same
  87. * struct fpsimd_state.
  88. */
  89. void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu)
  90. {
  91. unsigned long flags;
  92. local_irq_save(flags);
  93. if (guest_owns_fp_regs()) {
  94. /*
  95. * Flush (save and invalidate) the fpsimd/sve state so that if
  96. * the host tries to use fpsimd/sve, it's not using stale data
  97. * from the guest.
  98. *
  99. * Flushing the state sets the TIF_FOREIGN_FPSTATE bit for the
  100. * context unconditionally, in both nVHE and VHE. This allows
  101. * the kernel to restore the fpsimd/sve state, including ZCR_EL1
  102. * when needed.
  103. */
  104. fpsimd_save_and_flush_cpu_state();
  105. }
  106. local_irq_restore(flags);
  107. }