int mgos_upd_finalize(struct mgos_upd_hal_ctx *ctx) { struct boot_cfg cur_cfg, new_cfg; int r = read_boot_cfg(ctx->cur_boot_cfg_idx, &cur_cfg); if (r < 0) { ctx->status_msg = "Could not read current boot cfg"; return r; } LOG(LL_INFO, ("Boot cfg %d: 0x%llx, 0x%x, %s @ 0x%08x, %s", ctx->cur_boot_cfg_idx, cur_cfg.seq, (unsigned int) cur_cfg.flags, cur_cfg.app_image_file, (unsigned int) cur_cfg.app_load_addr, cur_cfg.fs_container_prefix)); memset(&new_cfg, 0, sizeof(new_cfg)); new_cfg.seq = cur_cfg.seq - 1; new_cfg.flags |= BOOT_F_FIRST_BOOT; if (ctx->app_image_file[0] != '\0') { strncpy(new_cfg.app_image_file, ctx->app_image_file, sizeof(new_cfg.app_image_file)); new_cfg.app_load_addr = ctx->app_load_addr; } else { strcpy(new_cfg.app_image_file, cur_cfg.app_image_file); new_cfg.app_load_addr = cur_cfg.app_load_addr; } if (ctx->fs_container_file[0] != '\0') { int n = strlen(ctx->fs_container_file); do { n--; } while (ctx->fs_container_file[n] != '.'); strncpy(new_cfg.fs_container_prefix, ctx->fs_container_file, n); new_cfg.flags |= BOOT_F_MERGE_SPIFFS; } else { strcpy(new_cfg.fs_container_prefix, cur_cfg.fs_container_prefix); } LOG(LL_INFO, ("Boot cfg %d: 0x%llx, 0x%x, %s @ 0x%08x, %s", ctx->new_boot_cfg_idx, new_cfg.seq, (unsigned int) new_cfg.flags, new_cfg.app_image_file, (unsigned int) new_cfg.app_load_addr, new_cfg.fs_container_prefix)); r = write_boot_cfg(&new_cfg, ctx->new_boot_cfg_idx); if (r < 0) { ctx->status_msg = "Could not write new boot cfg"; return r; } return 1; }
int mgos_upd_apply_update() { int boot_cfg_idx = g_boot_cfg_idx; struct boot_cfg *cfg = &g_boot_cfg; if (cfg->flags & BOOT_F_MERGE_SPIFFS) { int old_boot_cfg_idx = (boot_cfg_idx == 0 ? 1 : 0); struct boot_cfg old_boot_cfg; int r = read_boot_cfg(old_boot_cfg_idx, &old_boot_cfg); if (r < 0) return r; if (!cc32xx_fs_spiffs_container_mount("/old", old_boot_cfg.fs_container_prefix)) return -123; if (mgos_upd_merge_fs("/old", "/")) { r = 0; cfg->flags &= ~(BOOT_F_MERGE_SPIFFS); } else { r = -124; } mgos_vfs_umount("/old"); } return 0; }
static int tcmp(const struct json_token *tok, const char *str) { struct mg_str s = {.p = tok->ptr, .len = tok->len}; return mg_vcmp(&s, str); } enum mgos_upd_file_action mgos_upd_file_begin( struct mgos_upd_hal_ctx *ctx, const struct mgos_upd_file_info *fi) { struct mg_str part_name = MG_MK_STR(""); enum mgos_upd_file_action ret = MGOS_UPDATER_SKIP_FILE; struct find_part_info find_part_info = {fi->name, &part_name, &ctx->cur_part}; ctx->cur_part.len = part_name.len = 0; json_walk(ctx->parts->ptr, ctx->parts->len, find_part, &find_part_info); if (ctx->cur_part.len == 0) return ret; /* Drop any indexes from part name, we'll add our own. */ while (1) { char c = part_name.p[part_name.len - 1]; if (c != '.' && !(c >= '0' && c <= '9')) break; part_name.len--; } struct json_token type = JSON_INVALID_TOKEN; const char *fname = NULL; uint32_t falloc = 0; json_scanf(ctx->cur_part.ptr, ctx->cur_part.len, "{load_addr:%u, falloc:%u, type: %T}", &ctx->app_load_addr, &falloc, &type); if (falloc == 0) falloc = fi->size; if (tcmp(&type, "app") == 0) { struct boot_cfg cur_cfg; int r = read_boot_cfg(ctx->cur_boot_cfg_idx, &cur_cfg); if (r < 0) { ctx->status_msg = "Could not read current boot cfg"; return MGOS_UPDATER_ABORT; } #if CC3200_SAFE_CODE_UPDATE /* * When safe code update is enabled, we write code to a new file. * Otherwise we write to the same slot we're using currently, which is * unsafe, makes reverting code update not possible, but saves space. */ create_fname( mg_mk_str_n(cur_cfg.app_image_file, strlen(cur_cfg.app_image_file) - 2), ctx->new_boot_cfg_idx, ctx->app_image_file, sizeof(ctx->app_image_file)); #else { strncpy(ctx->app_image_file, cur_cfg.app_image_file, sizeof(ctx->app_image_file)); } #endif if (ctx->app_load_addr >= 0x20000000) { fname = ctx->app_image_file; } else { ctx->status_msg = "Bad/missing app load_addr"; ret = MGOS_UPDATER_ABORT; } } else if (tcmp(&type, "fs") == 0) { json_scanf( ctx->cur_part.ptr, ctx->cur_part.len, "{fs_size: %u, fs_block_size: %u, fs_page_size: %u, fs_erase_size: %u}", &ctx->fs_size, &ctx->fs_block_size, &ctx->fs_page_size, &ctx->fs_erase_size); if (ctx->fs_size > 0 && ctx->fs_block_size > 0 && ctx->fs_page_size > 0 && ctx->fs_erase_size > 0) { char fs_container_prefix[MAX_FS_CONTAINER_PREFIX_LEN]; create_fname(part_name, ctx->new_boot_cfg_idx, fs_container_prefix, sizeof(fs_container_prefix)); /* Delete container 1 (if any) so that 0 is the only one. */ cc32xx_vfs_dev_slfs_container_delete_container(fs_container_prefix, 1); cc32xx_vfs_dev_slfs_container_fname(fs_container_prefix, 0, (_u8 *) ctx->fs_container_file); fname = ctx->fs_container_file; if (fi->size > ctx->fs_size) { /* Assume meta has already been added. */ falloc = fi->size; } else { falloc = FS_CONTAINER_SIZE(fi->size); } } else { ctx->status_msg = "Missing FS parameters"; ret = MGOS_UPDATER_ABORT; } } if (fname != NULL) { int r = prepare_to_write(ctx, fi, fname, falloc, &ctx->cur_part); if (r < 0) { LOG(LL_ERROR, ("err = %d", r)); ret = MGOS_UPDATER_ABORT; } else { ret = (r > 0 ? MGOS_UPDATER_PROCESS_FILE : MGOS_UPDATER_SKIP_FILE); } } if (ret == MGOS_UPDATER_SKIP_FILE) { DBG(("Skipping %s %.*s", fi->name, (int) part_name.len, part_name.p)); } return ret; } int mgos_upd_file_data(struct mgos_upd_hal_ctx *ctx, const struct mgos_upd_file_info *fi, struct mg_str data) { _i32 r = sl_FsWrite(ctx->cur_fh, fi->processed, (_u8 *) data.p, data.len); if (r != data.len) { ctx->status_msg = "Write failed"; r = -1; } return r; }
int main(void) { MAP_IntVTableBaseSet((unsigned long) &int_vectors[0]); MAP_IntMasterEnable(); PRCMCC3200MCUInit(); /* Console UART init. */ #ifndef NO_DEBUG MAP_PRCMPeripheralClkEnable(DEBUG_UART_PERIPH, PRCM_RUN_MODE_CLK); #if MIOT_DEBUG_UART == 0 MAP_PinTypeUART(PIN_55, PIN_MODE_3); /* UART0_TX */ MAP_PinTypeUART(PIN_57, PIN_MODE_3); /* UART0_RX */ #else MAP_PinTypeUART(PIN_07, PIN_MODE_5); /* UART1_TX */ MAP_PinTypeUART(PIN_08, PIN_MODE_5); /* UART1_RX */ #endif MAP_UARTConfigSetExpClk( DEBUG_UART_BASE, MAP_PRCMPeripheralClockGet(DEBUG_UART_PERIPH), MIOT_DEBUG_UART_BAUD_RATE, (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE)); MAP_UARTFIFOLevelSet(DEBUG_UART_BASE, UART_FIFO_TX1_8, UART_FIFO_RX4_8); MAP_UARTFIFODisable(DEBUG_UART_BASE); #endif dbg_puts("\r\n\n"); if (sl_Start(NULL, NULL, NULL) < 0) abort(); dbg_putc('S'); int cidx = get_active_boot_cfg_idx(); if (cidx < 0) abort(); dbg_putc('0' + cidx); struct boot_cfg cfg; if (read_boot_cfg(cidx, &cfg) < 0) abort(); dbg_puts(cfg.app_image_file); dbg_putc('@'); print_addr(cfg.app_load_addr); /* * Zero memory before loading. * This should provide proper initialisation for BSS, wherever it is. */ uint32_t *pstart = (uint32_t *) 0x20000000; uint32_t *pend = (&_text_start - 0x100 /* our stack */); for (uint32_t *p = pstart; p < pend; p++) *p = 0; if (load_image(cfg.app_image_file, (_u8 *) cfg.app_load_addr) != 0) { abort(); } dbg_putc('.'); sl_Stop(0); print_addr(*(((uint32_t *) cfg.app_load_addr) + 1)); dbg_puts("\r\n\n"); MAP_IntMasterDisable(); MAP_IntVTableBaseSet(cfg.app_load_addr); run(cfg.app_load_addr); /* Does not return. */ abort(); return 0; /* not reached */ }
static enum cc3200_init_result cc3200_init(void *arg) { mongoose_init(); if (miot_uart_init(0, miot_uart_default_config(), NULL, NULL) == NULL) { return CC3200_INIT_UART_INIT_FAILED; } if (miot_uart_init(1, miot_uart_default_config(), NULL, NULL) == NULL) { return CC3200_INIT_UART_INIT_FAILED; } if (strcmp(MIOT_APP, "mongoose-iot") != 0) { LOG(LL_INFO, ("%s %s (%s)", MIOT_APP, build_version, build_id)); } LOG(LL_INFO, ("Mongoose IoT Firmware %s (%s)", mg_build_version, mg_build_id)); LOG(LL_INFO, ("RAM: %d total, %d free", miot_get_heap_size(), miot_get_free_heap_size())); int r = start_nwp(); if (r < 0) { LOG(LL_ERROR, ("Failed to start NWP: %d", r)); return CC3200_INIT_FAILED_TO_START_NWP; } g_boot_cfg_idx = get_active_boot_cfg_idx(); if (g_boot_cfg_idx < 0 || read_boot_cfg(g_boot_cfg_idx, &g_boot_cfg) < 0) { return CC3200_INIT_FAILED_TO_READ_BOOT_CFG; } LOG(LL_INFO, ("Boot cfg %d: 0x%llx, 0x%u, %s @ 0x%08x, %s", g_boot_cfg_idx, g_boot_cfg.seq, g_boot_cfg.flags, g_boot_cfg.app_image_file, g_boot_cfg.app_load_addr, g_boot_cfg.fs_container_prefix)); if (g_boot_cfg.flags & BOOT_F_FIRST_BOOT) { /* Tombstone the current config. If anything goes wrong between now and * commit, next boot will use the old one. */ uint64_t saved_seq = g_boot_cfg.seq; g_boot_cfg.seq = BOOT_CFG_TOMBSTONE_SEQ; write_boot_cfg(&g_boot_cfg, g_boot_cfg_idx); g_boot_cfg.seq = saved_seq; } r = cc3200_fs_init(g_boot_cfg.fs_container_prefix); if (r < 0) { LOG(LL_ERROR, ("FS init error: %d", r)); return CC3200_INIT_FS_INIT_FAILED; } else { /* * We aim to maintain at most 3 FS containers at all times. * Delete inactive FS container in the inactive boot configuration. */ struct boot_cfg cfg; int inactive_idx = (g_boot_cfg_idx == 0 ? 1 : 0); if (read_boot_cfg(inactive_idx, &cfg) >= 0) { fs_delete_inactive_container(cfg.fs_container_prefix); } } #if MIOT_ENABLE_UPDATER if (g_boot_cfg.flags & BOOT_F_FIRST_BOOT) { LOG(LL_INFO, ("Applying update")); r = miot_upd_apply_update(); if (r < 0) { LOG(LL_ERROR, ("Failed to apply update: %d", r)); return CC3200_INIT_UPDATE_FAILED; } } #endif enum miot_init_result ir = mg_init(); if (ir != MIOT_INIT_OK) { LOG(LL_ERROR, ("%s init error: %d", "MG", ir)); return CC3200_INIT_MG_INIT_FAILED; } #if MIOT_ENABLE_JS struct v7 *v7 = s_v7 = init_v7(&arg); ir = miot_init_js_all(v7); if (ir != MIOT_INIT_OK) { LOG(LL_ERROR, ("%s init error: %d", "JS", ir)); return CC3200_INIT_MG_INIT_JS_FAILED; } #endif #if MIOT_ENABLE_JS miot_prompt_init(v7, get_cfg()->debug.stdout_uart); #endif return CC3200_INIT_OK; }
static int sj_init() { struct v7 *v7 = s_v7; LOG(LL_INFO, ("Mongoose IoT Firmware %s", build_id)); LOG(LL_INFO, ("RAM: %d total, %d free", sj_get_heap_size(), sj_get_free_heap_size())); int r = start_nwp(); if (r < 0) { LOG(LL_ERROR, ("Failed to start NWP: %d", r)); return 0; } int boot_cfg_idx = get_active_boot_cfg_idx(); if (boot_cfg_idx < 0) return 0; struct boot_cfg boot_cfg; if (read_boot_cfg(boot_cfg_idx, &boot_cfg) < 0) return 0; LOG(LL_INFO, ("Boot cfg %d: 0x%llx, 0x%u, %s @ 0x%08x, %s", boot_cfg_idx, boot_cfg.seq, boot_cfg.flags, boot_cfg.app_image_file, boot_cfg.app_load_addr, boot_cfg.fs_container_prefix)); uint64_t saved_seq = 0; if (boot_cfg.flags & BOOT_F_FIRST_BOOT) { /* Tombstone the current config. If anything goes wrong between now and * commit, next boot will use the old one. */ saved_seq = boot_cfg.seq; boot_cfg.seq = BOOT_CFG_TOMBSTONE_SEQ; write_boot_cfg(&boot_cfg, boot_cfg_idx); } r = init_fs(boot_cfg.fs_container_prefix); if (r < 0) { LOG(LL_ERROR, ("FS init error: %d", r)); if (boot_cfg.flags & BOOT_F_FIRST_BOOT) { revert_update(boot_cfg_idx, &boot_cfg); } return 0; } if (boot_cfg.flags & BOOT_F_FIRST_BOOT) { LOG(LL_INFO, ("Applying update")); if (apply_update(boot_cfg_idx, &boot_cfg) < 0) { revert_update(boot_cfg_idx, &boot_cfg); } } mongoose_init(); #ifndef CS_DISABLE_JS v7 = s_v7 = init_v7(&v7); /* Disable GC during JS API initialization. */ v7_set_gc_enabled(v7, 0); sj_gpio_api_setup(v7); sj_i2c_api_setup(v7); sj_wifi_api_setup(v7); sj_timers_api_setup(v7); #endif sj_v7_ext_api_setup(v7); sj_init_sys(v7); sj_wifi_init(v7); #ifndef DISABLE_C_CLUBBY sj_clubby_init(); #endif sj_http_api_setup(v7); #if !defined(DISABLE_C_CLUBBY) && !defined(CS_DISABLE_JS) sj_clubby_api_setup(v7); #endif /* Common config infrastructure. Mongoose & v7 must be initialized. */ init_device(v7); sj_updater_post_init(v7); #ifndef DISABLE_C_CLUBBY init_updater_clubby(v7); #endif #ifndef CS_DISABLE_JS /* SJS initialized, enable GC back, and trigger it */ v7_set_gc_enabled(v7, 1); v7_gc(v7, 1); v7_val_t res; if (v7_exec_file(v7, "sys_init.js", &res) != V7_OK) { fprintf(stderr, "Error: "); v7_fprint(stderr, v7, res); } #endif LOG(LL_INFO, ("%s init done, RAM: %d free", "Sys", sj_get_free_heap_size())); if (!sj_app_init(v7)) { LOG(LL_ERROR, ("App init failed")); abort(); } LOG(LL_INFO, ("%s init done, RAM: %d free", "App", sj_get_free_heap_size())); if (boot_cfg.flags & BOOT_F_FIRST_BOOT) { boot_cfg.seq = saved_seq; commit_update(boot_cfg_idx, &boot_cfg); clubby_updater_finish(0); } else { /* * If there is no update reply state, this will just be ignored. * But if there is, then update was rolled back and reply will be sent. */ clubby_updater_finish(-1); } #ifndef CS_DISABLE_JS sj_prompt_init(v7); #endif return 1; }