1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <nos/transport.h>
18
19 #include <errno.h>
20 #include <stdarg.h>
21 #include <stdbool.h>
22 #include <stddef.h>
23 #include <stdint.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <time.h>
27 #include <unistd.h>
28
29 #include <application.h>
30
31 #include "crc16.h"
32
33 /* Note: evaluates expressions multiple times */
34 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
35
36 #define DEBUG_LOG 0
37 #define VERBOSE_LOG 0
38
39 #ifdef ANDROID
40 /* Logging for Android */
41 #define LOG_TAG "libnos_transport"
42 #include <android-base/endian.h>
43 #include <log/log.h>
44 #include <sys/types.h>
45
46 #define NLOGE(...) ALOGE(__VA_ARGS__)
47 #define NLOGW(...) ALOGW(__VA_ARGS__)
48 #define NLOGD(...) ALOGD(__VA_ARGS__)
49 #define NLOGV(...) ALOGV(__VA_ARGS__)
50
51 extern int usleep (uint32_t usec);
52
53 #else
54 /* Logging for other platforms */
55 #include <stdio.h>
56
57 #define NLOGE(...) do { fprintf(stderr, __VA_ARGS__); \
58 fprintf(stderr, "\n"); } while (0)
59 #define NLOGW(...) do { printf(__VA_ARGS__); \
60 printf("\n"); } while (0)
61 #define NLOGD(...) do { if (DEBUG_LOG) { \
62 printf(__VA_ARGS__); printf("\n"); } } while (0)
63 #define NLOGV(...) do { if (VERBOSE_LOG) { \
64 printf(__VA_ARGS__); printf("\n"); } } while (0)
65
66 #endif
67
68 /*
69 * If Citadel is rebooting it will take a while to become responsive again. We
70 * expect a reboot to take around 100ms but we'll keep trying for 300ms to leave
71 * plenty of margin.
72 */
73 #define RETRY_COUNT 240
74 #define RETRY_WAIT_TIME_US 5000
75
76 /* In case of CRC error, try to retransmit */
77 #define CRC_RETRY_COUNT 5
78
79 /* How long to poll before giving up */
80 #define POLL_LIMIT_SECONDS 60
81
82 struct transport_context {
83 const struct nos_device *dev;
84 uint8_t app_id;
85 uint16_t params;
86 const uint8_t *args;
87 uint32_t arg_len;
88 uint8_t *reply;
89 uint32_t *reply_len;
90 };
91
92 /*
93 * Read a datagram from the device, correctly handling retries.
94 */
nos_device_read(const struct nos_device * dev,uint32_t command,void * buf,uint32_t len)95 static int nos_device_read(const struct nos_device *dev, uint32_t command,
96 void *buf, uint32_t len) {
97 int retries = RETRY_COUNT;
98 while (retries--) {
99 int err = dev->ops.read(dev->ctx, command, buf, len);
100
101 if (err == -EAGAIN) {
102 /* Linux driver returns EAGAIN error if Citadel chip is asleep.
103 * Give to the chip a little bit of time to awake and retry reading
104 * status again. */
105 usleep(RETRY_WAIT_TIME_US);
106 continue;
107 }
108
109 if (err) {
110 NLOGE("Failed to read: %s", strerror(-err));
111 }
112 return -err;
113 }
114
115 return ETIMEDOUT;
116 }
117
118 /*
119 * Write a datagram to the device, correctly handling retries.
120 */
nos_device_write(const struct nos_device * dev,uint32_t command,const void * buf,uint32_t len)121 static int nos_device_write(const struct nos_device *dev, uint32_t command,
122 const void *buf, uint32_t len) {
123 int retries = RETRY_COUNT;
124 while (retries--) {
125 int err = dev->ops.write(dev->ctx, command, buf, len);
126
127 if (err == -EAGAIN) {
128 /* Linux driver returns EAGAIN error if Citadel chip is asleep.
129 * Give to the chip a little bit of time to awake and retry reading
130 * status again. */
131 usleep(RETRY_WAIT_TIME_US);
132 continue;
133 }
134
135 if (err) {
136 NLOGE("Failed to write: %s", strerror(-err));
137 }
138 return -err;
139 }
140
141 return ETIMEDOUT;
142 }
143
144 /*
145 * Get the status regardless of protocol version. All fields not passed by the
146 * slave are set to 0 so the caller must check the version before interpretting
147 * them.
148 *
149 * Returns non-zero on error.
150 */
get_status(const struct transport_context * ctx,struct transport_status * out)151 static int get_status(const struct transport_context *ctx,
152 struct transport_status *out) {
153 union {
154 struct transport_status status;
155 uint8_t data[STATUS_MAX_LENGTH];
156 } st;
157 int retries = CRC_RETRY_COUNT;
158
159 /* All unset fields will be 0. */
160 memset(out, 0, sizeof(*out));
161
162 while (retries--) {
163 /* Get the status from the device */
164 const uint32_t command = CMD_ID(ctx->app_id) | CMD_IS_READ | CMD_TRANSPORT;
165 if (nos_device_read(ctx->dev, command, &st, STATUS_MAX_LENGTH) != 0) {
166 NLOGE("Failed to read app %d status", ctx->app_id);
167 return -1;
168 }
169
170 /* Examine v0 fields */
171 out->status = le32toh(st.status.status);
172 out->reply_len = le16toh(st.status.reply_len);
173
174 /* Identify v0 as length will be an invalid value */
175 const uint16_t length = le16toh(st.status.length);
176 if (length < STATUS_MIN_LENGTH || length > STATUS_MAX_LENGTH) {
177 out->version = TRANSPORT_V0;
178 return 0;
179 }
180
181 /* Examine v1 fields */
182 out->length = length;
183 out->version = le16toh(st.status.version);
184 out->flags = le16toh(st.status.flags);
185 out->crc = le16toh(st.status.crc);
186 out->reply_crc = le16toh(st.status.reply_crc);
187
188 /* Calculate the CRC of the status message */
189 st.status.crc = 0;
190 const uint16_t our_crc = crc16(&st.status, length);
191
192 /* Check the CRC, if it fails we will retry */
193 if (out->crc != our_crc) {
194 NLOGW("App %d status CRC mismatch: theirs=%04x ours=%04x",
195 ctx->app_id, out->crc, our_crc);
196 continue;
197 }
198
199 /* Identify and examine v2+ fields here */
200
201 return 0;
202 }
203
204 NLOGE("Unable to get valid checksum on app %d status", ctx->app_id);
205 return -1;
206 }
207
208 /*
209 * Try and reset the protocol state on Citadel for a new transaction.
210 */
clear_status(const struct transport_context * ctx)211 static int clear_status(const struct transport_context *ctx) {
212 const uint32_t command = CMD_ID(ctx->app_id) | CMD_TRANSPORT;
213 if (nos_device_write(ctx->dev, command, NULL, 0) != 0) {
214 NLOGE("Failed to clear app %d status", ctx->app_id);
215 return -1;
216 }
217 return 0;
218 }
219
220 /*
221 * Ensure that the app is in an idle state ready to handle the transaction.
222 */
make_ready(const struct transport_context * ctx)223 static uint32_t make_ready(const struct transport_context *ctx) {
224 struct transport_status status;
225
226 if (get_status(ctx, &status) != 0) {
227 NLOGE("Failed to inspect app %d", ctx->app_id);
228 return APP_ERROR_IO;
229 }
230 NLOGD("App %d inspection status=0x%08x reply_len=%d protocol=%d flags=0x%04x",
231 ctx->app_id, status.status, status.reply_len, status.version, status.flags);
232
233 /* If it's already idle then we're ready to proceed */
234 if (status.status == APP_STATUS_IDLE) {
235 if (status.version != TRANSPORT_V0
236 && (status.flags & STATUS_FLAG_WORKING)) {
237 /* The app is still working when we don't expect it to be. We won't be
238 * able to clear the state so might need to force a reset to recover. */
239 NLOGE("App %d is still working", ctx->app_id);
240 return APP_ERROR_BUSY;
241 }
242 return APP_SUCCESS;
243 }
244
245 /* Try clearing the status */
246 NLOGD("Clearing previous app %d status", ctx->app_id);
247 if (clear_status(ctx) != 0) {
248 NLOGE("Failed to force app %d to idle status", ctx->app_id);
249 return APP_ERROR_IO;
250 }
251
252 /* Check again */
253 if (get_status(ctx, &status) != 0) {
254 NLOGE("Failed to get app %d's cleared status", ctx->app_id);
255 return APP_ERROR_IO;
256 }
257 NLOGD("Cleared app %d status=0x%08x reply_len=%d flags=0x%04x",
258 ctx->app_id, status.status, status.reply_len, status.flags);
259
260 /* It's ignoring us and is still not ready, so it's broken */
261 if (status.status != APP_STATUS_IDLE) {
262 NLOGE("App %d is not responding", ctx->app_id);
263 return APP_ERROR_IO;
264 }
265
266 return APP_SUCCESS;
267 }
268
269 /*
270 * Split request into datagrams and send command to have app process it.
271 */
send_command(const struct transport_context * ctx)272 static uint32_t send_command(const struct transport_context *ctx) {
273 const uint8_t *args = ctx->args;
274 uint16_t arg_len = ctx->arg_len;
275 uint16_t crc;
276
277 NLOGD("Send app %d command data (%d bytes)", ctx->app_id, arg_len);
278 uint32_t command = CMD_ID(ctx->app_id) | CMD_IS_DATA | CMD_TRANSPORT;
279 /* This always sends at least 1 packet to support the v0 protocol */
280 do {
281 /*
282 * We can't send more per datagram than the device can accept. For Citadel
283 * using the TPM Wait protocol on SPS, this is a constant. For other buses
284 * it may not be, but this is what we support here. Due to peculiarities of
285 * Citadel's SPS hardware, our protocol requires that we specify the length
286 * of what we're about to send in the params field of each Write.
287 */
288 const uint16_t ulen = MIN(arg_len, MAX_DEVICE_TRANSFER);
289 CMD_SET_PARAM(command, ulen);
290
291 NLOGV("Write app %d command 0x%08x, bytes %d", ctx->app_id, command, ulen);
292 if (nos_device_write(ctx->dev, command, args, ulen) != 0) {
293 NLOGE("Failed to send datagram to app %d", ctx->app_id);
294 return APP_ERROR_IO;
295 }
296
297 /* Any further Writes needed to send all the args must set the MORE bit */
298 command |= CMD_MORE_TO_COME;
299 if (args) args += ulen;
300 arg_len -= ulen;
301 } while (arg_len);
302
303 /* Finally, send the "go" command */
304 command = CMD_ID(ctx->app_id) | CMD_PARAM(ctx->params);
305
306 /*
307 * The outgoing crc covers:
308 *
309 * 1. the (16-bit) length of args
310 * 2. the args buffer (if any)
311 * 3. the (32-bit) "go" command
312 * 4. the command info with crc set to 0
313 */
314 struct transport_command_info command_info = {
315 .length = sizeof(command_info),
316 .version = htole16(TRANSPORT_V1),
317 .crc = 0,
318 .reply_len_hint = ctx->reply_len ? htole16(*ctx->reply_len) : 0,
319 };
320 arg_len = ctx->arg_len;
321 crc = crc16(&arg_len, sizeof(arg_len));
322 crc = crc16_update(ctx->args, ctx->arg_len, crc);
323 crc = crc16_update(&command, sizeof(command), crc);
324 crc = crc16_update(&command_info, sizeof(command_info), crc);
325 command_info.crc = htole16(crc);
326
327 /* Tell the app to handle the request while also sending the command_info
328 * which will be ignored by the v0 protocol. */
329 NLOGD("Send app %d go command 0x%08x", ctx->app_id, command);
330 if (0 != nos_device_write(ctx->dev, command, &command_info, sizeof(command_info))) {
331 NLOGE("Failed to send command datagram to app %d", ctx->app_id);
332 return APP_ERROR_IO;
333 }
334
335 return APP_SUCCESS;
336 }
337
timespec_before(const struct timespec * lhs,const struct timespec * rhs)338 static bool timespec_before(const struct timespec *lhs, const struct timespec *rhs) {
339 if (lhs->tv_sec == rhs->tv_sec) {
340 return lhs->tv_nsec < rhs->tv_nsec;
341 } else {
342 return lhs->tv_sec < rhs->tv_sec;
343 }
344 }
345
346 /*
347 * Keep polling until the app says it is done.
348 */
poll_until_done(const struct transport_context * ctx,struct transport_status * status)349 static uint32_t poll_until_done(const struct transport_context *ctx,
350 struct transport_status *status) {
351 uint32_t poll_count = 0;
352
353 /* Start the timer */
354 struct timespec now;
355 struct timespec abort_at;
356 if (clock_gettime(CLOCK_MONOTONIC, &now) != 0) {
357 NLOGE("clock_gettime() failing: %s", strerror(errno));
358 return APP_ERROR_IO;
359 }
360 abort_at.tv_sec = now.tv_sec + POLL_LIMIT_SECONDS;
361 abort_at.tv_nsec = now.tv_nsec;
362
363 NLOGD("Polling app %d", ctx->app_id);
364 do {
365 /* Poll the status */
366 if (get_status(ctx, status) != 0) {
367 return APP_ERROR_IO;
368 }
369 poll_count++;
370 /* Log at higher priority every 16 polls */
371 if ((poll_count & (16 - 1)) == 0) {
372 NLOGD("App %d poll=%d status=0x%08x reply_len=%d flags=0x%04x",
373 ctx->app_id, poll_count, status->status, status->reply_len, status->flags);
374 } else {
375 NLOGV("App %d poll=%d status=0x%08x reply_len=%d flags=0x%04x",
376 ctx->app_id, poll_count, status->status, status->reply_len, status->flags);
377 }
378
379 /* Check whether the app is done */
380 if (status->status & APP_STATUS_DONE) {
381 NLOGD("App %d polled=%d status=0x%08x reply_len=%d flags=0x%04x",
382 ctx->app_id, poll_count, status->status, status->reply_len, status->flags);
383 return APP_STATUS_CODE(status->status);
384 }
385
386 /* Check that the app is still working on it */
387 if (status->version != TRANSPORT_V0
388 && !(status->flags & STATUS_FLAG_WORKING)) {
389 /* The slave has stopped working without being done so it's misbehaving */
390 NLOGE("App %d just stopped working", ctx->app_id);
391 return APP_ERROR_INTERNAL;
392 }
393 if (clock_gettime(CLOCK_MONOTONIC, &now) != 0) {
394 NLOGE("clock_gettime() failing: %s", strerror(errno));
395 return APP_ERROR_IO;
396 }
397 } while (timespec_before(&now, &abort_at));
398
399 NLOGE("App %d not done after polling %d times in %d seconds",
400 ctx->app_id, poll_count, POLL_LIMIT_SECONDS);
401 return APP_ERROR_TIMEOUT;
402 }
403
404 /*
405 * Reconstruct the reply data from datagram stream.
406 */
receive_reply(const struct transport_context * ctx,const struct transport_status * status)407 static uint32_t receive_reply(const struct transport_context *ctx,
408 const struct transport_status *status) {
409 int retries = CRC_RETRY_COUNT;
410 while (retries--) {
411 NLOGD("Read app %d reply data (%d bytes)", ctx->app_id, status->reply_len);
412
413 uint32_t command = CMD_ID(ctx->app_id) | CMD_IS_READ | CMD_TRANSPORT | CMD_IS_DATA;
414 uint8_t *reply = ctx->reply;
415 uint16_t left = MIN(*ctx->reply_len, status->reply_len);
416 uint16_t got = 0;
417 uint16_t crc = 0;
418 while (left) {
419 /* We can't read more per datagram than the device can send */
420 const uint16_t gimme = MIN(left, MAX_DEVICE_TRANSFER);
421 NLOGV("Read app %d command=0x%08x, bytes=%d", ctx->app_id, command, gimme);
422 if (nos_device_read(ctx->dev, command, reply, gimme) != 0) {
423 NLOGE("Failed to receive datagram from app %d", ctx->app_id);
424 return APP_ERROR_IO;
425 }
426
427 /* Any further Reads should set the MORE bit. This only works if Nugget
428 * OS sends back CRCs, but that's the only time we'd retry anyway. */
429 command |= CMD_MORE_TO_COME;
430
431 crc = crc16_update(reply, gimme, crc);
432 reply += gimme;
433 left -= gimme;
434 got += gimme;
435 }
436 /* got it all */
437 *ctx->reply_len = got;
438
439 /* v0 protocol doesn't support CRC so hopefully it's ok */
440 if (status->version == TRANSPORT_V0) return APP_SUCCESS;
441
442 if (crc == status->reply_crc) return APP_SUCCESS;
443 NLOGW("App %d reply CRC mismatch: theirs=%04x ours=%04x", ctx->app_id, status->reply_crc, crc);
444 }
445
446 NLOGE("Unable to get valid checksum on app %d reply data", ctx->app_id);
447 return APP_ERROR_IO;
448 }
449
450 /*
451 * Driver for the master of the transport protocol.
452 */
nos_call_application(const struct nos_device * dev,uint8_t app_id,uint16_t params,const uint8_t * args,uint32_t arg_len,uint8_t * reply,uint32_t * reply_len)453 uint32_t nos_call_application(const struct nos_device *dev,
454 uint8_t app_id, uint16_t params,
455 const uint8_t *args, uint32_t arg_len,
456 uint8_t *reply, uint32_t *reply_len)
457 {
458 uint32_t res;
459 const struct transport_context ctx = {
460 .dev = dev,
461 .app_id = app_id,
462 .params = params,
463 .args = args,
464 .arg_len = arg_len,
465 .reply = reply,
466 .reply_len = reply_len,
467 };
468
469 if ((ctx.arg_len && !ctx.args) ||
470 (ctx.reply_len && *ctx.reply_len && !ctx.reply)) {
471 NLOGE("Invalid args to %s()", __func__);
472 return APP_ERROR_IO;
473 }
474
475 NLOGD("Calling App %d with params 0x%04x", app_id, params);
476
477 struct transport_status status;
478 uint32_t status_code;
479 int retries = CRC_RETRY_COUNT;
480 while (retries--) {
481 /* Wake up and wait for Citadel to be ready */
482 res = make_ready(&ctx);
483 if (res) return res;
484
485 /* Tell the app what to do */
486 res = send_command(&ctx);
487 if (res) return res;
488
489 /* Wait until the app has finished */
490 status_code = poll_until_done(&ctx, &status);
491
492 /* Citadel chip complained we sent it a count different from what we claimed
493 * or more than it can accept but this should not happen. Give to the chip a
494 * little bit of time and retry calling again. */
495 if (status_code == APP_ERROR_TOO_MUCH) {
496 NLOGD("App %d returning 0x%x, give a retry(%d/%d)",
497 app_id, status_code, retries, CRC_RETRY_COUNT);
498 usleep(RETRY_WAIT_TIME_US);
499 continue;
500 }
501 if (status_code != APP_ERROR_CHECKSUM) break;
502 NLOGW("App %d request checksum error", app_id);
503 }
504 if (status_code == APP_ERROR_CHECKSUM) {
505 NLOGE("App %d request checksum failed too many times", app_id);
506 status_code = APP_ERROR_IO;
507 }
508
509 /* Get the reply, but only if the app produced data and the caller wants it */
510 if (ctx.reply && ctx.reply_len && *ctx.reply_len && status.reply_len) {
511 res = receive_reply(&ctx, &status);
512 if (res) return res;
513 } else if (reply_len) {
514 *reply_len = 0;
515 }
516
517 NLOGV("Clear app %d reply for the next caller", app_id);
518 /* This should work, but isn't completely fatal if it doesn't because the
519 * next call will try again. */
520 (void)clear_status(&ctx);
521
522 NLOGD("App %d returning 0x%x", app_id, status_code);
523 return status_code;
524 }
525