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