micropython/cc3200/bootmgr/main.c

359 lines
14 KiB
C

/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2015 Daniel Campora
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdint.h>
#include <stdbool.h>
#include <std.h>
#include "py/mpconfig.h"
#include MICROPY_HAL_H
#include "hw_ints.h"
#include "hw_types.h"
#include "hw_gpio.h"
#include "hw_memmap.h"
#include "hw_gprcm.h"
#include "hw_common_reg.h"
#include "pin.h"
#include "gpio.h"
#include "rom.h"
#include "rom_map.h"
#include "prcm.h"
#include "simplelink.h"
#include "interrupt.h"
#include "gpio.h"
#include "flc.h"
#include "bootmgr.h"
#include "shamd5.h"
#include "hash.h"
#include "utils.h"
#include "cc3200_hal.h"
#include "debug.h"
#include "mperror.h"
//*****************************************************************************
// Local Constants
//*****************************************************************************
#define SL_STOP_TIMEOUT 35
#define BOOTMGR_HASH_ALGO SHAMD5_ALGO_MD5
#define BOOTMGR_HASH_SIZE 32
#define BOOTMGR_BUFF_SIZE 512
#define BOOTMGR_WAIT_SAFE_MODE_MS 1600
#define BOOTMGR_WAIT_SAFE_MODE_TOOGLE_MS 200
#define BOOTMGR_SAFE_MODE_ENTER_MS 800
#define BOOTMGR_SAFE_MODE_ENTER_TOOGLE_MS 80
//*****************************************************************************
// Exported functions declarations
//*****************************************************************************
extern void bootmgr_run_app (_u32 base);
//*****************************************************************************
// Local functions declarations
//*****************************************************************************
static void bootmgr_board_init (void);
static bool bootmgr_verify (void);
static void bootmgr_load_and_execute (_u8 *image);
static bool safe_mode_boot (void);
static void bootmgr_image_loader (sBootInfo_t *psBootInfo);
//*****************************************************************************
// Private data
//*****************************************************************************
static _u8 bootmgr_file_buf[BOOTMGR_BUFF_SIZE];
static _u8 bootmgr_hash_buf[BOOTMGR_HASH_SIZE + 1];
//*****************************************************************************
// Vector Table
//*****************************************************************************
extern void (* const g_pfnVectors[])(void);
//*****************************************************************************
// WLAN Event handler callback hookup function
//*****************************************************************************
void SimpleLinkWlanEventHandler(SlWlanEvent_t *pWlanEvent)
{
}
//*****************************************************************************
// HTTP Server callback hookup function
//*****************************************************************************
void SimpleLinkHttpServerCallback(SlHttpServerEvent_t *pHttpEvent,
SlHttpServerResponse_t *pHttpResponse)
{
}
//*****************************************************************************
// Net APP Event callback hookup function
//*****************************************************************************
void SimpleLinkNetAppEventHandler(SlNetAppEvent_t *pNetAppEvent)
{
}
//*****************************************************************************
// General Event callback hookup function
//*****************************************************************************
void SimpleLinkGeneralEventHandler(SlDeviceEvent_t *pDevEvent)
{
}
//*****************************************************************************
// Socket Event callback hookup function
//*****************************************************************************
void SimpleLinkSockEventHandler(SlSockEvent_t *pSock)
{
}
//*****************************************************************************
//! Board Initialization & Configuration
//*****************************************************************************
static void bootmgr_board_init(void) {
// Set vector table base
MAP_IntVTableBaseSet((unsigned long)&g_pfnVectors[0]);
// Enable Processor Interrupts
MAP_IntMasterEnable();
MAP_IntEnable(FAULT_SYSTICK);
// Mandatory MCU Initialization
PRCMCC3200MCUInit();
mperror_bootloader_check_reset_cause();
// Enable the Data Hashing Engine
HASH_Init();
// Init the system led and the system switch
mperror_init0();
// clear the safe boot flag, since we can't trust its content after reset
PRCMClearSafeBootRequest();
}
//*****************************************************************************
//! Verifies the integrity of the new application binary
//*****************************************************************************
static bool bootmgr_verify (void) {
SlFsFileInfo_t FsFileInfo;
_u32 reqlen, offset = 0;
_i32 fHandle;
// open the file for reading
if (0 == sl_FsOpen((_u8 *)IMG_UPDATE, FS_MODE_OPEN_READ, NULL, &fHandle)) {
// get the file size
sl_FsGetInfo((_u8 *)IMG_UPDATE, 0, &FsFileInfo);
if (FsFileInfo.FileLen > BOOTMGR_HASH_SIZE) {
FsFileInfo.FileLen -= BOOTMGR_HASH_SIZE;
HASH_SHAMD5Start(BOOTMGR_HASH_ALGO, FsFileInfo.FileLen);
do {
if ((FsFileInfo.FileLen - offset) > BOOTMGR_BUFF_SIZE) {
reqlen = BOOTMGR_BUFF_SIZE;
}
else {
reqlen = FsFileInfo.FileLen - offset;
}
offset += sl_FsRead(fHandle, offset, bootmgr_file_buf, reqlen);
HASH_SHAMD5Update(bootmgr_file_buf, reqlen);
} while (offset < FsFileInfo.FileLen);
HASH_SHAMD5Read (bootmgr_file_buf);
// convert the resulting hash to hex
for (_u32 i = 0; i < (BOOTMGR_HASH_SIZE / 2); i++) {
snprintf ((char *)&bootmgr_hash_buf[(i * 2)], 3, "%02x", bootmgr_file_buf[i]);
}
// read the hash from the file and close it
ASSERT (BOOTMGR_HASH_SIZE == sl_FsRead(fHandle, offset, bootmgr_file_buf, BOOTMGR_HASH_SIZE));
sl_FsClose (fHandle, NULL, NULL, 0);
bootmgr_file_buf[BOOTMGR_HASH_SIZE] = '\0';
// compare both hashes
if (!strcmp((const char *)bootmgr_hash_buf, (const char *)bootmgr_file_buf)) {
// it's a match
return true;
}
}
// close the file
sl_FsClose(fHandle, NULL, NULL, 0);
}
return false;
}
//*****************************************************************************
//! Loads the application from sFlash and executes
//*****************************************************************************
static void bootmgr_load_and_execute (_u8 *image) {
SlFsFileInfo_t pFsFileInfo;
_i32 fhandle;
// open the application binary
if (!sl_FsOpen(image, FS_MODE_OPEN_READ, NULL, &fhandle)) {
// get the file size
if (!sl_FsGetInfo(image, 0, &pFsFileInfo)) {
// read the application into SRAM
if (pFsFileInfo.FileLen == sl_FsRead(fhandle, 0, (unsigned char *)APP_IMG_SRAM_OFFSET, pFsFileInfo.FileLen)) {
// close the file
sl_FsClose(fhandle, 0, 0, 0);
// stop the network services
sl_Stop(SL_STOP_TIMEOUT);
// execute the application
bootmgr_run_app(APP_IMG_SRAM_OFFSET);
}
}
}
}
//*****************************************************************************
//! Check for the safe mode pin
//*****************************************************************************
static bool safe_mode_boot (void) {
_u32 count = 0;
while (MAP_GPIOPinRead(MICROPY_SAFE_BOOT_PORT, MICROPY_SAFE_BOOT_PORT_PIN) &&
((BOOTMGR_WAIT_SAFE_MODE_TOOGLE_MS * count++) < BOOTMGR_WAIT_SAFE_MODE_MS)) {
// toogle the led
MAP_GPIOPinWrite(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, ~MAP_GPIOPinRead(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN));
UtilsDelay(UTILS_DELAY_US_TO_COUNT(BOOTMGR_WAIT_SAFE_MODE_TOOGLE_MS * 1000));
}
mperror_deinit_sfe_pin();
return MAP_GPIOPinRead(MICROPY_SAFE_BOOT_PORT, MICROPY_SAFE_BOOT_PORT_PIN) ? true : false;
}
//*****************************************************************************
//! Load the proper image based on information from boot info and executes it.
//*****************************************************************************
static void bootmgr_image_loader(sBootInfo_t *psBootInfo) {
_i32 fhandle;
if (safe_mode_boot()) {
_u32 count = 0;
while ((BOOTMGR_SAFE_MODE_ENTER_TOOGLE_MS * count++) < BOOTMGR_SAFE_MODE_ENTER_MS) {
// toogle the led
MAP_GPIOPinWrite(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, ~MAP_GPIOPinRead(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN));
UtilsDelay(UTILS_DELAY_US_TO_COUNT(BOOTMGR_SAFE_MODE_ENTER_TOOGLE_MS * 1000));
}
psBootInfo->ActiveImg = IMG_ACT_FACTORY;
// turn the led off
MAP_GPIOPinWrite(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, 0);
// request a safe boot to the application
PRCMRequestSafeBoot();
}
// do we have a new update image that needs to be verified?
else if ((psBootInfo->ActiveImg == IMG_ACT_UPDATE) && (psBootInfo->Status == IMG_STATUS_CHECK)) {
if (!bootmgr_verify()) {
// delete the corrupted file
sl_FsDel((_u8 *)IMG_UPDATE, 0);
// switch to the factory image
psBootInfo->ActiveImg = IMG_ACT_FACTORY;
}
// in any case, set the status as "READY"
psBootInfo->Status = IMG_STATUS_READY;
// write the new boot info
if (!sl_FsOpen((unsigned char *)IMG_BOOT_INFO, FS_MODE_OPEN_WRITE, NULL, &fhandle)) {
sl_FsWrite(fhandle, 0, (unsigned char *)psBootInfo, sizeof(sBootInfo_t));
// close the file
sl_FsClose(fhandle, 0, 0, 0);
}
}
// now boot the active image
if (IMG_ACT_UPDATE == psBootInfo->ActiveImg) {
bootmgr_load_and_execute((unsigned char *)IMG_UPDATE);
}
else {
bootmgr_load_and_execute((unsigned char *)IMG_FACTORY);
}
}
//*****************************************************************************
//! Main function
//*****************************************************************************
int main (void) {
sBootInfo_t sBootInfo = { .ActiveImg = IMG_ACT_FACTORY, .Status = IMG_STATUS_READY };
bool bootapp = false;
_i32 fhandle;
// Board Initialization
bootmgr_board_init();
// start simplelink since we need it to access the sflash
sl_Start(0, 0, 0);
// if a boot info file is found, load it, else, create a new one with the default boot info
if (!sl_FsOpen((unsigned char *)IMG_BOOT_INFO, FS_MODE_OPEN_READ, NULL, &fhandle)) {
if (sizeof(sBootInfo_t) == sl_FsRead(fhandle, 0, (unsigned char *)&sBootInfo, sizeof(sBootInfo_t))) {
bootapp = true;
}
sl_FsClose(fhandle, 0, 0, 0);
}
if (!bootapp) {
// create a new boot info file
_u32 BootInfoCreateFlag = _FS_FILE_OPEN_FLAG_COMMIT | _FS_FILE_PUBLIC_WRITE | _FS_FILE_PUBLIC_READ;
if (!sl_FsOpen ((unsigned char *)IMG_BOOT_INFO, FS_MODE_OPEN_CREATE((2 * sizeof(sBootInfo_t)),
BootInfoCreateFlag), NULL, &fhandle)) {
// Write the default boot info.
if (sizeof(sBootInfo_t) == sl_FsWrite(fhandle, 0, (unsigned char *)&sBootInfo, sizeof(sBootInfo_t))) {
bootapp = true;
}
sl_FsClose(fhandle, 0, 0, 0);
}
}
if (bootapp) {
// load and execute the image based on the boot info
bootmgr_image_loader(&sBootInfo);
}
// stop simplelink
sl_Stop(SL_STOP_TIMEOUT);
// if we've reached this point, then it means a fatal error occurred and the application
// could not be loaded, so, loop forever and signal the crash to the user
while (true) {
// keep the bld on
MAP_GPIOPinWrite(MICROPY_SYS_LED_PORT, MICROPY_SYS_LED_PORT_PIN, MICROPY_SYS_LED_PORT_PIN);
__asm volatile(" dsb \n"
" isb \n"
" wfi \n");
}
}
//*****************************************************************************
//! The following stub function is needed to link mp_vprintf
//*****************************************************************************
#include "py/qstr.h"
const byte *qstr_data(qstr q, mp_uint_t *len) {
*len = 0;
return NULL;
}