1 /* 2 * Copyright (C) 2016 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 <inttypes.h> 18 #include <string.h> 19 #include <stdint.h> 20 #include <sys/endian.h> 21 22 #include <variant/inc/variant.h> 23 #include <eventnums.h> 24 25 #include <plat/inc/taggedPtr.h> 26 #include <plat/inc/rtc.h> 27 #include <plat/inc/bl.h> 28 #include <plat/inc/plat.h> 29 30 #include <nanohub/crc.h> 31 #include <nanohub/rsa.h> 32 33 #include <atomicBitset.h> 34 #include <atomic.h> 35 #include <hostIntf.h> 36 #include <hostIntf_priv.h> 37 #include <nanohubCommand.h> 38 #include <nanohubPacket.h> 39 #include <eeData.h> 40 #include <seos.h> 41 #include <util.h> 42 #include <mpu.h> 43 #include <heap.h> 44 #include <slab.h> 45 #include <sensType.h> 46 #include <timer.h> 47 #include <appSec.h> 48 #include <cpu.h> 49 50 #define NANOHUB_COMMAND(_reason, _fastHandler, _handler, _minReqType, _maxReqType) \ 51 { .reason = _reason, .fastHandler = _fastHandler, .handler = _handler, \ 52 .minDataLen = sizeof(_minReqType), .maxDataLen = sizeof(_maxReqType) } 53 54 #define NANOHUB_HAL_COMMAND(_msg, _handler) \ 55 { .msg = _msg, .handler = _handler } 56 57 #define SYNC_DATAPOINTS 16 58 #define SYNC_RESET 10000000000ULL /* 10 seconds, ~100us drift */ 59 60 // maximum number of bytes to feed into appSecRxData at once 61 // The bigger the number, the more time we block other event processing 62 // appSecRxData only feeds 16 bytes at a time into writeCbk, so large 63 // numbers don't buy us that much 64 #define MAX_APP_SEC_RX_DATA_LEN 64 65 66 #define REQUIRE_SIGNED_IMAGE true 67 68 struct DownloadState 69 { 70 struct AppSecState *appSecState; 71 uint32_t size; // document size, as reported by client 72 uint32_t srcOffset; // bytes received from client 73 uint32_t dstOffset; // bytes sent to flash 74 struct AppHdr *start; // start of flash segment, where to write 75 uint32_t crc; // document CRC-32, as reported by client 76 uint32_t srcCrc; // current state of CRC-32 we generate from input 77 uint8_t data[NANOHUB_PACKET_PAYLOAD_MAX]; 78 uint8_t len; 79 uint8_t lenLeft; 80 uint8_t chunkReply; 81 bool erase; 82 bool eraseScheduled; 83 }; 84 85 struct TimeSync 86 { 87 uint64_t lastTime; 88 uint64_t delta[SYNC_DATAPOINTS]; 89 uint64_t avgDelta; 90 uint8_t cnt; 91 uint8_t tail; 92 }; 93 94 static struct DownloadState *mDownloadState; 95 static AppSecErr mAppSecStatus; 96 static struct SlabAllocator *mEventSlab; 97 static struct HostIntfDataBuffer mTxCurr, mTxNext; 98 static uint8_t mTxCurrLength, mTxNextLength; 99 static uint8_t mPrefetchActive, mPrefetchTx; 100 static uint32_t mTxWakeCnt[2]; 101 static struct TimeSync mTimeSync = { }; 102 103 static inline bool isSensorEvent(uint32_t evtType) 104 { 105 return evtType > EVT_NO_FIRST_SENSOR_EVENT && evtType <= EVT_NO_FIRST_SENSOR_EVENT + SENS_TYPE_LAST_USER; 106 } 107 108 static void slabFree(void *ptr) 109 { 110 slabAllocatorFree(mEventSlab, ptr); 111 } 112 113 void nanohubInitCommand(void) 114 { 115 mEventSlab = slabAllocatorNew(NANOHUB_PACKET_PAYLOAD_MAX-sizeof(__le32), 4, 2); 116 } 117 118 static uint32_t getOsHwVersion(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp) 119 { 120 struct NanohubOsHwVersionsResponse *resp = tx; 121 resp->hwType = htole16(platHwType()); 122 resp->hwVer = htole16(platHwVer()); 123 resp->blVer = htole16(platBlVer()); 124 resp->osVer = htole16(OS_VER); 125 resp->variantVer = htole32(VARIANT_VER); 126 127 return sizeof(*resp); 128 } 129 130 static uint32_t getAppVersion(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp) 131 { 132 struct NanohubAppVersionsRequest *req = rx; 133 struct NanohubAppVersionsResponse *resp = tx; 134 uint32_t appIdx, appVer, appSize; 135 136 if (osAppInfoById(le64toh(req->appId), &appIdx, &appVer, &appSize)) { 137 resp->appVer = htole32(appVer); 138 return sizeof(*resp); 139 } 140 141 return 0; 142 } 143 144 static uint32_t queryAppInfo(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp) 145 { 146 struct NanohubAppInfoRequest *req = rx; 147 struct NanohubAppInfoResponse *resp = tx; 148 uint64_t appId; 149 uint32_t appVer, appSize; 150 151 if (osAppInfoByIndex(le32toh(req->appIdx), &appId, &appVer, &appSize)) { 152 resp->appId = htole64(appId); 153 resp->appVer = htole32(appVer); 154 resp->appSize = htole32(appSize); 155 return sizeof(*resp); 156 } 157 158 return 0; 159 } 160 161 static AppSecErr writeCbk(const void *data, uint32_t len) 162 { 163 AppSecErr ret = APP_SEC_BAD; 164 165 if (osWriteShared((uint8_t*)(mDownloadState->start) + mDownloadState->dstOffset, data, len)) { 166 ret = APP_SEC_NO_ERROR; 167 mDownloadState->dstOffset += len; 168 } 169 170 return ret; 171 } 172 173 static AppSecErr pubKeyFindCbk(const uint32_t *gotKey, bool *foundP) 174 { 175 const uint32_t *ptr; 176 uint32_t numKeys, i; 177 178 *foundP = false; 179 ptr = BL.blGetPubKeysInfo(&numKeys); 180 for (i = 0; ptr && i < numKeys; i++, ptr += RSA_LIMBS) { 181 if (!memcmp(gotKey, ptr, RSA_BYTES)) { 182 *foundP = true; 183 break; 184 } 185 } 186 187 return APP_SEC_NO_ERROR; 188 } 189 190 static AppSecErr osSecretKeyLookup(uint64_t keyId, void *keyBuf) 191 { 192 struct SeosEedataEncrKeyData kd; 193 void *state = NULL; 194 195 while(1) { 196 uint32_t sz = sizeof(struct SeosEedataEncrKeyData); 197 198 if (!eeDataGetAllVersions(EE_DATA_NAME_ENCR_KEY, &kd, &sz, &state)) 199 break; 200 201 if (sz == sizeof(struct SeosEedataEncrKeyData) && kd.keyID == keyId) { 202 if (keyBuf) 203 memcpy(keyBuf, kd.key, sizeof(kd.key)); 204 return APP_SEC_NO_ERROR; 205 } 206 } 207 208 return APP_SEC_KEY_NOT_FOUND; 209 } 210 211 static AppSecErr osSecretKeyDelete(uint64_t keyId) 212 { 213 struct SeosEedataEncrKeyData kd; 214 void *state = NULL; 215 bool good = true; 216 int count = 0; 217 218 while(1) { 219 uint32_t sz = sizeof(struct SeosEedataEncrKeyData); 220 void *addr = eeDataGetAllVersions(EE_DATA_NAME_ENCR_KEY, &kd, &sz, &state); 221 222 if (!addr) 223 break; 224 225 if (sz == sizeof(kd) && kd.keyID == keyId) { 226 good = eeDataEraseOldVersion(EE_DATA_NAME_ENCR_KEY, addr) && good; 227 count++; 228 } 229 } 230 231 return count == 0 ? APP_SEC_KEY_NOT_FOUND : good ? APP_SEC_NO_ERROR : APP_SEC_BAD; 232 } 233 234 static AppSecErr osSecretKeyAdd(uint64_t keyId, void *keyBuf) 235 { 236 struct SeosEedataEncrKeyData kd; 237 238 // do not add key if it already exists 239 if (osSecretKeyLookup(keyId, NULL) != APP_SEC_KEY_NOT_FOUND) 240 return APP_SEC_BAD; 241 242 memcpy(&kd.key, keyBuf, 32); 243 kd.keyID = keyId; 244 245 return eeDataSet(EE_DATA_NAME_ENCR_KEY, &kd, sizeof(kd)) ? APP_SEC_NO_ERROR : APP_SEC_BAD; 246 } 247 248 static void freeDownloadState() 249 { 250 if (mDownloadState->appSecState) 251 appSecDeinit(mDownloadState->appSecState); 252 heapFree(mDownloadState); 253 mDownloadState = NULL; 254 } 255 256 static void resetDownloadState(bool initial) 257 { 258 bool doCreate = true; 259 260 mAppSecStatus = APP_SEC_NO_ERROR; 261 if (mDownloadState->appSecState) 262 appSecDeinit(mDownloadState->appSecState); 263 mDownloadState->appSecState = appSecInit(writeCbk, pubKeyFindCbk, osSecretKeyLookup, REQUIRE_SIGNED_IMAGE); 264 mDownloadState->srcOffset = 0; 265 mDownloadState->srcCrc = ~0; 266 if (!initial) { 267 // if no data was written, we can reuse the same segment 268 if (mDownloadState->dstOffset) 269 osAppSegmentClose(mDownloadState->start, mDownloadState->dstOffset, SEG_ST_ERASED); 270 else 271 doCreate = false; 272 } 273 if (doCreate) 274 mDownloadState->start = osAppSegmentCreate(mDownloadState->size); 275 if (!mDownloadState->start) 276 mDownloadState->erase = true; 277 mDownloadState->dstOffset = 0; 278 } 279 280 static bool doStartFirmwareUpload(struct NanohubStartFirmwareUploadRequest *req) 281 { 282 if (!mDownloadState) { 283 mDownloadState = heapAlloc(sizeof(struct DownloadState)); 284 285 if (!mDownloadState) 286 return false; 287 else 288 memset(mDownloadState, 0x00, sizeof(struct DownloadState)); 289 } 290 291 mDownloadState->size = le32toh(req->size); 292 mDownloadState->crc = le32toh(req->crc); 293 mDownloadState->chunkReply = NANOHUB_FIRMWARE_CHUNK_REPLY_ACCEPTED; 294 resetDownloadState(true); 295 296 return true; 297 } 298 299 static uint32_t startFirmwareUpload(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp) 300 { 301 struct NanohubStartFirmwareUploadRequest *req = rx; 302 struct NanohubStartFirmwareUploadResponse *resp = tx; 303 304 resp->accepted = doStartFirmwareUpload(req); 305 306 return sizeof(*resp); 307 } 308 309 static void deferredUpdateOs(void *cookie) 310 { 311 const struct AppHdr *app = cookie; 312 struct OsUpdateHdr *os = (struct OsUpdateHdr *)(&(app->hdr) + 1); 313 uint32_t uploadStatus = OS_UPDT_HDR_CHECK_FAILED; 314 uint8_t marker = OS_UPDT_MARKER_DOWNLOADED; 315 struct Segment *seg = osGetSegment(app); 316 uint32_t segSize = osSegmentGetSize(seg); 317 318 osLog(LOG_INFO, "%s: checking OS image @ %p\n", __func__, os); 319 // some sanity checks before asking BL to do image lookup 320 hostIntfSetBusy(true); 321 if (segSize >= (sizeof(*app) + sizeof(*os)) && segSize > os->size) { 322 if (osWriteShared(&os->marker, &marker, sizeof(os->marker))) 323 uploadStatus = BL.blVerifyOsUpdate(); 324 else 325 osLog(LOG_ERROR, "%s: could not set marker on OS image\n", __func__); 326 } 327 hostIntfSetBusy(false); 328 osLog(LOG_INFO, "%s: status=%" PRIu32 "\n", __func__, uploadStatus); 329 } 330 331 static AppSecErr updateKey(const struct AppHdr *app) 332 { 333 AppSecErr ret; 334 struct KeyInfo *ki = (struct KeyInfo *)(&(app->hdr) + 1); 335 uint8_t *data = (uint8_t *)(ki + 1); 336 uint64_t keyId = KEY_ID_MAKE(APP_ID_GET_VENDOR(app->hdr.appId), ki->id); 337 const char *op; 338 339 if ((app->hdr.fwFlags & FL_KEY_HDR_DELETE) != 0) { 340 // removing existing key 341 ret = osSecretKeyDelete(keyId); 342 op = "Removing"; 343 } else { 344 // adding new key 345 ret = osSecretKeyAdd(keyId, data); 346 op = "Adding"; 347 } 348 osLog(LOG_INFO, "%s: %s key: id=%016" PRIX64 "; ret=%" PRIu32 "\n", 349 __func__, op, keyId, ret); 350 351 return ret; 352 } 353 354 static uint32_t appSecErrToNanohubReply(AppSecErr status) 355 { 356 uint32_t reply; 357 358 switch (status) { 359 case APP_SEC_NO_ERROR: 360 reply = NANOHUB_FIRMWARE_UPLOAD_SUCCESS; 361 break; 362 case APP_SEC_KEY_NOT_FOUND: 363 reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_KEY_NOT_FOUND; 364 break; 365 case APP_SEC_HEADER_ERROR: 366 reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_HEADER_ERROR; 367 break; 368 case APP_SEC_TOO_MUCH_DATA: 369 reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_TOO_MUCH_DATA; 370 break; 371 case APP_SEC_TOO_LITTLE_DATA: 372 reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_TOO_LITTLE_DATA; 373 break; 374 case APP_SEC_SIG_VERIFY_FAIL: 375 reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_SIG_VERIFY_FAIL; 376 break; 377 case APP_SEC_SIG_DECODE_FAIL: 378 reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_SIG_DECODE_FAIL; 379 break; 380 case APP_SEC_SIG_ROOT_UNKNOWN: 381 reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_SIG_ROOT_UNKNOWN; 382 break; 383 case APP_SEC_MEMORY_ERROR: 384 reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_MEMORY_ERROR; 385 break; 386 case APP_SEC_INVALID_DATA: 387 reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_INVALID_DATA; 388 break; 389 case APP_SEC_VERIFY_FAILED: 390 reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_VERIFY_FAILED; 391 break; 392 default: 393 reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_BAD; 394 break; 395 } 396 return reply; 397 } 398 399 static uint32_t firmwareFinish(bool valid) 400 { 401 struct AppHdr *app; 402 struct Segment *storageSeg; 403 uint32_t segState; 404 uint32_t ret = NANOHUB_FIRMWARE_UPLOAD_SUCCESS; 405 406 if (!mDownloadState) { 407 ret = appSecErrToNanohubReply(mAppSecStatus); 408 osLog(LOG_INFO, "%s: no DL status; decoding secure status: %" PRIu32 "\n", __func__, ret); 409 return ret; 410 } 411 412 app = mDownloadState->start; 413 storageSeg = osGetSegment(app); 414 415 if (mAppSecStatus == APP_SEC_NO_ERROR && valid) { 416 osLog(LOG_INFO, "%s: Secure verification passed\n", __func__); 417 if (storageSeg->state != SEG_ST_RESERVED || 418 mDownloadState->size < sizeof(struct FwCommonHdr) || 419 app->hdr.magic != APP_HDR_MAGIC || 420 app->hdr.fwVer != APP_HDR_VER_CUR) { 421 segState = SEG_ST_ERASED; 422 osLog(LOG_INFO, "%s: Header verification failed\n", __func__); 423 } else { 424 segState = SEG_ST_VALID; 425 } 426 } else { 427 segState = SEG_ST_ERASED; 428 osLog(LOG_INFO, "%s: Secure verification failed: valid=%d; status=%" PRIu32 "\n", __func__, valid, mAppSecStatus); 429 } 430 431 if (!osAppSegmentClose(app, mDownloadState->dstOffset, segState)) { 432 osLog(LOG_INFO, "%s: Failed to close segment\n", __func__); 433 valid = false; 434 } else { 435 segState = osAppSegmentGetState(app); 436 valid = (segState == SEG_ST_VALID); 437 } 438 osLog(LOG_INFO, "Loaded %s image type %" PRIu8 ": %" PRIu32 439 " bytes @ %p; state=%02" PRIX32 "\n", 440 valid ? "valid" : "invalid", 441 app->hdr.payInfoType, mDownloadState->size, 442 mDownloadState->start, segState); 443 444 freeDownloadState(); // no more access to mDownloadState 445 446 if (!valid) 447 ret = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_BAD; 448 449 // take extra care about some special payload types 450 if (ret == NANOHUB_FIRMWARE_UPLOAD_SUCCESS) { 451 switch(app->hdr.payInfoType) { 452 case LAYOUT_OS: 453 osLog(LOG_INFO, "Performing OS update\n"); 454 // we want to give this message a chance to reach host before we start erasing stuff 455 osDefer(deferredUpdateOs, (void*)app, false); 456 break; 457 case LAYOUT_KEY: 458 ret = appSecErrToNanohubReply(updateKey(app)); 459 break; 460 } 461 } 462 463 if (ret != NANOHUB_FIRMWARE_UPLOAD_SUCCESS || (app->hdr.fwFlags & FL_APP_HDR_VOLATILE)) { 464 if ((app->hdr.fwFlags & FL_APP_HDR_SECURE)) 465 osAppWipeData((struct AppHdr*)app); 466 osAppSegmentSetState(app, SEG_ST_ERASED); 467 } 468 469 // if any error happened after we downloaded and verified image, we say it is unknown fault 470 // we don't have download status, so e have to save returned value in secure status field, because 471 // host may request the same status multiple times 472 if (ret != NANOHUB_FIRMWARE_UPLOAD_SUCCESS) 473 mAppSecStatus = APP_SEC_BAD; 474 475 return ret; 476 } 477 478 static void firmwareErase(void *cookie) 479 { 480 if (mDownloadState->erase == true) { 481 osLog(LOG_INFO, "%s: erasing shared area\n", __func__); 482 osEraseShared(); 483 mDownloadState->start = osAppSegmentCreate(mDownloadState->size); 484 if (!mDownloadState->start) 485 firmwareFinish(false); 486 mDownloadState->erase = false; 487 hostIntfSetInterrupt(NANOHUB_INT_CMD_WAIT); 488 } 489 mDownloadState->eraseScheduled = false; 490 } 491 492 static void firmwareWrite(void *cookie) 493 { 494 bool valid; 495 bool finished = false; 496 struct NanohubHalContUploadTx *resp = cookie; 497 // only check crc when cookie is NULL (write came from kernel, not HAL) 498 bool checkCrc = !cookie; 499 500 if (mAppSecStatus == APP_SEC_NEED_MORE_TIME) { 501 mAppSecStatus = appSecDoSomeProcessing(mDownloadState->appSecState); 502 } else if (mDownloadState->lenLeft) { 503 const uint8_t *data = mDownloadState->data + mDownloadState->len - mDownloadState->lenLeft; 504 uint32_t len = mDownloadState->lenLeft, lenLeft, lenRem = 0; 505 506 if (len > MAX_APP_SEC_RX_DATA_LEN) { 507 lenRem = len - MAX_APP_SEC_RX_DATA_LEN; 508 len = MAX_APP_SEC_RX_DATA_LEN; 509 } 510 511 mAppSecStatus = appSecRxData(mDownloadState->appSecState, data, len, &lenLeft); 512 mDownloadState->lenLeft = lenLeft + lenRem; 513 } 514 515 valid = (mAppSecStatus == APP_SEC_NO_ERROR); 516 if (mAppSecStatus == APP_SEC_NEED_MORE_TIME || mDownloadState->lenLeft) { 517 osDefer(firmwareWrite, cookie, false); 518 return; 519 } else if (valid) { 520 if (mDownloadState->srcOffset == mDownloadState->size) { 521 finished = true; 522 valid = !checkCrc || mDownloadState->crc == ~mDownloadState->srcCrc; 523 } else if (mDownloadState->srcOffset > mDownloadState->size) { 524 valid = false; 525 } 526 } 527 if (!valid) 528 finished = true; 529 if (finished) { 530 if (firmwareFinish(valid) != NANOHUB_FIRMWARE_UPLOAD_SUCCESS) 531 valid = false; 532 } 533 if (resp) { 534 resp->success = valid; 535 osEnqueueEvtOrFree(EVT_APP_TO_HOST, resp, heapFree); 536 } 537 } 538 539 static uint32_t doFirmwareChunk(uint8_t *data, uint32_t offset, uint32_t len, void *cookie) 540 { 541 uint32_t reply; 542 543 if (!mDownloadState) { 544 reply = NANOHUB_FIRMWARE_CHUNK_REPLY_CANCEL_NO_RETRY; 545 } else if (mAppSecStatus == APP_SEC_NEED_MORE_TIME || mDownloadState->lenLeft) { 546 reply = NANOHUB_FIRMWARE_CHUNK_REPLY_RESEND; 547 } else if (mDownloadState->chunkReply != NANOHUB_FIRMWARE_CHUNK_REPLY_ACCEPTED) { 548 reply = mDownloadState->chunkReply; 549 firmwareFinish(false); 550 } else { 551 if (mDownloadState->erase == true) { 552 reply = NANOHUB_FIRMWARE_CHUNK_REPLY_WAIT; 553 if (!mDownloadState->eraseScheduled) 554 mDownloadState->eraseScheduled = osDefer(firmwareErase, NULL, false); 555 } else if (!mDownloadState->start) { 556 // this means we can't allocate enough space even after we did erase 557 reply = NANOHUB_FIRMWARE_CHUNK_REPLY_CANCEL_NO_RETRY; 558 firmwareFinish(false); 559 } else if (offset != mDownloadState->srcOffset) { 560 reply = NANOHUB_FIRMWARE_CHUNK_REPLY_RESTART; 561 resetDownloadState(false); 562 } else { 563 if (!cookie) 564 mDownloadState->srcCrc = crc32(data, len, mDownloadState->srcCrc); 565 mDownloadState->srcOffset += len; 566 memcpy(mDownloadState->data, data, len); 567 mDownloadState->lenLeft = mDownloadState->len = len; 568 reply = NANOHUB_FIRMWARE_CHUNK_REPLY_ACCEPTED; 569 osDefer(firmwareWrite, cookie, false); 570 } 571 } 572 573 return reply; 574 } 575 576 static uint32_t firmwareChunk(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp) 577 { 578 struct NanohubFirmwareChunkRequest *req = rx; 579 struct NanohubFirmwareChunkResponse *resp = tx; 580 uint32_t offset = le32toh(req->offset); 581 uint8_t len = rx_len - sizeof(req->offset); 582 583 resp->chunkReply = doFirmwareChunk(req->data, offset, len, NULL); 584 585 return sizeof(*resp); 586 } 587 588 static uint32_t doFinishFirmwareUpload() 589 { 590 uint32_t reply; 591 592 if (!mDownloadState) { 593 reply = appSecErrToNanohubReply(mAppSecStatus); 594 } else if (mDownloadState->srcOffset == mDownloadState->size) { 595 reply = NANOHUB_FIRMWARE_UPLOAD_PROCESSING; 596 } else { 597 reply = firmwareFinish(false); 598 } 599 600 return reply; 601 } 602 603 static uint32_t finishFirmwareUpload(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp) 604 { 605 struct NanohubFinishFirmwareUploadResponse *resp = tx; 606 resp->uploadReply = doFinishFirmwareUpload(); 607 if (resp->uploadReply != NANOHUB_FIRMWARE_UPLOAD_PROCESSING) 608 osLog(LOG_INFO, "%s: reply=%" PRIu8 "\n", __func__, resp->uploadReply); 609 return sizeof(*resp); 610 } 611 612 static uint32_t getInterrupt(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp) 613 { 614 struct NanohubGetInterruptRequest *req = rx; 615 struct NanohubGetInterruptResponse *resp = tx; 616 int i; 617 618 if (rx_len == sizeof(struct NanohubGetInterruptRequest)) { 619 for (i = 0; i < HOSTINTF_MAX_INTERRUPTS; i++) { 620 if (req->clear[i/32] & (1UL << (i & 31))) 621 hostIntfClearInterrupt(i); 622 } 623 } 624 625 hostIntfCopyInterrupts(resp->interrupts, HOSTINTF_MAX_INTERRUPTS); 626 627 return sizeof(*resp); 628 } 629 630 static uint32_t maskInterrupt(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp) 631 { 632 struct NanohubMaskInterruptRequest *req = rx; 633 struct NanohubMaskInterruptResponse *resp = tx; 634 635 hostIntfSetInterruptMask(req->interrupt); 636 637 resp->accepted = true; 638 return sizeof(*resp); 639 } 640 641 static uint32_t unmaskInterrupt(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp) 642 { 643 struct NanohubUnmaskInterruptRequest *req = rx; 644 struct NanohubUnmaskInterruptResponse *resp = tx; 645 646 hostIntfClearInterruptMask(req->interrupt); 647 648 resp->accepted = true; 649 return sizeof(*resp); 650 } 651 652 static void addDelta(struct TimeSync *sync, uint64_t apTime, uint64_t hubTime) 653 { 654 if (apTime - sync->lastTime > SYNC_RESET) { 655 sync->tail = 0; 656 sync->cnt = 0; 657 } 658 659 sync->delta[sync->tail++] = apTime - hubTime; 660 661 sync->lastTime = apTime; 662 663 if (sync->tail >= SYNC_DATAPOINTS) 664 sync->tail = 0; 665 666 if (sync->cnt < SYNC_DATAPOINTS) 667 sync->cnt ++; 668 669 sync->avgDelta = 0ULL; 670 } 671 672 static uint64_t getAvgDelta(struct TimeSync *sync) 673 { 674 int i; 675 int32_t avg; 676 677 if (!sync->cnt) 678 return 0ULL; 679 else if (!sync->avgDelta) { 680 for (i=1, avg=0; i<sync->cnt; i++) 681 avg += (int32_t)(sync->delta[i] - sync->delta[0]); 682 sync->avgDelta = (avg / sync->cnt) + sync->delta[0]; 683 } 684 return sync->avgDelta; 685 } 686 687 static int fillBuffer(void *tx, uint32_t totLength, uint32_t *wakeup, uint32_t *nonwakeup) 688 { 689 struct HostIntfDataBuffer *packet = &mTxNext; 690 struct HostIntfDataBuffer *firstPacket = tx; 691 uint8_t *buf = tx; 692 uint32_t length; 693 uint32_t prevWakeup, prevNonWakeup; 694 695 prevWakeup = *wakeup; 696 prevNonWakeup = *nonwakeup; 697 698 while (hostIntfPacketDequeue(&mTxNext, wakeup, nonwakeup)) { 699 length = packet->length + sizeof(packet->evtType); 700 if (packet->sensType == SENS_TYPE_INVALID) { 701 switch (packet->dataType) { 702 case HOSTINTF_DATA_TYPE_APP_TO_HOST: 703 packet->evtType = htole32(EVT_APP_TO_HOST); 704 break; 705 case HOSTINTF_DATA_TYPE_RESET_REASON: 706 packet->evtType = htole32(EVT_RESET_REASON); 707 break; 708 #ifdef DEBUG_LOG_EVT 709 case HOSTINTF_DATA_TYPE_LOG: 710 packet->evtType = htole32(HOST_EVT_DEBUG_LOG); 711 break; 712 #endif 713 default: 714 packet->evtType = htole32(0x00000000); 715 break; 716 } 717 } else { 718 packet->evtType = htole32(EVT_NO_FIRST_SENSOR_EVENT + packet->sensType); 719 if (packet->referenceTime) 720 packet->referenceTime += getAvgDelta(&mTimeSync); 721 722 if (*wakeup > 0) 723 packet->firstSample.interrupt = NANOHUB_INT_WAKEUP; 724 } 725 726 if ((!totLength || (isSensorEvent(firstPacket->evtType) && isSensorEvent(packet->evtType))) && totLength + length <= sizeof(struct HostIntfDataBuffer)) { 727 memcpy(buf + totLength, &mTxNext, length); 728 totLength += length; 729 if (isSensorEvent(packet->evtType) && packet->firstSample.interrupt == NANOHUB_INT_WAKEUP) 730 firstPacket->firstSample.interrupt = NANOHUB_INT_WAKEUP; 731 } else { 732 mTxNextLength = length; 733 *wakeup = prevWakeup; 734 *nonwakeup = prevNonWakeup; 735 break; 736 } 737 738 prevWakeup = *wakeup; 739 prevNonWakeup = *nonwakeup; 740 } 741 742 return totLength; 743 } 744 745 static void updateInterrupts(void) 746 { 747 uint32_t wakeup = atomicRead32bits(&mTxWakeCnt[0]); 748 uint32_t nonwakeup = atomicRead32bits(&mTxWakeCnt[1]); 749 bool wakeupStatus = hostIntfGetInterrupt(NANOHUB_INT_WAKEUP); 750 bool nonwakeupStatus = hostIntfGetInterrupt(NANOHUB_INT_NONWAKEUP); 751 752 if (!wakeup && wakeupStatus) 753 hostIntfClearInterrupt(NANOHUB_INT_WAKEUP); 754 else if (wakeup && !wakeupStatus) 755 hostIntfSetInterrupt(NANOHUB_INT_WAKEUP); 756 757 if (!nonwakeup && nonwakeupStatus) 758 hostIntfClearInterrupt(NANOHUB_INT_NONWAKEUP); 759 else if (nonwakeup && !nonwakeupStatus) 760 hostIntfSetInterrupt(NANOHUB_INT_NONWAKEUP); 761 } 762 763 void nanohubPrefetchTx(uint32_t interrupt, uint32_t wakeup, uint32_t nonwakeup) 764 { 765 uint64_t state; 766 767 if (wakeup < atomicRead32bits(&mTxWakeCnt[0])) 768 wakeup = atomicRead32bits(&mTxWakeCnt[0]); 769 770 if (nonwakeup < atomicRead32bits(&mTxWakeCnt[1])) 771 nonwakeup = atomicRead32bits(&mTxWakeCnt[1]); 772 773 if (interrupt == HOSTINTF_MAX_INTERRUPTS && !hostIntfGetInterrupt(NANOHUB_INT_WAKEUP) && !hostIntfGetInterrupt(NANOHUB_INT_NONWAKEUP)) 774 return; 775 776 atomicWriteByte(&mPrefetchActive, 1); 777 778 if (interrupt < HOSTINTF_MAX_INTERRUPTS) 779 hostIntfSetInterrupt(interrupt); 780 781 do { 782 if (atomicReadByte(&mTxCurrLength) == 0 && mTxNextLength > 0) { 783 memcpy(&mTxCurr, &mTxNext, mTxNextLength); 784 atomicWriteByte(&mTxCurrLength, mTxNextLength); 785 mTxNextLength = 0; 786 } 787 788 if (mTxNextLength == 0) { 789 atomicWriteByte(&mTxCurrLength, fillBuffer(&mTxCurr, atomicReadByte(&mTxCurrLength), &wakeup, &nonwakeup)); 790 atomicWrite32bits(&mTxWakeCnt[0], wakeup); 791 atomicWrite32bits(&mTxWakeCnt[1], nonwakeup); 792 } 793 794 atomicWriteByte(&mPrefetchActive, 0); 795 796 if (atomicReadByte(&mPrefetchTx)) { 797 state = cpuIntsOff(); 798 799 // interrupt occured during this call 800 // take care of it 801 hostIntfTxAck(&mTxCurr, atomicReadByte(&mTxCurrLength)); 802 atomicWriteByte(&mPrefetchTx, 0); 803 atomicWriteByte(&mTxCurrLength, 0); 804 805 cpuIntsRestore(state); 806 807 updateInterrupts(); 808 } else { 809 break; 810 } 811 } while (mTxNextLength > 0); 812 } 813 814 static void nanohubPrefetchTxDefer(void *cookie) 815 { 816 nanohubPrefetchTx(HOSTINTF_MAX_INTERRUPTS, 0, 0); 817 } 818 819 static uint32_t readEventFast(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp) 820 { 821 struct NanohubReadEventRequest *req = rx; 822 uint8_t ret = 0; 823 824 if (atomicReadByte(&mPrefetchActive)) { 825 atomicWriteByte(&mPrefetchTx, 1); 826 return NANOHUB_FAST_DONT_ACK; 827 } else { 828 if ((ret = atomicReadByte(&mTxCurrLength))) { 829 addDelta(&mTimeSync, req->apBootTime, timestamp); 830 831 memcpy(tx, &mTxCurr, ret); 832 atomicWriteByte(&mTxCurrLength, 0); 833 834 updateInterrupts(); 835 osDefer(nanohubPrefetchTxDefer, NULL, true); 836 } else { 837 return NANOHUB_FAST_UNHANDLED_ACK; 838 } 839 } 840 841 return ret; 842 } 843 844 static uint32_t readEvent(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp) 845 { 846 struct NanohubReadEventRequest *req = rx; 847 uint8_t *buf = tx; 848 uint32_t length, wakeup, nonwakeup; 849 uint32_t totLength = 0; 850 851 addDelta(&mTimeSync, req->apBootTime, timestamp); 852 853 if ((totLength = atomicReadByte(&mTxCurrLength))) { 854 memcpy(tx, &mTxCurr, totLength); 855 atomicWriteByte(&mTxCurrLength, 0); 856 updateInterrupts(); 857 return totLength; 858 } 859 860 if (mTxNextLength > 0) { 861 length = mTxNextLength; 862 wakeup = atomicRead32bits(&mTxWakeCnt[0]); 863 nonwakeup = atomicRead32bits(&mTxWakeCnt[1]); 864 memcpy(buf, &mTxNext, length); 865 totLength = length; 866 mTxNextLength = 0; 867 } 868 869 totLength = fillBuffer(buf, totLength, &wakeup, &nonwakeup); 870 atomicWrite32bits(&mTxWakeCnt[0], wakeup); 871 atomicWrite32bits(&mTxWakeCnt[1], nonwakeup); 872 873 if (totLength) { 874 updateInterrupts(); 875 } else { 876 hostIntfClearInterrupt(NANOHUB_INT_WAKEUP); 877 hostIntfClearInterrupt(NANOHUB_INT_NONWAKEUP); 878 } 879 880 return totLength; 881 } 882 883 static uint32_t writeEvent(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp) 884 { 885 struct NanohubWriteEventRequest *req = rx; 886 struct NanohubWriteEventResponse *resp = tx; 887 uint8_t *packet; 888 struct HostHubRawPacket *rawPacket; 889 uint32_t tid; 890 EventFreeF free = slabFree; 891 892 if (le32toh(req->evtType) == EVT_APP_FROM_HOST) { 893 rawPacket = (struct HostHubRawPacket *)req->evtData; 894 if (rx_len >= sizeof(req->evtType) + sizeof(struct HostHubRawPacket) && rx_len == sizeof(req->evtType) + sizeof(struct HostHubRawPacket) + rawPacket->dataLen && osTidById(rawPacket->appId, &tid)) { 895 packet = slabAllocatorAlloc(mEventSlab); 896 if (!packet) { 897 packet = heapAlloc(rawPacket->dataLen + 1); 898 free = heapFree; 899 } 900 if (!packet) { 901 resp->accepted = false; 902 } else { 903 packet[0] = rawPacket->dataLen; 904 memcpy(packet + 1, rawPacket + 1, rawPacket->dataLen); 905 resp->accepted = osEnqueuePrivateEvt(EVT_APP_FROM_HOST, packet, free, tid); 906 if (!resp->accepted) 907 free(packet); 908 } 909 } else { 910 resp->accepted = false; 911 } 912 } else { 913 packet = slabAllocatorAlloc(mEventSlab); 914 if (!packet) { 915 packet = heapAlloc(rx_len - sizeof(req->evtType)); 916 free = heapFree; 917 } 918 if (!packet) { 919 resp->accepted = false; 920 } else { 921 memcpy(packet, req->evtData, rx_len - sizeof(req->evtType)); 922 resp->accepted = osEnqueueEvtOrFree(le32toh(req->evtType), packet, free); 923 } 924 } 925 926 return sizeof(*resp); 927 } 928 929 const static struct NanohubCommand mBuiltinCommands[] = { 930 NANOHUB_COMMAND(NANOHUB_REASON_GET_OS_HW_VERSIONS, 931 getOsHwVersion, 932 getOsHwVersion, 933 struct NanohubOsHwVersionsRequest, 934 struct NanohubOsHwVersionsRequest), 935 NANOHUB_COMMAND(NANOHUB_REASON_GET_APP_VERSIONS, 936 NULL, 937 getAppVersion, 938 struct NanohubAppVersionsRequest, 939 struct NanohubAppVersionsRequest), 940 NANOHUB_COMMAND(NANOHUB_REASON_QUERY_APP_INFO, 941 NULL, 942 queryAppInfo, 943 struct NanohubAppInfoRequest, 944 struct NanohubAppInfoRequest), 945 NANOHUB_COMMAND(NANOHUB_REASON_START_FIRMWARE_UPLOAD, 946 NULL, 947 startFirmwareUpload, 948 struct NanohubStartFirmwareUploadRequest, 949 struct NanohubStartFirmwareUploadRequest), 950 NANOHUB_COMMAND(NANOHUB_REASON_FIRMWARE_CHUNK, 951 NULL, 952 firmwareChunk, 953 __le32, 954 struct NanohubFirmwareChunkRequest), 955 NANOHUB_COMMAND(NANOHUB_REASON_FINISH_FIRMWARE_UPLOAD, 956 NULL, 957 finishFirmwareUpload, 958 struct NanohubFinishFirmwareUploadRequest, 959 struct NanohubFinishFirmwareUploadRequest), 960 NANOHUB_COMMAND(NANOHUB_REASON_GET_INTERRUPT, 961 getInterrupt, 962 getInterrupt, 963 0, 964 struct NanohubGetInterruptRequest), 965 NANOHUB_COMMAND(NANOHUB_REASON_MASK_INTERRUPT, 966 maskInterrupt, 967 maskInterrupt, 968 struct NanohubMaskInterruptRequest, 969 struct NanohubMaskInterruptRequest), 970 NANOHUB_COMMAND(NANOHUB_REASON_UNMASK_INTERRUPT, 971 unmaskInterrupt, 972 unmaskInterrupt, 973 struct NanohubUnmaskInterruptRequest, 974 struct NanohubUnmaskInterruptRequest), 975 NANOHUB_COMMAND(NANOHUB_REASON_READ_EVENT, 976 readEventFast, 977 readEvent, 978 struct NanohubReadEventRequest, 979 struct NanohubReadEventRequest), 980 NANOHUB_COMMAND(NANOHUB_REASON_WRITE_EVENT, 981 writeEvent, 982 writeEvent, 983 __le32, 984 struct NanohubWriteEventRequest), 985 }; 986 987 const struct NanohubCommand *nanohubFindCommand(uint32_t packetReason) 988 { 989 uint32_t i; 990 991 for (i = 0; i < ARRAY_SIZE(mBuiltinCommands); i++) { 992 const struct NanohubCommand *cmd = &mBuiltinCommands[i]; 993 if (cmd->reason == packetReason) 994 return cmd; 995 } 996 return NULL; 997 } 998 999 static void halSendMgmtResponse(uint32_t cmd, uint32_t status) 1000 { 1001 struct NanohubHalMgmtTx *resp; 1002 1003 resp = heapAlloc(sizeof(*resp)); 1004 if (resp) { 1005 resp->hdr = (struct NanohubHalHdr) { 1006 .appId = APP_ID_MAKE(APP_ID_VENDOR_GOOGLE, 0), 1007 .len = sizeof(*resp) - sizeof(resp->hdr) + sizeof(resp->hdr.msg), 1008 .msg = cmd, 1009 }; 1010 resp->status = htole32(status); 1011 osEnqueueEvtOrFree(EVT_APP_TO_HOST, resp, heapFree); 1012 } 1013 } 1014 1015 static void halExtAppsOn(void *rx, uint8_t rx_len) 1016 { 1017 struct NanohubHalMgmtRx *req = rx; 1018 1019 halSendMgmtResponse(NANOHUB_HAL_EXT_APPS_ON, osExtAppStartApps(le64toh(req->appId))); 1020 } 1021 1022 static void halExtAppsOff(void *rx, uint8_t rx_len) 1023 { 1024 struct NanohubHalMgmtRx *req = rx; 1025 1026 halSendMgmtResponse(NANOHUB_HAL_EXT_APPS_OFF, osExtAppStopApps(le64toh(req->appId))); 1027 } 1028 1029 static void halExtAppDelete(void *rx, uint8_t rx_len) 1030 { 1031 struct NanohubHalMgmtRx *req = rx; 1032 1033 halSendMgmtResponse(NANOHUB_HAL_EXT_APP_DELETE, osExtAppEraseApps(le64toh(req->appId))); 1034 } 1035 1036 static void halQueryMemInfo(void *rx, uint8_t rx_len) 1037 { 1038 } 1039 1040 static void halQueryApps(void *rx, uint8_t rx_len) 1041 { 1042 struct NanohubHalQueryAppsRx *req = rx; 1043 struct NanohubHalQueryAppsTx *resp; 1044 struct NanohubHalHdr *hdr; 1045 uint64_t appId; 1046 uint32_t appVer, appSize; 1047 1048 if (osAppInfoByIndex(le32toh(req->idx), &appId, &appVer, &appSize)) { 1049 resp = heapAlloc(sizeof(*resp)); 1050 resp->hdr.appId = APP_ID_MAKE(APP_ID_VENDOR_GOOGLE, 0); 1051 resp->hdr.len = sizeof(*resp) - sizeof(struct NanohubHalHdr) + 1; 1052 resp->hdr.msg = NANOHUB_HAL_QUERY_APPS; 1053 resp->appId = appId; 1054 resp->version = appVer; 1055 resp->flashUse = appSize; 1056 resp->ramUse = 0; 1057 osEnqueueEvtOrFree(EVT_APP_TO_HOST, resp, heapFree); 1058 } else { 1059 hdr = heapAlloc(sizeof(*hdr)); 1060 hdr->appId = APP_ID_MAKE(APP_ID_VENDOR_GOOGLE, 0); 1061 hdr->len = 1; 1062 hdr->msg = NANOHUB_HAL_QUERY_APPS; 1063 osEnqueueEvtOrFree(EVT_APP_TO_HOST, hdr, heapFree); 1064 } 1065 } 1066 1067 static void halQueryRsaKeys(void *rx, uint8_t rx_len) 1068 { 1069 struct NanohubHalQueryRsaKeysRx *req = rx; 1070 struct NanohubHalQueryRsaKeysTx *resp; 1071 int len = 0; 1072 const uint32_t *ptr; 1073 uint32_t numKeys; 1074 1075 if (!(resp = heapAlloc(sizeof(*resp) + NANOHUB_RSA_KEY_CHUNK_LEN))) 1076 return; 1077 1078 ptr = BL.blGetPubKeysInfo(&numKeys); 1079 if (ptr && numKeys * RSA_BYTES > req->offset) { 1080 len = numKeys * RSA_BYTES - req->offset; 1081 if (len > NANOHUB_RSA_KEY_CHUNK_LEN) 1082 len = NANOHUB_RSA_KEY_CHUNK_LEN; 1083 memcpy(resp->data, (uint8_t *)ptr + req->offset, len); 1084 } 1085 1086 resp->hdr.appId = APP_ID_MAKE(APP_ID_VENDOR_GOOGLE, 0); 1087 resp->hdr.len = sizeof(*resp) - sizeof(struct NanohubHalHdr) + 1 + len; 1088 resp->hdr.msg = NANOHUB_HAL_QUERY_RSA_KEYS; 1089 1090 osEnqueueEvtOrFree(EVT_APP_TO_HOST, resp, heapFree); 1091 } 1092 1093 static void halStartUpload(void *rx, uint8_t rx_len) 1094 { 1095 struct NanohubHalStartUploadRx *req = rx; 1096 struct NanohubStartFirmwareUploadRequest hwReq = { 1097 .size= req->length 1098 }; 1099 struct NanohubHalStartUploadTx *resp; 1100 1101 if (!(resp = heapAlloc(sizeof(*resp)))) 1102 return; 1103 1104 resp->hdr.appId = APP_ID_MAKE(APP_ID_VENDOR_GOOGLE, 0); 1105 resp->hdr.len = sizeof(*resp) - sizeof(struct NanohubHalHdr) + 1; 1106 resp->hdr.msg = NANOHUB_HAL_START_UPLOAD; 1107 resp->success = doStartFirmwareUpload(&hwReq); 1108 1109 osEnqueueEvtOrFree(EVT_APP_TO_HOST, resp, heapFree); 1110 } 1111 1112 static void halContUpload(void *rx, uint8_t rx_len) 1113 { 1114 uint32_t offset; 1115 uint32_t reply; 1116 uint8_t len; 1117 struct NanohubHalContUploadRx *req = rx; 1118 struct NanohubHalContUploadTx *resp; 1119 1120 if (!(resp = heapAlloc(sizeof(*resp)))) 1121 return; 1122 1123 resp->hdr.appId = APP_ID_MAKE(APP_ID_VENDOR_GOOGLE, 0); 1124 resp->hdr.len = sizeof(*resp) - sizeof(struct NanohubHalHdr) + 1; 1125 resp->hdr.msg = NANOHUB_HAL_CONT_UPLOAD; 1126 1127 if (!mDownloadState) { 1128 reply = NANOHUB_FIRMWARE_CHUNK_REPLY_CANCEL_NO_RETRY; 1129 } else { 1130 offset = le32toh(req->offset); 1131 len = rx_len - sizeof(req->offset); 1132 reply = doFirmwareChunk(req->data, offset, len, resp); 1133 } 1134 if (reply != NANOHUB_FIRMWARE_CHUNK_REPLY_ACCEPTED) { 1135 osLog(LOG_ERROR, "%s: reply=%" PRIu32 "\n", __func__, reply); 1136 1137 resp->success = false; 1138 1139 osEnqueueEvtOrFree(EVT_APP_TO_HOST, resp, heapFree); 1140 } 1141 } 1142 1143 static void halFinishUpload(void *rx, uint8_t rx_len) 1144 { 1145 struct NanohubHalFinishUploadTx *resp; 1146 uint32_t reply; 1147 1148 if (!(resp = heapAlloc(sizeof(*resp)))) 1149 return; 1150 1151 resp->hdr.appId = APP_ID_MAKE(APP_ID_VENDOR_GOOGLE, 0); 1152 resp->hdr.len = sizeof(*resp) - sizeof(struct NanohubHalHdr) + 1; 1153 resp->hdr.msg = NANOHUB_HAL_FINISH_UPLOAD; 1154 1155 reply = doFinishFirmwareUpload(); 1156 1157 osLog(LOG_INFO, "%s: reply=%" PRIu32 "\n", __func__, reply); 1158 1159 resp->success = (reply == NANOHUB_FIRMWARE_UPLOAD_SUCCESS); 1160 1161 osEnqueueEvtOrFree(EVT_APP_TO_HOST, resp, heapFree); 1162 } 1163 1164 static void halReboot(void *rx, uint8_t rx_len) 1165 { 1166 BL.blReboot(); 1167 } 1168 1169 const static struct NanohubHalCommand mBuiltinHalCommands[] = { 1170 NANOHUB_HAL_COMMAND(NANOHUB_HAL_EXT_APPS_ON, 1171 halExtAppsOn), 1172 NANOHUB_HAL_COMMAND(NANOHUB_HAL_EXT_APPS_OFF, 1173 halExtAppsOff), 1174 NANOHUB_HAL_COMMAND(NANOHUB_HAL_EXT_APP_DELETE, 1175 halExtAppDelete), 1176 NANOHUB_HAL_COMMAND(NANOHUB_HAL_QUERY_MEMINFO, 1177 halQueryMemInfo), 1178 NANOHUB_HAL_COMMAND(NANOHUB_HAL_QUERY_APPS, 1179 halQueryApps), 1180 NANOHUB_HAL_COMMAND(NANOHUB_HAL_QUERY_RSA_KEYS, 1181 halQueryRsaKeys), 1182 NANOHUB_HAL_COMMAND(NANOHUB_HAL_START_UPLOAD, 1183 halStartUpload), 1184 NANOHUB_HAL_COMMAND(NANOHUB_HAL_CONT_UPLOAD, 1185 halContUpload), 1186 NANOHUB_HAL_COMMAND(NANOHUB_HAL_FINISH_UPLOAD, 1187 halFinishUpload), 1188 NANOHUB_HAL_COMMAND(NANOHUB_HAL_REBOOT, 1189 halReboot), 1190 }; 1191 1192 const struct NanohubHalCommand *nanohubHalFindCommand(uint8_t msg) 1193 { 1194 uint32_t i; 1195 1196 for (i = 0; i < ARRAY_SIZE(mBuiltinHalCommands); i++) { 1197 const struct NanohubHalCommand *cmd = &mBuiltinHalCommands[i]; 1198 if (cmd->msg == msg) 1199 return cmd; 1200 } 1201 return NULL; 1202 } 1203