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