xref: /aosp_15_r20/trusty/kernel/services/smc/smc_service.c (revision 344aa361028b423587d4ef3fa52a23d194628137)
1 /*
2  * Copyright (c) 2019, Google Inc. All rights reserved
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files
6  * (the "Software"), to deal in the Software without restriction,
7  * including without limitation the rights to use, copy, modify, merge,
8  * publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 
24 #include <err.h>
25 #include <interface/smc/smc.h>
26 #include <kernel/thread.h>
27 #include <lib/ktipc/ktipc.h>
28 #include <lib/trusty/handle_set.h>
29 #include <lib/trusty/ipc.h>
30 #include <lib/trusty/ipc_msg.h>
31 #include <lk/init.h>
32 #include <lk/trace.h>
33 #include <services/smc/acl.h>
34 #include <string.h>
35 
36 #define LOCAL_TRACE (0)
37 
38 struct smc_channel_ctx {
39     struct smc_access_policy policy;
40     struct uuid uuid;
41 };
42 
43 /**
44  * struct smc_regs - Struct representing input/output registers of an SMC
45  * @r0-3: registers r0-3/x0-3 for 32/64 bit respectively
46  */
47 struct smc_regs {
48     ulong r0;
49     ulong r1;
50     ulong r2;
51     ulong r3;
52 };
53 
54 #if ARCH_ARM64
55 #define SMC_ARG0 "x0"
56 #define SMC_ARG1 "x1"
57 #define SMC_ARG2 "x2"
58 #define SMC_ARG3 "x3"
59 #define SMC_ARCH_EXTENSION ""
60 #define SMC_REGISTERS_TRASHED                                              \
61     "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13", "x14", \
62             "x15", "x16", "x17"
63 #else
64 #define SMC_ARG0 "r0"
65 #define SMC_ARG1 "r1"
66 #define SMC_ARG2 "r2"
67 #define SMC_ARG3 "r3"
68 #define SMC_ARCH_EXTENSION ".arch_extension sec\n"
69 #define SMC_REGISTERS_TRASHED "ip"
70 #endif
71 
72 /* Perform a secure manager call with up to 4 inputs and 4 outputs */
smc(struct smc_regs * regs)73 static struct smc_regs smc(struct smc_regs* regs) {
74     register ulong _r0 __asm__(SMC_ARG0) = regs->r0;
75     register ulong _r1 __asm__(SMC_ARG1) = regs->r1;
76     register ulong _r2 __asm__(SMC_ARG2) = regs->r2;
77     register ulong _r3 __asm__(SMC_ARG3) = regs->r3;
78     __asm__ volatile(SMC_ARCH_EXTENSION "smc #0"
79                      : "=r"(_r0), "=r"(_r1), "=r"(_r2), "=r"(_r3)
80                      : "r"(_r0), "r"(_r1), "r"(_r2), "r"(_r3)
81                      : SMC_REGISTERS_TRASHED);
82     return (struct smc_regs){
83             .r0 = _r0,
84             .r1 = _r1,
85             .r2 = _r2,
86             .r3 = _r3,
87     };
88 }
89 
smc_service_handle_msg(const struct ktipc_port * port,struct handle * channel,void * ctx)90 static int smc_service_handle_msg(const struct ktipc_port* port,
91                                   struct handle* channel,
92                                   void* ctx) {
93     struct smc_channel_ctx* channel_ctx = ctx;
94     int rc;
95     struct smc_msg request;
96     struct smc_response response = {0};
97     struct smc_regs ret;
98     uint32_t smc_nr;
99 
100     rc = ktipc_recv(channel, sizeof(request), &request, sizeof(request));
101     if ((size_t)rc != sizeof(request)) {
102         TRACEF("%s: failed (%d) to read SMC request\n", __func__, rc);
103         goto err;
104     }
105 
106     smc_nr = (uint32_t)request.params[0];
107     rc = channel_ctx->policy.check_access(smc_nr);
108     if (rc != NO_ERROR) {
109         TRACEF("%s: failed (%d) client not allowed to call SMC number %x\n",
110                __func__, rc, smc_nr);
111         /*
112          * callers of smc_read_response should not consume the struct smc_msg
113          * out parameter if the status code is negative but we write the error
114          * code into the message anyway out of an over-abundance of caution.
115          */
116         response.msg.params[0] = (ulong)ERR_ACCESS_DENIED;
117         response.rc = ERR_ACCESS_DENIED;
118         goto send_response;
119     }
120 
121     rc = channel_ctx->policy.check_request(smc_nr, &channel_ctx->uuid,
122                                            &request);
123     if (rc != NO_ERROR) {
124         TRACEF("%s: failed (%d) invalid request for SMC number %x\n", __func__,
125                rc, smc_nr);
126         /* same reasoning as the ERR_ACCESS_DENIED case above */
127         response.msg.params[0] = (ulong)ERR_INVALID_ARGS;
128         response.rc = ERR_INVALID_ARGS;
129         goto send_response;
130     }
131 
132     struct smc_regs args = {
133             .r0 = (ulong)request.params[0],
134             .r1 = (ulong)request.params[1],
135             .r2 = (ulong)request.params[2],
136             .r3 = (ulong)request.params[3],
137     };
138     ret = smc(&args);
139 
140     response.msg.params[0] = ret.r0;
141     response.msg.params[1] = ret.r1;
142     response.msg.params[2] = ret.r2;
143     response.msg.params[3] = ret.r3;
144 
145     if ((int32_t)ret.r0 == SM_ERR_UNDEFINED_SMC) {
146         TRACEF("%s: unknown or failed smcall: %x\n", __func__, smc_nr);
147         response.rc = ERR_GENERIC;
148     }
149 
150 send_response:
151     rc = ktipc_send(channel, &response, sizeof(response));
152     if ((size_t)rc != sizeof(response)) {
153         TRACEF("%s: failed (%d) to send response\n", __func__, rc);
154     }
155 
156 err:
157     return rc;
158 }
159 
smc_service_handle_connect(const struct ktipc_port * port,struct handle * chan,const struct uuid * peer_uuid,void ** ctx_p)160 static int smc_service_handle_connect(const struct ktipc_port* port,
161                                       struct handle* chan,
162                                       const struct uuid* peer_uuid,
163                                       void** ctx_p) {
164     struct smc_channel_ctx* channel_ctx = calloc(1, sizeof(*channel_ctx));
165     if (!channel_ctx) {
166         TRACEF("%s: failed to allocate smc_channel_ctx\n", __func__);
167         return ERR_NO_MEMORY;
168     }
169 
170     smc_load_access_policy(peer_uuid, &channel_ctx->policy);
171     channel_ctx->uuid = *peer_uuid;
172 
173     *ctx_p = channel_ctx;
174 
175     return NO_ERROR;
176 }
177 
smc_service_handle_channel_cleanup(void * ctx)178 static void smc_service_handle_channel_cleanup(void* ctx) {
179     struct smc_channel_ctx* channel_ctx = ctx;
180     free(channel_ctx);
181 }
182 
183 const static struct ktipc_srv_ops smc_service_ops = {
184         .on_connect = smc_service_handle_connect,
185         .on_message = smc_service_handle_msg,
186         .on_channel_cleanup = smc_service_handle_channel_cleanup,
187 };
188 
189 const static struct ktipc_port_acl smc_service_port_acl = {
190         .flags = IPC_PORT_ALLOW_TA_CONNECT,
191         .uuids = NULL,
192         .uuid_num = 0,
193         .extra_data = NULL,
194 };
195 
196 const static struct ktipc_port smc_service_port = {
197         .name = SMC_SERVICE_PORT,
198         .uuid = &kernel_uuid,
199         .msg_max_size = sizeof(struct smc_response),
200         .msg_queue_len = 1,
201         .acl = &smc_service_port_acl,
202         .priv = NULL,
203 };
204 
205 static struct ktipc_server smc_ktipc_server =
206         KTIPC_SERVER_INITIAL_VALUE(smc_ktipc_server, "smc_ktipc_server");
207 
smc_service_init(uint level)208 static void smc_service_init(uint level) {
209     int rc;
210 
211     rc = ktipc_server_start(&smc_ktipc_server);
212     if (rc < 0) {
213         panic("Failed (%d) to start smc server\n", rc);
214     }
215 
216     rc = ktipc_server_add_port(&smc_ktipc_server, &smc_service_port,
217                                &smc_service_ops);
218     if (rc < 0) {
219         panic("Failed (%d) to create smc port\n", rc);
220     }
221 }
222 
223 LK_INIT_HOOK(smc, smc_service_init, LK_INIT_LEVEL_APPS);
224