host_sve.c 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Host SVE: Check FPSIMD/SVE/SME save/restore over KVM_RUN ioctls.
  4. *
  5. * Copyright 2025 Arm, Ltd
  6. */
  7. #include <errno.h>
  8. #include <signal.h>
  9. #include <sys/auxv.h>
  10. #include <asm/kvm.h>
  11. #include <kvm_util.h>
  12. #include "ucall_common.h"
  13. static void guest_code(void)
  14. {
  15. for (int i = 0; i < 10; i++) {
  16. GUEST_UCALL_NONE();
  17. }
  18. GUEST_DONE();
  19. }
  20. void handle_sigill(int sig, siginfo_t *info, void *ctx)
  21. {
  22. ucontext_t *uctx = ctx;
  23. printf(" < host signal %d >\n", sig);
  24. /*
  25. * Skip the UDF
  26. */
  27. uctx->uc_mcontext.pc += 4;
  28. }
  29. void register_sigill_handler(void)
  30. {
  31. struct sigaction sa = {
  32. .sa_sigaction = handle_sigill,
  33. .sa_flags = SA_SIGINFO,
  34. };
  35. sigaction(SIGILL, &sa, NULL);
  36. }
  37. static void do_sve_roundtrip(void)
  38. {
  39. unsigned long before, after;
  40. /*
  41. * Set all bits in a predicate register, force a save/restore via a
  42. * SIGILL (which handle_sigill() will recover from), then report
  43. * whether the value has changed.
  44. */
  45. asm volatile(
  46. " .arch_extension sve\n"
  47. " ptrue p0.B\n"
  48. " cntp %[before], p0, p0.B\n"
  49. " udf #0\n"
  50. " cntp %[after], p0, p0.B\n"
  51. : [before] "=r" (before),
  52. [after] "=r" (after)
  53. :
  54. : "p0"
  55. );
  56. if (before != after) {
  57. TEST_FAIL("Signal roundtrip discarded predicate bits (%ld => %ld)\n",
  58. before, after);
  59. } else {
  60. printf("Signal roundtrip preserved predicate bits (%ld => %ld)\n",
  61. before, after);
  62. }
  63. }
  64. static void test_run(void)
  65. {
  66. struct kvm_vcpu *vcpu;
  67. struct kvm_vm *vm;
  68. struct ucall uc;
  69. bool guest_done = false;
  70. register_sigill_handler();
  71. vm = vm_create_with_one_vcpu(&vcpu, guest_code);
  72. do_sve_roundtrip();
  73. while (!guest_done) {
  74. printf("Running VCPU...\n");
  75. vcpu_run(vcpu);
  76. switch (get_ucall(vcpu, &uc)) {
  77. case UCALL_NONE:
  78. do_sve_roundtrip();
  79. do_sve_roundtrip();
  80. break;
  81. case UCALL_DONE:
  82. guest_done = true;
  83. break;
  84. case UCALL_ABORT:
  85. REPORT_GUEST_ASSERT(uc);
  86. break;
  87. default:
  88. TEST_FAIL("Unexpected guest exit");
  89. }
  90. }
  91. kvm_vm_free(vm);
  92. }
  93. int main(void)
  94. {
  95. /*
  96. * This is testing the host environment, we don't care about
  97. * guest SVE support.
  98. */
  99. if (!(getauxval(AT_HWCAP) & HWCAP_SVE)) {
  100. printf("SVE not supported\n");
  101. return KSFT_SKIP;
  102. }
  103. test_run();
  104. return 0;
  105. }