xref: /aosp_15_r20/trusty/kernel/services/hwrng/hwrng_service.c (revision 344aa361028b423587d4ef3fa52a23d194628137)
1*344aa361SAndroid Build Coastguard Worker /*
2*344aa361SAndroid Build Coastguard Worker  * Copyright (c) 2022, Google Inc. All rights reserved
3*344aa361SAndroid Build Coastguard Worker  *
4*344aa361SAndroid Build Coastguard Worker  * Permission is hereby granted, free of charge, to any person obtaining
5*344aa361SAndroid Build Coastguard Worker  * a copy of this software and associated documentation files
6*344aa361SAndroid Build Coastguard Worker  * (the "Software"), to deal in the Software without restriction,
7*344aa361SAndroid Build Coastguard Worker  * including without limitation the rights to use, copy, modify, merge,
8*344aa361SAndroid Build Coastguard Worker  * publish, distribute, sublicense, and/or sell copies of the Software,
9*344aa361SAndroid Build Coastguard Worker  * and to permit persons to whom the Software is furnished to do so,
10*344aa361SAndroid Build Coastguard Worker  * subject to the following conditions:
11*344aa361SAndroid Build Coastguard Worker  *
12*344aa361SAndroid Build Coastguard Worker  * The above copyright notice and this permission notice shall be
13*344aa361SAndroid Build Coastguard Worker  * included in all copies or substantial portions of the Software.
14*344aa361SAndroid Build Coastguard Worker  *
15*344aa361SAndroid Build Coastguard Worker  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16*344aa361SAndroid Build Coastguard Worker  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17*344aa361SAndroid Build Coastguard Worker  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18*344aa361SAndroid Build Coastguard Worker  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19*344aa361SAndroid Build Coastguard Worker  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20*344aa361SAndroid Build Coastguard Worker  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21*344aa361SAndroid Build Coastguard Worker  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22*344aa361SAndroid Build Coastguard Worker  */
23*344aa361SAndroid Build Coastguard Worker 
24*344aa361SAndroid Build Coastguard Worker #define LOCAL_TRACE 0
25*344aa361SAndroid Build Coastguard Worker 
26*344aa361SAndroid Build Coastguard Worker #include <err.h>
27*344aa361SAndroid Build Coastguard Worker #include <inttypes.h>
28*344aa361SAndroid Build Coastguard Worker #include <lib/ktipc/ktipc.h>
29*344aa361SAndroid Build Coastguard Worker #include <lib/rand/rand.h>
30*344aa361SAndroid Build Coastguard Worker #include <lib/trusty/ipc.h>
31*344aa361SAndroid Build Coastguard Worker #include <lib/trusty/ipc_msg.h>
32*344aa361SAndroid Build Coastguard Worker #include <lib/trusty/uuid.h>
33*344aa361SAndroid Build Coastguard Worker #include <lk/init.h>
34*344aa361SAndroid Build Coastguard Worker #include <lk/list.h>
35*344aa361SAndroid Build Coastguard Worker #include <lk/trace.h>
36*344aa361SAndroid Build Coastguard Worker 
37*344aa361SAndroid Build Coastguard Worker #include <interface/hwrng/hwrng.h>
38*344aa361SAndroid Build Coastguard Worker 
39*344aa361SAndroid Build Coastguard Worker #define HWRNG_SRV_NAME HWRNG_PORT
40*344aa361SAndroid Build Coastguard Worker #define MAX_HWRNG_MSG_SIZE 128
41*344aa361SAndroid Build Coastguard Worker 
42*344aa361SAndroid Build Coastguard Worker struct hwrng_chan_ctx {
43*344aa361SAndroid Build Coastguard Worker     struct list_node node;
44*344aa361SAndroid Build Coastguard Worker     struct handle* chan;
45*344aa361SAndroid Build Coastguard Worker     size_t req_size;
46*344aa361SAndroid Build Coastguard Worker     int error;
47*344aa361SAndroid Build Coastguard Worker     bool send_blocked;
48*344aa361SAndroid Build Coastguard Worker };
49*344aa361SAndroid Build Coastguard Worker 
50*344aa361SAndroid Build Coastguard Worker static uint8_t rng_data[MAX_HWRNG_MSG_SIZE];
51*344aa361SAndroid Build Coastguard Worker 
52*344aa361SAndroid Build Coastguard Worker /* If we have data left over from the last request, keep track of it */
53*344aa361SAndroid Build Coastguard Worker static size_t rng_data_avail_count;
54*344aa361SAndroid Build Coastguard Worker static size_t rng_data_avail_pos;
55*344aa361SAndroid Build Coastguard Worker 
56*344aa361SAndroid Build Coastguard Worker static struct list_node hwrng_req_list = LIST_INITIAL_VALUE(hwrng_req_list);
57*344aa361SAndroid Build Coastguard Worker 
58*344aa361SAndroid Build Coastguard Worker /*
59*344aa361SAndroid Build Coastguard Worker  * Handle HWRNG request queue
60*344aa361SAndroid Build Coastguard Worker  */
hwrng_handle_req_queue(void)61*344aa361SAndroid Build Coastguard Worker static void hwrng_handle_req_queue(void) {
62*344aa361SAndroid Build Coastguard Worker     int rc;
63*344aa361SAndroid Build Coastguard Worker     struct hwrng_chan_ctx* ctx;
64*344aa361SAndroid Build Coastguard Worker     struct hwrng_chan_ctx* temp;
65*344aa361SAndroid Build Coastguard Worker 
66*344aa361SAndroid Build Coastguard Worker     /* for all pending requests */
67*344aa361SAndroid Build Coastguard Worker     bool more_requests;
68*344aa361SAndroid Build Coastguard Worker     do {
69*344aa361SAndroid Build Coastguard Worker         more_requests = false;
70*344aa361SAndroid Build Coastguard Worker         list_for_every_entry_safe(&hwrng_req_list, ctx, temp,
71*344aa361SAndroid Build Coastguard Worker                                   struct hwrng_chan_ctx, node) {
72*344aa361SAndroid Build Coastguard Worker             if (ctx->error || ctx->send_blocked)
73*344aa361SAndroid Build Coastguard Worker                 continue; /* can't service it right now */
74*344aa361SAndroid Build Coastguard Worker 
75*344aa361SAndroid Build Coastguard Worker             /*
76*344aa361SAndroid Build Coastguard Worker              * send up to MAX_HWRNG_MSG_SIZE per client at a time,
77*344aa361SAndroid Build Coastguard Worker              * to prevent a single client from starving all the others
78*344aa361SAndroid Build Coastguard Worker              */
79*344aa361SAndroid Build Coastguard Worker             size_t len = MIN(ctx->req_size, MAX_HWRNG_MSG_SIZE);
80*344aa361SAndroid Build Coastguard Worker             if (rng_data_avail_count) {
81*344aa361SAndroid Build Coastguard Worker                 /* use leftover data if there is any */
82*344aa361SAndroid Build Coastguard Worker                 len = MIN(len, rng_data_avail_count);
83*344aa361SAndroid Build Coastguard Worker             } else {
84*344aa361SAndroid Build Coastguard Worker                 /* get hwrng data */
85*344aa361SAndroid Build Coastguard Worker                 rand_get_bytes(rng_data, len);
86*344aa361SAndroid Build Coastguard Worker                 rng_data_avail_pos = 0;
87*344aa361SAndroid Build Coastguard Worker                 rng_data_avail_count = len;
88*344aa361SAndroid Build Coastguard Worker             }
89*344aa361SAndroid Build Coastguard Worker 
90*344aa361SAndroid Build Coastguard Worker             /* send reply */
91*344aa361SAndroid Build Coastguard Worker             rc = ktipc_send(ctx->chan, rng_data + rng_data_avail_pos, len);
92*344aa361SAndroid Build Coastguard Worker             if (rc < 0) {
93*344aa361SAndroid Build Coastguard Worker                 if (rc == ERR_NOT_ENOUGH_BUFFER) {
94*344aa361SAndroid Build Coastguard Worker                     /* mark it as send_blocked */
95*344aa361SAndroid Build Coastguard Worker                     ctx->send_blocked = true;
96*344aa361SAndroid Build Coastguard Worker                 } else {
97*344aa361SAndroid Build Coastguard Worker                     TRACEF("%s: failed (%d) to send_reply\n", __func__, rc);
98*344aa361SAndroid Build Coastguard Worker                     ctx->error = rc;
99*344aa361SAndroid Build Coastguard Worker                 }
100*344aa361SAndroid Build Coastguard Worker                 continue;
101*344aa361SAndroid Build Coastguard Worker             }
102*344aa361SAndroid Build Coastguard Worker 
103*344aa361SAndroid Build Coastguard Worker             rng_data_avail_pos += len;
104*344aa361SAndroid Build Coastguard Worker             rng_data_avail_count -= len;
105*344aa361SAndroid Build Coastguard Worker             ctx->req_size -= len;
106*344aa361SAndroid Build Coastguard Worker 
107*344aa361SAndroid Build Coastguard Worker             if (!ctx->req_size) {
108*344aa361SAndroid Build Coastguard Worker                 /* remove it from pending list */
109*344aa361SAndroid Build Coastguard Worker                 list_delete(&ctx->node);
110*344aa361SAndroid Build Coastguard Worker             } else {
111*344aa361SAndroid Build Coastguard Worker                 more_requests = true;
112*344aa361SAndroid Build Coastguard Worker             }
113*344aa361SAndroid Build Coastguard Worker         }
114*344aa361SAndroid Build Coastguard Worker     } while (more_requests);
115*344aa361SAndroid Build Coastguard Worker }
116*344aa361SAndroid Build Coastguard Worker 
hwrng_handle_msg(const struct ktipc_port * port,struct handle * chan,void * ctx_v)117*344aa361SAndroid Build Coastguard Worker static int hwrng_handle_msg(const struct ktipc_port* port,
118*344aa361SAndroid Build Coastguard Worker                             struct handle* chan,
119*344aa361SAndroid Build Coastguard Worker                             void* ctx_v) {
120*344aa361SAndroid Build Coastguard Worker     int rc;
121*344aa361SAndroid Build Coastguard Worker     struct hwrng_chan_ctx* ctx = ctx_v;
122*344aa361SAndroid Build Coastguard Worker     struct hwrng_req req;
123*344aa361SAndroid Build Coastguard Worker 
124*344aa361SAndroid Build Coastguard Worker     /* check for an error from a previous send attempt */
125*344aa361SAndroid Build Coastguard Worker     if (ctx->error) {
126*344aa361SAndroid Build Coastguard Worker         return ctx->error;
127*344aa361SAndroid Build Coastguard Worker     }
128*344aa361SAndroid Build Coastguard Worker 
129*344aa361SAndroid Build Coastguard Worker     /* read request */
130*344aa361SAndroid Build Coastguard Worker     rc = ktipc_recv(chan, sizeof(req), &req, sizeof(req));
131*344aa361SAndroid Build Coastguard Worker     if (rc < 0) {
132*344aa361SAndroid Build Coastguard Worker         TRACEF("%s: failed (%d) to receive msg for chan\n", __func__, rc);
133*344aa361SAndroid Build Coastguard Worker         return rc;
134*344aa361SAndroid Build Coastguard Worker     }
135*344aa361SAndroid Build Coastguard Worker 
136*344aa361SAndroid Build Coastguard Worker     /* check if we already have request in progress */
137*344aa361SAndroid Build Coastguard Worker     if (list_in_list(&ctx->node)) {
138*344aa361SAndroid Build Coastguard Worker         /* extend it */
139*344aa361SAndroid Build Coastguard Worker         ctx->req_size += req.len;
140*344aa361SAndroid Build Coastguard Worker     } else {
141*344aa361SAndroid Build Coastguard Worker         /* queue it */
142*344aa361SAndroid Build Coastguard Worker         ctx->req_size = req.len;
143*344aa361SAndroid Build Coastguard Worker         list_add_tail(&hwrng_req_list, &ctx->node);
144*344aa361SAndroid Build Coastguard Worker     }
145*344aa361SAndroid Build Coastguard Worker 
146*344aa361SAndroid Build Coastguard Worker     hwrng_handle_req_queue();
147*344aa361SAndroid Build Coastguard Worker 
148*344aa361SAndroid Build Coastguard Worker     return ctx->error;
149*344aa361SAndroid Build Coastguard Worker }
150*344aa361SAndroid Build Coastguard Worker 
hwrng_handle_connect(const struct ktipc_port * port,struct handle * chan,const struct uuid * peer,void ** ctx_p)151*344aa361SAndroid Build Coastguard Worker static int hwrng_handle_connect(const struct ktipc_port* port,
152*344aa361SAndroid Build Coastguard Worker                                 struct handle* chan,
153*344aa361SAndroid Build Coastguard Worker                                 const struct uuid* peer,
154*344aa361SAndroid Build Coastguard Worker                                 void** ctx_p) {
155*344aa361SAndroid Build Coastguard Worker     struct hwrng_chan_ctx* ctx = calloc(1, sizeof(*ctx));
156*344aa361SAndroid Build Coastguard Worker     if (!ctx) {
157*344aa361SAndroid Build Coastguard Worker         TRACEF("%s: failed to allocate context\n", __func__);
158*344aa361SAndroid Build Coastguard Worker         return ERR_NO_MEMORY;
159*344aa361SAndroid Build Coastguard Worker     }
160*344aa361SAndroid Build Coastguard Worker 
161*344aa361SAndroid Build Coastguard Worker     ctx->chan = chan;
162*344aa361SAndroid Build Coastguard Worker     *ctx_p = ctx;
163*344aa361SAndroid Build Coastguard Worker 
164*344aa361SAndroid Build Coastguard Worker     return NO_ERROR;
165*344aa361SAndroid Build Coastguard Worker }
166*344aa361SAndroid Build Coastguard Worker 
hwrng_handle_channel_cleanup(void * ctx_v)167*344aa361SAndroid Build Coastguard Worker static void hwrng_handle_channel_cleanup(void* ctx_v) {
168*344aa361SAndroid Build Coastguard Worker     struct hwrng_chan_ctx* ctx = ctx_v;
169*344aa361SAndroid Build Coastguard Worker 
170*344aa361SAndroid Build Coastguard Worker     if (list_in_list(&ctx->node)) {
171*344aa361SAndroid Build Coastguard Worker         list_delete(&ctx->node);
172*344aa361SAndroid Build Coastguard Worker     }
173*344aa361SAndroid Build Coastguard Worker 
174*344aa361SAndroid Build Coastguard Worker     free(ctx);
175*344aa361SAndroid Build Coastguard Worker }
176*344aa361SAndroid Build Coastguard Worker 
hwrng_handle_send_unblocked(const struct ktipc_port * port,struct handle * chan,void * ctx_v)177*344aa361SAndroid Build Coastguard Worker static int hwrng_handle_send_unblocked(const struct ktipc_port* port,
178*344aa361SAndroid Build Coastguard Worker                                        struct handle* chan,
179*344aa361SAndroid Build Coastguard Worker                                        void* ctx_v) {
180*344aa361SAndroid Build Coastguard Worker     struct hwrng_chan_ctx* ctx = ctx_v;
181*344aa361SAndroid Build Coastguard Worker 
182*344aa361SAndroid Build Coastguard Worker     if (ctx->error) {
183*344aa361SAndroid Build Coastguard Worker         return ctx->error;
184*344aa361SAndroid Build Coastguard Worker     }
185*344aa361SAndroid Build Coastguard Worker 
186*344aa361SAndroid Build Coastguard Worker     ctx->send_blocked = false;
187*344aa361SAndroid Build Coastguard Worker 
188*344aa361SAndroid Build Coastguard Worker     hwrng_handle_req_queue();
189*344aa361SAndroid Build Coastguard Worker 
190*344aa361SAndroid Build Coastguard Worker     return ctx->error;
191*344aa361SAndroid Build Coastguard Worker }
192*344aa361SAndroid Build Coastguard Worker 
193*344aa361SAndroid Build Coastguard Worker const static struct ktipc_srv_ops hwrng_srv_ops = {
194*344aa361SAndroid Build Coastguard Worker         .on_connect = hwrng_handle_connect,
195*344aa361SAndroid Build Coastguard Worker         .on_message = hwrng_handle_msg,
196*344aa361SAndroid Build Coastguard Worker         .on_channel_cleanup = hwrng_handle_channel_cleanup,
197*344aa361SAndroid Build Coastguard Worker         .on_send_unblocked = hwrng_handle_send_unblocked,
198*344aa361SAndroid Build Coastguard Worker };
199*344aa361SAndroid Build Coastguard Worker 
200*344aa361SAndroid Build Coastguard Worker const static struct ktipc_port_acl hwrng_srv_port_acl = {
201*344aa361SAndroid Build Coastguard Worker         .flags = IPC_PORT_ALLOW_TA_CONNECT,
202*344aa361SAndroid Build Coastguard Worker         .uuids = NULL,
203*344aa361SAndroid Build Coastguard Worker         .uuid_num = 0,
204*344aa361SAndroid Build Coastguard Worker         .extra_data = NULL,
205*344aa361SAndroid Build Coastguard Worker };
206*344aa361SAndroid Build Coastguard Worker 
207*344aa361SAndroid Build Coastguard Worker const static struct ktipc_port hwrng_srv_port = {
208*344aa361SAndroid Build Coastguard Worker         .name = HWRNG_SRV_NAME,
209*344aa361SAndroid Build Coastguard Worker         .uuid = &kernel_uuid,
210*344aa361SAndroid Build Coastguard Worker         .msg_max_size = MAX_HWRNG_MSG_SIZE,
211*344aa361SAndroid Build Coastguard Worker         .msg_queue_len = 1,
212*344aa361SAndroid Build Coastguard Worker         .acl = &hwrng_srv_port_acl,
213*344aa361SAndroid Build Coastguard Worker         .priv = NULL,
214*344aa361SAndroid Build Coastguard Worker };
215*344aa361SAndroid Build Coastguard Worker 
216*344aa361SAndroid Build Coastguard Worker static struct ktipc_server hwrng_ktipc_server =
217*344aa361SAndroid Build Coastguard Worker         KTIPC_SERVER_INITIAL_VALUE(hwrng_ktipc_server, "hwrng_ktipc_server");
218*344aa361SAndroid Build Coastguard Worker 
hwrng_ktipc_server_init(uint lvl)219*344aa361SAndroid Build Coastguard Worker static void hwrng_ktipc_server_init(uint lvl) {
220*344aa361SAndroid Build Coastguard Worker     int rc;
221*344aa361SAndroid Build Coastguard Worker 
222*344aa361SAndroid Build Coastguard Worker     rc = ktipc_server_start(&hwrng_ktipc_server);
223*344aa361SAndroid Build Coastguard Worker     if (rc < 0) {
224*344aa361SAndroid Build Coastguard Worker         panic("Failed (%d) to start hwrng server\n", rc);
225*344aa361SAndroid Build Coastguard Worker     }
226*344aa361SAndroid Build Coastguard Worker 
227*344aa361SAndroid Build Coastguard Worker     rc = ktipc_server_add_port(&hwrng_ktipc_server, &hwrng_srv_port,
228*344aa361SAndroid Build Coastguard Worker                                &hwrng_srv_ops);
229*344aa361SAndroid Build Coastguard Worker     if (rc < 0) {
230*344aa361SAndroid Build Coastguard Worker         panic("Failed (%d) to create hwrng service port\n", rc);
231*344aa361SAndroid Build Coastguard Worker     }
232*344aa361SAndroid Build Coastguard Worker }
233*344aa361SAndroid Build Coastguard Worker 
234*344aa361SAndroid Build Coastguard Worker LK_INIT_HOOK(hwrng_ktipc_server_init,
235*344aa361SAndroid Build Coastguard Worker              hwrng_ktipc_server_init,
236*344aa361SAndroid Build Coastguard Worker              LK_INIT_LEVEL_APPS - 1)
237