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 */
scmi_entry_msg(unsigned int channel_id,void * in_buf,size_t in_size,void * out_buf,size_t * out_size,uint32_t * sec_buf)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