nacl.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (c) 2024 Ventana Micro Systems Inc.
  4. */
  5. #include <linux/kvm_host.h>
  6. #include <linux/vmalloc.h>
  7. #include <asm/kvm_nacl.h>
  8. DEFINE_STATIC_KEY_FALSE(kvm_riscv_nacl_available);
  9. DEFINE_STATIC_KEY_FALSE(kvm_riscv_nacl_sync_csr_available);
  10. DEFINE_STATIC_KEY_FALSE(kvm_riscv_nacl_sync_hfence_available);
  11. DEFINE_STATIC_KEY_FALSE(kvm_riscv_nacl_sync_sret_available);
  12. DEFINE_STATIC_KEY_FALSE(kvm_riscv_nacl_autoswap_csr_available);
  13. DEFINE_PER_CPU(struct kvm_riscv_nacl, kvm_riscv_nacl);
  14. void __kvm_riscv_nacl_hfence(void *shmem,
  15. unsigned long control,
  16. unsigned long page_num,
  17. unsigned long page_count)
  18. {
  19. int i, ent = -1, try_count = 5;
  20. unsigned long *entp;
  21. again:
  22. for (i = 0; i < SBI_NACL_SHMEM_HFENCE_ENTRY_MAX; i++) {
  23. entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_CONFIG(i);
  24. if (lelong_to_cpu(*entp) & SBI_NACL_SHMEM_HFENCE_CONFIG_PEND)
  25. continue;
  26. ent = i;
  27. break;
  28. }
  29. if (ent < 0) {
  30. if (try_count) {
  31. nacl_sync_hfence(-1UL);
  32. goto again;
  33. } else {
  34. pr_warn("KVM: No free entry in NACL shared memory\n");
  35. return;
  36. }
  37. }
  38. entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_CONFIG(i);
  39. *entp = cpu_to_lelong(control);
  40. entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_PNUM(i);
  41. *entp = cpu_to_lelong(page_num);
  42. entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_PCOUNT(i);
  43. *entp = cpu_to_lelong(page_count);
  44. }
  45. int kvm_riscv_nacl_enable(void)
  46. {
  47. int rc;
  48. struct sbiret ret;
  49. struct kvm_riscv_nacl *nacl;
  50. if (!kvm_riscv_nacl_available())
  51. return 0;
  52. nacl = this_cpu_ptr(&kvm_riscv_nacl);
  53. ret = sbi_ecall(SBI_EXT_NACL, SBI_EXT_NACL_SET_SHMEM,
  54. nacl->shmem_phys, 0, 0, 0, 0, 0);
  55. rc = sbi_err_map_linux_errno(ret.error);
  56. if (rc)
  57. return rc;
  58. return 0;
  59. }
  60. void kvm_riscv_nacl_disable(void)
  61. {
  62. if (!kvm_riscv_nacl_available())
  63. return;
  64. sbi_ecall(SBI_EXT_NACL, SBI_EXT_NACL_SET_SHMEM,
  65. SBI_SHMEM_DISABLE, SBI_SHMEM_DISABLE, 0, 0, 0, 0);
  66. }
  67. void kvm_riscv_nacl_exit(void)
  68. {
  69. int cpu;
  70. struct kvm_riscv_nacl *nacl;
  71. if (!kvm_riscv_nacl_available())
  72. return;
  73. /* Allocate per-CPU shared memory */
  74. for_each_possible_cpu(cpu) {
  75. nacl = per_cpu_ptr(&kvm_riscv_nacl, cpu);
  76. if (!nacl->shmem)
  77. continue;
  78. free_pages((unsigned long)nacl->shmem,
  79. get_order(SBI_NACL_SHMEM_SIZE));
  80. nacl->shmem = NULL;
  81. nacl->shmem_phys = 0;
  82. }
  83. }
  84. static long nacl_probe_feature(long feature_id)
  85. {
  86. struct sbiret ret;
  87. if (!kvm_riscv_nacl_available())
  88. return 0;
  89. ret = sbi_ecall(SBI_EXT_NACL, SBI_EXT_NACL_PROBE_FEATURE,
  90. feature_id, 0, 0, 0, 0, 0);
  91. return ret.value;
  92. }
  93. int kvm_riscv_nacl_init(void)
  94. {
  95. int cpu;
  96. struct page *shmem_page;
  97. struct kvm_riscv_nacl *nacl;
  98. if (sbi_spec_version < sbi_mk_version(1, 0) ||
  99. sbi_probe_extension(SBI_EXT_NACL) <= 0)
  100. return -ENODEV;
  101. /* Enable NACL support */
  102. static_branch_enable(&kvm_riscv_nacl_available);
  103. /* Probe NACL features */
  104. if (nacl_probe_feature(SBI_NACL_FEAT_SYNC_CSR))
  105. static_branch_enable(&kvm_riscv_nacl_sync_csr_available);
  106. if (nacl_probe_feature(SBI_NACL_FEAT_SYNC_HFENCE))
  107. static_branch_enable(&kvm_riscv_nacl_sync_hfence_available);
  108. if (nacl_probe_feature(SBI_NACL_FEAT_SYNC_SRET))
  109. static_branch_enable(&kvm_riscv_nacl_sync_sret_available);
  110. if (nacl_probe_feature(SBI_NACL_FEAT_AUTOSWAP_CSR))
  111. static_branch_enable(&kvm_riscv_nacl_autoswap_csr_available);
  112. /* Allocate per-CPU shared memory */
  113. for_each_possible_cpu(cpu) {
  114. nacl = per_cpu_ptr(&kvm_riscv_nacl, cpu);
  115. shmem_page = alloc_pages(GFP_KERNEL | __GFP_ZERO,
  116. get_order(SBI_NACL_SHMEM_SIZE));
  117. if (!shmem_page) {
  118. kvm_riscv_nacl_exit();
  119. return -ENOMEM;
  120. }
  121. nacl->shmem = page_to_virt(shmem_page);
  122. nacl->shmem_phys = page_to_phys(shmem_page);
  123. }
  124. return 0;
  125. }