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