| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <inttypes.h> |
| #include <string.h> |
| #include <stdint.h> |
| #include <sys/endian.h> |
| |
| #include <variant/variant.h> |
| #include <eventnums.h> |
| |
| #include <plat/taggedPtr.h> |
| #include <plat/plat.h> |
| #include <plat/wdt.h> |
| |
| #include <nanohub/crc.h> |
| #include <nanohub/rsa.h> |
| #include <nanohub/nanohub.h> |
| |
| #include <bl.h> |
| #include <atomicBitset.h> |
| #include <atomic.h> |
| #include <hostIntf.h> |
| #include <hostIntf_priv.h> |
| #include <nanohubCommand.h> |
| #include <nanohubPacket.h> |
| #include <eeData.h> |
| #include <seos.h> |
| #include <seos_priv.h> |
| #include <util.h> |
| #include <mpu.h> |
| #include <heap.h> |
| #include <slab.h> |
| #include <sensType.h> |
| #include <timer.h> |
| #include <appSec.h> |
| #include <cpu.h> |
| #include <cpu/cpuMath.h> |
| #include <algos/ap_hub_sync.h> |
| #include <sensors_priv.h> |
| |
| #include <chre.h> |
| |
| #define NANOHUB_COMMAND(_reason, _fastHandler, _handler, _minReqType, _maxReqType) \ |
| { .reason = _reason, .fastHandler = _fastHandler, .handler = _handler, \ |
| .minDataLen = sizeof(_minReqType), .maxDataLen = sizeof(_maxReqType) } |
| |
| #define NANOHUB_HAL_LEGACY_COMMAND(_msg, _handler) \ |
| { .msg = _msg, .handler = _handler } |
| |
| #define NANOHUB_HAL_COMMAND(_msg, _handler, _minReqType, _maxReqType) \ |
| { .msg = _msg, .handler = _handler, \ |
| .minDataLen = sizeof(_minReqType), .maxDataLen = sizeof(_maxReqType) } |
| |
| // maximum number of bytes to feed into appSecRxData at once |
| // The bigger the number, the more time we block other event processing |
| // appSecRxData only feeds 16 bytes at a time into writeCbk, so large |
| // numbers don't buy us that much |
| #define MAX_APP_SEC_RX_DATA_LEN 64 |
| |
| #define REQUIRE_SIGNED_IMAGE true |
| #define DEBUG_APHUB_TIME_SYNC false |
| |
| #if DEBUG_APHUB_TIME_SYNC |
| static void syncDebugAdd(uint64_t, uint64_t); |
| #endif |
| |
| struct DownloadState |
| { |
| struct AppSecState *appSecState; |
| uint32_t size; // document size, as reported by client |
| uint32_t srcOffset; // bytes received from client |
| uint32_t dstOffset; // bytes sent to flash |
| struct AppHdr *start; // start of flash segment, where to write |
| uint32_t crc; // document CRC-32, as reported by client |
| uint32_t srcCrc; // current state of CRC-32 we generate from input |
| uint8_t data[NANOHUB_PACKET_PAYLOAD_MAX]; |
| uint8_t len; |
| uint8_t lenLeft; |
| uint8_t chunkReply; |
| bool erase; |
| bool eraseScheduled; |
| }; |
| |
| static struct DownloadState *mDownloadState; |
| static AppSecErr mAppSecStatus; |
| static struct AppHdr *mApp; |
| static struct SlabAllocator *mEventSlab; |
| static struct HostIntfDataBuffer mTxCurr, mTxNext; |
| static uint8_t mTxCurrLength, mTxNextLength; |
| static uint8_t mPrefetchActive, mPrefetchTx; |
| static uint32_t mTxWakeCnt[2]; |
| static struct ApHubSync mTimeSync; |
| |
| static inline bool isSensorEvent(uint32_t evtType) |
| { |
| return evtType > EVT_NO_FIRST_SENSOR_EVENT && evtType <= EVT_NO_FIRST_SENSOR_EVENT + SENS_TYPE_LAST_USER; |
| } |
| |
| static void slabFree(void *ptr) |
| { |
| slabAllocatorFree(mEventSlab, ptr); |
| } |
| |
| void nanohubInitCommand(void) |
| { |
| mEventSlab = slabAllocatorNew(NANOHUB_PACKET_PAYLOAD_MAX-sizeof(__le32), 4, 2); |
| } |
| |
| static inline uint64_t unaligned_u64(uint64_t *val) { |
| uint64_t local; |
| memcpy(&local, val, sizeof(local)); |
| return local; |
| } |
| |
| static inline uint32_t unaligned_u32(uint32_t *val) { |
| uint32_t local; |
| memcpy(&local, val, sizeof(local)); |
| return local; |
| } |
| |
| static uint32_t getOsHwVersion(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp) |
| { |
| struct NanohubOsHwVersionsResponse *resp = tx; |
| resp->hwType = htole16(platHwType()); |
| resp->hwVer = htole16(platHwVer()); |
| resp->blVer = htole16(platBlVer()); |
| resp->osVer = htole16(OS_VER); |
| resp->variantVer = htole32(VARIANT_VER); |
| |
| return sizeof(*resp); |
| } |
| |
| static uint32_t getAppVersion(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp) |
| { |
| struct NanohubAppVersionsRequest *req = rx; |
| struct NanohubAppVersionsResponse *resp = tx; |
| uint32_t appIdx, appVer, appSize; |
| |
| if (osAppInfoById(le64toh(unaligned_u64(&req->appId)), &appIdx, &appVer, &appSize)) { |
| resp->appVer = htole32(appVer); |
| return sizeof(*resp); |
| } |
| |
| return 0; |
| } |
| |
| static uint32_t queryAppInfo(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp) |
| { |
| struct NanohubAppInfoRequest *req = rx; |
| struct NanohubAppInfoResponse *resp = tx; |
| uint64_t appId; |
| uint32_t appVer, appSize; |
| |
| if (osAppInfoByIndex(le32toh(unaligned_u32(&req->appIdx)), &appId, &appVer, &appSize)) { |
| resp->appId = htole64(appId); |
| resp->appVer = htole32(appVer); |
| resp->appSize = htole32(appSize); |
| return sizeof(*resp); |
| } |
| |
| return 0; |
| } |
| |
| static AppSecErr writeCbk(const void *data, uint32_t len) |
| { |
| AppSecErr ret = APP_SEC_BAD; |
| |
| if (osWriteShared((uint8_t*)(mDownloadState->start) + mDownloadState->dstOffset, data, len)) { |
| ret = APP_SEC_NO_ERROR; |
| mDownloadState->dstOffset += len; |
| } |
| |
| return ret; |
| } |
| |
| static AppSecErr pubKeyFindCbk(const uint32_t *gotKey, bool *foundP) |
| { |
| const uint32_t *ptr; |
| uint32_t numKeys, i; |
| |
| *foundP = false; |
| ptr = BL.blGetPubKeysInfo(&numKeys); |
| for (i = 0; ptr && i < numKeys; i++, ptr += RSA_LIMBS) { |
| if (!memcmp(gotKey, ptr, RSA_BYTES)) { |
| *foundP = true; |
| break; |
| } |
| } |
| |
| return APP_SEC_NO_ERROR; |
| } |
| |
| static AppSecErr osSecretKeyLookup(uint64_t keyId, void *keyBuf) |
| { |
| struct SeosEedataEncrKeyData kd; |
| void *state = NULL; |
| |
| while(1) { |
| uint32_t sz = sizeof(struct SeosEedataEncrKeyData); |
| |
| if (!eeDataGetAllVersions(EE_DATA_NAME_ENCR_KEY, &kd, &sz, &state)) |
| break; |
| |
| if (sz == sizeof(struct SeosEedataEncrKeyData) && kd.keyID == keyId) { |
| if (keyBuf) |
| memcpy(keyBuf, kd.key, sizeof(kd.key)); |
| return APP_SEC_NO_ERROR; |
| } |
| } |
| |
| return APP_SEC_KEY_NOT_FOUND; |
| } |
| |
| static AppSecErr osSecretKeyDelete(uint64_t keyId) |
| { |
| struct SeosEedataEncrKeyData kd; |
| void *state = NULL; |
| bool good = true; |
| int count = 0; |
| |
| while(1) { |
| uint32_t sz = sizeof(struct SeosEedataEncrKeyData); |
| void *addr = eeDataGetAllVersions(EE_DATA_NAME_ENCR_KEY, &kd, &sz, &state); |
| |
| if (!addr) |
| break; |
| |
| if (sz == sizeof(kd) && kd.keyID == keyId) { |
| good = eeDataEraseOldVersion(EE_DATA_NAME_ENCR_KEY, addr) && good; |
| count++; |
| } |
| } |
| |
| return count == 0 ? APP_SEC_KEY_NOT_FOUND : good ? APP_SEC_NO_ERROR : APP_SEC_BAD; |
| } |
| |
| static AppSecErr osSecretKeyAdd(uint64_t keyId, void *keyBuf) |
| { |
| struct SeosEedataEncrKeyData kd; |
| |
| // do not add key if it already exists |
| if (osSecretKeyLookup(keyId, NULL) != APP_SEC_KEY_NOT_FOUND) |
| return APP_SEC_BAD; |
| |
| memcpy(&kd.key, keyBuf, 32); |
| kd.keyID = keyId; |
| |
| return eeDataSet(EE_DATA_NAME_ENCR_KEY, &kd, sizeof(kd)) ? APP_SEC_NO_ERROR : APP_SEC_BAD; |
| } |
| |
| static void freeDownloadState() |
| { |
| if (mDownloadState->appSecState) |
| appSecDeinit(mDownloadState->appSecState); |
| heapFree(mDownloadState); |
| mDownloadState = NULL; |
| } |
| |
| static bool resetDownloadState(bool initial, bool erase) |
| { |
| bool doCreate = true; |
| |
| mAppSecStatus = APP_SEC_NO_ERROR; |
| if (mDownloadState->appSecState) |
| appSecDeinit(mDownloadState->appSecState); |
| mDownloadState->appSecState = appSecInit(writeCbk, pubKeyFindCbk, osSecretKeyLookup, REQUIRE_SIGNED_IMAGE); |
| mDownloadState->srcOffset = 0; |
| mDownloadState->srcCrc = ~0; |
| if (!initial) { |
| // if no data was written, we can reuse the same segment |
| if (mDownloadState->dstOffset) |
| osAppSegmentClose(mDownloadState->start, mDownloadState->dstOffset, SEG_ST_ERASED); |
| else |
| doCreate = false; |
| } |
| mDownloadState->dstOffset = 0; |
| if (doCreate) |
| mDownloadState->start = osAppSegmentCreate(mDownloadState->size); |
| if (!mDownloadState->start) { |
| if (erase) |
| mDownloadState->erase = true; |
| else |
| return false; |
| } |
| return true; |
| } |
| |
| static bool doStartFirmwareUpload(struct NanohubStartFirmwareUploadRequest *req, bool erase) |
| { |
| if (!mDownloadState) { |
| mDownloadState = heapAlloc(sizeof(struct DownloadState)); |
| |
| if (!mDownloadState) |
| return false; |
| else |
| memset(mDownloadState, 0x00, sizeof(struct DownloadState)); |
| } |
| |
| mDownloadState->size = le32toh(req->size); |
| mDownloadState->crc = le32toh(req->crc); |
| mDownloadState->chunkReply = NANOHUB_FIRMWARE_CHUNK_REPLY_ACCEPTED; |
| return resetDownloadState(true, erase); |
| } |
| |
| static uint32_t startFirmwareUpload(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp) |
| { |
| struct NanohubStartFirmwareUploadRequest *req = rx; |
| struct NanohubStartFirmwareUploadResponse *resp = tx; |
| |
| resp->accepted = doStartFirmwareUpload(req, true); |
| |
| return sizeof(*resp); |
| } |
| |
| static void deferredUpdateOs(void *cookie) |
| { |
| const struct AppHdr *app = cookie; |
| struct OsUpdateHdr *os = (struct OsUpdateHdr *)(&(app->hdr) + 1); |
| uint32_t uploadStatus = OS_UPDT_HDR_CHECK_FAILED; |
| uint8_t marker = OS_UPDT_MARKER_DOWNLOADED; |
| struct Segment *seg = osGetSegment(app); |
| uint32_t segSize = osSegmentGetSize(seg); |
| |
| osLog(LOG_INFO, "%s: checking OS image @ %p\n", __func__, os); |
| // some sanity checks before asking BL to do image lookup |
| hostIntfSetBusy(true); |
| if (segSize >= (sizeof(*app) + sizeof(*os)) && segSize > os->size) { |
| if (osWriteShared(&os->marker, &marker, sizeof(os->marker))) { |
| wdtDisableClk(); |
| uploadStatus = BL.blVerifyOsUpdate(); |
| wdtEnableClk(); |
| } else { |
| osLog(LOG_ERROR, "%s: could not set marker on OS image\n", __func__); |
| } |
| } |
| hostIntfSetBusy(false); |
| osLog(LOG_INFO, "%s: status=%" PRIu32 "\n", __func__, uploadStatus); |
| } |
| |
| static AppSecErr updateKey(const struct AppHdr *app) |
| { |
| AppSecErr ret; |
| struct KeyInfo *ki = (struct KeyInfo *)(&(app->hdr) + 1); |
| uint8_t *data = (uint8_t *)(ki + 1); |
| uint64_t keyId = KEY_ID_MAKE(APP_ID_GET_VENDOR(app->hdr.appId), ki->id); |
| const char *op; |
| |
| if ((app->hdr.fwFlags & FL_KEY_HDR_DELETE) != 0) { |
| // removing existing key |
| ret = osSecretKeyDelete(keyId); |
| op = "Removing"; |
| } else { |
| // adding new key |
| ret = osSecretKeyAdd(keyId, data); |
| op = "Adding"; |
| } |
| osLog(LOG_INFO, "%s: %s key: id=%016" PRIX64 "; ret=%" PRIu32 "\n", |
| __func__, op, keyId, ret); |
| |
| return ret; |
| } |
| |
| static uint32_t appSecErrToNanohubReply(AppSecErr status) |
| { |
| uint32_t reply; |
| |
| switch (status) { |
| case APP_SEC_NO_ERROR: |
| reply = NANOHUB_FIRMWARE_UPLOAD_SUCCESS; |
| break; |
| case APP_SEC_KEY_NOT_FOUND: |
| reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_KEY_NOT_FOUND; |
| break; |
| case APP_SEC_HEADER_ERROR: |
| reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_HEADER_ERROR; |
| break; |
| case APP_SEC_TOO_MUCH_DATA: |
| reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_TOO_MUCH_DATA; |
| break; |
| case APP_SEC_TOO_LITTLE_DATA: |
| reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_TOO_LITTLE_DATA; |
| break; |
| case APP_SEC_SIG_VERIFY_FAIL: |
| reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_SIG_VERIFY_FAIL; |
| break; |
| case APP_SEC_SIG_DECODE_FAIL: |
| reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_SIG_DECODE_FAIL; |
| break; |
| case APP_SEC_SIG_ROOT_UNKNOWN: |
| reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_SIG_ROOT_UNKNOWN; |
| break; |
| case APP_SEC_MEMORY_ERROR: |
| reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_MEMORY_ERROR; |
| break; |
| case APP_SEC_INVALID_DATA: |
| reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_INVALID_DATA; |
| break; |
| case APP_SEC_VERIFY_FAILED: |
| reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_VERIFY_FAILED; |
| break; |
| default: |
| reply = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_BAD; |
| break; |
| } |
| return reply; |
| } |
| |
| static uint32_t firmwareFinish(bool valid) |
| { |
| struct AppHdr *app; |
| struct Segment *storageSeg; |
| uint32_t segState; |
| uint32_t ret = NANOHUB_FIRMWARE_UPLOAD_SUCCESS; |
| |
| if (!mDownloadState) { |
| ret = appSecErrToNanohubReply(mAppSecStatus); |
| osLog(LOG_INFO, "%s: no DL status; decoding secure status: %" PRIu32 "\n", __func__, ret); |
| return ret; |
| } |
| |
| app = mDownloadState->start; |
| storageSeg = osGetSegment(app); |
| |
| if (mAppSecStatus == APP_SEC_NO_ERROR && valid) { |
| osLog(LOG_INFO, "%s: Secure verification passed\n", __func__); |
| if (storageSeg->state != SEG_ST_RESERVED || |
| mDownloadState->size < sizeof(struct FwCommonHdr) || |
| app->hdr.magic != APP_HDR_MAGIC || |
| app->hdr.fwVer != APP_HDR_VER_CUR) { |
| segState = SEG_ST_ERASED; |
| osLog(LOG_INFO, "%s: Header verification failed\n", __func__); |
| } else { |
| segState = SEG_ST_VALID; |
| } |
| } else { |
| segState = SEG_ST_ERASED; |
| osLog(LOG_INFO, "%s: Secure verification failed: valid=%d; status=%" PRIu32 "\n", __func__, valid, mAppSecStatus); |
| } |
| |
| if (!osAppSegmentClose(app, mDownloadState->dstOffset, segState)) { |
| osLog(LOG_INFO, "%s: Failed to close segment\n", __func__); |
| valid = false; |
| mApp = NULL; |
| } else { |
| segState = osAppSegmentGetState(app); |
| mApp = app; |
| valid = (segState == SEG_ST_VALID); |
| } |
| osLog(LOG_INFO, "Loaded %s image type %" PRIu8 ": %" PRIu32 |
| " bytes @ %p; state=%02" PRIX32 "; crc=%08" PRIX32 "\n", |
| valid ? "valid" : "invalid", |
| app->hdr.payInfoType, mDownloadState->size, |
| mDownloadState->start, segState, |
| mApp ? osAppSegmentGetCrc(mApp) : 0xFFFFFFFF); |
| |
| freeDownloadState(); // no more access to mDownloadState |
| |
| if (!valid) |
| ret = NANOHUB_FIRMWARE_UPLOAD_APP_SEC_BAD; |
| |
| // take extra care about some special payload types |
| if (ret == NANOHUB_FIRMWARE_UPLOAD_SUCCESS) { |
| switch(app->hdr.payInfoType) { |
| case LAYOUT_OS: |
| osLog(LOG_INFO, "Performing OS update\n"); |
| // we want to give this message a chance to reach host before we start erasing stuff |
| osDefer(deferredUpdateOs, (void*)app, false); |
| break; |
| case LAYOUT_KEY: |
| ret = appSecErrToNanohubReply(updateKey(app)); |
| break; |
| } |
| } |
| |
| if (ret != NANOHUB_FIRMWARE_UPLOAD_SUCCESS || (app->hdr.fwFlags & FL_APP_HDR_VOLATILE)) { |
| if ((app->hdr.fwFlags & FL_APP_HDR_SECURE)) |
| osAppWipeData((struct AppHdr*)app); |
| osAppSegmentSetState(app, SEG_ST_ERASED); |
| } |
| |
| // if any error happened after we downloaded and verified image, we say it is unknown fault |
| // we don't have download status, so e have to save returned value in secure status field, because |
| // host may request the same status multiple times |
| if (ret != NANOHUB_FIRMWARE_UPLOAD_SUCCESS) |
| mAppSecStatus = APP_SEC_BAD; |
| |
| return ret; |
| } |
| |
| static void firmwareErase(void *cookie) |
| { |
| if (mDownloadState->erase == true) { |
| osLog(LOG_INFO, "%s: erasing shared area\n", __func__); |
| osEraseShared(); |
| mDownloadState->start = osAppSegmentCreate(mDownloadState->size); |
| if (!mDownloadState->start) |
| firmwareFinish(false); |
| mDownloadState->erase = false; |
| hostIntfSetInterrupt(NANOHUB_INT_CMD_WAIT); |
| } |
| mDownloadState->eraseScheduled = false; |
| } |
| |
| SET_PACKED_STRUCT_MODE_ON |
| struct FirmwareWriteCookie |
| { |
| uint32_t evtType; |
| union { |
| #ifdef LEGACY_HAL_ENABLED |
| struct NanohubHalLegacyContUploadTx respLegacy; |
| #endif |
| struct NanohubHalContUploadTx resp; |
| }; |
| } ATTRIBUTE_PACKED; |
| SET_PACKED_STRUCT_MODE_OFF |
| |
| static void writeCookieFree(void *ptr) |
| { |
| struct FirmwareWriteCookie *buf = container_of(ptr, struct FirmwareWriteCookie, resp); |
| heapFree(buf); |
| } |
| |
| static void firmwareWrite(void *cookie) |
| { |
| bool valid; |
| bool finished = false; |
| struct FirmwareWriteCookie *resp = cookie; |
| // only check crc when cookie is NULL (write came from kernel, not HAL) |
| bool checkCrc = !cookie; |
| |
| if (mAppSecStatus == APP_SEC_NEED_MORE_TIME) { |
| mAppSecStatus = appSecDoSomeProcessing(mDownloadState->appSecState); |
| } else if (mDownloadState->lenLeft) { |
| const uint8_t *data = mDownloadState->data + mDownloadState->len - mDownloadState->lenLeft; |
| uint32_t len = mDownloadState->lenLeft, lenLeft, lenRem = 0; |
| |
| if (len > MAX_APP_SEC_RX_DATA_LEN) { |
| lenRem = len - MAX_APP_SEC_RX_DATA_LEN; |
| len = MAX_APP_SEC_RX_DATA_LEN; |
| } |
| |
| mAppSecStatus = appSecRxData(mDownloadState->appSecState, data, len, &lenLeft); |
| mDownloadState->lenLeft = lenLeft + lenRem; |
| } |
| |
| valid = (mAppSecStatus == APP_SEC_NO_ERROR); |
| if (mAppSecStatus == APP_SEC_NEED_MORE_TIME || mDownloadState->lenLeft) { |
| osDefer(firmwareWrite, cookie, false); |
| return; |
| } else if (valid) { |
| if (mDownloadState->srcOffset == mDownloadState->size) { |
| mAppSecStatus = appSecRxDataOver(mDownloadState->appSecState); |
| finished = true; |
| valid = !checkCrc || mDownloadState->crc == ~mDownloadState->srcCrc; |
| } else if (mDownloadState->srcOffset > mDownloadState->size) { |
| valid = false; |
| } |
| } |
| if (!valid) |
| finished = true; |
| if (finished) { |
| if (firmwareFinish(valid) != NANOHUB_FIRMWARE_UPLOAD_SUCCESS) |
| valid = false; |
| } |
| if (resp) { |
| if (resp->evtType == EVT_APP_TO_HOST) { |
| #ifdef LEGACY_HAL_ENABLED |
| resp->respLegacy.success = valid; |
| osEnqueueEvtOrFree(EVT_APP_TO_HOST, &resp->respLegacy, writeCookieFree); |
| #endif |
| } else { |
| resp->resp.ret.status = !valid; |
| osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, &resp->resp, writeCookieFree); |
| } |
| } |
| } |
| |
| static uint32_t doFirmwareChunk(uint8_t *data, uint32_t offset, uint32_t len, void *cookie) |
| { |
| uint32_t reply, ret; |
| |
| if (!mDownloadState) { |
| reply = NANOHUB_FIRMWARE_CHUNK_REPLY_CANCEL_NO_RETRY; |
| } else if (mAppSecStatus == APP_SEC_NEED_MORE_TIME || mDownloadState->lenLeft) { |
| reply = NANOHUB_FIRMWARE_CHUNK_REPLY_RESEND; |
| } else if (mDownloadState->chunkReply != NANOHUB_FIRMWARE_CHUNK_REPLY_ACCEPTED) { |
| reply = mDownloadState->chunkReply; |
| firmwareFinish(false); |
| } else { |
| if (mDownloadState->erase == true) { |
| reply = NANOHUB_FIRMWARE_CHUNK_REPLY_WAIT; |
| if (!mDownloadState->eraseScheduled) { |
| ret = osExtAppStopAppsByAppId(APP_ID_ANY); |
| osLog(LOG_INFO, "%s: unloaded apps, ret=%08lx\n", __func__, ret); |
| mDownloadState->eraseScheduled = osDefer(firmwareErase, NULL, false); |
| } |
| } else if (!mDownloadState->start) { |
| // this means we can't allocate enough space even after we did erase |
| reply = NANOHUB_FIRMWARE_CHUNK_REPLY_CANCEL_NO_RETRY; |
| firmwareFinish(false); |
| } else if (offset != mDownloadState->srcOffset) { |
| reply = NANOHUB_FIRMWARE_CHUNK_REPLY_RESTART; |
| resetDownloadState(false, true); |
| } else { |
| if (!cookie) |
| mDownloadState->srcCrc = soft_crc32(data, len, mDownloadState->srcCrc); |
| mDownloadState->srcOffset += len; |
| memcpy(mDownloadState->data, data, len); |
| mDownloadState->lenLeft = mDownloadState->len = len; |
| reply = NANOHUB_FIRMWARE_CHUNK_REPLY_ACCEPTED; |
| osDefer(firmwareWrite, cookie, false); |
| } |
| } |
| |
| return reply; |
| } |
| |
| static uint32_t firmwareChunk(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp) |
| { |
| struct NanohubFirmwareChunkRequest *req = rx; |
| struct NanohubFirmwareChunkResponse *resp = tx; |
| uint32_t offset = le32toh(req->offset); |
| uint8_t len = rx_len - sizeof(req->offset); |
| |
| resp->chunkReply = doFirmwareChunk(req->data, offset, len, NULL); |
| |
| return sizeof(*resp); |
| } |
| |
| static uint32_t doFinishFirmwareUpload(uint32_t *addr, uint32_t *crc) |
| { |
| uint32_t reply; |
| |
| if (!mDownloadState) { |
| reply = appSecErrToNanohubReply(mAppSecStatus); |
| if (addr) { |
| if (mApp) |
| *addr = (uint32_t)mApp; |
| else |
| *addr = 0xFFFFFFFF; |
| } |
| if (crc) { |
| if (mApp) |
| *crc = osAppSegmentGetCrc(mApp); |
| else |
| *crc = 0xFFFFFFFF; |
| } |
| } else if (mDownloadState->srcOffset == mDownloadState->size) { |
| reply = NANOHUB_FIRMWARE_UPLOAD_PROCESSING; |
| } else { |
| reply = firmwareFinish(false); |
| } |
| |
| return reply; |
| } |
| |
| static uint32_t finishFirmwareUpload(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp) |
| { |
| struct NanohubFinishFirmwareUploadResponse *resp = tx; |
| resp->uploadReply = doFinishFirmwareUpload(NULL, NULL); |
| if (resp->uploadReply != NANOHUB_FIRMWARE_UPLOAD_PROCESSING) |
| osLog(LOG_INFO, "%s: reply=%" PRIu8 "\n", __func__, resp->uploadReply); |
| return sizeof(*resp); |
| } |
| |
| static uint32_t getInterrupt(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp) |
| { |
| struct NanohubGetInterruptRequest *req = rx; |
| struct NanohubGetInterruptResponse *resp = tx; |
| int i; |
| |
| if (rx_len == sizeof(struct NanohubGetInterruptRequest)) { |
| for (i = 0; i < HOSTINTF_MAX_INTERRUPTS; i++) { |
| if (req->clear[i/32] & (1UL << (i & 31))) |
| hostIntfClearInterrupt(i); |
| } |
| } |
| |
| hostIntfCopyInterrupts(resp->interrupts, HOSTINTF_MAX_INTERRUPTS); |
| |
| return sizeof(*resp); |
| } |
| |
| static uint32_t maskInterrupt(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp) |
| { |
| struct NanohubMaskInterruptRequest *req = rx; |
| struct NanohubMaskInterruptResponse *resp = tx; |
| |
| hostIntfSetInterruptMask(req->interrupt); |
| |
| resp->accepted = true; |
| return sizeof(*resp); |
| } |
| |
| static uint32_t unmaskInterrupt(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp) |
| { |
| struct NanohubUnmaskInterruptRequest *req = rx; |
| struct NanohubUnmaskInterruptResponse *resp = tx; |
| |
| hostIntfClearInterruptMask(req->interrupt); |
| |
| resp->accepted = true; |
| return sizeof(*resp); |
| } |
| |
| static void addDelta(struct ApHubSync *sync, uint64_t apTime, uint64_t hubTime) |
| { |
| #if DEBUG_APHUB_TIME_SYNC |
| syncDebugAdd(apTime, hubTime); |
| #endif |
| apHubSyncAddDelta(sync, apTime, hubTime); |
| } |
| |
| static int64_t getAvgDelta(struct ApHubSync *sync) |
| { |
| return apHubSyncGetDelta(sync, sensorGetTime()); |
| } |
| |
| static int fillBuffer(void *tx, uint32_t totLength, uint32_t *wakeup, uint32_t *nonwakeup) |
| { |
| struct HostIntfDataBuffer *packet = &mTxNext; |
| struct HostIntfDataBuffer *firstPacket = tx; |
| uint8_t *buf = tx; |
| uint32_t length; |
| uint32_t prevWakeup, prevNonWakeup; |
| |
| prevWakeup = *wakeup; |
| prevNonWakeup = *nonwakeup; |
| |
| while (hostIntfPacketDequeue(&mTxNext, wakeup, nonwakeup)) { |
| length = packet->length + sizeof(packet->evtType); |
| if (packet->sensType == SENS_TYPE_INVALID) { |
| switch (packet->dataType) { |
| case HOSTINTF_DATA_TYPE_APP_TO_HOST: |
| packet->evtType = htole32(EVT_APP_TO_HOST); |
| break; |
| case HOSTINTF_DATA_TYPE_RESET_REASON: |
| packet->evtType = htole32(EVT_RESET_REASON); |
| break; |
| case HOSTINTF_DATA_TYPE_APP_TO_SENSOR_HAL: |
| packet->evtType = htole32(EVT_APP_TO_SENSOR_HAL_DATA); |
| break; |
| #ifdef DEBUG_LOG_EVT |
| case HOSTINTF_DATA_TYPE_LOG: |
| packet->evtType = htole32(HOST_EVT_DEBUG_LOG); |
| break; |
| #endif |
| default: |
| packet->evtType = htole32(0x00000000); |
| break; |
| } |
| } else { |
| packet->evtType = htole32(EVT_NO_FIRST_SENSOR_EVENT + packet->sensType); |
| if (packet->referenceTime) |
| packet->referenceTime += getAvgDelta(&mTimeSync); |
| |
| if (*wakeup > 0) |
| packet->firstSample.interrupt = NANOHUB_INT_WAKEUP; |
| } |
| |
| if ((!totLength || (isSensorEvent(firstPacket->evtType) && isSensorEvent(packet->evtType))) && |
| totLength + length <= sizeof(struct HostIntfDataBuffer)) { |
| memcpy(buf + totLength, &mTxNext, length); |
| totLength += length; |
| if (isSensorEvent(packet->evtType) && packet->firstSample.interrupt == NANOHUB_INT_WAKEUP) |
| firstPacket->firstSample.interrupt = NANOHUB_INT_WAKEUP; |
| } else { |
| mTxNextLength = length; |
| *wakeup = prevWakeup; |
| *nonwakeup = prevNonWakeup; |
| break; |
| } |
| |
| prevWakeup = *wakeup; |
| prevNonWakeup = *nonwakeup; |
| } |
| |
| return totLength; |
| } |
| |
| static void updateInterrupts(void) |
| { |
| uint32_t wakeup = atomicRead32bits(&mTxWakeCnt[0]); |
| uint32_t nonwakeup = atomicRead32bits(&mTxWakeCnt[1]); |
| bool wakeupStatus = hostIntfGetInterrupt(NANOHUB_INT_WAKEUP); |
| bool nonwakeupStatus = hostIntfGetInterrupt(NANOHUB_INT_NONWAKEUP); |
| |
| if (!wakeup && wakeupStatus) |
| hostIntfClearInterrupt(NANOHUB_INT_WAKEUP); |
| else if (wakeup && !wakeupStatus) |
| hostIntfSetInterrupt(NANOHUB_INT_WAKEUP); |
| |
| if (!nonwakeup && nonwakeupStatus) |
| hostIntfClearInterrupt(NANOHUB_INT_NONWAKEUP); |
| else if (nonwakeup && !nonwakeupStatus) |
| hostIntfSetInterrupt(NANOHUB_INT_NONWAKEUP); |
| } |
| |
| void nanohubPrefetchTx(uint32_t interrupt, uint32_t wakeup, uint32_t nonwakeup) |
| { |
| uint64_t state; |
| |
| if (wakeup < atomicRead32bits(&mTxWakeCnt[0])) |
| wakeup = atomicRead32bits(&mTxWakeCnt[0]); |
| |
| if (nonwakeup < atomicRead32bits(&mTxWakeCnt[1])) |
| nonwakeup = atomicRead32bits(&mTxWakeCnt[1]); |
| |
| if (interrupt == HOSTINTF_MAX_INTERRUPTS && !hostIntfGetInterrupt(NANOHUB_INT_WAKEUP) && !hostIntfGetInterrupt(NANOHUB_INT_NONWAKEUP)) |
| return; |
| |
| atomicWriteByte(&mPrefetchActive, 1); |
| |
| if (interrupt < HOSTINTF_MAX_INTERRUPTS) |
| hostIntfSetInterrupt(interrupt); |
| |
| do { |
| if (atomicReadByte(&mTxCurrLength) == 0 && mTxNextLength > 0) { |
| memcpy(&mTxCurr, &mTxNext, mTxNextLength); |
| atomicWriteByte(&mTxCurrLength, mTxNextLength); |
| mTxNextLength = 0; |
| } |
| |
| if (mTxNextLength == 0) { |
| atomicWriteByte(&mTxCurrLength, fillBuffer(&mTxCurr, atomicReadByte(&mTxCurrLength), &wakeup, &nonwakeup)); |
| atomicWrite32bits(&mTxWakeCnt[0], wakeup); |
| atomicWrite32bits(&mTxWakeCnt[1], nonwakeup); |
| } |
| |
| atomicWriteByte(&mPrefetchActive, 0); |
| |
| if (atomicReadByte(&mPrefetchTx)) { |
| state = cpuIntsOff(); |
| |
| // interrupt occured during this call |
| // take care of it |
| hostIntfTxAck(&mTxCurr, atomicReadByte(&mTxCurrLength)); |
| atomicWriteByte(&mPrefetchTx, 0); |
| atomicWriteByte(&mTxCurrLength, 0); |
| |
| cpuIntsRestore(state); |
| |
| updateInterrupts(); |
| } else { |
| break; |
| } |
| } while (mTxNextLength > 0); |
| } |
| |
| static void nanohubPrefetchTxDefer(void *cookie) |
| { |
| nanohubPrefetchTx(HOSTINTF_MAX_INTERRUPTS, 0, 0); |
| } |
| |
| static uint32_t readEventFast(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp) |
| { |
| struct NanohubReadEventRequest *req = rx; |
| uint8_t ret = 0; |
| |
| if (atomicReadByte(&mPrefetchActive)) { |
| atomicWriteByte(&mPrefetchTx, 1); |
| return NANOHUB_FAST_DONT_ACK; |
| } else { |
| if ((ret = atomicReadByte(&mTxCurrLength))) { |
| addDelta(&mTimeSync, req->apBootTime, timestamp); |
| |
| memcpy(tx, &mTxCurr, ret); |
| atomicWriteByte(&mTxCurrLength, 0); |
| |
| updateInterrupts(); |
| osDefer(nanohubPrefetchTxDefer, NULL, true); |
| } else { |
| return NANOHUB_FAST_UNHANDLED_ACK; |
| } |
| } |
| |
| return ret; |
| } |
| |
| static uint32_t readEvent(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp) |
| { |
| struct NanohubReadEventRequest *req = rx; |
| uint8_t *buf = tx; |
| uint32_t length, wakeup, nonwakeup; |
| uint32_t totLength = 0; |
| |
| addDelta(&mTimeSync, req->apBootTime, timestamp); |
| |
| if ((totLength = atomicReadByte(&mTxCurrLength))) { |
| memcpy(tx, &mTxCurr, totLength); |
| atomicWriteByte(&mTxCurrLength, 0); |
| updateInterrupts(); |
| return totLength; |
| } |
| |
| wakeup = atomicRead32bits(&mTxWakeCnt[0]); |
| nonwakeup = atomicRead32bits(&mTxWakeCnt[1]); |
| |
| if (mTxNextLength > 0) { |
| length = mTxNextLength; |
| memcpy(buf, &mTxNext, length); |
| totLength = length; |
| mTxNextLength = 0; |
| } |
| |
| totLength = fillBuffer(buf, totLength, &wakeup, &nonwakeup); |
| atomicWrite32bits(&mTxWakeCnt[0], wakeup); |
| atomicWrite32bits(&mTxWakeCnt[1], nonwakeup); |
| |
| if (totLength) { |
| updateInterrupts(); |
| } else { |
| hostIntfClearInterrupt(NANOHUB_INT_WAKEUP); |
| hostIntfClearInterrupt(NANOHUB_INT_NONWAKEUP); |
| } |
| |
| return totLength; |
| } |
| |
| static bool forwardPacket(uint32_t event, void *data, size_t data_size, |
| void *hdr, size_t hdr_size, uint32_t tid) |
| { |
| bool res; |
| uint8_t *hostPacket = data; |
| uint8_t *packet = slabAllocatorAlloc(mEventSlab); |
| EventFreeF free = slabFree; |
| |
| if (!packet) { |
| packet = heapAlloc(data_size + hdr_size); |
| free = heapFree; |
| } |
| if (!packet) |
| return false; |
| |
| if (hdr && hdr_size) |
| memcpy(packet, hdr, hdr_size); |
| |
| memcpy(packet + hdr_size, hostPacket, data_size); |
| if (tid) { |
| // send to specific TID |
| res = osEnqueuePrivateEvt(event, packet, free, tid); |
| if (!res) |
| free(packet); |
| } else { |
| // broadcast to all |
| res = osEnqueueEvtOrFree(event, packet, free); |
| } |
| |
| return res; |
| } |
| |
| static uint32_t writeEvent(void *rx, uint8_t rx_len, void *tx, uint64_t timestamp) |
| { |
| struct NanohubWriteEventRequest *req = rx; |
| struct NanohubWriteEventResponse *resp = tx; |
| uint32_t tid; |
| uint32_t event = le32toh(req->evtType); |
| |
| if (event == EVT_APP_FROM_HOST) { |
| // old version of HAL; message_type is not delivered to CHRE apps |
| struct HostMsgHdr *hostPacket = rx; |
| if (rx_len >= sizeof(struct HostMsgHdr) && |
| rx_len == sizeof(struct HostMsgHdr) + hostPacket->len && |
| osTidById(&hostPacket->appId, &tid)) { |
| resp->accepted = forwardPacket(event, hostPacket + 1, hostPacket->len, |
| &hostPacket->len, sizeof(hostPacket->len), tid); |
| } else { |
| resp->accepted = false; |
| } |
| } else if (event == EVT_APP_FROM_HOST_CHRE) { |
| // new version of HAL; full support for CHRE apps |
| struct HostMsgHdrChreV10 *hostPacketV10 = rx; |
| struct HostMsgHdrChre *hostPacket = rx; |
| if (rx_len >= sizeof(struct HostMsgHdrChre) && |
| rx_len == sizeof(struct HostMsgHdrChre) + hostPacket->len && |
| osTidById(&hostPacket->appId, &tid)) { |
| if (osAppChreVersion(tid) >= CHRE_API_VERSION_1_1) { |
| struct NanohubMsgChreHdr hdr = { |
| .size = hostPacket->len, |
| .endpoint = hostPacket->endpoint, |
| .appEvent = hostPacket->appEventId, |
| }; |
| // CHRE app receives message in new format |
| resp->accepted = forwardPacket(event, hostPacket + 1, hostPacket->len, |
| &hdr, sizeof(hdr), tid); |
| } else if (osAppChreVersion(tid) == CHRE_API_VERSION_1_0) { |
| struct NanohubMsgChreHdrV10 hdr = { |
| .size = hostPacket->len, |
| .appEvent = hostPacket->appEventId, |
| }; |
| // CHRE app receives message in new format |
| resp->accepted = forwardPacket(event, hostPacket + 1, hostPacket->len, |
| &hdr, sizeof(hdr), tid); |
| } else { |
| // legacy app receives message in old format |
| resp->accepted = forwardPacket(EVT_APP_FROM_HOST, hostPacket + 1, hostPacket->len, |
| &hostPacket->len, sizeof(hostPacket->len), tid); |
| } |
| } else if (rx_len >= sizeof(struct HostMsgHdrChreV10) && |
| rx_len == sizeof(struct HostMsgHdrChreV10) + hostPacketV10->len && |
| osTidById(&hostPacketV10->appId, &tid)) { |
| if (osAppChreVersion(tid) >= CHRE_API_VERSION_1_1) { |
| struct NanohubMsgChreHdr hdr = { |
| .size = hostPacketV10->len, |
| .endpoint = CHRE_HOST_ENDPOINT_UNSPECIFIED, |
| .appEvent = hostPacketV10->appEventId, |
| }; |
| // CHRE app receives message in new format |
| resp->accepted = forwardPacket(event, hostPacketV10 + 1, hostPacketV10->len, |
| &hdr, sizeof(hdr), tid); |
| } else if (osAppChreVersion(tid) == CHRE_API_VERSION_1_0) { |
| struct NanohubMsgChreHdrV10 hdr = { |
| .size = hostPacketV10->len, |
| .appEvent = hostPacketV10->appEventId, |
| }; |
| // CHRE app receives message in new format |
| resp->accepted = forwardPacket(event, hostPacketV10 + 1, hostPacketV10->len, |
| &hdr, sizeof(hdr), tid); |
| } else { |
| // legacy app receives message in old format |
| resp->accepted = forwardPacket(EVT_APP_FROM_HOST, hostPacketV10 + 1, hostPacketV10->len, |
| &hostPacketV10->len, sizeof(hostPacketV10->len), tid); |
| } |
| } else { |
| resp->accepted = false; |
| } |
| } else { |
| resp->accepted = forwardPacket(event, |
| req->evtData, rx_len - sizeof(req->evtType), |
| NULL, 0, 0); |
| } |
| |
| return sizeof(*resp); |
| } |
| |
| const static struct NanohubCommand mBuiltinCommands[] = { |
| NANOHUB_COMMAND(NANOHUB_REASON_GET_OS_HW_VERSIONS, |
| getOsHwVersion, |
| getOsHwVersion, |
| struct NanohubOsHwVersionsRequest, |
| struct NanohubOsHwVersionsRequest), |
| NANOHUB_COMMAND(NANOHUB_REASON_GET_APP_VERSIONS, |
| NULL, |
| getAppVersion, |
| struct NanohubAppVersionsRequest, |
| struct NanohubAppVersionsRequest), |
| NANOHUB_COMMAND(NANOHUB_REASON_QUERY_APP_INFO, |
| NULL, |
| queryAppInfo, |
| struct NanohubAppInfoRequest, |
| struct NanohubAppInfoRequest), |
| NANOHUB_COMMAND(NANOHUB_REASON_START_FIRMWARE_UPLOAD, |
| NULL, |
| startFirmwareUpload, |
| struct NanohubStartFirmwareUploadRequest, |
| struct NanohubStartFirmwareUploadRequest), |
| NANOHUB_COMMAND(NANOHUB_REASON_FIRMWARE_CHUNK, |
| NULL, |
| firmwareChunk, |
| __le32, |
| struct NanohubFirmwareChunkRequest), |
| NANOHUB_COMMAND(NANOHUB_REASON_FINISH_FIRMWARE_UPLOAD, |
| NULL, |
| finishFirmwareUpload, |
| struct NanohubFinishFirmwareUploadRequest, |
| struct NanohubFinishFirmwareUploadRequest), |
| NANOHUB_COMMAND(NANOHUB_REASON_GET_INTERRUPT, |
| getInterrupt, |
| getInterrupt, |
| struct { }, |
| struct NanohubGetInterruptRequest), |
| NANOHUB_COMMAND(NANOHUB_REASON_MASK_INTERRUPT, |
| maskInterrupt, |
| maskInterrupt, |
| struct NanohubMaskInterruptRequest, |
| struct NanohubMaskInterruptRequest), |
| NANOHUB_COMMAND(NANOHUB_REASON_UNMASK_INTERRUPT, |
| unmaskInterrupt, |
| unmaskInterrupt, |
| struct NanohubUnmaskInterruptRequest, |
| struct NanohubUnmaskInterruptRequest), |
| NANOHUB_COMMAND(NANOHUB_REASON_READ_EVENT, |
| readEventFast, |
| readEvent, |
| struct NanohubReadEventRequest, |
| struct NanohubReadEventRequest), |
| NANOHUB_COMMAND(NANOHUB_REASON_WRITE_EVENT, |
| writeEvent, |
| writeEvent, |
| __le32, |
| struct NanohubWriteEventRequest), |
| }; |
| |
| const struct NanohubCommand *nanohubFindCommand(uint32_t packetReason) |
| { |
| uint32_t i; |
| |
| for (i = 0; i < ARRAY_SIZE(mBuiltinCommands); i++) { |
| const struct NanohubCommand *cmd = &mBuiltinCommands[i]; |
| if (cmd->reason == packetReason) |
| return cmd; |
| } |
| return NULL; |
| } |
| |
| #ifdef LEGACY_HAL_ENABLED |
| |
| static void halSendLegacyMgmtResponse(uint32_t cmd, uint32_t status) |
| { |
| struct NanohubHalLegacyMgmtTx *resp; |
| |
| resp = heapAlloc(sizeof(*resp)); |
| if (resp) { |
| resp->hdr = (struct NanohubHalLegacyHdr) { |
| .appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0), |
| .len = sizeof(*resp) - sizeof(resp->hdr) + sizeof(resp->hdr.msg), |
| .msg = cmd, |
| }; |
| resp->status = htole32(status); |
| osEnqueueEvtOrFree(EVT_APP_TO_HOST, resp, heapFree); |
| } |
| } |
| |
| static void halLegacyExtAppsOn(void *rx, uint8_t rx_len) |
| { |
| struct NanohubHalLegacyMgmtRx *req = rx; |
| |
| halSendLegacyMgmtResponse(NANOHUB_HAL_LEGACY_EXT_APPS_ON, osExtAppStartAppsByAppId(le64toh(unaligned_u64(&req->appId)))); |
| } |
| |
| static void halLegacyExtAppsOff(void *rx, uint8_t rx_len) |
| { |
| struct NanohubHalLegacyMgmtRx *req = rx; |
| |
| halSendLegacyMgmtResponse(NANOHUB_HAL_LEGACY_EXT_APPS_OFF, osExtAppStopAppsByAppId(le64toh(unaligned_u64(&req->appId)))); |
| } |
| |
| static void halLegacyExtAppDelete(void *rx, uint8_t rx_len) |
| { |
| struct NanohubHalLegacyMgmtRx *req = rx; |
| |
| halSendLegacyMgmtResponse(NANOHUB_HAL_LEGACY_EXT_APP_DELETE, osExtAppEraseAppsByAppId(le64toh(unaligned_u64(&req->appId)))); |
| } |
| |
| static void halLegacyQueryMemInfo(void *rx, uint8_t rx_len) |
| { |
| } |
| |
| static void halLegacyQueryApps(void *rx, uint8_t rx_len) |
| { |
| struct NanohubHalLegacyQueryAppsRx *req = rx; |
| struct NanohubHalLegacyQueryAppsTx *resp; |
| struct NanohubHalLegacyHdr *hdr; |
| uint64_t appId; |
| uint32_t appVer, appSize; |
| |
| if (osExtAppInfoByIndex(le32toh(req->idx), &appId, &appVer, &appSize)) { |
| resp = heapAlloc(sizeof(*resp)); |
| if (resp) { |
| resp->hdr.appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0); |
| resp->hdr.len = sizeof(*resp) - sizeof(struct NanohubHalLegacyHdr) + 1; |
| resp->hdr.msg = NANOHUB_HAL_LEGACY_QUERY_APPS; |
| resp->appId = appId; |
| resp->version = appVer; |
| resp->flashUse = appSize; |
| resp->ramUse = 0; |
| osEnqueueEvtOrFree(EVT_APP_TO_HOST, resp, heapFree); |
| } |
| } else { |
| hdr = heapAlloc(sizeof(*hdr)); |
| if (hdr) { |
| hdr->appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0); |
| hdr->len = 1; |
| hdr->msg = NANOHUB_HAL_LEGACY_QUERY_APPS; |
| osEnqueueEvtOrFree(EVT_APP_TO_HOST, hdr, heapFree); |
| } |
| } |
| } |
| |
| static void halLegacyQueryRsaKeys(void *rx, uint8_t rx_len) |
| { |
| struct NanohubHalLegacyQueryRsaKeysRx *req = rx; |
| struct NanohubHalLegacyQueryRsaKeysTx *resp; |
| int len = 0; |
| const uint32_t *ptr; |
| uint32_t numKeys; |
| |
| if (!(resp = heapAlloc(sizeof(*resp) + NANOHUB_RSA_KEY_CHUNK_LEN))) |
| return; |
| |
| ptr = BL.blGetPubKeysInfo(&numKeys); |
| if (ptr && numKeys * RSA_BYTES > req->offset) { |
| len = numKeys * RSA_BYTES - req->offset; |
| if (len > NANOHUB_RSA_KEY_CHUNK_LEN) |
| len = NANOHUB_RSA_KEY_CHUNK_LEN; |
| memcpy(resp->data, (uint8_t *)ptr + req->offset, len); |
| } |
| |
| resp->hdr.appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0); |
| resp->hdr.len = sizeof(*resp) - sizeof(struct NanohubHalLegacyHdr) + 1 + len; |
| resp->hdr.msg = NANOHUB_HAL_LEGACY_QUERY_RSA_KEYS; |
| |
| osEnqueueEvtOrFree(EVT_APP_TO_HOST, resp, heapFree); |
| } |
| |
| static void halLegacyStartUpload(void *rx, uint8_t rx_len) |
| { |
| struct NanohubHalLegacyStartUploadRx *req = rx; |
| struct NanohubStartFirmwareUploadRequest hwReq = { |
| .size = req->length |
| }; |
| struct NanohubHalLegacyStartUploadTx *resp; |
| |
| if (!(resp = heapAlloc(sizeof(*resp)))) |
| return; |
| |
| resp->hdr.appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0); |
| resp->hdr.len = sizeof(*resp) - sizeof(struct NanohubHalLegacyHdr) + 1; |
| resp->hdr.msg = NANOHUB_HAL_LEGACY_START_UPLOAD; |
| resp->success = doStartFirmwareUpload(&hwReq, true); |
| |
| osEnqueueEvtOrFree(EVT_APP_TO_HOST, resp, heapFree); |
| } |
| |
| static void halLegacyContUpload(void *rx, uint8_t rx_len) |
| { |
| uint32_t offset; |
| uint32_t reply; |
| uint8_t len; |
| struct NanohubHalLegacyContUploadRx *req = rx; |
| struct FirmwareWriteCookie *cookie; |
| |
| if (!(cookie = heapAlloc(sizeof(*cookie)))) |
| return; |
| |
| cookie->evtType = EVT_APP_TO_HOST; |
| cookie->respLegacy.hdr = (struct NanohubHalLegacyHdr) { |
| .appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0), |
| .len = sizeof(cookie->respLegacy) - sizeof(struct NanohubHalLegacyHdr) + 1, |
| .msg = NANOHUB_HAL_LEGACY_CONT_UPLOAD, |
| }; |
| cookie->respLegacy.success = false; |
| |
| if (!mDownloadState) { |
| reply = NANOHUB_FIRMWARE_CHUNK_REPLY_CANCEL_NO_RETRY; |
| } else { |
| offset = le32toh(req->offset); |
| len = rx_len - sizeof(req->offset); |
| reply = doFirmwareChunk(req->data, offset, len, cookie); |
| } |
| if (reply != NANOHUB_FIRMWARE_CHUNK_REPLY_ACCEPTED) { |
| osLog(LOG_ERROR, "%s: reply=%" PRIu32 "\n", __func__, reply); |
| |
| osEnqueueEvtOrFree(EVT_APP_TO_HOST, &cookie->respLegacy, writeCookieFree); |
| } |
| } |
| |
| static void halLegacyFinishUpload(void *rx, uint8_t rx_len) |
| { |
| struct NanohubHalLegacyFinishUploadTx *resp; |
| uint32_t reply; |
| |
| if (!(resp = heapAlloc(sizeof(*resp)))) |
| return; |
| |
| resp->hdr.appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0); |
| resp->hdr.len = sizeof(*resp) - sizeof(struct NanohubHalLegacyHdr) + 1; |
| resp->hdr.msg = NANOHUB_HAL_LEGACY_FINISH_UPLOAD; |
| |
| reply = doFinishFirmwareUpload(NULL, NULL); |
| |
| osLog(LOG_INFO, "%s: reply=%" PRIu32 "\n", __func__, reply); |
| |
| resp->success = (reply == NANOHUB_FIRMWARE_UPLOAD_SUCCESS); |
| |
| osEnqueueEvtOrFree(EVT_APP_TO_HOST, resp, heapFree); |
| } |
| |
| static void halLegacyReboot(void *rx, uint8_t rx_len) |
| { |
| BL.blReboot(); |
| } |
| |
| const static struct NanohubHalLegacyCommand mBuiltinHalLegacyCommands[] = { |
| NANOHUB_HAL_LEGACY_COMMAND(NANOHUB_HAL_LEGACY_EXT_APPS_ON, |
| halLegacyExtAppsOn), |
| NANOHUB_HAL_LEGACY_COMMAND(NANOHUB_HAL_LEGACY_EXT_APPS_OFF, |
| halLegacyExtAppsOff), |
| NANOHUB_HAL_LEGACY_COMMAND(NANOHUB_HAL_LEGACY_EXT_APP_DELETE, |
| halLegacyExtAppDelete), |
| NANOHUB_HAL_LEGACY_COMMAND(NANOHUB_HAL_LEGACY_QUERY_MEMINFO, |
| halLegacyQueryMemInfo), |
| NANOHUB_HAL_LEGACY_COMMAND(NANOHUB_HAL_LEGACY_QUERY_APPS, |
| halLegacyQueryApps), |
| NANOHUB_HAL_LEGACY_COMMAND(NANOHUB_HAL_LEGACY_QUERY_RSA_KEYS, |
| halLegacyQueryRsaKeys), |
| NANOHUB_HAL_LEGACY_COMMAND(NANOHUB_HAL_LEGACY_START_UPLOAD, |
| halLegacyStartUpload), |
| NANOHUB_HAL_LEGACY_COMMAND(NANOHUB_HAL_LEGACY_CONT_UPLOAD, |
| halLegacyContUpload), |
| NANOHUB_HAL_LEGACY_COMMAND(NANOHUB_HAL_LEGACY_FINISH_UPLOAD, |
| halLegacyFinishUpload), |
| NANOHUB_HAL_LEGACY_COMMAND(NANOHUB_HAL_LEGACY_REBOOT, |
| halLegacyReboot), |
| }; |
| |
| const struct NanohubHalLegacyCommand *nanohubHalLegacyFindCommand(uint8_t msg) |
| { |
| uint32_t i; |
| |
| for (i = 0; i < ARRAY_SIZE(mBuiltinHalLegacyCommands); i++) { |
| const struct NanohubHalLegacyCommand *cmd = &mBuiltinHalLegacyCommands[i]; |
| if (cmd->msg == msg) |
| return cmd; |
| } |
| return NULL; |
| } |
| |
| #endif /* LEGACY_HAL_ENABLED */ |
| |
| static void halSendAppMgmtResponse(struct NanohubHalAppMgmtRx *req, uint32_t status, struct MgmtStatus stat, uint32_t transactionId) |
| { |
| struct NanohubHalAppMgmtTx *resp; |
| |
| resp = heapAlloc(sizeof(*resp)); |
| if (resp) { |
| resp->hdr = (struct NanohubHalHdr) { |
| .appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0), |
| .len = sizeof(*resp) - sizeof(resp->hdr), |
| .transactionId = transactionId, |
| }; |
| resp->ret = (struct NanohubHalRet) { |
| .msg = NANOHUB_HAL_APP_MGMT, |
| .status = htole32(status), |
| }; |
| resp->cmd = req->cmd; |
| resp->stat = stat; |
| osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree); |
| } |
| } |
| |
| static void halAppMgmt(void *rx, uint8_t rx_len, uint32_t transactionId) |
| { |
| struct NanohubHalAppMgmtRx *req = rx; |
| struct MgmtStatus stat; |
| uint32_t ret; |
| |
| switch (req->cmd) { |
| case NANOHUB_HAL_APP_MGMT_START: |
| stat.value= osExtAppStartAppsByAppId(le64toh(unaligned_u64(&req->appId))); |
| ret = stat.op > 0 ? 0 : -1; |
| break; |
| case NANOHUB_HAL_APP_MGMT_STOP: |
| stat.value = osExtAppStopAppsByAppId(le64toh(unaligned_u64(&req->appId))); |
| ret = stat.op > 0 ? 0 : -1; |
| break; |
| case NANOHUB_HAL_APP_MGMT_UNLOAD: |
| stat.value = osExtAppStopAppsByAppId(le64toh(unaligned_u64(&req->appId))); |
| ret = stat.op > 0 ? 0 : -1; |
| break; |
| case NANOHUB_HAL_APP_MGMT_DELETE: |
| stat.value = osExtAppEraseAppsByAppId(le64toh(unaligned_u64(&req->appId))); |
| ret = stat.erase > 0 ? 0 : -1; |
| break; |
| default: |
| return; |
| } |
| |
| halSendAppMgmtResponse(req, ret, stat, transactionId); |
| } |
| |
| static void deferHalSysMgmtErase(void *cookie) |
| { |
| struct NanohubHalSysMgmtTx *resp = cookie; |
| |
| bool success = osEraseShared(); |
| |
| if (success) |
| resp->ret.status = htole32(0); |
| else |
| resp->ret.status = htole32(-1); |
| |
| osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree); |
| } |
| |
| static void halSysMgmt(void *rx, uint8_t rx_len, uint32_t transactionId) |
| { |
| struct NanohubHalSysMgmtRx *req = rx; |
| struct NanohubHalSysMgmtTx *resp; |
| uint32_t ret = 0; |
| |
| if (!(resp = heapAlloc(sizeof(*resp)))) |
| return; |
| |
| resp->hdr = (struct NanohubHalHdr) { |
| .appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0), |
| .len = sizeof(*resp) - sizeof(resp->hdr), |
| .transactionId = transactionId, |
| }; |
| resp->ret = (struct NanohubHalRet) { |
| .msg = NANOHUB_HAL_SYS_MGMT, |
| }; |
| resp->cmd = req->cmd; |
| |
| switch (req->cmd) { |
| case NANOHUB_HAL_SYS_MGMT_ERASE: |
| ret = osExtAppStopAppsByAppId(APP_ID_ANY); |
| osLog(LOG_INFO, "%s: unloaded apps, ret=%08lx\n", __func__, ret); |
| // delay to make sure all apps are unloaded before erasing |
| if (osDefer(deferHalSysMgmtErase, resp, false) == false) { |
| resp->ret.status = htole32(-1); |
| osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree); |
| } |
| break; |
| case NANOHUB_HAL_SYS_MGMT_REBOOT: |
| BL.blReboot(); |
| break; |
| default: |
| resp->ret.status = htole32(-1); |
| osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree); |
| } |
| } |
| |
| static bool copyTLV64(uint8_t *buf, size_t *offset, size_t max_len, uint8_t tag, uint64_t val) |
| { |
| if (*offset + sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint64_t) > max_len) |
| return false; |
| buf[(*offset)++] = tag; |
| buf[(*offset)++] = sizeof(uint64_t); |
| memcpy(&buf[*offset], &val, sizeof(uint64_t)); |
| *offset += sizeof(uint64_t); |
| return true; |
| } |
| |
| static bool copyTLV32(uint8_t *buf, size_t *offset, size_t max_len, uint8_t tag, uint32_t val) |
| { |
| if (*offset + sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint32_t) > max_len) |
| return false; |
| buf[(*offset)++] = tag; |
| buf[(*offset)++] = sizeof(uint32_t); |
| memcpy(&buf[*offset], &val, sizeof(uint32_t)); |
| *offset += sizeof(uint32_t); |
| return true; |
| } |
| |
| static bool copyTLV8(uint8_t *buf, size_t *offset, size_t max_len, uint8_t tag, uint8_t val) |
| { |
| if (*offset + sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint8_t) > max_len) |
| return false; |
| buf[(*offset)++] = tag; |
| buf[(*offset)++] = sizeof(uint8_t); |
| memcpy(&buf[*offset], &val, sizeof(uint8_t)); |
| *offset += sizeof(uint8_t); |
| return true; |
| } |
| |
| static bool copyTLVEmpty(uint8_t *buf, size_t *offset, size_t max_len, uint8_t tag) |
| { |
| if (*offset + sizeof(uint8_t) + sizeof(uint8_t) > max_len) |
| return false; |
| buf[(*offset)++] = tag; |
| buf[(*offset)++] = 0; |
| return true; |
| } |
| |
| static int processAppTags(const struct AppHdr *app, uint32_t crc, uint32_t size, uint8_t *data, uint8_t *tags, int cnt, bool req_tid) |
| { |
| int i; |
| size_t offset = 0; |
| const size_t max_len = HOST_HUB_CHRE_PACKET_MAX_LEN - sizeof(struct NanohubHalRet); |
| bool success = true; |
| uint32_t tid; |
| bool tid_valid = false; |
| struct Task *task; |
| |
| if (app->hdr.magic != APP_HDR_MAGIC || |
| app->hdr.fwVer != APP_HDR_VER_CUR || |
| (app->hdr.fwFlags & FL_APP_HDR_APPLICATION) == 0 || |
| app->hdr.payInfoType != LAYOUT_APP) { |
| return 0; |
| } |
| |
| if (osTidById(&app->hdr.appId, &tid)) { |
| tid_valid = true; |
| task = osTaskFindByTid(tid); |
| if (task) { |
| if (task->app != app) |
| tid_valid = false; |
| } else |
| tid_valid = false; |
| } |
| |
| if (!tid_valid && req_tid) |
| return 0; |
| |
| for (i=0; i<cnt && success; i++) { |
| switch(tags[i]) { |
| case NANOHUB_HAL_APP_INFO_APPID: |
| success = copyTLV64(data, &offset, max_len, tags[i], app->hdr.appId); |
| break; |
| case NANOHUB_HAL_APP_INFO_CRC: |
| if (size) |
| success = copyTLV32(data, &offset, max_len, tags[i], crc); |
| else |
| success = copyTLVEmpty(data, &offset, max_len, tags[i]); |
| break; |
| case NANOHUB_HAL_APP_INFO_TID: |
| if (tid_valid) |
| success = copyTLV32(data, &offset, max_len, tags[i], tid); |
| else |
| success = copyTLVEmpty(data, &offset, max_len, tags[i]); |
| break; |
| case NANOHUB_HAL_APP_INFO_VERSION: |
| success = copyTLV32(data, &offset, max_len, tags[i], app->hdr.appVer); |
| break; |
| case NANOHUB_HAL_APP_INFO_ADDR: |
| success = copyTLV32(data, &offset, max_len, tags[i], (uint32_t)app); |
| break; |
| case NANOHUB_HAL_APP_INFO_SIZE: |
| if (size) |
| success = copyTLV32(data, &offset, max_len, tags[i], size); |
| else |
| success = copyTLVEmpty(data, &offset, max_len, tags[i]); |
| break; |
| case NANOHUB_HAL_APP_INFO_HEAP: |
| if (tid_valid) |
| success = copyTLV32(data, &offset, max_len, tags[i], heapGetTaskSize(tid)); |
| else |
| success = copyTLVEmpty(data, &offset, max_len, tags[i]); |
| break; |
| case NANOHUB_HAL_APP_INFO_DATA: |
| success = copyTLV32(data, &offset, max_len, tags[i], app->sect.got_end - app->sect.data_start); |
| break; |
| case NANOHUB_HAL_APP_INFO_BSS: |
| success = copyTLV32(data, &offset, max_len, tags[i], app->sect.bss_end - app->sect.bss_start); |
| break; |
| case NANOHUB_HAL_APP_INFO_CHRE_MAJOR: |
| if (app->hdr.fwFlags & FL_APP_HDR_CHRE) |
| success = copyTLV8(data, &offset, max_len, tags[i], |
| (app->hdr.chreApiMajor == 0xFF && app->hdr.chreApiMinor == 0xFF) ? 0x01 : |
| app->hdr.chreApiMajor); |
| else |
| success = copyTLVEmpty(data, &offset, max_len, tags[i]); |
| break; |
| case NANOHUB_HAL_APP_INFO_CHRE_MINOR: |
| if (app->hdr.fwFlags & FL_APP_HDR_CHRE) |
| success = copyTLV8(data, &offset, max_len, tags[i], |
| (app->hdr.chreApiMajor == 0xFF && app->hdr.chreApiMinor == 0xFF) ? 0x00 : |
| app->hdr.chreApiMinor); |
| else |
| success = copyTLVEmpty(data, &offset, max_len, tags[i]); |
| break; |
| case NANOHUB_HAL_APP_INFO_END: |
| default: |
| success = false; |
| copyTLVEmpty(data, &offset, max_len, NANOHUB_HAL_APP_INFO_END); |
| break; |
| } |
| } |
| |
| return offset; |
| } |
| |
| static void halAppInfo(void *rx, uint8_t rx_len, uint32_t transactionId) |
| { |
| struct NanohubHalAppInfoRx *req = rx; |
| struct NanohubHalAppInfoTx *resp; |
| struct SegmentIterator it; |
| uint32_t state; |
| int ret, i; |
| uint32_t sharedSize, numApps; |
| const struct AppHdr *internal; |
| const uint8_t *shared; |
| |
| if (!(resp = heapAlloc(sizeof(*resp)))) |
| return; |
| |
| resp->hdr = (struct NanohubHalHdr) { |
| .appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0), |
| .len = sizeof(*resp) - sizeof(resp->hdr) - sizeof(resp->data), |
| .transactionId = transactionId, |
| }; |
| resp->ret = (struct NanohubHalRet) { |
| .msg = NANOHUB_HAL_APP_INFO, |
| }; |
| |
| shared = platGetSharedAreaInfo(&sharedSize); |
| internal = platGetInternalAppList(&numApps); |
| |
| if ((le32toh(req->addr) >= (uint32_t)shared && le32toh(req->addr) < (uint32_t)shared + sharedSize) || |
| (le32toh(req->addr) < (uint32_t)shared && |
| ((uint32_t)shared < (uint32_t)internal || |
| (numApps > 0 && le32toh(req->addr) > (uint32_t)(internal+numApps-1))))) { |
| osSegmentIteratorInit(&it); |
| while (osSegmentIteratorNext(&it)) { |
| state = osSegmentGetState(it.seg); |
| switch (state) { |
| case SEG_ST_EMPTY: |
| case SEG_ST_RESERVED: |
| osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree); |
| return; |
| case SEG_ST_ERASED: |
| case SEG_ST_VALID: |
| if (le32toh(req->addr) <= (uint32_t)osSegmentGetData(it.seg)) { |
| ret = processAppTags(osSegmentGetData(it.seg), osSegmentGetCrc(it.seg), osSegmentGetSize(it.seg), resp->data, req->tags, rx_len - 4, state == SEG_ST_ERASED); |
| if (ret > 0) { |
| resp->hdr.len += ret; |
| osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree); |
| return; |
| } |
| } |
| break; |
| } |
| } |
| } else { |
| for (i = 0; i < numApps; i++, internal++) { |
| if (le32toh(req->addr) <= (uint32_t)internal) { |
| ret = processAppTags(internal, 0, 0, resp->data, req->tags, rx_len - 4, false); |
| if (ret > 0) { |
| resp->hdr.len += ret; |
| osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree); |
| return; |
| } |
| } |
| } |
| } |
| |
| osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree); |
| } |
| |
| static void halSysInfo(void *rx, uint8_t rx_len, uint32_t transactionId) |
| { |
| extern uint8_t __code_start[]; |
| extern uint8_t __code_end[]; |
| extern uint8_t __text_end[]; |
| extern uint8_t __ram_start[]; |
| extern uint8_t __ram_end[]; |
| |
| struct NanohubHalSysInfoRx *req = rx; |
| struct NanohubHalSysInfoTx *resp; |
| int i; |
| size_t offset = 0; |
| const size_t max_len = HOST_HUB_CHRE_PACKET_MAX_LEN - sizeof(struct NanohubHalRet); |
| bool success = true; |
| int free, chunks, largest; |
| uint32_t shared_size; |
| |
| free = heapGetFreeSize(&chunks, &largest); |
| |
| if (!(resp = heapAlloc(sizeof(*resp)))) |
| return; |
| |
| resp->hdr = (struct NanohubHalHdr) { |
| .appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0), |
| .len = sizeof(*resp) - sizeof(resp->hdr) - sizeof(resp->data), |
| .transactionId = transactionId, |
| }; |
| resp->ret = (struct NanohubHalRet) { |
| .msg = NANOHUB_HAL_SYS_INFO, |
| }; |
| |
| for (i=0; i<rx_len && success; i++) { |
| switch(req->tags[i]) { |
| case NANOHUB_HAL_SYS_INFO_HEAP_FREE: |
| if (free >= 0) |
| success = copyTLV32(resp->data, &offset, max_len, req->tags[i], free); |
| else |
| success = copyTLVEmpty(resp->data, &offset, max_len, req->tags[i]); |
| break; |
| case NANOHUB_HAL_SYS_INFO_RAM_SIZE: |
| success = copyTLV32(resp->data, &offset, max_len, req->tags[i], __ram_end - __ram_start); |
| break; |
| case NANOHUB_HAL_SYS_INFO_EEDATA_SIZE: |
| success = copyTLV32(resp->data, &offset, max_len, req->tags[i], eeDataGetSize()); |
| break; |
| case NANOHUB_HAL_SYS_INFO_EEDATA_FREE: |
| success = copyTLV32(resp->data, &offset, max_len, req->tags[i], eeDataGetFree()); |
| break; |
| case NANOHUB_HAL_SYS_INFO_CODE_SIZE: |
| success = copyTLV32(resp->data, &offset, max_len, req->tags[i], __code_end - __code_start); |
| break; |
| case NANOHUB_HAL_SYS_INFO_CODE_FREE: |
| success = copyTLV32(resp->data, &offset, max_len, req->tags[i], __code_end - __text_end); |
| break; |
| case NANOHUB_HAL_SYS_INFO_SHARED_SIZE: |
| platGetSharedAreaInfo(&shared_size); |
| success = copyTLV32(resp->data, &offset, max_len, req->tags[i], shared_size); |
| break; |
| case NANOHUB_HAL_SYS_INFO_SHARED_FREE: |
| success = copyTLV32(resp->data, &offset, max_len, req->tags[i], osSegmentGetFree()); |
| break; |
| case NANOHUB_HAL_SYS_INFO_END: |
| default: |
| success = false; |
| copyTLVEmpty(resp->data, &offset, max_len, NANOHUB_HAL_APP_INFO_END); |
| break; |
| } |
| } |
| |
| resp->hdr.len += offset; |
| |
| osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree); |
| } |
| |
| static void halKeyInfo(void *rx, uint8_t rx_len, uint32_t transactionId) |
| { |
| struct NanohubHalKeyInfoRx *req = rx; |
| struct NanohubHalKeyInfoTx *resp; |
| const uint32_t *ptr; |
| uint32_t numKeys; |
| uint32_t dataLength; |
| |
| if (!(resp = heapAlloc(sizeof(*resp)))) |
| return; |
| |
| ptr = BL.blGetPubKeysInfo(&numKeys); |
| |
| resp->hdr = (struct NanohubHalHdr) { |
| .appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0), |
| .len = sizeof(*resp) - sizeof(resp->hdr) - sizeof(resp->data), |
| .transactionId = transactionId, |
| }; |
| resp->ret = (struct NanohubHalRet) { |
| .msg = NANOHUB_HAL_KEY_INFO, |
| }; |
| |
| resp->keyLength = 0; |
| |
| if (ptr && req->keyNum < numKeys) { |
| if (req->dataOffset < RSA_BYTES) { |
| resp->keyLength = RSA_BYTES; |
| if (RSA_BYTES - req->dataOffset > NANOHUB_RSA_KEY_CHUNK_LEN) |
| dataLength = NANOHUB_RSA_KEY_CHUNK_LEN; |
| else |
| dataLength = RSA_BYTES - req->dataOffset; |
| memcpy(resp->data, (const uint8_t *)ptr + (req->keyNum * RSA_BYTES) + req->dataOffset, dataLength); |
| resp->hdr.len += dataLength; |
| } |
| } |
| |
| osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree); |
| } |
| |
| static void halStartUpload(void *rx, uint8_t rx_len, uint32_t transactionId) |
| { |
| struct NanohubHalStartUploadRx *req = rx; |
| struct NanohubStartFirmwareUploadRequest hwReq = { |
| .size = req->length |
| }; |
| struct NanohubHalStartUploadTx *resp; |
| |
| if (!(resp = heapAlloc(sizeof(*resp)))) |
| return; |
| |
| resp->hdr = (struct NanohubHalHdr) { |
| .appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0), |
| .len = sizeof(*resp) - sizeof(resp->hdr), |
| .transactionId = transactionId, |
| }; |
| |
| resp->ret.msg = NANOHUB_HAL_START_UPLOAD; |
| if (doStartFirmwareUpload(&hwReq, false)) |
| resp->ret.status = NANOHUB_FIRMWARE_CHUNK_REPLY_ACCEPTED; |
| else |
| resp->ret.status = NANOHUB_FIRMWARE_CHUNK_REPLY_NO_SPACE; |
| |
| osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree); |
| } |
| |
| static void halContUpload(void *rx, uint8_t rx_len, uint32_t transactionId) |
| { |
| uint32_t offset; |
| uint32_t reply; |
| uint8_t len; |
| struct NanohubHalContUploadRx *req = rx; |
| struct FirmwareWriteCookie *cookie; |
| |
| if (!(cookie = heapAlloc(sizeof(*cookie)))) |
| return; |
| |
| cookie->evtType = EVT_APP_TO_HOST_CHRE; |
| cookie->resp.hdr = (struct NanohubHalHdr) { |
| .appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0), |
| .len = sizeof(cookie->resp) - sizeof(cookie->resp.hdr), |
| .transactionId = transactionId, |
| }; |
| cookie->resp.ret = (struct NanohubHalRet) { |
| .msg = NANOHUB_HAL_CONT_UPLOAD, |
| }; |
| |
| if (!mDownloadState) { |
| reply = NANOHUB_FIRMWARE_CHUNK_REPLY_CANCEL_NO_RETRY; |
| } else { |
| offset = le32toh(req->offset); |
| len = rx_len - sizeof(req->offset); |
| reply = doFirmwareChunk(req->data, offset, len, cookie); |
| } |
| if (reply != NANOHUB_FIRMWARE_CHUNK_REPLY_ACCEPTED) { |
| osLog(LOG_ERROR, "%s: reply=%" PRIu32 "\n", __func__, reply); |
| |
| cookie->resp.ret.status = reply; |
| |
| osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, &cookie->resp, writeCookieFree); |
| } |
| } |
| |
| static void halFinishUpload(void *rx, uint8_t rx_len, uint32_t transactionId) |
| { |
| struct NanohubHalFinishUploadTx *resp; |
| uint32_t reply; |
| uint32_t addr = 0xFFFFFFFF; |
| uint32_t crc = 0xFFFFFFFF; |
| |
| if (!(resp = heapAlloc(sizeof(*resp)))) |
| return; |
| |
| resp->hdr = (struct NanohubHalHdr) { |
| .appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0), |
| .len = sizeof(*resp) - sizeof(resp->hdr), |
| .transactionId = transactionId, |
| }; |
| |
| reply = doFinishFirmwareUpload(&addr, &crc); |
| |
| osLog(LOG_INFO, "%s: reply=%" PRIu32 "\n", __func__, reply); |
| |
| resp->ret = (struct NanohubHalRet) { |
| .msg = NANOHUB_HAL_FINISH_UPLOAD, |
| .status = reply, |
| }; |
| |
| resp->addr = addr; |
| resp->crc = crc; |
| |
| osEnqueueEvtOrFree(EVT_APP_TO_HOST_CHRE, resp, heapFree); |
| } |
| |
| const static struct NanohubHalCommand mBuiltinHalCommands[] = { |
| NANOHUB_HAL_COMMAND(NANOHUB_HAL_APP_MGMT, |
| halAppMgmt, |
| struct NanohubHalAppMgmtRx, |
| struct NanohubHalAppMgmtRx), |
| NANOHUB_HAL_COMMAND(NANOHUB_HAL_SYS_MGMT, |
| halSysMgmt, |
| struct NanohubHalSysMgmtRx, |
| struct NanohubHalSysMgmtRx), |
| NANOHUB_HAL_COMMAND(NANOHUB_HAL_APP_INFO, |
| halAppInfo, |
| __le32, |
| struct NanohubHalAppInfoRx), |
| NANOHUB_HAL_COMMAND(NANOHUB_HAL_SYS_INFO, |
| halSysInfo, |
| struct { }, |
| struct NanohubHalSysInfoRx), |
| NANOHUB_HAL_COMMAND(NANOHUB_HAL_KEY_INFO, |
| halKeyInfo, |
| struct NanohubHalKeyInfoRx, |
| struct NanohubHalKeyInfoRx), |
| NANOHUB_HAL_COMMAND(NANOHUB_HAL_START_UPLOAD, |
| halStartUpload, |
| struct NanohubHalStartUploadRx, |
| struct NanohubHalStartUploadRx), |
| NANOHUB_HAL_COMMAND(NANOHUB_HAL_CONT_UPLOAD, |
| halContUpload, |
| __le32, |
| struct NanohubHalContUploadRx), |
| NANOHUB_HAL_COMMAND(NANOHUB_HAL_FINISH_UPLOAD, |
| halFinishUpload, |
| struct { }, |
| struct { }), |
| }; |
| |
| const struct NanohubHalCommand *nanohubHalFindCommand(uint8_t msg) |
| { |
| uint32_t i; |
| |
| for (i = 0; i < ARRAY_SIZE(mBuiltinHalCommands); i++) { |
| const struct NanohubHalCommand *cmd = &mBuiltinHalCommands[i]; |
| if (cmd->msg == msg) |
| return cmd; |
| } |
| return NULL; |
| } |
| |
| |
| int64_t hostGetTimeDelta(void) |
| { |
| int64_t delta = getAvgDelta(&mTimeSync); |
| |
| if (delta == INT64_MIN) |
| return 0ULL; |
| else |
| return delta; |
| } |
| |
| uint64_t hostGetTime(void) |
| { |
| int64_t delta = getAvgDelta(&mTimeSync); |
| |
| if (!delta || delta == INT64_MIN) |
| return 0ULL; |
| else |
| return sensorGetTime() + delta; |
| } |
| |
| #if DEBUG_APHUB_TIME_SYNC |
| |
| #define N_APHUB_SYNC_DATA 256 |
| #define PRINT_DELAY 20000000 // unit ns, 20ms |
| struct ApHubSyncDebug { |
| uint64_t apFirst; |
| uint64_t hubFirst; |
| uint32_t apDelta[N_APHUB_SYNC_DATA]; // us |
| uint32_t hubDelta[N_APHUB_SYNC_DATA]; // us |
| int printIndex; //negative means not printing |
| int writeIndex; |
| |
| uint32_t printTimer; |
| }; |
| |
| static struct ApHubSyncDebug mApHubSyncDebug; |
| |
| static void syncDebugCallback(uint32_t timerId, void *data) |
| { |
| |
| if (mApHubSyncDebug.printIndex >= mApHubSyncDebug.writeIndex || |
| mApHubSyncDebug.printIndex >= N_APHUB_SYNC_DATA) { |
| timTimerCancel(mApHubSyncDebug.printTimer); |
| |
| osLog(LOG_DEBUG, "APHUB Done printing %d items", mApHubSyncDebug.printIndex); |
| mApHubSyncDebug.writeIndex = 0; |
| mApHubSyncDebug.printIndex = -1; |
| |
| mApHubSyncDebug.printTimer = 0; |
| } else { |
| if (mApHubSyncDebug.printIndex == 0) { |
| osLog(LOG_DEBUG, "APHUB init %" PRIu64 " %" PRIu64, |
| mApHubSyncDebug.apFirst, |
| mApHubSyncDebug.hubFirst); |
| } |
| |
| osLog(LOG_DEBUG, "APHUB %d %" PRIu32 " %" PRIu32, |
| mApHubSyncDebug.printIndex, |
| mApHubSyncDebug.apDelta[mApHubSyncDebug.printIndex], |
| mApHubSyncDebug.hubDelta[mApHubSyncDebug.printIndex]); |
| |
| mApHubSyncDebug.printIndex++; |
| } |
| } |
| |
| static void syncDebugTriggerPrint() |
| { |
| if (mApHubSyncDebug.printTimer) { |
| //printing already going |
| return; |
| } |
| |
| mApHubSyncDebug.printIndex = 0; |
| |
| syncDebugCallback(0, NULL); |
| if (!(mApHubSyncDebug.printTimer = |
| timTimerSet(PRINT_DELAY, 0, 50, syncDebugCallback, NULL, false /*oneShot*/))) { |
| osLog(LOG_WARN, "Cannot get timer for printing"); |
| |
| mApHubSyncDebug.writeIndex = 0; // discard all data |
| mApHubSyncDebug.printIndex = -1; // not printing |
| } |
| } |
| |
| static void syncDebugAdd(uint64_t ap, uint64_t hub) |
| { |
| if (mApHubSyncDebug.writeIndex >= N_APHUB_SYNC_DATA) { |
| //full |
| syncDebugTriggerPrint(); |
| return; |
| } |
| |
| if (mApHubSyncDebug.writeIndex == 0) { |
| mApHubSyncDebug.apFirst = ap; |
| mApHubSyncDebug.hubFirst = hub; |
| } |
| |
| // convert ns to us |
| mApHubSyncDebug.apDelta[mApHubSyncDebug.writeIndex] = |
| (uint32_t) U64_DIV_BY_CONST_U16((ap - mApHubSyncDebug.apFirst), 1000u); |
| mApHubSyncDebug.hubDelta[mApHubSyncDebug.writeIndex] = |
| (uint32_t) U64_DIV_BY_CONST_U16((hub - mApHubSyncDebug.hubFirst), 1000u); |
| |
| ++mApHubSyncDebug.writeIndex; |
| } |
| #endif |