xref: /aosp_15_r20/trusty/kernel/services/hwrng/hwrng_service.c (revision 344aa361028b423587d4ef3fa52a23d194628137)
1 /*
2  * Copyright (c) 2022, 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 #define LOCAL_TRACE 0
25 
26 #include <err.h>
27 #include <inttypes.h>
28 #include <lib/ktipc/ktipc.h>
29 #include <lib/rand/rand.h>
30 #include <lib/trusty/ipc.h>
31 #include <lib/trusty/ipc_msg.h>
32 #include <lib/trusty/uuid.h>
33 #include <lk/init.h>
34 #include <lk/list.h>
35 #include <lk/trace.h>
36 
37 #include <interface/hwrng/hwrng.h>
38 
39 #define HWRNG_SRV_NAME HWRNG_PORT
40 #define MAX_HWRNG_MSG_SIZE 128
41 
42 struct hwrng_chan_ctx {
43     struct list_node node;
44     struct handle* chan;
45     size_t req_size;
46     int error;
47     bool send_blocked;
48 };
49 
50 static uint8_t rng_data[MAX_HWRNG_MSG_SIZE];
51 
52 /* If we have data left over from the last request, keep track of it */
53 static size_t rng_data_avail_count;
54 static size_t rng_data_avail_pos;
55 
56 static struct list_node hwrng_req_list = LIST_INITIAL_VALUE(hwrng_req_list);
57 
58 /*
59  * Handle HWRNG request queue
60  */
hwrng_handle_req_queue(void)61 static void hwrng_handle_req_queue(void) {
62     int rc;
63     struct hwrng_chan_ctx* ctx;
64     struct hwrng_chan_ctx* temp;
65 
66     /* for all pending requests */
67     bool more_requests;
68     do {
69         more_requests = false;
70         list_for_every_entry_safe(&hwrng_req_list, ctx, temp,
71                                   struct hwrng_chan_ctx, node) {
72             if (ctx->error || ctx->send_blocked)
73                 continue; /* can't service it right now */
74 
75             /*
76              * send up to MAX_HWRNG_MSG_SIZE per client at a time,
77              * to prevent a single client from starving all the others
78              */
79             size_t len = MIN(ctx->req_size, MAX_HWRNG_MSG_SIZE);
80             if (rng_data_avail_count) {
81                 /* use leftover data if there is any */
82                 len = MIN(len, rng_data_avail_count);
83             } else {
84                 /* get hwrng data */
85                 rand_get_bytes(rng_data, len);
86                 rng_data_avail_pos = 0;
87                 rng_data_avail_count = len;
88             }
89 
90             /* send reply */
91             rc = ktipc_send(ctx->chan, rng_data + rng_data_avail_pos, len);
92             if (rc < 0) {
93                 if (rc == ERR_NOT_ENOUGH_BUFFER) {
94                     /* mark it as send_blocked */
95                     ctx->send_blocked = true;
96                 } else {
97                     TRACEF("%s: failed (%d) to send_reply\n", __func__, rc);
98                     ctx->error = rc;
99                 }
100                 continue;
101             }
102 
103             rng_data_avail_pos += len;
104             rng_data_avail_count -= len;
105             ctx->req_size -= len;
106 
107             if (!ctx->req_size) {
108                 /* remove it from pending list */
109                 list_delete(&ctx->node);
110             } else {
111                 more_requests = true;
112             }
113         }
114     } while (more_requests);
115 }
116 
hwrng_handle_msg(const struct ktipc_port * port,struct handle * chan,void * ctx_v)117 static int hwrng_handle_msg(const struct ktipc_port* port,
118                             struct handle* chan,
119                             void* ctx_v) {
120     int rc;
121     struct hwrng_chan_ctx* ctx = ctx_v;
122     struct hwrng_req req;
123 
124     /* check for an error from a previous send attempt */
125     if (ctx->error) {
126         return ctx->error;
127     }
128 
129     /* read request */
130     rc = ktipc_recv(chan, sizeof(req), &req, sizeof(req));
131     if (rc < 0) {
132         TRACEF("%s: failed (%d) to receive msg for chan\n", __func__, rc);
133         return rc;
134     }
135 
136     /* check if we already have request in progress */
137     if (list_in_list(&ctx->node)) {
138         /* extend it */
139         ctx->req_size += req.len;
140     } else {
141         /* queue it */
142         ctx->req_size = req.len;
143         list_add_tail(&hwrng_req_list, &ctx->node);
144     }
145 
146     hwrng_handle_req_queue();
147 
148     return ctx->error;
149 }
150 
hwrng_handle_connect(const struct ktipc_port * port,struct handle * chan,const struct uuid * peer,void ** ctx_p)151 static int hwrng_handle_connect(const struct ktipc_port* port,
152                                 struct handle* chan,
153                                 const struct uuid* peer,
154                                 void** ctx_p) {
155     struct hwrng_chan_ctx* ctx = calloc(1, sizeof(*ctx));
156     if (!ctx) {
157         TRACEF("%s: failed to allocate context\n", __func__);
158         return ERR_NO_MEMORY;
159     }
160 
161     ctx->chan = chan;
162     *ctx_p = ctx;
163 
164     return NO_ERROR;
165 }
166 
hwrng_handle_channel_cleanup(void * ctx_v)167 static void hwrng_handle_channel_cleanup(void* ctx_v) {
168     struct hwrng_chan_ctx* ctx = ctx_v;
169 
170     if (list_in_list(&ctx->node)) {
171         list_delete(&ctx->node);
172     }
173 
174     free(ctx);
175 }
176 
hwrng_handle_send_unblocked(const struct ktipc_port * port,struct handle * chan,void * ctx_v)177 static int hwrng_handle_send_unblocked(const struct ktipc_port* port,
178                                        struct handle* chan,
179                                        void* ctx_v) {
180     struct hwrng_chan_ctx* ctx = ctx_v;
181 
182     if (ctx->error) {
183         return ctx->error;
184     }
185 
186     ctx->send_blocked = false;
187 
188     hwrng_handle_req_queue();
189 
190     return ctx->error;
191 }
192 
193 const static struct ktipc_srv_ops hwrng_srv_ops = {
194         .on_connect = hwrng_handle_connect,
195         .on_message = hwrng_handle_msg,
196         .on_channel_cleanup = hwrng_handle_channel_cleanup,
197         .on_send_unblocked = hwrng_handle_send_unblocked,
198 };
199 
200 const static struct ktipc_port_acl hwrng_srv_port_acl = {
201         .flags = IPC_PORT_ALLOW_TA_CONNECT,
202         .uuids = NULL,
203         .uuid_num = 0,
204         .extra_data = NULL,
205 };
206 
207 const static struct ktipc_port hwrng_srv_port = {
208         .name = HWRNG_SRV_NAME,
209         .uuid = &kernel_uuid,
210         .msg_max_size = MAX_HWRNG_MSG_SIZE,
211         .msg_queue_len = 1,
212         .acl = &hwrng_srv_port_acl,
213         .priv = NULL,
214 };
215 
216 static struct ktipc_server hwrng_ktipc_server =
217         KTIPC_SERVER_INITIAL_VALUE(hwrng_ktipc_server, "hwrng_ktipc_server");
218 
hwrng_ktipc_server_init(uint lvl)219 static void hwrng_ktipc_server_init(uint lvl) {
220     int rc;
221 
222     rc = ktipc_server_start(&hwrng_ktipc_server);
223     if (rc < 0) {
224         panic("Failed (%d) to start hwrng server\n", rc);
225     }
226 
227     rc = ktipc_server_add_port(&hwrng_ktipc_server, &hwrng_srv_port,
228                                &hwrng_srv_ops);
229     if (rc < 0) {
230         panic("Failed (%d) to create hwrng service port\n", rc);
231     }
232 }
233 
234 LK_INIT_HOOK(hwrng_ktipc_server_init,
235              hwrng_ktipc_server_init,
236              LK_INIT_LEVEL_APPS - 1)
237