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