1 /* 2 * Copyright (c) 2022, Arm Limited. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <stddef.h> 9 #include <stdint.h> 10 #include <string.h> 11 12 #include <drivers/arm/mhu.h> 13 14 #include "mhu_v2_x.h" 15 16 #define MHU_NOTIFY_VALUE (1234u) 17 18 /* 19 * MHU devices for host: 20 * HSE: Host to Secure Enclave (sender device) 21 * SEH: Secure Enclave to Host (receiver device) 22 */ 23 struct mhu_v2_x_dev_t MHU1_HSE_DEV = {0, MHU_V2_X_SENDER_FRAME}; 24 struct mhu_v2_x_dev_t MHU1_SEH_DEV = {0, MHU_V2_X_RECEIVER_FRAME}; 25 26 static enum mhu_error_t error_mapping_to_mhu_error_t(enum mhu_v2_x_error_t err) 27 { 28 switch (err) { 29 case MHU_V_2_X_ERR_NONE: 30 return MHU_ERR_NONE; 31 case MHU_V_2_X_ERR_NOT_INIT: 32 return MHU_ERR_NOT_INIT; 33 case MHU_V_2_X_ERR_ALREADY_INIT: 34 return MHU_ERR_ALREADY_INIT; 35 case MHU_V_2_X_ERR_UNSUPPORTED_VERSION: 36 return MHU_ERR_UNSUPPORTED_VERSION; 37 case MHU_V_2_X_ERR_INVALID_ARG: 38 return MHU_ERR_INVALID_ARG; 39 case MHU_V_2_X_ERR_GENERAL: 40 return MHU_ERR_GENERAL; 41 default: 42 return MHU_ERR_GENERAL; 43 } 44 } 45 46 static enum mhu_v2_x_error_t signal_and_wait_for_clear(void) 47 { 48 enum mhu_v2_x_error_t err; 49 struct mhu_v2_x_dev_t *dev = &MHU1_HSE_DEV; 50 uint32_t val = MHU_NOTIFY_VALUE; 51 /* Using the last channel for notifications */ 52 uint32_t channel_notify = mhu_v2_x_get_num_channel_implemented(dev) - 1; 53 54 err = mhu_v2_x_channel_send(dev, channel_notify, val); 55 if (err != MHU_V_2_X_ERR_NONE) { 56 return err; 57 } 58 59 do { 60 err = mhu_v2_x_channel_poll(dev, channel_notify, &val); 61 if (err != MHU_V_2_X_ERR_NONE) { 62 break; 63 } 64 } while (val != 0); 65 66 return err; 67 } 68 69 static enum mhu_v2_x_error_t wait_for_signal(void) 70 { 71 enum mhu_v2_x_error_t err; 72 struct mhu_v2_x_dev_t *dev = &MHU1_SEH_DEV; 73 uint32_t val = 0; 74 /* Using the last channel for notifications */ 75 uint32_t channel_notify = mhu_v2_x_get_num_channel_implemented(dev) - 1; 76 77 do { 78 err = mhu_v2_x_channel_receive(dev, channel_notify, &val); 79 if (err != MHU_V_2_X_ERR_NONE) { 80 break; 81 } 82 } while (val != MHU_NOTIFY_VALUE); 83 84 return err; 85 } 86 87 static enum mhu_v2_x_error_t clear_and_wait_for_next_signal(void) 88 { 89 enum mhu_v2_x_error_t err; 90 struct mhu_v2_x_dev_t *dev = &MHU1_SEH_DEV; 91 uint32_t num_channels = mhu_v2_x_get_num_channel_implemented(dev); 92 uint32_t i; 93 94 /* Clear all channels */ 95 for (i = 0; i < num_channels; ++i) { 96 err = mhu_v2_x_channel_clear(dev, i); 97 if (err != MHU_V_2_X_ERR_NONE) { 98 return err; 99 } 100 } 101 102 return wait_for_signal(); 103 } 104 105 enum mhu_error_t mhu_init_sender(uintptr_t mhu_sender_base) 106 { 107 enum mhu_v2_x_error_t err; 108 109 assert(mhu_sender_base != (uintptr_t)NULL); 110 111 MHU1_HSE_DEV.base = mhu_sender_base; 112 113 err = mhu_v2_x_driver_init(&MHU1_HSE_DEV, MHU_REV_READ_FROM_HW); 114 return error_mapping_to_mhu_error_t(err); 115 } 116 117 enum mhu_error_t mhu_init_receiver(uintptr_t mhu_receiver_base) 118 { 119 enum mhu_v2_x_error_t err; 120 uint32_t num_channels, i; 121 122 assert(mhu_receiver_base != (uintptr_t)NULL); 123 124 MHU1_SEH_DEV.base = mhu_receiver_base; 125 126 err = mhu_v2_x_driver_init(&MHU1_SEH_DEV, MHU_REV_READ_FROM_HW); 127 if (err != MHU_V_2_X_ERR_NONE) { 128 return error_mapping_to_mhu_error_t(err); 129 } 130 131 num_channels = mhu_v2_x_get_num_channel_implemented(&MHU1_SEH_DEV); 132 133 /* Mask all channels except the notifying channel */ 134 for (i = 0; i < (num_channels - 1); ++i) { 135 err = mhu_v2_x_channel_mask_set(&MHU1_SEH_DEV, i, UINT32_MAX); 136 if (err != MHU_V_2_X_ERR_NONE) { 137 return error_mapping_to_mhu_error_t(err); 138 } 139 } 140 141 /* The last channel is used for notifications */ 142 err = mhu_v2_x_channel_mask_clear( 143 &MHU1_SEH_DEV, (num_channels - 1), UINT32_MAX); 144 return error_mapping_to_mhu_error_t(err); 145 } 146 147 /* 148 * Public function. See mhu.h 149 * 150 * The basic steps of transferring a message: 151 * 1. Initiate MHU transfer. 152 * 2. Send over the size of the payload on Channel 1. It is the very first 153 * 4 Bytes of the transfer. Continue with Channel 2. 154 * 3. Send over the payload, writing the channels one after the other 155 * (4 Bytes each). The last available channel is reserved for controlling 156 * the transfer. 157 * When the last channel is reached or no more data is left, STOP. 158 * 4. Notify the receiver using the last channel and wait for acknowledge. 159 * If there is still data to transfer, jump to step 3. Otherwise, proceed. 160 * 5. Close MHU transfer. 161 * 162 */ 163 enum mhu_error_t mhu_send_data(const uint8_t *send_buffer, size_t size) 164 { 165 enum mhu_v2_x_error_t err; 166 struct mhu_v2_x_dev_t *dev = &MHU1_HSE_DEV; 167 uint32_t num_channels = mhu_v2_x_get_num_channel_implemented(dev); 168 uint32_t chan = 0; 169 uint32_t i; 170 uint32_t *p; 171 172 /* For simplicity, require the send_buffer to be 4-byte aligned */ 173 if ((uintptr_t)send_buffer & 0x3U) { 174 return MHU_ERR_INVALID_ARG; 175 } 176 177 err = mhu_v2_x_initiate_transfer(dev); 178 if (err != MHU_V_2_X_ERR_NONE) { 179 return error_mapping_to_mhu_error_t(err); 180 } 181 182 /* First send over the size of the actual message */ 183 err = mhu_v2_x_channel_send(dev, chan, (uint32_t)size); 184 if (err != MHU_V_2_X_ERR_NONE) { 185 return error_mapping_to_mhu_error_t(err); 186 } 187 chan++; 188 189 p = (uint32_t *)send_buffer; 190 for (i = 0; i < size; i += 4) { 191 err = mhu_v2_x_channel_send(dev, chan, *p++); 192 if (err != MHU_V_2_X_ERR_NONE) { 193 return error_mapping_to_mhu_error_t(err); 194 } 195 if (++chan == (num_channels - 1)) { 196 err = signal_and_wait_for_clear(); 197 if (err != MHU_V_2_X_ERR_NONE) { 198 return error_mapping_to_mhu_error_t(err); 199 } 200 chan = 0; 201 } 202 } 203 204 /* Signal the end of transfer. 205 * It's not required to send a signal when the message was 206 * perfectly-aligned (num_channels - 1 channels were used in the last 207 * round) preventing it from signaling twice at the end of transfer. 208 */ 209 if (chan != 0) { 210 err = signal_and_wait_for_clear(); 211 if (err != MHU_V_2_X_ERR_NONE) { 212 return error_mapping_to_mhu_error_t(err); 213 } 214 } 215 216 err = mhu_v2_x_close_transfer(dev); 217 return error_mapping_to_mhu_error_t(err); 218 } 219 220 /* 221 * Public function. See mhu.h 222 * 223 * The basic steps of receiving a message: 224 * 1. Read the size of the payload from Channel 1. It is the very first 225 * 4 Bytes of the transfer. Continue with Channel 2. 226 * 2. Receive the payload, read the channels one after the other 227 * (4 Bytes each). The last available channel is reserved for controlling 228 * the transfer. 229 * When the last channel is reached clear all the channels 230 * (also sending an acknowledge on the last channel). 231 * 3. If there is still data to receive wait for a notification on the last 232 * channel and jump to step 2 as soon as it arrived. Otherwise, proceed. 233 * 4. End of transfer. 234 * 235 */ 236 enum mhu_error_t mhu_receive_data(uint8_t *receive_buffer, size_t *size) 237 { 238 enum mhu_v2_x_error_t err; 239 struct mhu_v2_x_dev_t *dev = &MHU1_SEH_DEV; 240 uint32_t num_channels = mhu_v2_x_get_num_channel_implemented(dev); 241 uint32_t chan = 0; 242 uint32_t message_len; 243 uint32_t i; 244 uint32_t *p; 245 246 /* For simplicity, require: 247 * - the receive_buffer to be 4-byte aligned, 248 * - the buffer size to be a multiple of 4. 249 */ 250 if (((uintptr_t)receive_buffer & 0x3U) || (*size & 0x3U)) { 251 return MHU_ERR_INVALID_ARG; 252 } 253 254 /* Busy wait for incoming reply */ 255 err = wait_for_signal(); 256 if (err != MHU_V_2_X_ERR_NONE) { 257 return error_mapping_to_mhu_error_t(err); 258 } 259 260 /* The first word is the length of the actual message */ 261 err = mhu_v2_x_channel_receive(dev, chan, &message_len); 262 if (err != MHU_V_2_X_ERR_NONE) { 263 return error_mapping_to_mhu_error_t(err); 264 } 265 chan++; 266 267 if (message_len > *size) { 268 /* Message buffer too small */ 269 *size = message_len; 270 return MHU_ERR_BUFFER_TOO_SMALL; 271 } 272 273 p = (uint32_t *)receive_buffer; 274 for (i = 0; i < message_len; i += 4) { 275 err = mhu_v2_x_channel_receive(dev, chan, p++); 276 if (err != MHU_V_2_X_ERR_NONE) { 277 return error_mapping_to_mhu_error_t(err); 278 } 279 280 /* Only wait for next transfer if there is still missing data */ 281 if (++chan == (num_channels - 1) && (message_len - i) > 4) { 282 /* Busy wait for next transfer */ 283 err = clear_and_wait_for_next_signal(); 284 if (err != MHU_V_2_X_ERR_NONE) { 285 return error_mapping_to_mhu_error_t(err); 286 } 287 chan = 0; 288 } 289 } 290 291 /* Clear all channels */ 292 for (i = 0; i < num_channels; ++i) { 293 err = mhu_v2_x_channel_clear(dev, i); 294 if (err != MHU_V_2_X_ERR_NONE) { 295 return error_mapping_to_mhu_error_t(err); 296 } 297 } 298 299 *size = message_len; 300 301 return MHU_ERR_NONE; 302 } 303 304 size_t mhu_get_max_message_size(void) 305 { 306 struct mhu_v2_x_dev_t *dev = &MHU1_SEH_DEV; 307 uint32_t num_channels = mhu_v2_x_get_num_channel_implemented(dev); 308 309 assert(num_channels != 0); 310 311 return num_channels * sizeof(uint32_t); 312 } 313