ucall_common.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. #include "linux/types.h"
  3. #include "linux/bitmap.h"
  4. #include "linux/atomic.h"
  5. #include "kvm_util.h"
  6. #include "ucall_common.h"
  7. #define GUEST_UCALL_FAILED -1
  8. struct ucall_header {
  9. DECLARE_BITMAP(in_use, KVM_MAX_VCPUS);
  10. struct ucall ucalls[KVM_MAX_VCPUS];
  11. };
  12. int ucall_nr_pages_required(uint64_t page_size)
  13. {
  14. return align_up(sizeof(struct ucall_header), page_size) / page_size;
  15. }
  16. /*
  17. * ucall_pool holds per-VM values (global data is duplicated by each VM), it
  18. * must not be accessed from host code.
  19. */
  20. static struct ucall_header *ucall_pool;
  21. void ucall_init(struct kvm_vm *vm, vm_paddr_t mmio_gpa)
  22. {
  23. struct ucall_header *hdr;
  24. struct ucall *uc;
  25. vm_vaddr_t vaddr;
  26. int i;
  27. vaddr = vm_vaddr_alloc_shared(vm, sizeof(*hdr), KVM_UTIL_MIN_VADDR,
  28. MEM_REGION_DATA);
  29. hdr = (struct ucall_header *)addr_gva2hva(vm, vaddr);
  30. memset(hdr, 0, sizeof(*hdr));
  31. for (i = 0; i < KVM_MAX_VCPUS; ++i) {
  32. uc = &hdr->ucalls[i];
  33. uc->hva = uc;
  34. }
  35. write_guest_global(vm, ucall_pool, (struct ucall_header *)vaddr);
  36. ucall_arch_init(vm, mmio_gpa);
  37. }
  38. static struct ucall *ucall_alloc(void)
  39. {
  40. struct ucall *uc;
  41. int i;
  42. if (!ucall_pool)
  43. goto ucall_failed;
  44. for (i = 0; i < KVM_MAX_VCPUS; ++i) {
  45. if (!test_and_set_bit(i, ucall_pool->in_use)) {
  46. uc = &ucall_pool->ucalls[i];
  47. memset(uc->args, 0, sizeof(uc->args));
  48. return uc;
  49. }
  50. }
  51. ucall_failed:
  52. /*
  53. * If the vCPU cannot grab a ucall structure, make a bare ucall with a
  54. * magic value to signal to get_ucall() that things went sideways.
  55. * GUEST_ASSERT() depends on ucall_alloc() and so cannot be used here.
  56. */
  57. ucall_arch_do_ucall(GUEST_UCALL_FAILED);
  58. return NULL;
  59. }
  60. static void ucall_free(struct ucall *uc)
  61. {
  62. /* Beware, here be pointer arithmetic. */
  63. clear_bit(uc - ucall_pool->ucalls, ucall_pool->in_use);
  64. }
  65. void ucall_assert(uint64_t cmd, const char *exp, const char *file,
  66. unsigned int line, const char *fmt, ...)
  67. {
  68. struct ucall *uc;
  69. va_list va;
  70. uc = ucall_alloc();
  71. uc->cmd = cmd;
  72. WRITE_ONCE(uc->args[GUEST_ERROR_STRING], (uint64_t)(exp));
  73. WRITE_ONCE(uc->args[GUEST_FILE], (uint64_t)(file));
  74. WRITE_ONCE(uc->args[GUEST_LINE], line);
  75. va_start(va, fmt);
  76. guest_vsnprintf(uc->buffer, UCALL_BUFFER_LEN, fmt, va);
  77. va_end(va);
  78. ucall_arch_do_ucall((vm_vaddr_t)uc->hva);
  79. ucall_free(uc);
  80. }
  81. void ucall_fmt(uint64_t cmd, const char *fmt, ...)
  82. {
  83. struct ucall *uc;
  84. va_list va;
  85. uc = ucall_alloc();
  86. uc->cmd = cmd;
  87. va_start(va, fmt);
  88. guest_vsnprintf(uc->buffer, UCALL_BUFFER_LEN, fmt, va);
  89. va_end(va);
  90. ucall_arch_do_ucall((vm_vaddr_t)uc->hva);
  91. ucall_free(uc);
  92. }
  93. void ucall(uint64_t cmd, int nargs, ...)
  94. {
  95. struct ucall *uc;
  96. va_list va;
  97. int i;
  98. uc = ucall_alloc();
  99. WRITE_ONCE(uc->cmd, cmd);
  100. nargs = min(nargs, UCALL_MAX_ARGS);
  101. va_start(va, nargs);
  102. for (i = 0; i < nargs; ++i)
  103. WRITE_ONCE(uc->args[i], va_arg(va, uint64_t));
  104. va_end(va);
  105. ucall_arch_do_ucall((vm_vaddr_t)uc->hva);
  106. ucall_free(uc);
  107. }
  108. uint64_t get_ucall(struct kvm_vcpu *vcpu, struct ucall *uc)
  109. {
  110. struct ucall ucall;
  111. void *addr;
  112. if (!uc)
  113. uc = &ucall;
  114. addr = ucall_arch_get_ucall(vcpu);
  115. if (addr) {
  116. TEST_ASSERT(addr != (void *)GUEST_UCALL_FAILED,
  117. "Guest failed to allocate ucall struct");
  118. memcpy(uc, addr, sizeof(*uc));
  119. vcpu_run_complete_io(vcpu);
  120. } else {
  121. memset(uc, 0, sizeof(*uc));
  122. }
  123. return uc->cmd;
  124. }