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/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