1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2021-2022, Linaro Limited 4 */ 5 #include <assert.h> 6 #include <drivers/scmi-msg.h> 7 #include <drivers/scmi.h> 8 #include <io.h> 9 #include <kernel/misc.h> 10 #include <stdint.h> 11 #include <string.h> 12 #include <trace.h> 13 #include <util.h> 14 15 #include "common.h" 16 17 /** 18 * struct msg_header - MSG formatted header for MSG base shared memory transfer 19 * 20 * @message_header: 32bit header used in MSG shared memory protocol 21 * @payload: SCMI message payload data 22 */ 23 struct msg_header { 24 uint32_t message_header; 25 uint32_t payload[]; 26 }; 27 28 /* Bit fields packed in msg_header::message_header */ 29 #define MSG_ID_MASK GENMASK_32(7, 0) 30 #define MSG_ID(_hdr) ((_hdr) & MSG_ID_MASK) 31 32 #define MSG_TYPE_MASK GENMASK_32(9, 8) 33 #define MSG_TYPE(_hdr) (((_hdr) & MSG_TYPE_MASK) >> 8) 34 35 #define MSG_PROT_ID_MASK GENMASK_32(17, 10) 36 #define MSG_PROT_ID(_hdr) (((_hdr) & MSG_PROT_ID_MASK) >> 10) 37 38 /* 39 * Creates a SCMI message instance in secure memory and push it in the SCMI 40 * message drivers. Message structure contains SCMI protocol meta-data and 41 * references to input payload in secure memory and output message buffer 42 * in shared memory. 43 */ 44 TEE_Result scmi_entry_msg(unsigned int channel_id, void *in_buf, size_t in_size, 45 void *out_buf, size_t *out_size, uint32_t *sec_buf) 46 { 47 struct scmi_msg_channel *channel = plat_scmi_get_channel(channel_id); 48 struct msg_header *hdr = NULL; 49 struct scmi_msg msg = { }; 50 uint32_t msg_header = 0; 51 52 if (!channel) { 53 DMSG("Invalid channel ID %u", channel_id); 54 return TEE_ERROR_BAD_PARAMETERS; 55 } 56 57 assert(in_buf && out_buf && out_size && sec_buf); 58 59 if (in_size < sizeof(struct msg_header) || 60 in_size - sizeof(struct msg_header) > SCMI_SEC_PAYLOAD_SIZE || 61 !IS_ALIGNED_WITH_TYPE(in_buf, uint32_t) || 62 *out_size < sizeof(struct msg_header) || 63 !IS_ALIGNED_WITH_TYPE(out_buf, uint32_t)) { 64 DMSG("Invalid SCMI buffer references %zu@%p / %zu@%p", 65 in_size, in_buf, *out_size, out_buf); 66 return TEE_ERROR_BAD_PARAMETERS; 67 } 68 69 if (!scmi_msg_claim_channel(channel)) { 70 DMSG("SCMI channel %u busy", channel_id); 71 return TEE_ERROR_BUSY; 72 } 73 74 /* Copy SCMI protocol data and message payload in secure memory */ 75 hdr = (struct msg_header *)in_buf; 76 msg_header = READ_ONCE(hdr->message_header); 77 78 msg.protocol_id = MSG_PROT_ID(msg_header); 79 msg.message_id = MSG_ID(msg_header); 80 msg.channel_id = channel_id; 81 82 msg.in = (char *)sec_buf; 83 msg.in_size = in_size - sizeof(struct msg_header); 84 memcpy(msg.in, hdr->payload, msg.in_size); 85 86 /* Prepare output message buffer references */ 87 hdr = (struct msg_header *)out_buf; 88 89 msg.out = (char *)hdr->payload; 90 msg.out_size = *out_size - sizeof(struct msg_header); 91 92 scmi_process_message(&msg); 93 94 /* Update SCMI protocol data and output shared buffer size */ 95 hdr->message_header = msg_header; 96 *out_size = msg.out_size_out + sizeof(struct msg_header); 97 98 scmi_msg_release_channel(channel); 99 100 return TEE_SUCCESS; 101 } 102