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