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 <seos_priv.h>
     43 #include <util.h>
     44 #include <mpu.h>
     45 #include <heap.h>
     46 #include <slab.h>
     47 #include <sensType.h>
     48 #include <timer.h>
     49 #include <appSec.h>
     50 #include <cpu.h>
     51 #include <cpu/cpuMath.h>
     52 #include <algos/ap_hub_sync.h>
     53 #include <sensors_priv.h>
     54 
     55 #include <chre.h>
     56 
     57 #define NANOHUB_COMMAND(_reason, _fastHandler, _handler, _minReqType, _maxReqType) \
     58         { .reason = _reason, .fastHandler = _fastHandler, .handler = _handler, \
     59           .minDataLen = sizeof(_minReqType), .maxDataLen = sizeof(_maxReqType) }
     60 
     61 #define NANOHUB_HAL_LEGACY_COMMAND(_msg, _handler) \
     62         { .msg = _msg, .handler = _handler }
     63 
     64 #define NANOHUB_HAL_COMMAND(_msg, _handler, _minReqType, _maxReqType) \
     65         { .msg = _msg, .handler = _handler, \
     66           .minDataLen = sizeof(_minReqType), .maxDataLen = sizeof(_maxReqType) }
     67 
     68 // maximum number of bytes to feed into appSecRxData at once
     69 // The bigger the number, the more time we block other event processing
     70 // appSecRxData only feeds 16 bytes at a time into writeCbk, so large
     71 // numbers don't buy us that much
     72 #define MAX_APP_SEC_RX_DATA_LEN 64
     73 
     74 #define REQUIRE_SIGNED_IMAGE    true
     75 #define DEBUG_APHUB_TIME_SYNC   false
     76 
     77 #if DEBUG_APHUB_TIME_SYNC
     78 static void syncDebugAdd(uint64_t, uint64_t);
     79 #endif
     80 
     81 struct DownloadState
     82 {
     83     struct AppSecState *appSecState;
     84     uint32_t size;      // document size, as reported by client
     85     uint32_t srcOffset; // bytes received from client
     86     uint32_t dstOffset; // bytes sent to flash
     87     struct AppHdr *start;     // start of flash segment, where to write
     88     uint32_t crc;       // document CRC-32, as reported by client
     89     uint32_t srcCrc;    // current state of CRC-32 we generate from input
     90     uint8_t  data[NANOHUB_PACKET_PAYLOAD_MAX];
     91     uint8_t  len;
     92     uint8_t  lenLeft;
     93     uint8_t  chunkReply;
     94     bool     erase;
     95     bool     eraseScheduled;
     96 };
     97 
     98 static struct DownloadState *mDownloadState;
     99 static AppSecErr mAppSecStatus;
    100 static struct AppHdr *mApp;
    101 static struct SlabAllocator *mEventSlab;
    102 static struct HostIntfDataBuffer mTxCurr, mTxNext;
    103 static uint8_t mTxCurrLength, mTxNextLength;
    104 static uint8_t mPrefetchActive, mPrefetchTx;
    105 static uint32_t mTxWakeCnt[2];
    106 static struct ApHubSync mTimeSync;
    107 
    108 static inline bool isSensorEvent(uint32_t evtType)
    109 {
    110     return evtType > EVT_NO_FIRST_SENSOR_EVENT && evtType <= EVT_NO_FIRST_SENSOR_EVENT + SENS_TYPE_LAST_USER;
    111 }
    112 
    113 static void slabFree(void *ptr)
    114 {
    115     slabAllocatorFree(mEventSlab, ptr);
    116 }
    117 
    118 void nanohubInitCommand(void)
    119 {
    120     mEventSlab = slabAllocatorNew(NANOHUB_PACKET_PAYLOAD_MAX-sizeof(__le32), 4, 2);
    121 }
    122 
    123 static inline uint64_t unaligned_u64(uint64_t *val) {
    124     uint64_t local;
    125     memcpy(&local, val, sizeof(local));
    126     return local;
    127 }
    128 
    129 static inline uint32_t unaligned_u32(uint32_t *val) {
    130     uint32_t local;
    131     memcpy(&local, val, sizeof(local));
    132     return local;
    133 }
    134 
    135 static uint32_t getOsHwVersion(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp)
    136 {
    137     struct NanohubOsHwVersionsResponse *resp = tx;
    138     resp->hwType = htole16(platHwType());
    139     resp->hwVer = htole16(platHwVer());
    140     resp->blVer = htole16(platBlVer());
    141     resp->osVer = htole16(OS_VER);
    142     resp->variantVer = htole32(VARIANT_VER);
    143 
    144     return sizeof(*resp);
    145 }
    146 
    147 static uint32_t getAppVersion(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp)
    148 {
    149     struct NanohubAppVersionsRequest *req = rx;
    150     struct NanohubAppVersionsResponse *resp = tx;
    151     uint32_t appIdx, appVer, appSize;
    152 
    153     if (osAppInfoById(le64toh(unaligned_u64(&req->appId)), &appIdx, &appVer, &appSize)) {
    154         resp->appVer = htole32(appVer);
    155         return sizeof(*resp);
    156     }
    157 
    158     return 0;
    159 }
    160 
    161 static uint32_t queryAppInfo(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp)
    162 {
    163     struct NanohubAppInfoRequest *req = rx;
    164     struct NanohubAppInfoResponse *resp = tx;
    165     uint64_t appId;
    166     uint32_t appVer, appSize;
    167 
    168     if (osAppInfoByIndex(le32toh(unaligned_u32(&req->appIdx)), &appId, &appVer, &appSize)) {
    169         resp->appId = htole64(appId);
    170         resp->appVer = htole32(appVer);
    171         resp->appSize = htole32(appSize);
    172         return sizeof(*resp);
    173     }
    174 
    175     return 0;
    176 }
    177 
    178 static AppSecErr writeCbk(const void *data, uint32_t len)
    179 {
    180     AppSecErr ret = APP_SEC_BAD;
    181 
    182     if (osWriteShared((uint8_t*)(mDownloadState->start) + mDownloadState->dstOffset, data, len)) {
    183         ret = APP_SEC_NO_ERROR;
    184         mDownloadState->dstOffset += len;
    185     }
    186 
    187     return ret;
    188 }
    189 
    190 static AppSecErr pubKeyFindCbk(const uint32_t *gotKey, bool *foundP)
    191 {
    192     const uint32_t *ptr;
    193     uint32_t numKeys, i;
    194 
    195     *foundP = false;
    196     ptr = BL.blGetPubKeysInfo(&numKeys);
    197     for (i = 0; ptr && i < numKeys; i++, ptr += RSA_LIMBS) {
    198         if (!memcmp(gotKey, ptr, RSA_BYTES)) {
    199             *foundP = true;
    200             break;
    201         }
    202     }
    203 
    204     return APP_SEC_NO_ERROR;
    205 }
    206 
    207 static AppSecErr osSecretKeyLookup(uint64_t keyId, void *keyBuf)
    208 {
    209     struct SeosEedataEncrKeyData kd;
    210     void *state = NULL;
    211 
    212     while(1) {
    213         uint32_t sz = sizeof(struct SeosEedataEncrKeyData);
    214 
    215         if (!eeDataGetAllVersions(EE_DATA_NAME_ENCR_KEY, &kd, &sz, &state))
    216             break;
    217 
    218         if (sz == sizeof(struct SeosEedataEncrKeyData) && kd.keyID == keyId) {
    219             if (keyBuf)
    220                 memcpy(keyBuf, kd.key, sizeof(kd.key));
    221             return APP_SEC_NO_ERROR;
    222         }
    223     }
    224 
    225     return APP_SEC_KEY_NOT_FOUND;
    226 }
    227 
    228 static AppSecErr osSecretKeyDelete(uint64_t keyId)
    229 {
    230     struct SeosEedataEncrKeyData kd;
    231     void *state = NULL;
    232     bool good = true;
    233     int count = 0;
    234 
    235     while(1) {
    236         uint32_t sz = sizeof(struct SeosEedataEncrKeyData);
    237         void *addr = eeDataGetAllVersions(EE_DATA_NAME_ENCR_KEY, &kd, &sz, &state);
    238 
    239         if (!addr)
    240             break;
    241 
    242         if (sz == sizeof(kd) && kd.keyID == keyId) {
    243             good = eeDataEraseOldVersion(EE_DATA_NAME_ENCR_KEY, addr) && good;
    244             count++;
    245         }
    246     }
    247 
    248     return count == 0 ? APP_SEC_KEY_NOT_FOUND : good ? APP_SEC_NO_ERROR : APP_SEC_BAD;
    249 }
    250 
    251 static AppSecErr osSecretKeyAdd(uint64_t keyId, void *keyBuf)
    252 {
    253     struct SeosEedataEncrKeyData kd;
    254 
    255     // do not add key if it already exists
    256     if (osSecretKeyLookup(keyId, NULL) != APP_SEC_KEY_NOT_FOUND)
    257         return APP_SEC_BAD;
    258 
    259     memcpy(&kd.key, keyBuf, 32);
    260     kd.keyID = keyId;
    261 
    262     return eeDataSet(EE_DATA_NAME_ENCR_KEY, &kd, sizeof(kd)) ? APP_SEC_NO_ERROR : APP_SEC_BAD;
    263 }
    264 
    265 static void freeDownloadState()
    266 {
    267     if (mDownloadState->appSecState)
    268         appSecDeinit(mDownloadState->appSecState);
    269     heapFree(mDownloadState);
    270     mDownloadState = NULL;
    271 }
    272 
    273 static bool resetDownloadState(bool initial, bool erase)
    274 {
    275     bool doCreate = true;
    276 
    277     mAppSecStatus = APP_SEC_NO_ERROR;
    278     if (mDownloadState->appSecState)
    279         appSecDeinit(mDownloadState->appSecState);
    280     mDownloadState->appSecState = appSecInit(writeCbk, pubKeyFindCbk, osSecretKeyLookup, REQUIRE_SIGNED_IMAGE);
    281     mDownloadState->srcOffset = 0;
    282     mDownloadState->srcCrc = ~0;
    283     if (!initial) {
    284         // if no data was written, we can reuse the same segment
    285         if (mDownloadState->dstOffset)
    286             osAppSegmentClose(mDownloadState->start, mDownloadState->dstOffset, SEG_ST_ERASED);
    287         else
    288             doCreate = false;
    289     }
    290     mDownloadState->dstOffset = 0;
    291     if (doCreate)
    292         mDownloadState->start = osAppSegmentCreate(mDownloadState->size);
    293     if (!mDownloadState->start) {
    294         if (erase)
    295             mDownloadState->erase = true;
    296         else
    297             return false;
    298     }
    299     return true;
    300 }
    301 
    302 static bool doStartFirmwareUpload(struct NanohubStartFirmwareUploadRequest *req, bool erase)
    303 {
    304     if (!mDownloadState) {
    305         mDownloadState = heapAlloc(sizeof(struct DownloadState));
    306 
    307         if (!mDownloadState)
    308             return false;
    309         else
    310             memset(mDownloadState, 0x00, sizeof(struct DownloadState));
    311     }
    312 
    313     mDownloadState->size = le32toh(req->size);
    314     mDownloadState->crc = le32toh(req->crc);
    315     mDownloadState->chunkReply = NANOHUB_FIRMWARE_CHUNK_REPLY_ACCEPTED;
    316     return resetDownloadState(true, erase);
    317 }
    318 
    319 static uint32_t startFirmwareUpload(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp)
    320 {
    321     struct NanohubStartFirmwareUploadRequest *req = rx;
    322     struct NanohubStartFirmwareUploadResponse *resp = tx;
    323 
    324     resp->accepted = doStartFirmwareUpload(req, true);
    325 
    326     return sizeof(*resp);
    327 }
    328 
    329 static void deferredUpdateOs(void *cookie)
    330 {
    331     const struct AppHdr *app = cookie;
    332     struct OsUpdateHdr *os = (struct OsUpdateHdr *)(&(app->hdr) + 1);
    333     uint32_t uploadStatus = OS_UPDT_HDR_CHECK_FAILED;
    334     uint8_t marker = OS_UPDT_MARKER_DOWNLOADED;
    335     struct Segment *seg = osGetSegment(app);
    336     uint32_t segSize = osSegmentGetSize(seg);
    337 
    338     osLog(LOG_INFO, "%s: checking OS image @ %p\n", __func__, os);
    339     // some sanity checks before asking BL to do image lookup
    340     hostIntfSetBusy(true);
    341     if (segSize >= (sizeof(*app) + sizeof(*os)) && segSize > os->size) {
    342         if (osWriteShared(&os->marker, &marker, sizeof(os->marker))) {
    343             wdtDisableClk();
    344             uploadStatus = BL.blVerifyOsUpdate();
    345             wdtEnableClk();
    346         } else {
    347             osLog(LOG_ERROR, "%s: could not set marker on OS image\n", __func__);
    348         }
    349     }
    350     hostIntfSetBusy(false);
    351     osLog(LOG_INFO, "%s: status=%" PRIu32 "\n", __func__, uploadStatus);
    352 }
    353 
    354 static AppSecErr updateKey(const struct AppHdr *app)
    355 {
    356     AppSecErr ret;
    357     struct KeyInfo *ki = (struct KeyInfo *)(&(app->hdr) + 1);
    358     uint8_t *data = (uint8_t *)(ki + 1);
    359     uint64_t keyId = KEY_ID_MAKE(APP_ID_GET_VENDOR(app->hdr.appId), ki->id);
    360     const char *op;
    361 
    362     if ((app->hdr.fwFlags & FL_KEY_HDR_DELETE) != 0) {
    363         // removing existing key
    364         ret = osSecretKeyDelete(keyId);
    365         op = "Removing";
    366     } else {
    367         // adding new key
    368         ret = osSecretKeyAdd(keyId, data);
    369         op = "Adding";
    370     }
    371     osLog(LOG_INFO, "%s: %s key: id=%016" PRIX64 "; ret=%" PRIu32 "\n",
    372           __func__, op, keyId, ret);
    373 
    374     return ret;
    375 }
    376 
    377 static uint32_t appSecErrToNanohubReply(AppSecErr status)
    378 {
    379     uint32_t reply;
    380 
    381     switch (status) {
    382     case APP_SEC_NO_ERROR:
    383         reply = NANOHUB_FIRMWARE_UPLOAD_SUCCESS;
    384         break;
    385     case APP_SEC_KEY_NOT_FOUND:
    386         reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_KEY_NOT_FOUND;
    387         break;
    388     case APP_SEC_HEADER_ERROR:
    389         reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_HEADER_ERROR;
    390         break;
    391     case APP_SEC_TOO_MUCH_DATA:
    392         reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_TOO_MUCH_DATA;
    393         break;
    394     case APP_SEC_TOO_LITTLE_DATA:
    395         reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_TOO_LITTLE_DATA;
    396         break;
    397     case APP_SEC_SIG_VERIFY_FAIL:
    398         reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_SIG_VERIFY_FAIL;
    399         break;
    400     case APP_SEC_SIG_DECODE_FAIL:
    401         reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_SIG_DECODE_FAIL;
    402         break;
    403     case APP_SEC_SIG_ROOT_UNKNOWN:
    404         reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_SIG_ROOT_UNKNOWN;
    405         break;
    406     case APP_SEC_MEMORY_ERROR:
    407         reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_MEMORY_ERROR;
    408         break;
    409     case APP_SEC_INVALID_DATA:
    410         reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_INVALID_DATA;
    411         break;
    412     case APP_SEC_VERIFY_FAILED:
    413         reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_VERIFY_FAILED;
    414         break;
    415     default:
    416         reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_BAD;
    417         break;
    418     }
    419     return reply;
    420 }
    421 
    422 static uint32_t firmwareFinish(bool valid)
    423 {
    424     struct AppHdr *app;
    425     struct Segment *storageSeg;
    426     uint32_t segState;
    427     uint32_t ret = NANOHUB_FIRMWARE_UPLOAD_SUCCESS;
    428 
    429     if (!mDownloadState) {
    430         ret = appSecErrToNanohubReply(mAppSecStatus);
    431         osLog(LOG_INFO, "%s: no DL status; decoding secure status: %" PRIu32 "\n", __func__, ret);
    432         return ret;
    433     }
    434 
    435     app = mDownloadState->start;
    436     storageSeg = osGetSegment(app);
    437 
    438     if (mAppSecStatus == APP_SEC_NO_ERROR && valid) {
    439         osLog(LOG_INFO, "%s: Secure verification passed\n", __func__);
    440         if (storageSeg->state != SEG_ST_RESERVED ||
    441                 mDownloadState->size < sizeof(struct FwCommonHdr) ||
    442                 app->hdr.magic != APP_HDR_MAGIC ||
    443                 app->hdr.fwVer != APP_HDR_VER_CUR) {
    444             segState = SEG_ST_ERASED;
    445             osLog(LOG_INFO, "%s: Header verification failed\n", __func__);
    446         } else {
    447             segState = SEG_ST_VALID;
    448         }
    449     } else {
    450         segState = SEG_ST_ERASED;
    451         osLog(LOG_INFO, "%s: Secure verification failed: valid=%d; status=%" PRIu32 "\n", __func__, valid, mAppSecStatus);
    452     }
    453 
    454     if (!osAppSegmentClose(app, mDownloadState->dstOffset, segState)) {
    455         osLog(LOG_INFO, "%s: Failed to close segment\n", __func__);
    456         valid = false;
    457         mApp = NULL;
    458     } else {
    459         segState = osAppSegmentGetState(app);
    460         mApp = app;
    461         valid = (segState == SEG_ST_VALID);
    462     }
    463     osLog(LOG_INFO, "Loaded %s image type %" PRIu8 ": %" PRIu32
    464                     " bytes @ %p; state=%02" PRIX32 "; crc=%08" PRIX32 "\n",
    465                     valid ? "valid" : "invalid",
    466                     app->hdr.payInfoType, mDownloadState->size,
    467                     mDownloadState->start, segState,
    468                     mApp ? osAppSegmentGetCrc(mApp) : 0xFFFFFFFF);
    469 
    470     freeDownloadState(); // no more access to mDownloadState
    471 
    472     if (!valid)
    473         ret = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_BAD;
    474 
    475     // take extra care about some special payload types
    476     if (ret == NANOHUB_FIRMWARE_UPLOAD_SUCCESS) {
    477         switch(app->hdr.payInfoType) {
    478         case LAYOUT_OS:
    479             osLog(LOG_INFO, "Performing OS update\n");
    480             // we want to give this message a chance to reach host before we start erasing stuff
    481             osDefer(deferredUpdateOs, (void*)app, false);
    482             break;
    483         case LAYOUT_KEY:
    484             ret = appSecErrToNanohubReply(updateKey(app));
    485             break;
    486         }
    487     }
    488 
    489     if (ret != NANOHUB_FIRMWARE_UPLOAD_SUCCESS || (app->hdr.fwFlags & FL_APP_HDR_VOLATILE)) {
    490         if ((app->hdr.fwFlags & FL_APP_HDR_SECURE))
    491             osAppWipeData((struct AppHdr*)app);
    492         osAppSegmentSetState(app, SEG_ST_ERASED);
    493     }
    494 
    495     // if any error happened after we downloaded and verified image, we say it is unknown fault
    496     // we don't have download status, so e have to save returned value in secure status field, because
    497     // host may request the same status multiple times
    498     if (ret != NANOHUB_FIRMWARE_UPLOAD_SUCCESS)
    499         mAppSecStatus = APP_SEC_BAD;
    500 
    501     return ret;
    502 }
    503 
    504 static void firmwareErase(void *cookie)
    505 {
    506     if (mDownloadState->erase == true) {
    507         osLog(LOG_INFO, "%s: erasing shared area\n", __func__);
    508         osEraseShared();
    509         mDownloadState->start = osAppSegmentCreate(mDownloadState->size);
    510         if (!mDownloadState->start)
    511             firmwareFinish(false);
    512         mDownloadState->erase = false;
    513         hostIntfSetInterrupt(NANOHUB_INT_CMD_WAIT);
    514     }
    515     mDownloadState->eraseScheduled = false;
    516 }
    517 
    518 SET_PACKED_STRUCT_MODE_ON
    519 struct FirmwareWriteCookie
    520 {
    521     uint32_t evtType;
    522     union {
    523 #ifdef LEGACY_HAL_ENABLED
    524         struct NanohubHalLegacyContUploadTx respLegacy;
    525 #endif
    526         struct NanohubHalContUploadTx resp;
    527     };
    528 } ATTRIBUTE_PACKED;
    529 SET_PACKED_STRUCT_MODE_OFF
    530 
    531 static void writeCookieFree(void *ptr)
    532 {
    533     struct FirmwareWriteCookie *buf = container_of(ptr, struct FirmwareWriteCookie, resp);
    534     heapFree(buf);
    535 }
    536 
    537 static void firmwareWrite(void *cookie)
    538 {
    539     bool valid;
    540     bool finished = false;
    541     struct FirmwareWriteCookie *resp = cookie;
    542     // only check crc when cookie is NULL (write came from kernel, not HAL)
    543     bool checkCrc = !cookie;
    544 
    545     if (mAppSecStatus == APP_SEC_NEED_MORE_TIME) {
    546         mAppSecStatus = appSecDoSomeProcessing(mDownloadState->appSecState);
    547     } else if (mDownloadState->lenLeft) {
    548         const uint8_t *data = mDownloadState->data + mDownloadState->len - mDownloadState->lenLeft;
    549         uint32_t len = mDownloadState->lenLeft, lenLeft, lenRem = 0;
    550 
    551         if (len > MAX_APP_SEC_RX_DATA_LEN) {
    552             lenRem = len - MAX_APP_SEC_RX_DATA_LEN;
    553             len = MAX_APP_SEC_RX_DATA_LEN;
    554         }
    555 
    556         mAppSecStatus = appSecRxData(mDownloadState->appSecState, data, len, &lenLeft);
    557         mDownloadState->lenLeft = lenLeft + lenRem;
    558     }
    559 
    560     valid = (mAppSecStatus == APP_SEC_NO_ERROR);
    561     if (mAppSecStatus == APP_SEC_NEED_MORE_TIME || mDownloadState->lenLeft) {
    562         osDefer(firmwareWrite, cookie, false);
    563         return;
    564     } else if (valid) {
    565         if (mDownloadState->srcOffset == mDownloadState->size) {
    566             mAppSecStatus = appSecRxDataOver(mDownloadState->appSecState);
    567             finished = true;
    568             valid = !checkCrc || mDownloadState->crc == ~mDownloadState->srcCrc;
    569         } else if (mDownloadState->srcOffset > mDownloadState->size) {
    570             valid = false;
    571         }
    572     }
    573     if (!valid)
    574         finished = true;
    575     if (finished) {
    576         if (firmwareFinish(valid) != NANOHUB_FIRMWARE_UPLOAD_SUCCESS)
    577             valid = false;
    578     }
    579     if (resp) {
    580         if (resp->evtType == EVT_APP_TO_HOST) {
    581 #ifdef LEGACY_HAL_ENABLED
    582             resp->respLegacy.success = valid;
    583             osEnqueueEvtOrFree(EVT_APP_TO_HOST, &resp->respLegacy, writeCookieFree);
    584 #endif
    585         } else {
    586             resp->resp.ret.status = !valid;
    587             osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, &resp->resp, writeCookieFree);
    588         }
    589     }
    590 }
    591 
    592 static uint32_t doFirmwareChunk(uint8_t *data, uint32_t offset, uint32_t len, void *cookie)
    593 {
    594     uint32_t reply, ret;
    595 
    596     if (!mDownloadState) {
    597         reply = NANOHUB_FIRMWARE_CHUNK_REPLY_CANCEL_NO_RETRY;
    598     } else if (mAppSecStatus == APP_SEC_NEED_MORE_TIME || mDownloadState->lenLeft) {
    599         reply = NANOHUB_FIRMWARE_CHUNK_REPLY_RESEND;
    600     } else if (mDownloadState->chunkReply != NANOHUB_FIRMWARE_CHUNK_REPLY_ACCEPTED) {
    601         reply = mDownloadState->chunkReply;
    602         firmwareFinish(false);
    603     } else {
    604         if (mDownloadState->erase == true) {
    605             reply = NANOHUB_FIRMWARE_CHUNK_REPLY_WAIT;
    606             if (!mDownloadState->eraseScheduled) {
    607                 ret = osExtAppStopAppsByAppId(APP_ID_ANY);
    608                 osLog(LOG_INFO, "%s: unloaded apps, ret=%08lx\n", __func__, ret);
    609                 mDownloadState->eraseScheduled = osDefer(firmwareErase, NULL, false);
    610             }
    611         } else if (!mDownloadState->start) {
    612             // this means we can't allocate enough space even after we did erase
    613             reply = NANOHUB_FIRMWARE_CHUNK_REPLY_CANCEL_NO_RETRY;
    614             firmwareFinish(false);
    615         } else if (offset != mDownloadState->srcOffset) {
    616             reply = NANOHUB_FIRMWARE_CHUNK_REPLY_RESTART;
    617             resetDownloadState(false, true);
    618         } else {
    619             if (!cookie)
    620                 mDownloadState->srcCrc = soft_crc32(data, len, mDownloadState->srcCrc);
    621             mDownloadState->srcOffset += len;
    622             memcpy(mDownloadState->data, data, len);
    623             mDownloadState->lenLeft = mDownloadState->len = len;
    624             reply = NANOHUB_FIRMWARE_CHUNK_REPLY_ACCEPTED;
    625             osDefer(firmwareWrite, cookie, false);
    626         }
    627     }
    628 
    629     return reply;
    630 }
    631 
    632 static uint32_t firmwareChunk(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp)
    633 {
    634     struct NanohubFirmwareChunkRequest *req = rx;
    635     struct NanohubFirmwareChunkResponse *resp = tx;
    636     uint32_t offset = le32toh(req->offset);
    637     uint8_t len = rx_len - sizeof(req->offset);
    638 
    639     resp->chunkReply = doFirmwareChunk(req->data, offset, len, NULL);
    640 
    641     return sizeof(*resp);
    642 }
    643 
    644 static uint32_t doFinishFirmwareUpload(uint32_t *addr, uint32_t *crc)
    645 {
    646     uint32_t reply;
    647 
    648     if (!mDownloadState) {
    649         reply = appSecErrToNanohubReply(mAppSecStatus);
    650         if (addr) {
    651             if (mApp)
    652                 *addr = (uint32_t)mApp;
    653             else
    654                 *addr = 0xFFFFFFFF;
    655         }
    656         if (crc) {
    657             if (mApp)
    658                 *crc = osAppSegmentGetCrc(mApp);
    659             else
    660                 *crc = 0xFFFFFFFF;
    661         }
    662     } else if (mDownloadState->srcOffset == mDownloadState->size) {
    663         reply = NANOHUB_FIRMWARE_UPLOAD_PROCESSING;
    664     } else {
    665         reply = firmwareFinish(false);
    666     }
    667 
    668     return reply;
    669 }
    670 
    671 static uint32_t finishFirmwareUpload(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp)
    672 {
    673     struct NanohubFinishFirmwareUploadResponse *resp = tx;
    674     resp->uploadReply = doFinishFirmwareUpload(NULL, NULL);
    675     if (resp->uploadReply != NANOHUB_FIRMWARE_UPLOAD_PROCESSING)
    676         osLog(LOG_INFO, "%s: reply=%" PRIu8 "\n", __func__, resp->uploadReply);
    677     return sizeof(*resp);
    678 }
    679 
    680 static uint32_t getInterrupt(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp)
    681 {
    682     struct NanohubGetInterruptRequest *req = rx;
    683     struct NanohubGetInterruptResponse *resp = tx;
    684     int i;
    685 
    686     if (rx_len == sizeof(struct NanohubGetInterruptRequest)) {
    687         for (i = 0; i < HOSTINTF_MAX_INTERRUPTS; i++) {
    688             if (req->clear[i/32] & (1UL << (i & 31)))
    689                 hostIntfClearInterrupt(i);
    690         }
    691     }
    692 
    693     hostIntfCopyInterrupts(resp->interrupts, HOSTINTF_MAX_INTERRUPTS);
    694 
    695     return sizeof(*resp);
    696 }
    697 
    698 static uint32_t maskInterrupt(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp)
    699 {
    700     struct NanohubMaskInterruptRequest *req = rx;
    701     struct NanohubMaskInterruptResponse *resp = tx;
    702 
    703     hostIntfSetInterruptMask(req->interrupt);
    704 
    705     resp->accepted = true;
    706     return sizeof(*resp);
    707 }
    708 
    709 static uint32_t unmaskInterrupt(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp)
    710 {
    711     struct NanohubUnmaskInterruptRequest *req = rx;
    712     struct NanohubUnmaskInterruptResponse *resp = tx;
    713 
    714     hostIntfClearInterruptMask(req->interrupt);
    715 
    716     resp->accepted = true;
    717     return sizeof(*resp);
    718 }
    719 
    720 static void addDelta(struct ApHubSync *sync, uint64_t apTime, uint64_t hubTime)
    721 {
    722 #if DEBUG_APHUB_TIME_SYNC
    723     syncDebugAdd(apTime, hubTime);
    724 #endif
    725     apHubSyncAddDelta(sync, apTime, hubTime);
    726 }
    727 
    728 static int64_t getAvgDelta(struct ApHubSync *sync)
    729 {
    730     return apHubSyncGetDelta(sync, sensorGetTime());
    731 }
    732 
    733 static int fillBuffer(void *tx, uint32_t totLength, uint32_t *wakeup, uint32_t *nonwakeup)
    734 {
    735     struct HostIntfDataBuffer *packet = &mTxNext;
    736     struct HostIntfDataBuffer *firstPacket = tx;
    737     uint8_t *buf = tx;
    738     uint32_t length;
    739     uint32_t prevWakeup, prevNonWakeup;
    740 
    741     prevWakeup = *wakeup;
    742     prevNonWakeup = *nonwakeup;
    743 
    744     while (hostIntfPacketDequeue(&mTxNext, wakeup, nonwakeup)) {
    745         length = packet->length + sizeof(packet->evtType);
    746         if (packet->sensType == SENS_TYPE_INVALID) {
    747             switch (packet->dataType) {
    748             case HOSTINTF_DATA_TYPE_APP_TO_HOST:
    749                 packet->evtType = htole32(EVT_APP_TO_HOST);
    750                 break;
    751             case HOSTINTF_DATA_TYPE_RESET_REASON:
    752                 packet->evtType = htole32(EVT_RESET_REASON);
    753                 break;
    754             case HOSTINTF_DATA_TYPE_APP_TO_SENSOR_HAL:
    755                 packet->evtType = htole32(EVT_APP_TO_SENSOR_HAL_DATA);
    756                 break;
    757 #ifdef DEBUG_LOG_EVT
    758             case HOSTINTF_DATA_TYPE_LOG:
    759                 packet->evtType = htole32(HOST_EVT_DEBUG_LOG);
    760                 break;
    761 #endif
    762             default:
    763                 packet->evtType = htole32(0x00000000);
    764                 break;
    765             }
    766         } else {
    767             packet->evtType = htole32(EVT_NO_FIRST_SENSOR_EVENT + packet->sensType);
    768             if (packet->referenceTime)
    769                 packet->referenceTime += getAvgDelta(&mTimeSync);
    770 
    771             if (*wakeup > 0)
    772                 packet->firstSample.interrupt = NANOHUB_INT_WAKEUP;
    773         }
    774 
    775         if ((!totLength || (isSensorEvent(firstPacket->evtType) && isSensorEvent(packet->evtType))) &&
    776              totLength + length <= sizeof(struct HostIntfDataBuffer)) {
    777             memcpy(buf + totLength, &mTxNext, length);
    778             totLength += length;
    779             if (isSensorEvent(packet->evtType) && packet->firstSample.interrupt == NANOHUB_INT_WAKEUP)
    780                 firstPacket->firstSample.interrupt = NANOHUB_INT_WAKEUP;
    781         } else {
    782             mTxNextLength = length;
    783             *wakeup = prevWakeup;
    784             *nonwakeup = prevNonWakeup;
    785             break;
    786         }
    787 
    788         prevWakeup = *wakeup;
    789         prevNonWakeup = *nonwakeup;
    790     }
    791 
    792     return totLength;
    793 }
    794 
    795 static void updateInterrupts(void)
    796 {
    797     uint32_t wakeup = atomicRead32bits(&mTxWakeCnt[0]);
    798     uint32_t nonwakeup = atomicRead32bits(&mTxWakeCnt[1]);
    799     bool wakeupStatus = hostIntfGetInterrupt(NANOHUB_INT_WAKEUP);
    800     bool nonwakeupStatus = hostIntfGetInterrupt(NANOHUB_INT_NONWAKEUP);
    801 
    802     if (!wakeup && wakeupStatus)
    803         hostIntfClearInterrupt(NANOHUB_INT_WAKEUP);
    804     else if (wakeup && !wakeupStatus)
    805         hostIntfSetInterrupt(NANOHUB_INT_WAKEUP);
    806 
    807     if (!nonwakeup && nonwakeupStatus)
    808         hostIntfClearInterrupt(NANOHUB_INT_NONWAKEUP);
    809     else if (nonwakeup && !nonwakeupStatus)
    810         hostIntfSetInterrupt(NANOHUB_INT_NONWAKEUP);
    811 }
    812 
    813 void nanohubPrefetchTx(uint32_t interrupt, uint32_t wakeup, uint32_t nonwakeup)
    814 {
    815     uint64_t state;
    816 
    817     if (wakeup < atomicRead32bits(&mTxWakeCnt[0]))
    818         wakeup = atomicRead32bits(&mTxWakeCnt[0]);
    819 
    820     if (nonwakeup < atomicRead32bits(&mTxWakeCnt[1]))
    821         nonwakeup = atomicRead32bits(&mTxWakeCnt[1]);
    822 
    823     if (interrupt == HOSTINTF_MAX_INTERRUPTS && !hostIntfGetInterrupt(NANOHUB_INT_WAKEUP) && !hostIntfGetInterrupt(NANOHUB_INT_NONWAKEUP))
    824         return;
    825 
    826     atomicWriteByte(&mPrefetchActive, 1);
    827 
    828     if (interrupt < HOSTINTF_MAX_INTERRUPTS)
    829         hostIntfSetInterrupt(interrupt);
    830 
    831     do {
    832         if (atomicReadByte(&mTxCurrLength) == 0 && mTxNextLength > 0) {
    833             memcpy(&mTxCurr, &mTxNext, mTxNextLength);
    834             atomicWriteByte(&mTxCurrLength, mTxNextLength);
    835             mTxNextLength = 0;
    836         }
    837 
    838         if (mTxNextLength == 0) {
    839             atomicWriteByte(&mTxCurrLength, fillBuffer(&mTxCurr, atomicReadByte(&mTxCurrLength), &wakeup, &nonwakeup));
    840             atomicWrite32bits(&mTxWakeCnt[0], wakeup);
    841             atomicWrite32bits(&mTxWakeCnt[1], nonwakeup);
    842         }
    843 
    844         atomicWriteByte(&mPrefetchActive, 0);
    845 
    846         if (atomicReadByte(&mPrefetchTx)) {
    847             state = cpuIntsOff();
    848 
    849             // interrupt occured during this call
    850             // take care of it
    851             hostIntfTxAck(&mTxCurr, atomicReadByte(&mTxCurrLength));
    852             atomicWriteByte(&mPrefetchTx, 0);
    853             atomicWriteByte(&mTxCurrLength, 0);
    854 
    855             cpuIntsRestore(state);
    856 
    857             updateInterrupts();
    858         } else {
    859             break;
    860         }
    861     } while (mTxNextLength > 0);
    862 }
    863 
    864 static void nanohubPrefetchTxDefer(void *cookie)
    865 {
    866     nanohubPrefetchTx(HOSTINTF_MAX_INTERRUPTS, 0, 0);
    867 }
    868 
    869 static uint32_t readEventFast(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp)
    870 {
    871     struct NanohubReadEventRequest *req = rx;
    872     uint8_t ret = 0;
    873 
    874     if (atomicReadByte(&mPrefetchActive)) {
    875         atomicWriteByte(&mPrefetchTx, 1);
    876         return NANOHUB_FAST_DONT_ACK;
    877     } else {
    878         if ((ret = atomicReadByte(&mTxCurrLength))) {
    879             addDelta(&mTimeSync, req->apBootTime, timestamp);
    880 
    881             memcpy(tx, &mTxCurr, ret);
    882             atomicWriteByte(&mTxCurrLength, 0);
    883 
    884             updateInterrupts();
    885             osDefer(nanohubPrefetchTxDefer, NULL, true);
    886         } else {
    887             return NANOHUB_FAST_UNHANDLED_ACK;
    888         }
    889     }
    890 
    891     return ret;
    892 }
    893 
    894 static uint32_t readEvent(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp)
    895 {
    896     struct NanohubReadEventRequest *req = rx;
    897     uint8_t *buf = tx;
    898     uint32_t length, wakeup, nonwakeup;
    899     uint32_t totLength = 0;
    900 
    901     addDelta(&mTimeSync, req->apBootTime, timestamp);
    902 
    903     if ((totLength = atomicReadByte(&mTxCurrLength))) {
    904         memcpy(tx, &mTxCurr, totLength);
    905         atomicWriteByte(&mTxCurrLength, 0);
    906         updateInterrupts();
    907         return totLength;
    908     }
    909 
    910     wakeup = atomicRead32bits(&mTxWakeCnt[0]);
    911     nonwakeup = atomicRead32bits(&mTxWakeCnt[1]);
    912 
    913     if (mTxNextLength > 0) {
    914         length = mTxNextLength;
    915         memcpy(buf, &mTxNext, length);
    916         totLength = length;
    917         mTxNextLength = 0;
    918     }
    919 
    920     totLength = fillBuffer(buf, totLength, &wakeup, &nonwakeup);
    921     atomicWrite32bits(&mTxWakeCnt[0], wakeup);
    922     atomicWrite32bits(&mTxWakeCnt[1], nonwakeup);
    923 
    924     if (totLength) {
    925         updateInterrupts();
    926     } else {
    927         hostIntfClearInterrupt(NANOHUB_INT_WAKEUP);
    928         hostIntfClearInterrupt(NANOHUB_INT_NONWAKEUP);
    929     }
    930 
    931     return totLength;
    932 }
    933 
    934 static bool forwardPacket(uint32_t event, void *data, size_t data_size,
    935                           void *hdr, size_t hdr_size, uint32_t tid)
    936 {
    937     bool res;
    938     uint8_t *hostPacket = data;
    939     uint8_t *packet = slabAllocatorAlloc(mEventSlab);
    940     EventFreeF free = slabFree;
    941 
    942     if (!packet) {
    943         packet = heapAlloc(data_size + hdr_size);
    944         free = heapFree;
    945     }
    946     if (!packet)
    947         return false;
    948 
    949     if (hdr && hdr_size)
    950         memcpy(packet, hdr, hdr_size);
    951 
    952     memcpy(packet + hdr_size, hostPacket, data_size);
    953     if (tid) {
    954         // send to specific TID
    955         res = osEnqueuePrivateEvt(event, packet, free, tid);
    956         if (!res)
    957             free(packet);
    958     } else {
    959         // broadcast to all
    960         res = osEnqueueEvtOrFree(event, packet, free);
    961     }
    962 
    963     return res;
    964 }
    965 
    966 static uint32_t writeEvent(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp)
    967 {
    968     struct NanohubWriteEventRequest *req = rx;
    969     struct NanohubWriteEventResponse *resp = tx;
    970     uint32_t tid;
    971     uint32_t event = le32toh(req->evtType);
    972 
    973     if (event == EVT_APP_FROM_HOST) {
    974         // old version of HAL; message_type is not delivered to CHRE apps
    975         struct HostMsgHdr *hostPacket = rx;
    976         if (rx_len >= sizeof(struct HostMsgHdr) &&
    977             rx_len == sizeof(struct HostMsgHdr) + hostPacket->len &&
    978             osTidById(&hostPacket->appId, &tid)) {
    979             resp->accepted = forwardPacket(event, hostPacket + 1, hostPacket->len,
    980                                            &hostPacket->len, sizeof(hostPacket->len), tid);
    981         } else {
    982             resp->accepted = false;
    983         }
    984     } else if (event == EVT_APP_FROM_HOST_CHRE) {
    985         // new version of HAL; full support for CHRE apps
    986         struct HostMsgHdrChreV10 *hostPacketV10 = rx;
    987         struct HostMsgHdrChre *hostPacket = rx;
    988         if (rx_len >= sizeof(struct HostMsgHdrChre) &&
    989             rx_len == sizeof(struct HostMsgHdrChre) + hostPacket->len &&
    990             osTidById(&hostPacket->appId, &tid)) {
    991             if (osAppChreVersion(tid) >= CHRE_API_VERSION_1_1) {
    992                 struct NanohubMsgChreHdr hdr = {
    993                     .size = hostPacket->len,
    994                     .endpoint = hostPacket->endpoint,
    995                     .appEvent = hostPacket->appEventId,
    996                 };
    997                 // CHRE app receives message in new format
    998                 resp->accepted = forwardPacket(event, hostPacket + 1, hostPacket->len,
    999                                                &hdr, sizeof(hdr), tid);
   1000             } else if (osAppChreVersion(tid) == CHRE_API_VERSION_1_0) {
   1001                 struct NanohubMsgChreHdrV10 hdr = {
   1002                     .size = hostPacket->len,
   1003                     .appEvent = hostPacket->appEventId,
   1004                 };
   1005                 // CHRE app receives message in new format
   1006                 resp->accepted = forwardPacket(event, hostPacket + 1, hostPacket->len,
   1007                                                &hdr, sizeof(hdr), tid);
   1008             } else {
   1009                 // legacy app receives message in old format
   1010                 resp->accepted = forwardPacket(EVT_APP_FROM_HOST, hostPacket + 1, hostPacket->len,
   1011                                                &hostPacket->len, sizeof(hostPacket->len), tid);
   1012             }
   1013         } else if (rx_len >= sizeof(struct HostMsgHdrChreV10) &&
   1014                    rx_len == sizeof(struct HostMsgHdrChreV10) + hostPacketV10->len &&
   1015                    osTidById(&hostPacketV10->appId, &tid)) {
   1016             if (osAppChreVersion(tid) >= CHRE_API_VERSION_1_1) {
   1017                 struct NanohubMsgChreHdr hdr = {
   1018                     .size = hostPacketV10->len,
   1019                     .endpoint = CHRE_HOST_ENDPOINT_UNSPECIFIED,
   1020                     .appEvent = hostPacketV10->appEventId,
   1021                 };
   1022                 // CHRE app receives message in new format
   1023                 resp->accepted = forwardPacket(event, hostPacketV10 + 1, hostPacketV10->len,
   1024                                                &hdr, sizeof(hdr), tid);
   1025             } else if (osAppChreVersion(tid) == CHRE_API_VERSION_1_0) {
   1026                 struct NanohubMsgChreHdrV10 hdr = {
   1027                     .size = hostPacketV10->len,
   1028                     .appEvent = hostPacketV10->appEventId,
   1029                 };
   1030                 // CHRE app receives message in new format
   1031                 resp->accepted = forwardPacket(event, hostPacketV10 + 1, hostPacketV10->len,
   1032                                                &hdr, sizeof(hdr), tid);
   1033             } else {
   1034                 // legacy app receives message in old format
   1035                 resp->accepted = forwardPacket(EVT_APP_FROM_HOST, hostPacketV10 + 1, hostPacketV10->len,
   1036                                                &hostPacketV10->len, sizeof(hostPacketV10->len), tid);
   1037             }
   1038         } else {
   1039             resp->accepted = false;
   1040         }
   1041     } else {
   1042         resp->accepted = forwardPacket(event,
   1043                                        req->evtData, rx_len - sizeof(req->evtType),
   1044                                        NULL, 0, 0);
   1045     }
   1046 
   1047     return sizeof(*resp);
   1048 }
   1049 
   1050 const static struct NanohubCommand mBuiltinCommands[] = {
   1051     NANOHUB_COMMAND(NANOHUB_REASON_GET_OS_HW_VERSIONS,
   1052                     getOsHwVersion,
   1053                     getOsHwVersion,
   1054                     struct NanohubOsHwVersionsRequest,
   1055                     struct NanohubOsHwVersionsRequest),
   1056     NANOHUB_COMMAND(NANOHUB_REASON_GET_APP_VERSIONS,
   1057                     NULL,
   1058                     getAppVersion,
   1059                     struct NanohubAppVersionsRequest,
   1060                     struct NanohubAppVersionsRequest),
   1061     NANOHUB_COMMAND(NANOHUB_REASON_QUERY_APP_INFO,
   1062                     NULL,
   1063                     queryAppInfo,
   1064                     struct NanohubAppInfoRequest,
   1065                     struct NanohubAppInfoRequest),
   1066     NANOHUB_COMMAND(NANOHUB_REASON_START_FIRMWARE_UPLOAD,
   1067                     NULL,
   1068                     startFirmwareUpload,
   1069                     struct NanohubStartFirmwareUploadRequest,
   1070                     struct NanohubStartFirmwareUploadRequest),
   1071     NANOHUB_COMMAND(NANOHUB_REASON_FIRMWARE_CHUNK,
   1072                     NULL,
   1073                     firmwareChunk,
   1074                     __le32,
   1075                     struct NanohubFirmwareChunkRequest),
   1076     NANOHUB_COMMAND(NANOHUB_REASON_FINISH_FIRMWARE_UPLOAD,
   1077                     NULL,
   1078                     finishFirmwareUpload,
   1079                     struct NanohubFinishFirmwareUploadRequest,
   1080                     struct NanohubFinishFirmwareUploadRequest),
   1081     NANOHUB_COMMAND(NANOHUB_REASON_GET_INTERRUPT,
   1082                     getInterrupt,
   1083                     getInterrupt,
   1084                     struct { },
   1085                     struct NanohubGetInterruptRequest),
   1086     NANOHUB_COMMAND(NANOHUB_REASON_MASK_INTERRUPT,
   1087                     maskInterrupt,
   1088                     maskInterrupt,
   1089                     struct NanohubMaskInterruptRequest,
   1090                     struct NanohubMaskInterruptRequest),
   1091     NANOHUB_COMMAND(NANOHUB_REASON_UNMASK_INTERRUPT,
   1092                     unmaskInterrupt,
   1093                     unmaskInterrupt,
   1094                     struct NanohubUnmaskInterruptRequest,
   1095                     struct NanohubUnmaskInterruptRequest),
   1096     NANOHUB_COMMAND(NANOHUB_REASON_READ_EVENT,
   1097                     readEventFast,
   1098                     readEvent,
   1099                     struct NanohubReadEventRequest,
   1100                     struct NanohubReadEventRequest),
   1101     NANOHUB_COMMAND(NANOHUB_REASON_WRITE_EVENT,
   1102                     writeEvent,
   1103                     writeEvent,
   1104                     __le32,
   1105                     struct NanohubWriteEventRequest),
   1106 };
   1107 
   1108 const struct NanohubCommand *nanohubFindCommand(uint32_t packetReason)
   1109 {
   1110     uint32_t i;
   1111 
   1112     for (i = 0; i < ARRAY_SIZE(mBuiltinCommands); i++) {
   1113         const struct NanohubCommand *cmd = &mBuiltinCommands[i];
   1114         if (cmd->reason == packetReason)
   1115             return cmd;
   1116     }
   1117     return NULL;
   1118 }
   1119 
   1120 #ifdef LEGACY_HAL_ENABLED
   1121 
   1122 static void halSendLegacyMgmtResponse(uint32_t cmd, uint32_t status)
   1123 {
   1124     struct NanohubHalLegacyMgmtTx *resp;
   1125 
   1126     resp = heapAlloc(sizeof(*resp));
   1127     if (resp) {
   1128         resp->hdr = (struct NanohubHalLegacyHdr) {
   1129             .appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0),
   1130             .len = sizeof(*resp) - sizeof(resp->hdr) + sizeof(resp->hdr.msg),
   1131             .msg = cmd,
   1132         };
   1133         resp->status = htole32(status);
   1134         osEnqueueEvtOrFree(EVT_APP_TO_HOST, resp, heapFree);
   1135     }
   1136 }
   1137 
   1138 static void halLegacyExtAppsOn(void *rx, uint8_t rx_len)
   1139 {
   1140     struct NanohubHalLegacyMgmtRx *req = rx;
   1141 
   1142     halSendLegacyMgmtResponse(NANOHUB_HAL_LEGACY_EXT_APPS_ON, osExtAppStartAppsByAppId(le64toh(unaligned_u64(&req->appId))));
   1143 }
   1144 
   1145 static void halLegacyExtAppsOff(void *rx, uint8_t rx_len)
   1146 {
   1147     struct NanohubHalLegacyMgmtRx *req = rx;
   1148 
   1149     halSendLegacyMgmtResponse(NANOHUB_HAL_LEGACY_EXT_APPS_OFF, osExtAppStopAppsByAppId(le64toh(unaligned_u64(&req->appId))));
   1150 }
   1151 
   1152 static void halLegacyExtAppDelete(void *rx, uint8_t rx_len)
   1153 {
   1154     struct NanohubHalLegacyMgmtRx *req = rx;
   1155 
   1156     halSendLegacyMgmtResponse(NANOHUB_HAL_LEGACY_EXT_APP_DELETE, osExtAppEraseAppsByAppId(le64toh(unaligned_u64(&req->appId))));
   1157 }
   1158 
   1159 static void halLegacyQueryMemInfo(void *rx, uint8_t rx_len)
   1160 {
   1161 }
   1162 
   1163 static void halLegacyQueryApps(void *rx, uint8_t rx_len)
   1164 {
   1165     struct NanohubHalLegacyQueryAppsRx *req = rx;
   1166     struct NanohubHalLegacyQueryAppsTx *resp;
   1167     struct NanohubHalLegacyHdr *hdr;
   1168     uint64_t appId;
   1169     uint32_t appVer, appSize;
   1170 
   1171     if (osExtAppInfoByIndex(le32toh(req->idx), &appId, &appVer, &appSize)) {
   1172         resp = heapAlloc(sizeof(*resp));
   1173         if (resp) {
   1174             resp->hdr.appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0);
   1175             resp->hdr.len = sizeof(*resp) - sizeof(struct NanohubHalLegacyHdr) + 1;
   1176             resp->hdr.msg = NANOHUB_HAL_LEGACY_QUERY_APPS;
   1177             resp->appId = appId;
   1178             resp->version = appVer;
   1179             resp->flashUse = appSize;
   1180             resp->ramUse = 0;
   1181             osEnqueueEvtOrFree(EVT_APP_TO_HOST, resp, heapFree);
   1182         }
   1183     } else {
   1184         hdr = heapAlloc(sizeof(*hdr));
   1185         if (hdr) {
   1186             hdr->appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0);
   1187             hdr->len = 1;
   1188             hdr->msg = NANOHUB_HAL_LEGACY_QUERY_APPS;
   1189             osEnqueueEvtOrFree(EVT_APP_TO_HOST, hdr, heapFree);
   1190         }
   1191     }
   1192 }
   1193 
   1194 static void halLegacyQueryRsaKeys(void *rx, uint8_t rx_len)
   1195 {
   1196     struct NanohubHalLegacyQueryRsaKeysRx *req = rx;
   1197     struct NanohubHalLegacyQueryRsaKeysTx *resp;
   1198     int len = 0;
   1199     const uint32_t *ptr;
   1200     uint32_t numKeys;
   1201 
   1202     if (!(resp = heapAlloc(sizeof(*resp) + NANOHUB_RSA_KEY_CHUNK_LEN)))
   1203         return;
   1204 
   1205     ptr = BL.blGetPubKeysInfo(&numKeys);
   1206     if (ptr && numKeys * RSA_BYTES > req->offset) {
   1207         len = numKeys * RSA_BYTES - req->offset;
   1208         if (len > NANOHUB_RSA_KEY_CHUNK_LEN)
   1209             len = NANOHUB_RSA_KEY_CHUNK_LEN;
   1210         memcpy(resp->data, (uint8_t *)ptr + req->offset, len);
   1211     }
   1212 
   1213     resp->hdr.appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0);
   1214     resp->hdr.len = sizeof(*resp) - sizeof(struct NanohubHalLegacyHdr) + 1 + len;
   1215     resp->hdr.msg = NANOHUB_HAL_LEGACY_QUERY_RSA_KEYS;
   1216 
   1217     osEnqueueEvtOrFree(EVT_APP_TO_HOST, resp, heapFree);
   1218 }
   1219 
   1220 static void halLegacyStartUpload(void *rx, uint8_t rx_len)
   1221 {
   1222     struct NanohubHalLegacyStartUploadRx *req = rx;
   1223     struct NanohubStartFirmwareUploadRequest hwReq = {
   1224         .size = req->length
   1225     };
   1226     struct NanohubHalLegacyStartUploadTx *resp;
   1227 
   1228     if (!(resp = heapAlloc(sizeof(*resp))))
   1229         return;
   1230 
   1231     resp->hdr.appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0);
   1232     resp->hdr.len = sizeof(*resp) - sizeof(struct NanohubHalLegacyHdr) + 1;
   1233     resp->hdr.msg = NANOHUB_HAL_LEGACY_START_UPLOAD;
   1234     resp->success = doStartFirmwareUpload(&hwReq, true);
   1235 
   1236     osEnqueueEvtOrFree(EVT_APP_TO_HOST, resp, heapFree);
   1237 }
   1238 
   1239 static void halLegacyContUpload(void *rx, uint8_t rx_len)
   1240 {
   1241     uint32_t offset;
   1242     uint32_t reply;
   1243     uint8_t len;
   1244     struct NanohubHalLegacyContUploadRx *req = rx;
   1245     struct FirmwareWriteCookie *cookie;
   1246 
   1247     if (!(cookie = heapAlloc(sizeof(*cookie))))
   1248         return;
   1249 
   1250     cookie->evtType = EVT_APP_TO_HOST;
   1251     cookie->respLegacy.hdr = (struct NanohubHalLegacyHdr) {
   1252         .appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0),
   1253         .len = sizeof(cookie->respLegacy) - sizeof(struct NanohubHalLegacyHdr) + 1,
   1254         .msg = NANOHUB_HAL_LEGACY_CONT_UPLOAD,
   1255     };
   1256     cookie->respLegacy.success = false;
   1257 
   1258     if (!mDownloadState) {
   1259         reply = NANOHUB_FIRMWARE_CHUNK_REPLY_CANCEL_NO_RETRY;
   1260     } else {
   1261         offset = le32toh(req->offset);
   1262         len = rx_len - sizeof(req->offset);
   1263         reply = doFirmwareChunk(req->data, offset, len, cookie);
   1264     }
   1265     if (reply != NANOHUB_FIRMWARE_CHUNK_REPLY_ACCEPTED) {
   1266         osLog(LOG_ERROR, "%s: reply=%" PRIu32 "\n", __func__, reply);
   1267 
   1268         osEnqueueEvtOrFree(EVT_APP_TO_HOST, &cookie->respLegacy, writeCookieFree);
   1269     }
   1270 }
   1271 
   1272 static void halLegacyFinishUpload(void *rx, uint8_t rx_len)
   1273 {
   1274     struct NanohubHalLegacyFinishUploadTx *resp;
   1275     uint32_t reply;
   1276 
   1277     if (!(resp = heapAlloc(sizeof(*resp))))
   1278         return;
   1279 
   1280     resp->hdr.appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0);
   1281     resp->hdr.len = sizeof(*resp) - sizeof(struct NanohubHalLegacyHdr) + 1;
   1282     resp->hdr.msg = NANOHUB_HAL_LEGACY_FINISH_UPLOAD;
   1283 
   1284     reply = doFinishFirmwareUpload(NULL, NULL);
   1285 
   1286     osLog(LOG_INFO, "%s: reply=%" PRIu32 "\n", __func__, reply);
   1287 
   1288     resp->success = (reply == NANOHUB_FIRMWARE_UPLOAD_SUCCESS);
   1289 
   1290     osEnqueueEvtOrFree(EVT_APP_TO_HOST, resp, heapFree);
   1291 }
   1292 
   1293 static void halLegacyReboot(void *rx, uint8_t rx_len)
   1294 {
   1295     BL.blReboot();
   1296 }
   1297 
   1298 const static struct NanohubHalLegacyCommand mBuiltinHalLegacyCommands[] = {
   1299     NANOHUB_HAL_LEGACY_COMMAND(NANOHUB_HAL_LEGACY_EXT_APPS_ON,
   1300                             halLegacyExtAppsOn),
   1301     NANOHUB_HAL_LEGACY_COMMAND(NANOHUB_HAL_LEGACY_EXT_APPS_OFF,
   1302                             halLegacyExtAppsOff),
   1303     NANOHUB_HAL_LEGACY_COMMAND(NANOHUB_HAL_LEGACY_EXT_APP_DELETE,
   1304                             halLegacyExtAppDelete),
   1305     NANOHUB_HAL_LEGACY_COMMAND(NANOHUB_HAL_LEGACY_QUERY_MEMINFO,
   1306                             halLegacyQueryMemInfo),
   1307     NANOHUB_HAL_LEGACY_COMMAND(NANOHUB_HAL_LEGACY_QUERY_APPS,
   1308                             halLegacyQueryApps),
   1309     NANOHUB_HAL_LEGACY_COMMAND(NANOHUB_HAL_LEGACY_QUERY_RSA_KEYS,
   1310                             halLegacyQueryRsaKeys),
   1311     NANOHUB_HAL_LEGACY_COMMAND(NANOHUB_HAL_LEGACY_START_UPLOAD,
   1312                             halLegacyStartUpload),
   1313     NANOHUB_HAL_LEGACY_COMMAND(NANOHUB_HAL_LEGACY_CONT_UPLOAD,
   1314                             halLegacyContUpload),
   1315     NANOHUB_HAL_LEGACY_COMMAND(NANOHUB_HAL_LEGACY_FINISH_UPLOAD,
   1316                             halLegacyFinishUpload),
   1317     NANOHUB_HAL_LEGACY_COMMAND(NANOHUB_HAL_LEGACY_REBOOT,
   1318                             halLegacyReboot),
   1319 };
   1320 
   1321 const struct NanohubHalLegacyCommand *nanohubHalLegacyFindCommand(uint8_t msg)
   1322 {
   1323     uint32_t i;
   1324 
   1325     for (i = 0; i < ARRAY_SIZE(mBuiltinHalLegacyCommands); i++) {
   1326         const struct NanohubHalLegacyCommand *cmd = &mBuiltinHalLegacyCommands[i];
   1327         if (cmd->msg == msg)
   1328             return cmd;
   1329     }
   1330     return NULL;
   1331 }
   1332 
   1333 #endif /* LEGACY_HAL_ENABLED */
   1334 
   1335 static void halSendAppMgmtResponse(struct NanohubHalAppMgmtRx *req, uint32_t status, struct MgmtStatus stat, uint32_t transactionId)
   1336 {
   1337     struct NanohubHalAppMgmtTx *resp;
   1338 
   1339     resp = heapAlloc(sizeof(*resp));
   1340     if (resp) {
   1341         resp->hdr = (struct NanohubHalHdr) {
   1342             .appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0),
   1343             .len = sizeof(*resp) - sizeof(resp->hdr),
   1344             .transactionId = transactionId,
   1345         };
   1346         resp->ret = (struct NanohubHalRet) {
   1347             .msg = NANOHUB_HAL_APP_MGMT,
   1348             .status = htole32(status),
   1349         };
   1350         resp->cmd = req->cmd;
   1351         resp->stat = stat;
   1352         osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree);
   1353     }
   1354 }
   1355 
   1356 static void halAppMgmt(void *rx, uint8_t rx_len, uint32_t transactionId)
   1357 {
   1358     struct NanohubHalAppMgmtRx *req = rx;
   1359     struct MgmtStatus stat;
   1360     uint32_t ret;
   1361 
   1362     switch (req->cmd) {
   1363     case NANOHUB_HAL_APP_MGMT_START:
   1364         stat.value= osExtAppStartAppsByAppId(le64toh(unaligned_u64(&req->appId)));
   1365         ret = stat.op > 0 ? 0 : -1;
   1366         break;
   1367     case NANOHUB_HAL_APP_MGMT_STOP:
   1368         stat.value = osExtAppStopAppsByAppId(le64toh(unaligned_u64(&req->appId)));
   1369         ret = stat.op > 0 ? 0 : -1;
   1370         break;
   1371     case NANOHUB_HAL_APP_MGMT_UNLOAD:
   1372         stat.value = osExtAppStopAppsByAppId(le64toh(unaligned_u64(&req->appId)));
   1373         ret = stat.op > 0 ? 0 : -1;
   1374         break;
   1375     case NANOHUB_HAL_APP_MGMT_DELETE:
   1376         stat.value = osExtAppEraseAppsByAppId(le64toh(unaligned_u64(&req->appId)));
   1377         ret = stat.erase > 0 ? 0 : -1;
   1378         break;
   1379     default:
   1380         return;
   1381     }
   1382 
   1383     halSendAppMgmtResponse(req, ret, stat, transactionId);
   1384 }
   1385 
   1386 static void deferHalSysMgmtErase(void *cookie)
   1387 {
   1388     struct NanohubHalSysMgmtTx *resp = cookie;
   1389 
   1390     bool success = osEraseShared();
   1391 
   1392     if (success)
   1393         resp->ret.status = htole32(0);
   1394     else
   1395         resp->ret.status = htole32(-1);
   1396 
   1397     osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree);
   1398 }
   1399 
   1400 static void halSysMgmt(void *rx, uint8_t rx_len, uint32_t transactionId)
   1401 {
   1402     struct NanohubHalSysMgmtRx *req = rx;
   1403     struct NanohubHalSysMgmtTx *resp;
   1404     uint32_t ret = 0;
   1405 
   1406     if (!(resp = heapAlloc(sizeof(*resp))))
   1407         return;
   1408 
   1409     resp->hdr = (struct NanohubHalHdr) {
   1410         .appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0),
   1411         .len = sizeof(*resp) - sizeof(resp->hdr),
   1412         .transactionId = transactionId,
   1413     };
   1414     resp->ret = (struct NanohubHalRet) {
   1415         .msg = NANOHUB_HAL_SYS_MGMT,
   1416     };
   1417     resp->cmd = req->cmd;
   1418 
   1419     switch (req->cmd) {
   1420     case NANOHUB_HAL_SYS_MGMT_ERASE:
   1421         ret = osExtAppStopAppsByAppId(APP_ID_ANY);
   1422         osLog(LOG_INFO, "%s: unloaded apps, ret=%08lx\n", __func__, ret);
   1423         // delay to make sure all apps are unloaded before erasing
   1424         if (osDefer(deferHalSysMgmtErase, resp, false) == false) {
   1425             resp->ret.status = htole32(-1);
   1426             osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree);
   1427         }
   1428         break;
   1429     case NANOHUB_HAL_SYS_MGMT_REBOOT:
   1430         BL.blReboot();
   1431         break;
   1432     default:
   1433         resp->ret.status = htole32(-1);
   1434         osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree);
   1435     }
   1436 }
   1437 
   1438 static bool copyTLV64(uint8_t *buf, size_t *offset, size_t max_len, uint8_t tag, uint64_t val)
   1439 {
   1440     if (*offset + sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint64_t) > max_len)
   1441         return false;
   1442     buf[(*offset)++] = tag;
   1443     buf[(*offset)++] = sizeof(uint64_t);
   1444     memcpy(&buf[*offset], &val, sizeof(uint64_t));
   1445     *offset += sizeof(uint64_t);
   1446     return true;
   1447 }
   1448 
   1449 static bool copyTLV32(uint8_t *buf, size_t *offset, size_t max_len, uint8_t tag, uint32_t val)
   1450 {
   1451     if (*offset + sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint32_t) > max_len)
   1452         return false;
   1453     buf[(*offset)++] = tag;
   1454     buf[(*offset)++] = sizeof(uint32_t);
   1455     memcpy(&buf[*offset], &val, sizeof(uint32_t));
   1456     *offset += sizeof(uint32_t);
   1457     return true;
   1458 }
   1459 
   1460 static bool copyTLV8(uint8_t *buf, size_t *offset, size_t max_len, uint8_t tag, uint8_t val)
   1461 {
   1462     if (*offset + sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint8_t) > max_len)
   1463         return false;
   1464     buf[(*offset)++] = tag;
   1465     buf[(*offset)++] = sizeof(uint8_t);
   1466     memcpy(&buf[*offset], &val, sizeof(uint8_t));
   1467     *offset += sizeof(uint8_t);
   1468     return true;
   1469 }
   1470 
   1471 static bool copyTLVEmpty(uint8_t *buf, size_t *offset, size_t max_len, uint8_t tag)
   1472 {
   1473     if (*offset + sizeof(uint8_t) + sizeof(uint8_t) > max_len)
   1474         return false;
   1475     buf[(*offset)++] = tag;
   1476     buf[(*offset)++] = 0;
   1477     return true;
   1478 }
   1479 
   1480 static int processAppTags(const struct AppHdr *app, uint32_t crc, uint32_t size, uint8_t *data, uint8_t *tags, int cnt, bool req_tid)
   1481 {
   1482     int i;
   1483     size_t offset = 0;
   1484     const size_t max_len = HOST_HUB_CHRE_PACKET_MAX_LEN - sizeof(struct NanohubHalRet);
   1485     bool success = true;
   1486     uint32_t tid;
   1487     bool tid_valid = false;
   1488     struct Task *task;
   1489 
   1490     if (app->hdr.magic != APP_HDR_MAGIC ||
   1491         app->hdr.fwVer != APP_HDR_VER_CUR ||
   1492         (app->hdr.fwFlags & FL_APP_HDR_APPLICATION) == 0 ||
   1493         app->hdr.payInfoType != LAYOUT_APP) {
   1494         return 0;
   1495     }
   1496 
   1497     if (osTidById(&app->hdr.appId, &tid)) {
   1498         tid_valid = true;
   1499         task = osTaskFindByTid(tid);
   1500         if (task) {
   1501             if (task->app != app)
   1502                 tid_valid = false;
   1503         } else
   1504             tid_valid = false;
   1505     }
   1506 
   1507     if (!tid_valid && req_tid)
   1508         return 0;
   1509 
   1510     for (i=0; i<cnt && success; i++) {
   1511         switch(tags[i]) {
   1512         case NANOHUB_HAL_APP_INFO_APPID:
   1513             success = copyTLV64(data, &offset, max_len, tags[i], app->hdr.appId);
   1514             break;
   1515         case NANOHUB_HAL_APP_INFO_CRC:
   1516             if (size)
   1517                 success = copyTLV32(data, &offset, max_len, tags[i], crc);
   1518             else
   1519                 success = copyTLVEmpty(data, &offset, max_len, tags[i]);
   1520             break;
   1521         case NANOHUB_HAL_APP_INFO_TID:
   1522             if (tid_valid)
   1523                 success = copyTLV32(data, &offset, max_len, tags[i], tid);
   1524             else
   1525                 success = copyTLVEmpty(data, &offset, max_len, tags[i]);
   1526             break;
   1527         case NANOHUB_HAL_APP_INFO_VERSION:
   1528             success = copyTLV32(data, &offset, max_len, tags[i], app->hdr.appVer);
   1529             break;
   1530         case NANOHUB_HAL_APP_INFO_ADDR:
   1531             success = copyTLV32(data, &offset, max_len, tags[i], (uint32_t)app);
   1532             break;
   1533         case NANOHUB_HAL_APP_INFO_SIZE:
   1534             if (size)
   1535                 success = copyTLV32(data, &offset, max_len, tags[i], size);
   1536             else
   1537                 success = copyTLVEmpty(data, &offset, max_len, tags[i]);
   1538             break;
   1539         case NANOHUB_HAL_APP_INFO_HEAP:
   1540             if (tid_valid)
   1541                 success = copyTLV32(data, &offset, max_len, tags[i], heapGetTaskSize(tid));
   1542             else
   1543                 success = copyTLVEmpty(data, &offset, max_len, tags[i]);
   1544             break;
   1545         case NANOHUB_HAL_APP_INFO_DATA:
   1546             success = copyTLV32(data, &offset, max_len, tags[i], app->sect.got_end - app->sect.data_start);
   1547             break;
   1548         case NANOHUB_HAL_APP_INFO_BSS:
   1549             success = copyTLV32(data, &offset, max_len, tags[i], app->sect.bss_end - app->sect.bss_start);
   1550             break;
   1551         case NANOHUB_HAL_APP_INFO_CHRE_MAJOR:
   1552             if (app->hdr.fwFlags & FL_APP_HDR_CHRE)
   1553                 success = copyTLV8(data, &offset, max_len, tags[i],
   1554                     (app->hdr.chreApiMajor == 0xFF && app->hdr.chreApiMinor == 0xFF) ? 0x01 :
   1555                         app->hdr.chreApiMajor);
   1556             else
   1557                 success = copyTLVEmpty(data, &offset, max_len, tags[i]);
   1558             break;
   1559         case NANOHUB_HAL_APP_INFO_CHRE_MINOR:
   1560             if (app->hdr.fwFlags & FL_APP_HDR_CHRE)
   1561                 success = copyTLV8(data, &offset, max_len, tags[i],
   1562                     (app->hdr.chreApiMajor == 0xFF && app->hdr.chreApiMinor == 0xFF) ? 0x00 :
   1563                         app->hdr.chreApiMinor);
   1564             else
   1565                 success = copyTLVEmpty(data, &offset, max_len, tags[i]);
   1566             break;
   1567         case NANOHUB_HAL_APP_INFO_END:
   1568         default:
   1569             success = false;
   1570             copyTLVEmpty(data, &offset, max_len, NANOHUB_HAL_APP_INFO_END);
   1571             break;
   1572         }
   1573     }
   1574 
   1575     return offset;
   1576 }
   1577 
   1578 static void halAppInfo(void *rx, uint8_t rx_len, uint32_t transactionId)
   1579 {
   1580     struct NanohubHalAppInfoRx *req = rx;
   1581     struct NanohubHalAppInfoTx *resp;
   1582     struct SegmentIterator it;
   1583     uint32_t state;
   1584     int ret, i;
   1585     uint32_t sharedSize, numApps;
   1586     const struct AppHdr *internal;
   1587     const uint8_t *shared;
   1588 
   1589     if (!(resp = heapAlloc(sizeof(*resp))))
   1590         return;
   1591 
   1592     resp->hdr = (struct NanohubHalHdr) {
   1593         .appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0),
   1594         .len = sizeof(*resp) - sizeof(resp->hdr) - sizeof(resp->data),
   1595         .transactionId = transactionId,
   1596     };
   1597     resp->ret = (struct NanohubHalRet) {
   1598         .msg = NANOHUB_HAL_APP_INFO,
   1599     };
   1600 
   1601     shared = platGetSharedAreaInfo(&sharedSize);
   1602     internal = platGetInternalAppList(&numApps);
   1603 
   1604     if ((le32toh(req->addr) >= (uint32_t)shared && le32toh(req->addr) < (uint32_t)shared + sharedSize) ||
   1605         (le32toh(req->addr) < (uint32_t)shared &&
   1606             ((uint32_t)shared < (uint32_t)internal ||
   1607                 (numApps > 0 && le32toh(req->addr) > (uint32_t)(internal+numApps-1))))) {
   1608         osSegmentIteratorInit(&it);
   1609         while (osSegmentIteratorNext(&it)) {
   1610             state = osSegmentGetState(it.seg);
   1611             switch (state) {
   1612             case SEG_ST_EMPTY:
   1613             case SEG_ST_RESERVED:
   1614                  osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree);
   1615                  return;
   1616             case SEG_ST_ERASED:
   1617             case SEG_ST_VALID:
   1618                 if (le32toh(req->addr) <= (uint32_t)osSegmentGetData(it.seg)) {
   1619                     ret = processAppTags(osSegmentGetData(it.seg), osSegmentGetCrc(it.seg), osSegmentGetSize(it.seg), resp->data, req->tags, rx_len - 4, state == SEG_ST_ERASED);
   1620                     if (ret > 0) {
   1621                         resp->hdr.len += ret;
   1622                         osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree);
   1623                         return;
   1624                     }
   1625                 }
   1626                 break;
   1627             }
   1628         }
   1629     } else {
   1630         for (i = 0; i < numApps; i++, internal++) {
   1631             if (le32toh(req->addr) <= (uint32_t)internal) {
   1632                 ret = processAppTags(internal, 0, 0, resp->data, req->tags, rx_len - 4, false);
   1633                 if (ret > 0) {
   1634                     resp->hdr.len += ret;
   1635                     osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree);
   1636                     return;
   1637                 }
   1638             }
   1639         }
   1640     }
   1641 
   1642     osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree);
   1643 }
   1644 
   1645 static void halSysInfo(void *rx, uint8_t rx_len, uint32_t transactionId)
   1646 {
   1647     extern uint8_t __code_start[];
   1648     extern uint8_t __code_end[];
   1649     extern uint8_t __text_end[];
   1650     extern uint8_t __ram_start[];
   1651     extern uint8_t __ram_end[];
   1652 
   1653     struct NanohubHalSysInfoRx *req = rx;
   1654     struct NanohubHalSysInfoTx *resp;
   1655     int i;
   1656     size_t offset = 0;
   1657     const size_t max_len = HOST_HUB_CHRE_PACKET_MAX_LEN - sizeof(struct NanohubHalRet);
   1658     bool success = true;
   1659     int free, chunks, largest;
   1660     uint32_t shared_size;
   1661 
   1662     free = heapGetFreeSize(&chunks, &largest);
   1663 
   1664     if (!(resp = heapAlloc(sizeof(*resp))))
   1665         return;
   1666 
   1667     resp->hdr = (struct NanohubHalHdr) {
   1668         .appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0),
   1669         .len = sizeof(*resp) - sizeof(resp->hdr) - sizeof(resp->data),
   1670         .transactionId = transactionId,
   1671     };
   1672     resp->ret = (struct NanohubHalRet) {
   1673         .msg = NANOHUB_HAL_SYS_INFO,
   1674     };
   1675 
   1676     for (i=0; i<rx_len && success; i++) {
   1677         switch(req->tags[i]) {
   1678         case NANOHUB_HAL_SYS_INFO_HEAP_FREE:
   1679             if (free >= 0)
   1680                 success = copyTLV32(resp->data, &offset, max_len, req->tags[i], free);
   1681             else
   1682                 success = copyTLVEmpty(resp->data, &offset, max_len, req->tags[i]);
   1683             break;
   1684         case NANOHUB_HAL_SYS_INFO_RAM_SIZE:
   1685             success = copyTLV32(resp->data, &offset, max_len, req->tags[i], __ram_end - __ram_start);
   1686             break;
   1687         case NANOHUB_HAL_SYS_INFO_EEDATA_SIZE:
   1688             success = copyTLV32(resp->data, &offset, max_len, req->tags[i], eeDataGetSize());
   1689             break;
   1690         case NANOHUB_HAL_SYS_INFO_EEDATA_FREE:
   1691             success = copyTLV32(resp->data, &offset, max_len, req->tags[i], eeDataGetFree());
   1692             break;
   1693         case NANOHUB_HAL_SYS_INFO_CODE_SIZE:
   1694             success = copyTLV32(resp->data, &offset, max_len, req->tags[i], __code_end - __code_start);
   1695             break;
   1696         case NANOHUB_HAL_SYS_INFO_CODE_FREE:
   1697             success = copyTLV32(resp->data, &offset, max_len, req->tags[i], __code_end - __text_end);
   1698             break;
   1699         case NANOHUB_HAL_SYS_INFO_SHARED_SIZE:
   1700             platGetSharedAreaInfo(&shared_size);
   1701             success = copyTLV32(resp->data, &offset, max_len, req->tags[i], shared_size);
   1702             break;
   1703         case NANOHUB_HAL_SYS_INFO_SHARED_FREE:
   1704             success = copyTLV32(resp->data, &offset, max_len, req->tags[i], osSegmentGetFree());
   1705             break;
   1706         case NANOHUB_HAL_SYS_INFO_END:
   1707         default:
   1708             success = false;
   1709             copyTLVEmpty(resp->data, &offset, max_len, NANOHUB_HAL_APP_INFO_END);
   1710             break;
   1711         }
   1712     }
   1713 
   1714     resp->hdr.len += offset;
   1715 
   1716     osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree);
   1717 }
   1718 
   1719 static void halKeyInfo(void *rx, uint8_t rx_len, uint32_t transactionId)
   1720 {
   1721     struct NanohubHalKeyInfoRx *req = rx;
   1722     struct NanohubHalKeyInfoTx *resp;
   1723     const uint32_t *ptr;
   1724     uint32_t numKeys;
   1725     uint32_t dataLength;
   1726 
   1727     if (!(resp = heapAlloc(sizeof(*resp))))
   1728         return;
   1729 
   1730     ptr = BL.blGetPubKeysInfo(&numKeys);
   1731 
   1732     resp->hdr = (struct NanohubHalHdr) {
   1733         .appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0),
   1734         .len = sizeof(*resp) - sizeof(resp->hdr) - sizeof(resp->data),
   1735         .transactionId = transactionId,
   1736     };
   1737     resp->ret = (struct NanohubHalRet) {
   1738         .msg = NANOHUB_HAL_KEY_INFO,
   1739     };
   1740 
   1741     resp->keyLength = 0;
   1742 
   1743     if (ptr && req->keyNum < numKeys) {
   1744         if (req->dataOffset < RSA_BYTES) {
   1745             resp->keyLength = RSA_BYTES;
   1746             if (RSA_BYTES - req->dataOffset > NANOHUB_RSA_KEY_CHUNK_LEN)
   1747                 dataLength = NANOHUB_RSA_KEY_CHUNK_LEN;
   1748             else
   1749                 dataLength = RSA_BYTES - req->dataOffset;
   1750             memcpy(resp->data, (const uint8_t *)ptr + (req->keyNum * RSA_BYTES) + req->dataOffset, dataLength);
   1751             resp->hdr.len += dataLength;
   1752         }
   1753     }
   1754 
   1755     osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree);
   1756 }
   1757 
   1758 static void halStartUpload(void *rx, uint8_t rx_len, uint32_t transactionId)
   1759 {
   1760     struct NanohubHalStartUploadRx *req = rx;
   1761     struct NanohubStartFirmwareUploadRequest hwReq = {
   1762         .size = req->length
   1763     };
   1764     struct NanohubHalStartUploadTx *resp;
   1765 
   1766     if (!(resp = heapAlloc(sizeof(*resp))))
   1767         return;
   1768 
   1769     resp->hdr = (struct NanohubHalHdr) {
   1770         .appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0),
   1771         .len = sizeof(*resp) - sizeof(resp->hdr),
   1772         .transactionId = transactionId,
   1773     };
   1774 
   1775     resp->ret.msg = NANOHUB_HAL_START_UPLOAD;
   1776     if (doStartFirmwareUpload(&hwReq, false))
   1777         resp->ret.status = NANOHUB_FIRMWARE_CHUNK_REPLY_ACCEPTED;
   1778     else
   1779         resp->ret.status = NANOHUB_FIRMWARE_CHUNK_REPLY_NO_SPACE;
   1780 
   1781     osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree);
   1782 }
   1783 
   1784 static void halContUpload(void *rx, uint8_t rx_len, uint32_t transactionId)
   1785 {
   1786     uint32_t offset;
   1787     uint32_t reply;
   1788     uint8_t len;
   1789     struct NanohubHalContUploadRx *req = rx;
   1790     struct FirmwareWriteCookie *cookie;
   1791 
   1792     if (!(cookie = heapAlloc(sizeof(*cookie))))
   1793         return;
   1794 
   1795     cookie->evtType = EVT_APP_TO_HOST_CHRE;
   1796     cookie->resp.hdr = (struct NanohubHalHdr) {
   1797         .appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0),
   1798         .len = sizeof(cookie->resp) - sizeof(cookie->resp.hdr),
   1799         .transactionId = transactionId,
   1800     };
   1801     cookie->resp.ret = (struct NanohubHalRet) {
   1802         .msg = NANOHUB_HAL_CONT_UPLOAD,
   1803     };
   1804 
   1805     if (!mDownloadState) {
   1806         reply = NANOHUB_FIRMWARE_CHUNK_REPLY_CANCEL_NO_RETRY;
   1807     } else {
   1808         offset = le32toh(req->offset);
   1809         len = rx_len - sizeof(req->offset);
   1810         reply = doFirmwareChunk(req->data, offset, len, cookie);
   1811     }
   1812     if (reply != NANOHUB_FIRMWARE_CHUNK_REPLY_ACCEPTED) {
   1813         osLog(LOG_ERROR, "%s: reply=%" PRIu32 "\n", __func__, reply);
   1814 
   1815         cookie->resp.ret.status = reply;
   1816 
   1817         osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, &cookie->resp, writeCookieFree);
   1818     }
   1819 }
   1820 
   1821 static void halFinishUpload(void *rx, uint8_t rx_len, uint32_t transactionId)
   1822 {
   1823     struct NanohubHalFinishUploadTx *resp;
   1824     uint32_t reply;
   1825     uint32_t addr = 0xFFFFFFFF;
   1826     uint32_t crc = 0xFFFFFFFF;
   1827 
   1828     if (!(resp = heapAlloc(sizeof(*resp))))
   1829         return;
   1830 
   1831     resp->hdr = (struct NanohubHalHdr) {
   1832         .appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0),
   1833         .len = sizeof(*resp) - sizeof(resp->hdr),
   1834         .transactionId = transactionId,
   1835     };
   1836 
   1837     reply = doFinishFirmwareUpload(&addr, &crc);
   1838 
   1839     osLog(LOG_INFO, "%s: reply=%" PRIu32 "\n", __func__, reply);
   1840 
   1841     resp->ret = (struct NanohubHalRet) {
   1842         .msg = NANOHUB_HAL_FINISH_UPLOAD,
   1843         .status = reply,
   1844     };
   1845 
   1846     resp->addr = addr;
   1847     resp->crc = crc;
   1848 
   1849     osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree);
   1850 }
   1851 
   1852 const static struct NanohubHalCommand mBuiltinHalCommands[] = {
   1853     NANOHUB_HAL_COMMAND(NANOHUB_HAL_APP_MGMT,
   1854                             halAppMgmt,
   1855                             struct NanohubHalAppMgmtRx,
   1856                             struct NanohubHalAppMgmtRx),
   1857     NANOHUB_HAL_COMMAND(NANOHUB_HAL_SYS_MGMT,
   1858                             halSysMgmt,
   1859                             struct NanohubHalSysMgmtRx,
   1860                             struct NanohubHalSysMgmtRx),
   1861     NANOHUB_HAL_COMMAND(NANOHUB_HAL_APP_INFO,
   1862                             halAppInfo,
   1863                             __le32,
   1864                             struct NanohubHalAppInfoRx),
   1865     NANOHUB_HAL_COMMAND(NANOHUB_HAL_SYS_INFO,
   1866                             halSysInfo,
   1867                             struct { },
   1868                             struct NanohubHalSysInfoRx),
   1869     NANOHUB_HAL_COMMAND(NANOHUB_HAL_KEY_INFO,
   1870                             halKeyInfo,
   1871                             struct NanohubHalKeyInfoRx,
   1872                             struct NanohubHalKeyInfoRx),
   1873     NANOHUB_HAL_COMMAND(NANOHUB_HAL_START_UPLOAD,
   1874                             halStartUpload,
   1875                             struct NanohubHalStartUploadRx,
   1876                             struct NanohubHalStartUploadRx),
   1877     NANOHUB_HAL_COMMAND(NANOHUB_HAL_CONT_UPLOAD,
   1878                             halContUpload,
   1879                             __le32,
   1880                             struct NanohubHalContUploadRx),
   1881     NANOHUB_HAL_COMMAND(NANOHUB_HAL_FINISH_UPLOAD,
   1882                             halFinishUpload,
   1883                             struct { },
   1884                             struct { }),
   1885 };
   1886 
   1887 const struct NanohubHalCommand *nanohubHalFindCommand(uint8_t msg)
   1888 {
   1889     uint32_t i;
   1890 
   1891     for (i = 0; i < ARRAY_SIZE(mBuiltinHalCommands); i++) {
   1892         const struct NanohubHalCommand *cmd = &mBuiltinHalCommands[i];
   1893         if (cmd->msg == msg)
   1894             return cmd;
   1895     }
   1896     return NULL;
   1897 }
   1898 
   1899 
   1900 int64_t hostGetTimeDelta(void)
   1901 {
   1902     int64_t delta = getAvgDelta(&mTimeSync);
   1903 
   1904     if (delta == INT64_MIN)
   1905         return 0ULL;
   1906     else
   1907         return delta;
   1908 }
   1909 
   1910 uint64_t hostGetTime(void)
   1911 {
   1912     int64_t delta = getAvgDelta(&mTimeSync);
   1913 
   1914     if (!delta || delta == INT64_MIN)
   1915         return 0ULL;
   1916     else
   1917         return sensorGetTime() + delta;
   1918 }
   1919 
   1920 #if DEBUG_APHUB_TIME_SYNC
   1921 
   1922 #define N_APHUB_SYNC_DATA 256
   1923 #define PRINT_DELAY 20000000  // unit ns, 20ms
   1924 struct ApHubSyncDebug {
   1925     uint64_t apFirst;
   1926     uint64_t hubFirst;
   1927     uint32_t apDelta[N_APHUB_SYNC_DATA]; // us
   1928     uint32_t hubDelta[N_APHUB_SYNC_DATA]; // us
   1929     int printIndex; //negative means not printing
   1930     int writeIndex;
   1931 
   1932     uint32_t printTimer;
   1933 };
   1934 
   1935 static struct ApHubSyncDebug mApHubSyncDebug;
   1936 
   1937 static void syncDebugCallback(uint32_t timerId, void *data)
   1938 {
   1939 
   1940     if (mApHubSyncDebug.printIndex >= mApHubSyncDebug.writeIndex ||
   1941         mApHubSyncDebug.printIndex >= N_APHUB_SYNC_DATA) {
   1942         timTimerCancel(mApHubSyncDebug.printTimer);
   1943 
   1944         osLog(LOG_DEBUG, "APHUB Done printing %d items", mApHubSyncDebug.printIndex);
   1945         mApHubSyncDebug.writeIndex = 0;
   1946         mApHubSyncDebug.printIndex = -1;
   1947 
   1948         mApHubSyncDebug.printTimer = 0;
   1949     } else {
   1950         if (mApHubSyncDebug.printIndex == 0) {
   1951             osLog(LOG_DEBUG, "APHUB init %" PRIu64 " %" PRIu64,
   1952                   mApHubSyncDebug.apFirst,
   1953                   mApHubSyncDebug.hubFirst);
   1954         }
   1955 
   1956         osLog(LOG_DEBUG, "APHUB %d %" PRIu32 " %" PRIu32,
   1957               mApHubSyncDebug.printIndex,
   1958               mApHubSyncDebug.apDelta[mApHubSyncDebug.printIndex],
   1959               mApHubSyncDebug.hubDelta[mApHubSyncDebug.printIndex]);
   1960 
   1961         mApHubSyncDebug.printIndex++;
   1962     }
   1963 }
   1964 
   1965 static void syncDebugTriggerPrint()
   1966 {
   1967     if (mApHubSyncDebug.printTimer) {
   1968         //printing already going
   1969         return;
   1970     }
   1971 
   1972     mApHubSyncDebug.printIndex = 0;
   1973 
   1974     syncDebugCallback(0, NULL);
   1975     if (!(mApHubSyncDebug.printTimer =
   1976           timTimerSet(PRINT_DELAY, 0, 50, syncDebugCallback, NULL, false /*oneShot*/))) {
   1977         osLog(LOG_WARN, "Cannot get timer for printing");
   1978 
   1979         mApHubSyncDebug.writeIndex = 0; // discard all data
   1980         mApHubSyncDebug.printIndex = -1; // not printing
   1981     }
   1982 }
   1983 
   1984 static void syncDebugAdd(uint64_t ap, uint64_t hub)
   1985 {
   1986     if (mApHubSyncDebug.writeIndex >= N_APHUB_SYNC_DATA) {
   1987         //full
   1988         syncDebugTriggerPrint();
   1989         return;
   1990     }
   1991 
   1992     if (mApHubSyncDebug.writeIndex == 0) {
   1993         mApHubSyncDebug.apFirst = ap;
   1994         mApHubSyncDebug.hubFirst = hub;
   1995     }
   1996 
   1997     // convert ns to us
   1998     mApHubSyncDebug.apDelta[mApHubSyncDebug.writeIndex] =
   1999             (uint32_t) U64_DIV_BY_CONST_U16((ap - mApHubSyncDebug.apFirst), 1000u);
   2000     mApHubSyncDebug.hubDelta[mApHubSyncDebug.writeIndex] =
   2001             (uint32_t) U64_DIV_BY_CONST_U16((hub - mApHubSyncDebug.hubFirst), 1000u);
   2002 
   2003     ++mApHubSyncDebug.writeIndex;
   2004 }
   2005 #endif
   2006