diff options
author | Ben Fennema <fennema@google.com> | 2016-05-26 12:29:19 -0700 |
---|---|---|
committer | Ben Fennema <fennema@google.com> | 2016-05-27 14:48:36 -0700 |
commit | 019ae84cb5b18417772b683fded7719450349272 (patch) | |
tree | 263f0dc3fabdb83f22c9ac435cd8cee3d11952e7 | |
parent | d61f9ebd0671c1066118199537cd6057ecbf8697 (diff) | |
download | contexthub-019ae84cb5b18417772b683fded7719450349272.tar.gz |
hostIntf: Schedule appSec processing in the background
Bug: 28982986
Bug: 28917000
Change-Id: I05769ac3d476f5a197ad6813df8f4c0f9b9f309e
Signed-off-by: Ben Fennema <fennema@google.com>
-rw-r--r-- | firmware/src/nanohubCommand.c | 217 | ||||
-rw-r--r-- | firmware/src/platform/stm32f4xx/bl.c | 42 | ||||
-rw-r--r-- | firmware/src/seos.c | 3 |
3 files changed, 146 insertions, 116 deletions
diff --git a/firmware/src/nanohubCommand.c b/firmware/src/nanohubCommand.c index 838d4ba4..5e5f33bd 100644 --- a/firmware/src/nanohubCommand.c +++ b/firmware/src/nanohubCommand.c @@ -57,7 +57,13 @@ #define SYNC_DATAPOINTS 16 #define SYNC_RESET 10000000000ULL /* 10 seconds, ~100us drift */ -#define REQUIRE_SIGNED_IMAGE true +// 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 struct DownloadState { @@ -70,6 +76,7 @@ struct DownloadState 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; @@ -299,16 +306,6 @@ static uint32_t startFirmwareUpload(void *rx, uint8_t rx_len, void *tx, uint64_t return sizeof(*resp); } -static AppSecErr giveAppSecTimeIfNeeded(struct AppSecState *state, AppSecErr prevRet) -{ - /* XXX: this will need to go away for real asynchronicity */ - - while (prevRet == APP_SEC_NEED_MORE_TIME) - prevRet = appSecDoSomeProcessing(state); - - return prevRet; -} - static void deferredUpdateOs(void *cookie) { const struct AppHdr *app = cookie; @@ -354,49 +351,103 @@ static AppSecErr updateKey(const struct AppHdr *app) 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_CHUNK_REPLY_ACCEPTED; - - if (!mDownloadState) - return mAppSecStatus; + uint32_t ret = NANOHUB_FIRMWARE_UPLOAD_SUCCESS; - mAppSecStatus = appSecRxDataOver(mDownloadState->appSecState); - mAppSecStatus = giveAppSecTimeIfNeeded(mDownloadState->appSecState, mAppSecStatus); + 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)) - ret = NANOHUB_FIRMWARE_CHUNK_REPLY_RESEND; - - segState = osAppSegmentGetState(app); + if (!osAppSegmentClose(app, mDownloadState->dstOffset, segState)) { + osLog(LOG_INFO, "%s: Failed to close segment\n", __func__); + valid = false; + } else { + segState = osAppSegmentGetState(app); + valid = (segState == SEG_ST_VALID); + } osLog(LOG_INFO, "Loaded %s image type %" PRIu8 ": %" PRIu32 " bytes @ %p; state=%02" PRIX32 "\n", - segState == SEG_ST_VALID ? "valid" : "invalid", + valid ? "valid" : "invalid", app->hdr.payInfoType, mDownloadState->size, mDownloadState->start, segState); 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 == APP_SEC_NO_ERROR) { + if (ret == NANOHUB_FIRMWARE_UPLOAD_SUCCESS) { switch(app->hdr.payInfoType) { case LAYOUT_OS: osLog(LOG_INFO, "Performing OS update\n"); @@ -404,17 +455,23 @@ static uint32_t firmwareFinish(bool valid) osDefer(deferredUpdateOs, (void*)app, false); break; case LAYOUT_KEY: - ret = updateKey(app); + ret = appSecErrToNanohubReply(updateKey(app)); break; } } - if (ret != APP_SEC_NO_ERROR || (app->hdr.fwFlags & FL_APP_HDR_VOLATILE)) { - if ((app->hdr.fwFlags | FL_APP_HDR_SECURE)) + 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; } @@ -432,25 +489,34 @@ static void firmwareErase(void *cookie) mDownloadState->eraseScheduled = false; } -static bool firmwareWrite(bool checkCrc) +static void firmwareWrite(void *cookie) { - /* XXX: this will need to change for real asynchronicity */ - const uint8_t *data = mDownloadState->data; - uint32_t len = mDownloadState->len, lenLeft; - mAppSecStatus = APP_SEC_NO_ERROR; bool valid; bool finished = false; + struct NanohubHalContUploadTx *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; + } - while (len) { mAppSecStatus = appSecRxData(mDownloadState->appSecState, data, len, &lenLeft); - data += len - lenLeft; - len = lenLeft; - - mAppSecStatus = giveAppSecTimeIfNeeded(mDownloadState->appSecState, mAppSecStatus); + mDownloadState->lenLeft = lenLeft + lenRem; } valid = (mAppSecStatus == APP_SEC_NO_ERROR); - if (valid) { + if (mAppSecStatus == APP_SEC_NEED_MORE_TIME || mDownloadState->lenLeft) { + osDefer(firmwareWrite, cookie, false); + return; + } else if (valid) { if (mDownloadState->srcOffset == mDownloadState->size) { finished = true; valid = !checkCrc || mDownloadState->crc == ~mDownloadState->srcCrc; @@ -460,18 +526,24 @@ static bool firmwareWrite(bool checkCrc) } if (!valid) finished = true; - if (finished) - firmwareFinish(valid); - - return valid; + if (finished) { + if (firmwareFinish(valid) != NANOHUB_FIRMWARE_UPLOAD_SUCCESS) + valid = false; + } + if (resp) { + resp->success = valid; + osEnqueueEvtOrFree(EVT_APP_TO_HOST, resp, heapFree); + } } -static uint32_t doFirmwareChunk(uint8_t *data, uint32_t offset, uint32_t len, bool checkCrc) +static uint32_t doFirmwareChunk(uint8_t *data, uint32_t offset, uint32_t len, void *cookie) { uint32_t reply; 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); @@ -488,13 +560,13 @@ static uint32_t doFirmwareChunk(uint8_t *data, uint32_t offset, uint32_t len, bo reply = NANOHUB_FIRMWARE_CHUNK_REPLY_RESTART; resetDownloadState(false); } else { - if (checkCrc) + if (!cookie) mDownloadState->srcCrc = crc32(data, len, mDownloadState->srcCrc); mDownloadState->srcOffset += len; memcpy(mDownloadState->data, data, len); - mDownloadState->len = len; - reply = firmwareWrite(checkCrc) ? NANOHUB_FIRMWARE_CHUNK_REPLY_ACCEPTED : - NANOHUB_FIRMWARE_CHUNK_REPLY_CANCEL; + mDownloadState->lenLeft = mDownloadState->len = len; + reply = NANOHUB_FIRMWARE_CHUNK_REPLY_ACCEPTED; + osDefer(firmwareWrite, cookie, false); } } @@ -508,7 +580,7 @@ static uint32_t firmwareChunk(void *rx, uint8_t rx_len, void *tx, uint64_t times uint32_t offset = le32toh(req->offset); uint8_t len = rx_len - sizeof(req->offset); - resp->chunkReply = doFirmwareChunk(req->data, offset, len, true); + resp->chunkReply = doFirmwareChunk(req->data, offset, len, NULL); return sizeof(*resp); } @@ -518,44 +590,7 @@ static uint32_t doFinishFirmwareUpload() uint32_t reply; if (!mDownloadState) { - switch (mAppSecStatus) { - 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; - } + reply = appSecErrToNanohubReply(mAppSecStatus); } else if (mDownloadState->srcOffset == mDownloadState->size) { reply = NANOHUB_FIRMWARE_UPLOAD_PROCESSING; } else { @@ -569,7 +604,8 @@ static uint32_t finishFirmwareUpload(void *rx, uint8_t rx_len, void *tx, uint64_ { struct NanohubFinishFirmwareUploadResponse *resp = tx; resp->uploadReply = doFinishFirmwareUpload(); - osLog(LOG_INFO, "%s: reply=%" PRIu8 "\n", __func__, resp->uploadReply); + if (resp->uploadReply != NANOHUB_FIRMWARE_UPLOAD_PROCESSING) + osLog(LOG_INFO, "%s: reply=%" PRIu8 "\n", __func__, resp->uploadReply); return sizeof(*resp); } @@ -1093,14 +1129,15 @@ static void halContUpload(void *rx, uint8_t rx_len) } else { offset = le32toh(req->offset); len = rx_len - sizeof(req->offset); - reply = doFirmwareChunk(req->data, offset, len, false); + reply = doFirmwareChunk(req->data, offset, len, resp); } - if (reply != NANOHUB_FIRMWARE_CHUNK_REPLY_ACCEPTED) + if (reply != NANOHUB_FIRMWARE_CHUNK_REPLY_ACCEPTED) { osLog(LOG_ERROR, "%s: reply=%" PRIu32 "\n", __func__, reply); - resp->success = (reply == NANOHUB_FIRMWARE_CHUNK_REPLY_ACCEPTED); + resp->success = false; - osEnqueueEvtOrFree(EVT_APP_TO_HOST, resp, heapFree); + osEnqueueEvtOrFree(EVT_APP_TO_HOST, resp, heapFree); + } } static void halFinishUpload(void *rx, uint8_t rx_len) diff --git a/firmware/src/platform/stm32f4xx/bl.c b/firmware/src/platform/stm32f4xx/bl.c index ac2d4ec9..2786c365 100644 --- a/firmware/src/platform/stm32f4xx/bl.c +++ b/firmware/src/platform/stm32f4xx/bl.c @@ -430,8 +430,7 @@ static bool blProgramFlash(uint8_t *dst, const uint8_t *src, uint32_t length, ui { struct StmFlash *flash = (struct StmFlash *)FLASH_BASE; const uint32_t sector_cnt = sizeof(mBlFlashTable) / sizeof(struct blFlashTable); - uint32_t acr_cache, cr_cache, offset, i, j = 0, int_state = 0, erase_cnt = 0; - uint8_t erase_mask[sector_cnt]; + uint32_t acr_cache, cr_cache, offset, i, j = 0, int_state = 0; uint8_t *ptr; if (((length == 0)) || @@ -442,15 +441,6 @@ static bool blProgramFlash(uint8_t *dst, const uint8_t *src, uint32_t length, ui return false; } - // disable interrupts - // otherwise an interrupt during flash write/erase will stall the processor - // until the write/erase completes - int_state = blDisableInts(); - - // figure out which (if any) blocks we have to erase - for (i = 0; i < sector_cnt; i++) - erase_mask[i] = 0; - // compute which flash block we are starting from for (i = 0; i < sector_cnt; i++) { if (dst >= mBlFlashTable[i].address && @@ -460,7 +450,7 @@ static bool blProgramFlash(uint8_t *dst, const uint8_t *src, uint32_t length, ui } // now loop through all the flash blocks and see if we have to do any - // 0 -> 1 transitions of a bit. If so, we must erase that block + // 0 -> 1 transitions of a bit. If so, return false // 1 -> 0 transitions of a bit do not require an erase offset = (uint32_t)(dst - mBlFlashTable[i].address); ptr = mBlFlashTable[i].address; @@ -472,16 +462,18 @@ static bool blProgramFlash(uint8_t *dst, const uint8_t *src, uint32_t length, ui } if ((ptr[offset] & src[j]) != src[j]) { - erase_mask[i] = 1; - erase_cnt++; - j += mBlFlashTable[i].length - offset; - offset = mBlFlashTable[i].length; + return false; } else { j++; offset++; } } + // disable interrupts + // otherwise an interrupt during flash write will stall the processor + // until the write completes + int_state = blDisableInts(); + // wait for flash to not be busy (should never be set at this point) while (flash->SR & FLASH_SR_BSY); @@ -508,9 +500,6 @@ static bool blProgramFlash(uint8_t *dst, const uint8_t *src, uint32_t length, ui flash->ACR &= ~(FLASH_ACR_DCEN | FLASH_ACR_ICEN); flash->ACR |= (FLASH_ACR_DCRST | FLASH_ACR_ICRST); - if (erase_cnt) - blEraseSectors(sector_cnt, erase_mask); - blWriteBytes(dst, src, length); flash->ACR = acr_cache; @@ -521,7 +510,7 @@ static bool blProgramFlash(uint8_t *dst, const uint8_t *src, uint32_t length, ui return !memcmp(dst, src, length); } -static bool blProgramTypedArea(uint8_t *dst, const uint8_t *src, uint32_t length, uint32_t key1, uint32_t key2, uint32_t type) +static bool blProgramTypedArea(uint8_t *dst, const uint8_t *src, uint32_t length, uint32_t type, uint32_t key1, uint32_t key2) { const uint32_t sector_cnt = sizeof(mBlFlashTable) / sizeof(struct blFlashTable); uint32_t i; @@ -542,12 +531,12 @@ static bool blProgramTypedArea(uint8_t *dst, const uint8_t *src, uint32_t length static bool blExtApiProgramSharedArea(uint8_t *dst, const uint8_t *src, uint32_t length, uint32_t key1, uint32_t key2) { - return blProgramTypedArea(dst, src, length, key1, key2, BL_FLASH_SHARED); + return blProgramTypedArea(dst, src, length, BL_FLASH_SHARED, key1, key2); } static bool blExtApiProgramEe(uint8_t *dst, const uint8_t *src, uint32_t length, uint32_t key1, uint32_t key2) { - return blProgramTypedArea(dst, src, length, key1, key2, BL_FLASH_EEDATA); + return blProgramTypedArea(dst, src, length, BL_FLASH_EEDATA, key1, key2); } static bool blEraseTypedArea(uint32_t type, uint32_t key1, uint32_t key2) @@ -716,15 +705,16 @@ const struct BlVecTable __attribute__((section(".blvec"))) __BL_VECTORS = static void blApplyVerifiedUpdate(const struct OsUpdateHdr *os) //only called if an update has been found to exist and be valid, signed, etc! { //copy shared to code, and if successful, erase shared area - if (blProgramFlash(__code_start, (const uint8_t*)(os + 1), os->size, BL_FLASH_KEY1, BL_FLASH_KEY2)) - (void)blExtApiEraseSharedArea(BL_FLASH_KEY1, BL_FLASH_KEY2); + if (blEraseTypedArea(BL_FLASH_KERNEL, BL_FLASH_KEY1, BL_FLASH_KEY2)) + if (blProgramTypedArea(__code_start, (const uint8_t*)(os + 1), os->size, BL_FLASH_KERNEL, BL_FLASH_KEY1, BL_FLASH_KEY2)) + (void)blExtApiEraseSharedArea(BL_FLASH_KEY1, BL_FLASH_KEY2); } static void blWriteMark(struct OsUpdateHdr *hdr, uint32_t mark) { uint8_t dstVal = mark; - (void)blProgramFlash(&hdr->marker, &dstVal, sizeof(hdr->marker), BL_FLASH_KEY1, BL_FLASH_KEY2); + (void)blExtApiProgramSharedArea(&hdr->marker, &dstVal, sizeof(hdr->marker), BL_FLASH_KEY1, BL_FLASH_KEY2); } static void blUpdateMark(uint32_t old, uint32_t new) @@ -1071,7 +1061,7 @@ static void blSpiLoader(bool force) break; //do it - ack = blProgramFlash(__shared_start + addr, data, len, BL_FLASH_KEY1, BL_FLASH_KEY2); + ack = blExtApiProgramSharedArea(__shared_start + addr, data, len, BL_FLASH_KEY1, BL_FLASH_KEY2); blSpiLoaderDrainRxFifo(spi); nextAddr += len; break; diff --git a/firmware/src/seos.c b/firmware/src/seos.c index c0a0dd46..cc245760 100644 --- a/firmware/src/seos.c +++ b/firmware/src/seos.c @@ -508,6 +508,9 @@ bool osWriteShared(void *dest, const void *src, uint32_t len) mpuAllowRomWrite(false); mpuAllowRamExecution(false); + if (!ret) + osLog(LOG_ERROR, "osWriteShared: blProgramShared return false\n"); + return ret; } |