gunyah_hypercall.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  4. */
  5. #include <linux/arm-smccc.h>
  6. #include <linux/module.h>
  7. #include <linux/gunyah.h>
  8. #include <linux/uuid.h>
  9. /* {c1d58fcd-a453-5fdb-9265-ce36673d5f14} */
  10. static const uuid_t GUNYAH_UUID =
  11. UUID_INIT(0xc1d58fcd, 0xa453, 0x5fdb, 0x92, 0x65, 0xce, 0x36, 0x67, 0x3d, 0x5f, 0x14);
  12. bool arch_is_gh_guest(void)
  13. {
  14. struct arm_smccc_res res;
  15. uuid_t uuid;
  16. u32 *up;
  17. arm_smccc_1_1_hvc(ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID, &res);
  18. up = (u32 *)&uuid.b[0];
  19. up[0] = lower_32_bits(res.a0);
  20. up[1] = lower_32_bits(res.a1);
  21. up[2] = lower_32_bits(res.a2);
  22. up[3] = lower_32_bits(res.a3);
  23. return uuid_equal(&uuid, &GUNYAH_UUID);
  24. }
  25. EXPORT_SYMBOL_GPL(arch_is_gh_guest);
  26. #define GH_HYPERCALL(fn) ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64, \
  27. ARM_SMCCC_OWNER_VENDOR_HYP, \
  28. fn)
  29. #define GH_HYPERCALL_HYP_IDENTIFY GH_HYPERCALL(0x8000)
  30. #define GH_HYPERCALL_BELL_SEND GH_HYPERCALL(0x8012)
  31. #define GH_HYPERCALL_BELL_SET_MASK GH_HYPERCALL(0x8015)
  32. #define GH_HYPERCALL_MSGQ_SEND GH_HYPERCALL(0x801B)
  33. #define GH_HYPERCALL_MSGQ_RECV GH_HYPERCALL(0x801C)
  34. #define GH_HYPERCALL_VCPU_RUN GH_HYPERCALL(0x8065)
  35. /**
  36. * gh_hypercall_hyp_identify() - Returns build information and feature flags
  37. * supported by Gunyah.
  38. * @hyp_identity: filled by the hypercall with the API info and feature flags.
  39. */
  40. void gh_hypercall_hyp_identify(struct gh_hypercall_hyp_identify_resp *hyp_identity)
  41. {
  42. struct arm_smccc_res res;
  43. arm_smccc_1_1_hvc(GH_HYPERCALL_HYP_IDENTIFY, &res);
  44. hyp_identity->api_info = res.a0;
  45. hyp_identity->flags[0] = res.a1;
  46. hyp_identity->flags[1] = res.a2;
  47. hyp_identity->flags[2] = res.a3;
  48. }
  49. EXPORT_SYMBOL_GPL(gh_hypercall_hyp_identify);
  50. enum gh_error gh_hypercall_bell_send(u64 capid, u64 new_flags, u64 *old_flags)
  51. {
  52. struct arm_smccc_res res;
  53. arm_smccc_1_1_hvc(GH_HYPERCALL_BELL_SEND, capid, new_flags, 0, &res);
  54. if (res.a0 == GH_ERROR_OK && old_flags)
  55. *old_flags = res.a1;
  56. return res.a0;
  57. }
  58. EXPORT_SYMBOL_GPL(gh_hypercall_bell_send);
  59. enum gh_error gh_hypercall_bell_set_mask(u64 capid, u64 enable_mask, u64 ack_mask)
  60. {
  61. struct arm_smccc_res res;
  62. arm_smccc_1_1_hvc(GH_HYPERCALL_BELL_SET_MASK, capid, enable_mask, ack_mask, 0, &res);
  63. return res.a0;
  64. }
  65. EXPORT_SYMBOL_GPL(gh_hypercall_bell_set_mask);
  66. enum gh_error gh_hypercall_msgq_send(u64 capid, size_t size, void *buff, u64 tx_flags, bool *ready)
  67. {
  68. struct arm_smccc_res res;
  69. arm_smccc_1_1_hvc(GH_HYPERCALL_MSGQ_SEND, capid, size, (uintptr_t)buff, tx_flags, 0, &res);
  70. if (res.a0 == GH_ERROR_OK)
  71. *ready = !!res.a1;
  72. return res.a0;
  73. }
  74. EXPORT_SYMBOL_GPL(gh_hypercall_msgq_send);
  75. enum gh_error gh_hypercall_msgq_recv(u64 capid, void *buff, size_t size, size_t *recv_size,
  76. bool *ready)
  77. {
  78. struct arm_smccc_res res;
  79. arm_smccc_1_1_hvc(GH_HYPERCALL_MSGQ_RECV, capid, (uintptr_t)buff, size, 0, &res);
  80. if (res.a0 == GH_ERROR_OK) {
  81. *recv_size = res.a1;
  82. *ready = !!res.a2;
  83. }
  84. return res.a0;
  85. }
  86. EXPORT_SYMBOL_GPL(gh_hypercall_msgq_recv);
  87. enum gh_error gh_hypercall_vcpu_run(u64 capid, u64 *resume_data,
  88. struct gh_hypercall_vcpu_run_resp *resp)
  89. {
  90. struct arm_smccc_1_2_regs args = {
  91. .a0 = GH_HYPERCALL_VCPU_RUN,
  92. .a1 = capid,
  93. .a2 = resume_data[0],
  94. .a3 = resume_data[1],
  95. .a4 = resume_data[2],
  96. /* C language says this will be implictly zero. Gunyah requires 0, so be explicit */
  97. .a5 = 0,
  98. };
  99. struct arm_smccc_1_2_regs res;
  100. arm_smccc_1_2_hvc(&args, &res);
  101. if (res.a0 == GH_ERROR_OK) {
  102. resp->sized_state = res.a1;
  103. resp->state_data[0] = res.a2;
  104. resp->state_data[1] = res.a3;
  105. resp->state_data[2] = res.a4;
  106. }
  107. return res.a0;
  108. }
  109. EXPORT_SYMBOL_GPL(gh_hypercall_vcpu_run);
  110. MODULE_LICENSE("GPL");
  111. MODULE_DESCRIPTION("Gunyah Hypervisor Hypercalls");