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 0x%02x 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 0x%02x check status=0x%08x reply_len=%d protocol=%d flags=0x%04x",
231         ctx->app_id, status.status, status.reply_len, status.version,
232         status.flags);
233 
234   /* If it's already idle then we're ready to proceed */
235   if (status.status == APP_STATUS_IDLE) {
236     if (status.version != TRANSPORT_V0
237         && (status.flags & STATUS_FLAG_WORKING)) {
238       /* The app is still working when we don't expect it to be. We won't be
239        * able to clear the state so might need to force a reset to recover. */
240       NLOGE("App 0x%02x is still working", ctx->app_id);
241       return APP_ERROR_BUSY;
242     }
243     return APP_SUCCESS;
244   }
245 
246   /* Try clearing the status */
247   NLOGD("Clearing previous app %d status", ctx->app_id);
248   if (clear_status(ctx) != 0) {
249     NLOGE("Failed to force app %d to idle status", ctx->app_id);
250     return APP_ERROR_IO;
251   }
252 
253   /* Check again */
254   if (get_status(ctx, &status) != 0) {
255     NLOGE("Failed to get app %d's cleared status", ctx->app_id);
256     return APP_ERROR_IO;
257   }
258   NLOGD("Cleared app %d status=0x%08x reply_len=%d flags=0x%04x",
259         ctx->app_id, status.status, status.reply_len, status.flags);
260 
261   /* It's ignoring us and is still not ready, so it's broken */
262   if (status.status != APP_STATUS_IDLE) {
263     NLOGE("App 0x%02x is not responding", ctx->app_id);
264     return APP_ERROR_IO;
265   }
266 
267   return APP_SUCCESS;
268 }
269 
270 /*
271  * Split request into datagrams and send command to have app process it.
272  */
send_command(const struct transport_context * ctx)273 static uint32_t send_command(const struct transport_context *ctx) {
274   const uint8_t *args = ctx->args;
275   uint16_t arg_len = ctx->arg_len;
276   uint16_t crc;
277 
278   NLOGD("Send app %d command data (%d bytes)", ctx->app_id, arg_len);
279   uint32_t command = CMD_ID(ctx->app_id) | CMD_IS_DATA | CMD_TRANSPORT;
280   /* This always sends at least 1 packet to support the v0 protocol */
281   do {
282     /*
283      * We can't send more per datagram than the device can accept. For Citadel
284      * using the TPM Wait protocol on SPS, this is a constant. For other buses
285      * it may not be, but this is what we support here. Due to peculiarities of
286      * Citadel's SPS hardware, our protocol requires that we specify the length
287      * of what we're about to send in the params field of each Write.
288      */
289     const uint16_t ulen = MIN(arg_len, MAX_DEVICE_TRANSFER);
290     CMD_SET_PARAM(command, ulen);
291 
292     NLOGV("Write app %d command 0x%08x, bytes %d", ctx->app_id, command, ulen);
293     if (nos_device_write(ctx->dev, command, args, ulen) != 0) {
294       NLOGE("Failed to send datagram to app %d", ctx->app_id);
295       return APP_ERROR_IO;
296     }
297 
298     /* Any further Writes needed to send all the args must set the MORE bit */
299     command |= CMD_MORE_TO_COME;
300     if (args) args += ulen;
301     arg_len -= ulen;
302   } while (arg_len);
303 
304   /* Finally, send the "go" command */
305   command = CMD_ID(ctx->app_id) | CMD_PARAM(ctx->params);
306 
307   /*
308    * The outgoing crc covers:
309    *
310    *   1. the (16-bit) length of args
311    *   2. the args buffer (if any)
312    *   3. the (32-bit) "go" command
313    *   4. the command info with crc set to 0
314    */
315   struct transport_command_info command_info = {
316     .length = sizeof(command_info),
317     .version = htole16(TRANSPORT_V1),
318     .crc = 0,
319     .reply_len_hint = ctx->reply_len ? htole16(*ctx->reply_len) : 0,
320   };
321   arg_len = ctx->arg_len;
322   crc = crc16(&arg_len, sizeof(arg_len));
323   crc = crc16_update(ctx->args, ctx->arg_len, crc);
324   crc = crc16_update(&command, sizeof(command), crc);
325   crc = crc16_update(&command_info, sizeof(command_info), crc);
326   command_info.crc = htole16(crc);
327 
328   /* Tell the app to handle the request while also sending the command_info
329    * which will be ignored by the v0 protocol. */
330   NLOGD("Send app %d go command 0x%08x", ctx->app_id, command);
331   if (0 != nos_device_write(ctx->dev, command, &command_info, sizeof(command_info))) {
332     NLOGE("Failed to send command datagram to app %d", ctx->app_id);
333     return APP_ERROR_IO;
334   }
335 
336   return APP_SUCCESS;
337 }
338 
timespec_before(const struct timespec * lhs,const struct timespec * rhs)339 static bool timespec_before(const struct timespec *lhs, const struct timespec *rhs) {
340   if (lhs->tv_sec == rhs->tv_sec) {
341     return lhs->tv_nsec < rhs->tv_nsec;
342   } else {
343     return lhs->tv_sec < rhs->tv_sec;
344   }
345 }
346 
347 /*
348  * Keep polling until the app says it is done.
349  */
poll_until_done(const struct transport_context * ctx,struct transport_status * status)350 static uint32_t poll_until_done(const struct transport_context *ctx,
351                                 struct transport_status *status) {
352   uint32_t poll_count = 0;
353 
354   /* Start the timer */
355   struct timespec now;
356   struct timespec abort_at;
357   if (clock_gettime(CLOCK_MONOTONIC, &now) != 0) {
358     NLOGE("clock_gettime() failing: %s", strerror(errno));
359     return APP_ERROR_IO;
360   }
361   abort_at.tv_sec = now.tv_sec + POLL_LIMIT_SECONDS;
362   abort_at.tv_nsec = now.tv_nsec;
363 
364   NLOGD("Polling app %d", ctx->app_id);
365   do {
366     /* Poll the status */
367     if (get_status(ctx, status) != 0) {
368       return APP_ERROR_IO;
369     }
370     poll_count++;
371     /* Log at higher priority every 16 polls */
372     if ((poll_count & (16 - 1)) == 0) {
373       NLOGD("App 0x%02x poll=%d status=0x%08x reply_len=%d flags=0x%04x",
374             ctx->app_id, poll_count, status->status, status->reply_len,
375             status->flags);
376     } else {
377       NLOGV("App 0x%02x poll=%d status=0x%08x reply_len=%d flags=0x%04x",
378             ctx->app_id, poll_count, status->status, status->reply_len,
379             status->flags);
380     }
381 
382     /* Check whether the app is done */
383     if (status->status & APP_STATUS_DONE) {
384       NLOGD("App 0x%02x polled=%d status=0x%08x reply_len=%d flags=0x%04x",
385             ctx->app_id, poll_count, status->status, status->reply_len,
386             status->flags);
387       return APP_STATUS_CODE(status->status);
388     }
389 
390     /* Check that the app is still working on it */
391     if (status->version != TRANSPORT_V0
392         && !(status->flags & STATUS_FLAG_WORKING)) {
393       /* The slave has stopped working without being done so it's misbehaving */
394       NLOGE("App 0x%02x just stopped working", ctx->app_id);
395       return APP_ERROR_INTERNAL;
396     }
397     if (clock_gettime(CLOCK_MONOTONIC, &now) != 0) {
398       NLOGE("clock_gettime() failing: %s", strerror(errno));
399       return APP_ERROR_IO;
400     }
401   } while (timespec_before(&now, &abort_at));
402 
403   NLOGE("App 0x%02x not done after polling %d times in %d seconds", ctx->app_id,
404         poll_count, POLL_LIMIT_SECONDS);
405   return APP_ERROR_TIMEOUT;
406 }
407 
408 /*
409  * Reconstruct the reply data from datagram stream.
410  */
receive_reply(const struct transport_context * ctx,const struct transport_status * status)411 static uint32_t receive_reply(const struct transport_context *ctx,
412                               const struct transport_status *status) {
413   int retries = CRC_RETRY_COUNT;
414   while (retries--) {
415     NLOGD("Read app %d reply data (%d bytes)", ctx->app_id, status->reply_len);
416 
417     uint32_t command = CMD_ID(ctx->app_id) | CMD_IS_READ | CMD_TRANSPORT | CMD_IS_DATA;
418     uint8_t *reply = ctx->reply;
419     uint16_t left = MIN(*ctx->reply_len, status->reply_len);
420     uint16_t got = 0;
421     uint16_t crc = 0;
422     while (left) {
423       /* We can't read more per datagram than the device can send */
424       const uint16_t gimme = MIN(left, MAX_DEVICE_TRANSFER);
425       NLOGV("Read app %d command=0x%08x, bytes=%d", ctx->app_id, command, gimme);
426       if (nos_device_read(ctx->dev, command, reply, gimme) != 0) {
427         NLOGE("Failed to receive datagram from app %d", ctx->app_id);
428         return APP_ERROR_IO;
429       }
430 
431       /* Any further Reads should set the MORE bit. This only works if Nugget
432        * OS sends back CRCs, but that's the only time we'd retry anyway. */
433       command |= CMD_MORE_TO_COME;
434 
435       crc = crc16_update(reply, gimme, crc);
436       reply += gimme;
437       left -= gimme;
438       got += gimme;
439     }
440     /* got it all */
441     *ctx->reply_len = got;
442 
443     /* v0 protocol doesn't support CRC so hopefully it's ok */
444     if (status->version == TRANSPORT_V0) return APP_SUCCESS;
445 
446     if (crc == status->reply_crc) return APP_SUCCESS;
447     NLOGW("App 0x%02x reply CRC mismatch: theirs=%04x ours=%04x", ctx->app_id,
448           status->reply_crc, crc);
449   }
450 
451   NLOGE("Unable to get valid checksum on app %d reply data", ctx->app_id);
452   return APP_ERROR_IO;
453 }
454 
455 /*
456  * Driver for the master of the transport protocol.
457  */
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)458 uint32_t nos_call_application(const struct nos_device *dev,
459                               uint8_t app_id, uint16_t params,
460                               const uint8_t *args, uint32_t arg_len,
461                               uint8_t *reply, uint32_t *reply_len)
462 {
463   uint32_t res;
464   uint32_t status_code;
465   const struct transport_context ctx = {
466     .dev = dev,
467     .app_id = app_id,
468     .params = params,
469     .args = args,
470     .arg_len = arg_len,
471     .reply = reply,
472     .reply_len = reply_len,
473   };
474 
475   if ((ctx.arg_len && !ctx.args) ||
476       (ctx.reply_len && *ctx.reply_len && !ctx.reply)) {
477     NLOGE("Invalid args to %s()", __func__);
478     return APP_ERROR_IO;
479   }
480 
481 #ifdef ANDROID
482   if (!dev) {
483     NLOGE("Invalid args to %s()", __func__);
484     return APP_ERROR_IO;
485   }
486 
487   // Call GSA nos_call IOCTL interface if needed
488   if (dev->use_one_pass_call) {
489     int err = dev->ops.one_pass_call(dev->ctx, app_id, params, args, arg_len,
490                                      reply, reply_len, &status_code);
491     if (err < 0) {
492       NLOGE("one_pass_call failed: %s", strerror(-err));
493       status_code = APP_ERROR_IO;
494     }
495 
496     return status_code;
497   }
498 #endif
499 
500   NLOGD("Calling App 0x%02x with params 0x%04x", app_id, params);
501 
502   struct transport_status status;
503   int retries = CRC_RETRY_COUNT;
504   while (retries--) {
505     /* Wake up and wait for Citadel to be ready */
506     res = make_ready(&ctx);
507     if (res) return res;
508 
509     /* Tell the app what to do */
510     res = send_command(&ctx);
511     if (res) return res;
512 
513     /* Wait until the app has finished */
514     status_code = poll_until_done(&ctx, &status);
515 
516     /* Citadel chip complained we sent it a count different from what we claimed
517      * or more than it can accept but this should not happen. Give to the chip a
518      * little bit of time and retry calling again. */
519     if (status_code == APP_ERROR_TOO_MUCH) {
520       NLOGD("App 0x%02x returning 0x%x, give a retry(%d/%d)", app_id,
521             status_code, retries, CRC_RETRY_COUNT);
522       usleep(RETRY_WAIT_TIME_US);
523       continue;
524     }
525     if (status_code != APP_ERROR_CHECKSUM) break;
526     NLOGW("App 0x%02x request checksum error", app_id);
527   }
528   if (status_code == APP_ERROR_CHECKSUM) {
529     NLOGE("App 0x%02x request checksum failed too many times", app_id);
530     status_code = APP_ERROR_IO;
531   }
532 
533   /* Get the reply, but only if the app produced data and the caller wants it */
534   if (ctx.reply && ctx.reply_len && *ctx.reply_len && status.reply_len) {
535     res = receive_reply(&ctx, &status);
536     if (res) return res;
537   } else if (reply_len) {
538     *reply_len = 0;
539   }
540 
541   NLOGV("Clear app %d reply for the next caller", app_id);
542   /* This should work, but isn't completely fatal if it doesn't because the
543    * next call will try again. */
544   (void)clear_status(&ctx);
545 
546   NLOGD("App 0x%02x returning 0x%x", app_id, status_code);
547   return status_code;
548 }
549