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 60 74 #define RETRY_WAIT_TIME_US 5000 75 76 /* In case of CRC error, try to retransmit */ 77 #define CRC_RETRY_COUNT 3 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 */ 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 */ 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 */ 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 while (retries--) { 159 /* Get the status from the device */ 160 const uint32_t command = CMD_ID(ctx->app_id) | CMD_IS_READ | CMD_TRANSPORT; 161 if (nos_device_read(ctx->dev, command, &st, STATUS_MAX_LENGTH) != 0) { 162 NLOGE("Failed to read app %d status", ctx->app_id); 163 return -1; 164 } 165 166 /* All unset fields will be 0. */ 167 memset(out, 0, sizeof(*out)); 168 169 /* Examine v0 fields */ 170 out->status = le32toh(st.status.status); 171 out->reply_len = le16toh(st.status.reply_len); 172 173 /* Identify v0 as length will be an invalid value */ 174 const uint16_t length = le16toh(st.status.length); 175 if (length < STATUS_MIN_LENGTH || length > STATUS_MAX_LENGTH) { 176 out->version = TRANSPORT_V0; 177 return 0; 178 } 179 180 /* Examine v1 fields */ 181 out->length = length; 182 out->version = le16toh(st.status.version); 183 out->flags = le16toh(st.status.flags); 184 out->crc = le16toh(st.status.crc); 185 out->reply_crc = le16toh(st.status.reply_crc); 186 187 /* Calculate the CRC of the status message */ 188 st.status.crc = 0; 189 const uint16_t our_crc = crc16(&st.status, length); 190 191 /* Check the CRC, if it fails we will retry */ 192 if (out->crc != our_crc) { 193 NLOGW("App %d status CRC mismatch: theirs=%04x ours=%04x", 194 ctx->app_id, out->crc, our_crc); 195 continue; 196 } 197 198 /* Identify and examine v2+ fields here */ 199 200 return 0; 201 } 202 203 NLOGE("Unable to get valid checksum on app %d status", ctx->app_id); 204 return -1; 205 } 206 207 /* 208 * Try and reset the protocol state on Citadel for a new transaction. 209 */ 210 static int clear_status(const struct transport_context *ctx) { 211 const uint32_t command = CMD_ID(ctx->app_id) | CMD_TRANSPORT; 212 if (nos_device_write(ctx->dev, command, NULL, 0) != 0) { 213 NLOGE("Failed to clear app %d status", ctx->app_id); 214 return -1; 215 } 216 return 0; 217 } 218 219 /* 220 * Ensure that the app is in an idle state ready to handle the transaction. 221 */ 222 static uint32_t make_ready(const struct transport_context *ctx) { 223 struct transport_status status; 224 225 if (get_status(ctx, &status) != 0) { 226 NLOGE("Failed to inspect app %d", ctx->app_id); 227 return APP_ERROR_IO; 228 } 229 NLOGD("App %d inspection status=0x%08x reply_len=%d protocol=%d flags=0x%04x", 230 ctx->app_id, status.status, status.reply_len, status.version, status.flags); 231 232 /* If it's already idle then we're ready to proceed */ 233 if (status.status == APP_STATUS_IDLE) { 234 if (status.version != TRANSPORT_V0 235 && (status.flags & STATUS_FLAG_WORKING)) { 236 /* The app is still working when we don't expect it to be. We won't be 237 * able to clear the state so might need to force a reset to recover. */ 238 NLOGE("App %d is still working", ctx->app_id); 239 return APP_ERROR_BUSY; 240 } 241 return APP_SUCCESS; 242 } 243 244 /* Try clearing the status */ 245 NLOGD("Clearing previous app %d status", ctx->app_id); 246 if (clear_status(ctx) != 0) { 247 NLOGE("Failed to force app %d to idle status", ctx->app_id); 248 return APP_ERROR_IO; 249 } 250 251 /* Check again */ 252 if (get_status(ctx, &status) != 0) { 253 NLOGE("Failed to get app %d's cleared status", ctx->app_id); 254 return APP_ERROR_IO; 255 } 256 NLOGD("Cleared app %d status=0x%08x reply_len=%d flags=0x%04x", 257 ctx->app_id, status.status, status.reply_len, status.flags); 258 259 /* It's ignoring us and is still not ready, so it's broken */ 260 if (status.status != APP_STATUS_IDLE) { 261 NLOGE("App %d is not responding", ctx->app_id); 262 return APP_ERROR_IO; 263 } 264 265 return APP_SUCCESS; 266 } 267 268 /* 269 * Split request into datagrams and send command to have app process it. 270 */ 271 static uint32_t send_command(const struct transport_context *ctx) { 272 const uint8_t *args = ctx->args; 273 uint16_t arg_len = ctx->arg_len; 274 uint16_t crc; 275 276 NLOGD("Send app %d command data (%d bytes)", ctx->app_id, arg_len); 277 uint32_t command = CMD_ID(ctx->app_id) | CMD_IS_DATA | CMD_TRANSPORT; 278 /* This always sends at least 1 packet to support the v0 protocol */ 279 do { 280 /* 281 * We can't send more per datagram than the device can accept. For Citadel 282 * using the TPM Wait protocol on SPS, this is a constant. For other buses 283 * it may not be, but this is what we support here. Due to peculiarities of 284 * Citadel's SPS hardware, our protocol requires that we specify the length 285 * of what we're about to send in the params field of each Write. 286 */ 287 const uint16_t ulen = MIN(arg_len, MAX_DEVICE_TRANSFER); 288 CMD_SET_PARAM(command, ulen); 289 290 NLOGV("Write app %d command 0x%08x, bytes %d", ctx->app_id, command, ulen); 291 if (nos_device_write(ctx->dev, command, args, ulen) != 0) { 292 NLOGE("Failed to send datagram to app %d", ctx->app_id); 293 return APP_ERROR_IO; 294 } 295 296 /* Any further Writes needed to send all the args must set the MORE bit */ 297 command |= CMD_MORE_TO_COME; 298 args += ulen; 299 arg_len -= ulen; 300 } while (arg_len); 301 302 /* Finally, send the "go" command */ 303 command = CMD_ID(ctx->app_id) | CMD_PARAM(ctx->params); 304 305 /* 306 * The outgoing crc covers: 307 * 308 * 1. the (16-bit) length of args 309 * 2. the args buffer (if any) 310 * 3. the (32-bit) "go" command 311 * 4. the command info with crc set to 0 312 */ 313 struct transport_command_info command_info = { 314 .length = sizeof(command_info), 315 .version = htole16(TRANSPORT_V1), 316 .crc = 0, 317 .reply_len_hint = ctx->reply_len ? htole16(*ctx->reply_len) : 0, 318 }; 319 arg_len = ctx->arg_len; 320 crc = crc16(&arg_len, sizeof(arg_len)); 321 crc = crc16_update(ctx->args, ctx->arg_len, crc); 322 crc = crc16_update(&command, sizeof(command), crc); 323 crc = crc16_update(&command_info, sizeof(command_info), crc); 324 command_info.crc = htole16(crc); 325 326 /* Tell the app to handle the request while also sending the command_info 327 * which will be ignored by the v0 protocol. */ 328 NLOGD("Send app %d go command 0x%08x", ctx->app_id, command); 329 if (0 != nos_device_write(ctx->dev, command, &command_info, sizeof(command_info))) { 330 NLOGE("Failed to send command datagram to app %d", ctx->app_id); 331 return APP_ERROR_IO; 332 } 333 334 return APP_SUCCESS; 335 } 336 337 static bool timespec_before(const struct timespec *lhs, const struct timespec *rhs) { 338 if (lhs->tv_sec == rhs->tv_sec) { 339 return lhs->tv_nsec < rhs->tv_nsec; 340 } else { 341 return lhs->tv_sec < rhs->tv_sec; 342 } 343 } 344 345 /* 346 * Keep polling until the app says it is done. 347 */ 348 static uint32_t poll_until_done(const struct transport_context *ctx, 349 struct transport_status *status) { 350 uint32_t poll_count = 0; 351 352 /* Start the timer */ 353 struct timespec now; 354 struct timespec abort_at; 355 if (clock_gettime(CLOCK_MONOTONIC, &now) != 0) { 356 NLOGE("clock_gettime() failing: %s", strerror(errno)); 357 return APP_ERROR_IO; 358 } 359 abort_at.tv_sec = now.tv_sec + POLL_LIMIT_SECONDS; 360 abort_at.tv_nsec = now.tv_nsec; 361 362 NLOGD("Polling app %d", ctx->app_id); 363 do { 364 /* Poll the status */ 365 if (get_status(ctx, status) != 0) { 366 return APP_ERROR_IO; 367 } 368 poll_count++; 369 /* Log at higher priority every 16 polls */ 370 if ((poll_count & (16 - 1)) == 0) { 371 NLOGD("App %d poll=%d status=0x%08x reply_len=%d flags=0x%04x", 372 ctx->app_id, poll_count, status->status, status->reply_len, status->flags); 373 } else { 374 NLOGV("App %d poll=%d status=0x%08x reply_len=%d flags=0x%04x", 375 ctx->app_id, poll_count, status->status, status->reply_len, status->flags); 376 } 377 378 /* Check whether the app is done */ 379 if (status->status & APP_STATUS_DONE) { 380 NLOGD("App %d polled=%d status=0x%08x reply_len=%d flags=0x%04x", 381 ctx->app_id, poll_count, status->status, status->reply_len, status->flags); 382 return APP_STATUS_CODE(status->status); 383 } 384 385 /* Check that the app is still working on it */ 386 if (status->version != TRANSPORT_V0 387 && !(status->flags & STATUS_FLAG_WORKING)) { 388 /* The slave has stopped working without being done so it's misbehaving */ 389 NLOGE("App %d just stopped working", ctx->app_id); 390 return APP_ERROR_INTERNAL; 391 } 392 if (clock_gettime(CLOCK_MONOTONIC, &now) != 0) { 393 NLOGE("clock_gettime() failing: %s", strerror(errno)); 394 return APP_ERROR_IO; 395 } 396 } while (timespec_before(&now, &abort_at)); 397 398 NLOGE("App %d not done after polling %d times in %d seconds", 399 ctx->app_id, poll_count, POLL_LIMIT_SECONDS); 400 return APP_ERROR_TIMEOUT; 401 } 402 403 /* 404 * Reconstruct the reply data from datagram stream. 405 */ 406 static uint32_t receive_reply(const struct transport_context *ctx, 407 const struct transport_status *status) { 408 int retries = CRC_RETRY_COUNT; 409 while (retries--) { 410 NLOGD("Read app %d reply data (%d bytes)", ctx->app_id, status->reply_len); 411 412 uint32_t command = CMD_ID(ctx->app_id) | CMD_IS_READ | CMD_TRANSPORT | CMD_IS_DATA; 413 uint8_t *reply = ctx->reply; 414 uint16_t left = MIN(*ctx->reply_len, status->reply_len); 415 uint16_t got = 0; 416 uint16_t crc = 0; 417 while (left) { 418 /* We can't read more per datagram than the device can send */ 419 const uint16_t gimme = MIN(left, MAX_DEVICE_TRANSFER); 420 NLOGV("Read app %d command=0x%08x, bytes=%d", ctx->app_id, command, gimme); 421 if (nos_device_read(ctx->dev, command, reply, gimme) != 0) { 422 NLOGE("Failed to receive datagram from app %d", ctx->app_id); 423 return APP_ERROR_IO; 424 } 425 426 /* Any further Reads should set the MORE bit. This only works if Nugget 427 * OS sends back CRCs, but that's the only time we'd retry anyway. */ 428 command |= CMD_MORE_TO_COME; 429 430 crc = crc16_update(reply, gimme, crc); 431 reply += gimme; 432 left -= gimme; 433 got += gimme; 434 } 435 /* got it all */ 436 *ctx->reply_len = got; 437 438 /* v0 protocol doesn't support CRC so hopefully it's ok */ 439 if (status->version == TRANSPORT_V0) return APP_SUCCESS; 440 441 if (crc == status->reply_crc) return APP_SUCCESS; 442 NLOGW("App %d reply CRC mismatch: theirs=%04x ours=%04x", ctx->app_id, status->reply_crc, crc); 443 } 444 445 NLOGE("Unable to get valid checksum on app %d reply data", ctx->app_id); 446 return APP_ERROR_IO; 447 } 448 449 /* 450 * Driver for the master of the transport protocol. 451 */ 452 uint32_t nos_call_application(const struct nos_device *dev, 453 uint8_t app_id, uint16_t params, 454 const uint8_t *args, uint32_t arg_len, 455 uint8_t *reply, uint32_t *reply_len) 456 { 457 uint32_t res; 458 const struct transport_context ctx = { 459 .dev = dev, 460 .app_id = app_id, 461 .params = params, 462 .args = args, 463 .arg_len = arg_len, 464 .reply = reply, 465 .reply_len = reply_len, 466 }; 467 468 if ((ctx.arg_len && !ctx.args) || 469 (ctx.reply_len && *ctx.reply_len && !ctx.reply)) { 470 NLOGE("Invalid args to %s()", __func__); 471 return APP_ERROR_IO; 472 } 473 474 NLOGD("Calling app %d with params 0x%04x", app_id, params); 475 476 struct transport_status status; 477 uint32_t status_code; 478 int retries = CRC_RETRY_COUNT; 479 while (retries--) { 480 /* Wake up and wait for Citadel to be ready */ 481 res = make_ready(&ctx); 482 if (res) return res; 483 484 /* Tell the app what to do */ 485 res = send_command(&ctx); 486 if (res) return res; 487 488 /* Wait until the app has finished */ 489 status_code = poll_until_done(&ctx, &status); 490 if (status_code != APP_ERROR_CHECKSUM) break; 491 NLOGW("App %d request checksum error", app_id); 492 } 493 if (status_code == APP_ERROR_CHECKSUM) { 494 NLOGE("App %d equest checksum failed too many times", app_id); 495 status_code = APP_ERROR_IO; 496 } 497 498 /* Get the reply, but only if the app produced data and the caller wants it */ 499 if (ctx.reply && ctx.reply_len && *ctx.reply_len && status.reply_len) { 500 res = receive_reply(&ctx, &status); 501 if (res) return res; 502 } else if (reply_len) { 503 *reply_len = 0; 504 } 505 506 NLOGV("Clear app %d reply for the next caller", app_id); 507 /* This should work, but isn't completely fatal if it doesn't because the 508 * next call will try again. */ 509 (void)clear_status(&ctx); 510 511 NLOGD("App %d returning 0x%x", app_id, status_code); 512 return status_code; 513 } 514