2006 lines
66 KiB
C
2006 lines
66 KiB
C
/*
|
|
* 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
|