rse_comms.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. /*
  2. * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. */
  6. #include <stdint.h>
  7. #include <string.h>
  8. #include <common/debug.h>
  9. #include <drivers/arm/mhu.h>
  10. #include <drivers/arm/rse_comms.h>
  11. #include <psa/client.h>
  12. #include <rse_comms_protocol.h>
  13. /* Union as message space and reply space are never used at the same time, and this saves space as
  14. * we can overlap them.
  15. */
  16. union __packed __attribute__((aligned(4))) rse_comms_io_buffer_t {
  17. struct serialized_rse_comms_msg_t msg;
  18. struct serialized_rse_comms_reply_t reply;
  19. };
  20. static uint8_t select_protocol_version(const psa_invec *in_vec, size_t in_len,
  21. const psa_outvec *out_vec, size_t out_len)
  22. {
  23. size_t comms_mhu_msg_size;
  24. size_t comms_embed_msg_min_size;
  25. size_t comms_embed_reply_min_size;
  26. size_t in_size_total = 0;
  27. size_t out_size_total = 0;
  28. size_t i;
  29. for (i = 0U; i < in_len; ++i) {
  30. in_size_total += in_vec[i].len;
  31. }
  32. for (i = 0U; i < out_len; ++i) {
  33. out_size_total += out_vec[i].len;
  34. }
  35. comms_mhu_msg_size = mhu_get_max_message_size();
  36. comms_embed_msg_min_size = sizeof(struct serialized_rse_comms_header_t) +
  37. sizeof(struct rse_embed_msg_t) -
  38. PLAT_RSE_COMMS_PAYLOAD_MAX_SIZE;
  39. comms_embed_reply_min_size = sizeof(struct serialized_rse_comms_header_t) +
  40. sizeof(struct rse_embed_reply_t) -
  41. PLAT_RSE_COMMS_PAYLOAD_MAX_SIZE;
  42. /* Use embed if we can pack into one message and reply, else use
  43. * pointer_access. The underlying MHU transport protocol uses a
  44. * single uint32_t to track the length, so the amount of data that
  45. * can be in a message is 4 bytes less than mhu_get_max_message_size
  46. * reports.
  47. *
  48. * TODO tune this with real performance numbers, it's possible a
  49. * pointer_access message is less performant than multiple embed
  50. * messages due to ATU configuration costs to allow access to the
  51. * pointers.
  52. */
  53. if ((comms_embed_msg_min_size + in_size_total >
  54. comms_mhu_msg_size - sizeof(uint32_t)) ||
  55. (comms_embed_reply_min_size + out_size_total >
  56. comms_mhu_msg_size - sizeof(uint32_t))) {
  57. return RSE_COMMS_PROTOCOL_POINTER_ACCESS;
  58. } else {
  59. return RSE_COMMS_PROTOCOL_EMBED;
  60. }
  61. }
  62. psa_status_t psa_call(psa_handle_t handle, int32_t type, const psa_invec *in_vec, size_t in_len,
  63. psa_outvec *out_vec, size_t out_len)
  64. {
  65. /* Declared statically to avoid using huge amounts of stack space. Maybe revisit if
  66. * functions not being reentrant becomes a problem.
  67. */
  68. static union rse_comms_io_buffer_t io_buf;
  69. enum mhu_error_t err;
  70. psa_status_t status;
  71. static uint8_t seq_num = 1U;
  72. size_t msg_size;
  73. size_t reply_size = sizeof(io_buf.reply);
  74. psa_status_t return_val;
  75. size_t idx;
  76. if (type > PSA_CALL_TYPE_MAX || type < PSA_CALL_TYPE_MIN ||
  77. in_len > PSA_MAX_IOVEC || out_len > PSA_MAX_IOVEC) {
  78. return PSA_ERROR_INVALID_ARGUMENT;
  79. }
  80. io_buf.msg.header.seq_num = seq_num,
  81. /* No need to distinguish callers (currently concurrent calls are not supported). */
  82. io_buf.msg.header.client_id = 1U,
  83. io_buf.msg.header.protocol_ver = select_protocol_version(in_vec, in_len, out_vec, out_len);
  84. status = rse_protocol_serialize_msg(handle, type, in_vec, in_len, out_vec,
  85. out_len, &io_buf.msg, &msg_size);
  86. if (status != PSA_SUCCESS) {
  87. return status;
  88. }
  89. VERBOSE("[RSE-COMMS] Sending message\n");
  90. VERBOSE("protocol_ver=%u\n", io_buf.msg.header.protocol_ver);
  91. VERBOSE("seq_num=%u\n", io_buf.msg.header.seq_num);
  92. VERBOSE("client_id=%u\n", io_buf.msg.header.client_id);
  93. for (idx = 0; idx < in_len; idx++) {
  94. VERBOSE("in_vec[%lu].len=%lu\n", idx, in_vec[idx].len);
  95. VERBOSE("in_vec[%lu].buf=%p\n", idx, (void *)in_vec[idx].base);
  96. }
  97. err = mhu_send_data((uint8_t *)&io_buf.msg, msg_size);
  98. if (err != MHU_ERR_NONE) {
  99. return PSA_ERROR_COMMUNICATION_FAILURE;
  100. }
  101. #if DEBUG
  102. /*
  103. * Poisoning the message buffer (with a known pattern).
  104. * Helps in detecting hypothetical RSE communication bugs.
  105. */
  106. memset(&io_buf.msg, 0xA5, msg_size);
  107. #endif
  108. err = mhu_receive_data((uint8_t *)&io_buf.reply, &reply_size);
  109. if (err != MHU_ERR_NONE) {
  110. return PSA_ERROR_COMMUNICATION_FAILURE;
  111. }
  112. VERBOSE("[RSE-COMMS] Received reply\n");
  113. VERBOSE("protocol_ver=%u\n", io_buf.reply.header.protocol_ver);
  114. VERBOSE("seq_num=%u\n", io_buf.reply.header.seq_num);
  115. VERBOSE("client_id=%u\n", io_buf.reply.header.client_id);
  116. status = rse_protocol_deserialize_reply(out_vec, out_len, &return_val,
  117. &io_buf.reply, reply_size);
  118. if (status != PSA_SUCCESS) {
  119. return status;
  120. }
  121. VERBOSE("return_val=%d\n", return_val);
  122. for (idx = 0U; idx < out_len; idx++) {
  123. VERBOSE("out_vec[%lu].len=%lu\n", idx, out_vec[idx].len);
  124. VERBOSE("out_vec[%lu].buf=%p\n", idx, (void *)out_vec[idx].base);
  125. }
  126. /* Clear the MHU message buffer to remove assets from memory */
  127. memset(&io_buf, 0x0, sizeof(io_buf));
  128. seq_num++;
  129. return return_val;
  130. }
  131. int rse_comms_init(uintptr_t mhu_sender_base, uintptr_t mhu_receiver_base)
  132. {
  133. enum mhu_error_t err;
  134. err = mhu_init_sender(mhu_sender_base);
  135. if (err != MHU_ERR_NONE) {
  136. if (err == MHU_ERR_ALREADY_INIT) {
  137. INFO("[RSE-COMMS] Host to RSE MHU driver already initialized\n");
  138. } else {
  139. ERROR("[RSE-COMMS] Host to RSE MHU driver initialization failed: %d\n", err);
  140. return -1;
  141. }
  142. }
  143. err = mhu_init_receiver(mhu_receiver_base);
  144. if (err != MHU_ERR_NONE) {
  145. if (err == MHU_ERR_ALREADY_INIT) {
  146. INFO("[RSE-COMMS] RSE to Host MHU driver already initialized\n");
  147. } else {
  148. ERROR("[RSE-COMMS] RSE to Host MHU driver initialization failed: %d\n", err);
  149. return -1;
  150. }
  151. }
  152. return 0;
  153. }