esp-open-rtos/extras/rboot-ota/rboot-ota.c

204 lines
6.1 KiB
C
Raw Normal View History

#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <espressif/spi_flash.h>
#include <espressif/esp_system.h>
#include <lwip/sockets.h>
#include <FreeRTOS.h>
#include <task.h>
#define SECTOR_SIZE 0x1000
#define BOOT_CONFIG_SECTOR 1
#include "rboot-ota.h"
#define ROM_MAGIC_OLD 0xe9
#define ROM_MAGIC_NEW 0xea
// get the rboot config
rboot_config_t rboot_get_config() {
rboot_config_t conf;
sdk_spi_flash_read(BOOT_CONFIG_SECTOR * SECTOR_SIZE, (uint32_t*)&conf, sizeof(rboot_config_t));
return conf;
}
// write the rboot config
// preserves contents of rest of sector, so rest
// of sector can be used to store user data
// updates checksum automatically, if enabled
bool rboot_set_config(rboot_config_t *conf) {
uint8_t *buffer;
#ifdef RBOOT_CONFIG_CHKSUM
uint8_t chksum;
uint8_t *ptr;
#endif
buffer = (uint8_t*)malloc(SECTOR_SIZE);
if (!buffer) {
printf("Failed to allocate sector buffer\r\n");
return false;
}
#ifdef BOOT_CONFIG_CHKSUM
chksum = CHKSUM_INIT;
for (ptr = (uint8_t*)conf; ptr < &conf->chksum; ptr++) {
chksum ^= *ptr;
}
conf->chksum = chksum;
#endif
sdk_spi_flash_read(BOOT_CONFIG_SECTOR * SECTOR_SIZE, (uint32_t*)buffer, SECTOR_SIZE);
memcpy(buffer, conf, sizeof(rboot_config_t));
vPortEnterCritical();
sdk_spi_flash_erase_sector(BOOT_CONFIG_SECTOR);
vPortExitCritical();
taskYIELD();
vPortEnterCritical();
sdk_spi_flash_write(BOOT_CONFIG_SECTOR * SECTOR_SIZE, (uint32_t*)buffer, SECTOR_SIZE);
vPortExitCritical();
free(buffer);
return true;
}
// get current boot rom
uint8_t rboot_get_current_rom() {
rboot_config_t conf;
conf = rboot_get_config();
return conf.current_rom;
}
// set current boot rom
bool rboot_set_current_rom(uint8_t rom) {
rboot_config_t conf;
conf = rboot_get_config();
if (rom >= conf.count) return false;
conf.current_rom = rom;
return rboot_set_config(&conf);
}
int rboot_ota_update(int fd, int slot, bool reboot_now)
{
rboot_config_t conf;
conf = rboot_get_config();
if(slot == -1) {
slot = (conf.current_rom + 1) % RBOOT_MAX_ROMS;
}
size_t sector = conf.roms[slot] / SECTOR_SIZE;
uint8_t *sector_buf = (uint8_t *)malloc(SECTOR_SIZE);
if(!sector_buf) {
printf("Failed to malloc sector buffer\r\n");
return 0;
}
printf("New image going into sector %d @ 0x%lx\r\n", slot, conf.roms[slot]);
/* Read bootloader header */
int r = read(fd, sector_buf, 8);
if(r != 8 || (sector_buf[0] != ROM_MAGIC_OLD && sector_buf[0] != ROM_MAGIC_NEW)) {
printf("Failed to read ESP bootloader header r=%d magic=%d.\r\n", r, sector_buf[0]);
slot = -1;
goto cleanup;
}
/* if we saw a v1.2 header, we can expect a v1.1 header after the first section */
bool in_new_header = (sector_buf[0] == ROM_MAGIC_NEW);
int remaining_sections = sector_buf[1];
size_t offs = 8;
size_t total_read = 8;
size_t left_section = 0; /* Number of bytes left in this section */
while(remaining_sections > 0 || left_section > 0)
{
if(left_section == 0) {
/* No more bytes in this section, read the next section header */
if(offs + (in_new_header ? 16 : 8) > SECTOR_SIZE) {
printf("PANIC: reading section header overflows sector boundary. FIXME.\r\n");
slot = -1;
goto cleanup;
}
if(in_new_header && total_read > 8)
{
/* expecting an "old" style 8 byte image header here, following irom0 */
int r = read(fd, sector_buf+offs, 8);
if(r != 8 || sector_buf[offs] != ROM_MAGIC_OLD) {
printf("Failed to read second flash header r=%d magic=0x%02x.\r\n", r, sector_buf[offs]);
slot = -1;
goto cleanup;
}
/* treat this number as the reliable number of remaining sections */
remaining_sections = sector_buf[offs+1];
in_new_header = false;
}
int r = read(fd, sector_buf+offs, 8);
if(r != 8) {
printf("Failed to read section header.\r\n");
slot = -1;
goto cleanup;
}
offs += 8;
total_read += 8;
left_section = *((uint32_t *)(sector_buf+offs-4));
/* account for padding from the reported section size out to the alignment barrier */
size_t section_align = in_new_header ? 16 : 4;
left_section = (left_section+section_align-1) & ~(section_align-1);
remaining_sections--;
printf("New section @ 0x%x length 0x%x align 0x%x remaining 0x%x\r\n", total_read, left_section, section_align, remaining_sections);
}
size_t bytes_to_read = left_section > (SECTOR_SIZE-offs) ? (SECTOR_SIZE-offs) : left_section;
int r = read(fd, sector_buf+offs, bytes_to_read);
if(r < 0) {
printf("Failed to read from fd\r\n");
slot = -1;
goto cleanup;
}
if(r == 0) {
printf("EOF before end of image remaining_sections=%d this_section=%d\r\n",
remaining_sections, left_section);
slot = -1;
goto cleanup;
}
offs += r;
total_read += r;
left_section -= r;
if(offs == SECTOR_SIZE || (left_section == 0 && remaining_sections == 0)) {
/* sector buffer is full, or we're at the very end, so write sector to flash */
printf("Sector buffer full. Erasing sector 0x%02x\r\n", sector);
sdk_spi_flash_erase_sector(sector);
printf("Erase done.\r\n");
//sdk_spi_flash_write(sector * SECTOR_SIZE, (uint32_t*)sector_buf, SECTOR_SIZE);
printf("Flash done.\r\n");
offs = 0;
sector++;
}
}
/* Done reading image from fd and writing it out */
if(reboot_now)
{
close(fd);
conf.current_rom = slot;
rboot_set_config(&conf);
sdk_system_restart();
}
cleanup:
free(sector_buf);
return slot;
}