From 219be7d4c3141d6f8974a0dba257c8e8f479a907 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 1 Jun 2015 02:08:48 +0300 Subject: [PATCH] reading eboot commands via RTC, flash erase/copy --- .../esp8266/bootloaders/eboot/Makefile | 3 +- .../esp8266/bootloaders/eboot/eboot.c | 94 +++++++++++++++++- .../esp8266/bootloaders/eboot/eboot.elf | Bin 5209 -> 11738 bytes .../esp8266/bootloaders/eboot/eboot.h | 3 + .../esp8266/bootloaders/eboot/eboot_command.c | 47 +++++++++ .../esp8266/bootloaders/eboot/eboot_command.h | 29 ++++++ 6 files changed, 174 insertions(+), 2 deletions(-) create mode 100644 hardware/esp8266com/esp8266/bootloaders/eboot/eboot_command.c create mode 100644 hardware/esp8266com/esp8266/bootloaders/eboot/eboot_command.h diff --git a/hardware/esp8266com/esp8266/bootloaders/eboot/Makefile b/hardware/esp8266com/esp8266/bootloaders/eboot/Makefile index 32e325f34..8aaac9cab 100644 --- a/hardware/esp8266com/esp8266/bootloaders/eboot/Makefile +++ b/hardware/esp8266com/esp8266/bootloaders/eboot/Makefile @@ -5,6 +5,7 @@ TARGET_DIR := ./ TARGET_OBJ_FILES := \ eboot.o \ + eboot_command.o \ TARGET_OBJ_PATHS := $(addprefix $(TARGET_DIR)/,$(TARGET_OBJ_FILES)) @@ -17,7 +18,7 @@ OBJDUMP := $(XTENSA_TOOCHAIN)xtensa-lx106-elf-objdump CFLAGS += -std=gnu99 -CFLAGS += -O0 -g -Wpointer-arith -Wno-implicit-function-declaration -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mno-text-section-literals +CFLAGS += -Os -g -Wpointer-arith -Wno-implicit-function-declaration -Wl,-EL -fno-inline-functions -nostdlib -mlongcalls -mno-text-section-literals LDFLAGS += -nostdlib -Wl,--no-check-sections -umain diff --git a/hardware/esp8266com/esp8266/bootloaders/eboot/eboot.c b/hardware/esp8266com/esp8266/bootloaders/eboot/eboot.c index e39375d2d..86a27eff0 100644 --- a/hardware/esp8266com/esp8266/bootloaders/eboot/eboot.c +++ b/hardware/esp8266com/esp8266/bootloaders/eboot/eboot.c @@ -10,6 +10,7 @@ #include #include #include "eboot.h" +#include "eboot_command.h" extern void* flashchip; #define SWRST do { (*((volatile uint32_t*) 0x60000700)) |= 0x80000000; } while(0); @@ -71,9 +72,100 @@ int load_app_from_flash_raw(const uint32_t flash_addr) } + +int erase(const uint32_t start, const uint32_t size) +{ + if (start & (FLASH_SECTOR_SIZE - 1) != 0) { + return 1; + } + + const uint32_t sectors_per_block = FLASH_BLOCK_SIZE / FLASH_SECTOR_SIZE; + uint32_t current_sector = start / FLASH_SECTOR_SIZE; + uint32_t sector_count = (size + FLASH_SECTOR_SIZE - 1) / FLASH_SECTOR_SIZE; + const uint32_t end = current_sector + sector_count; + + for (; current_sector < end && (current_sector & (sectors_per_block-1)); + ++current_sector, --sector_count) { + if (SPIEraseSector(current_sector)) { + return 2; + } + } + + for (;current_sector + sectors_per_block <= end; + current_sector += sectors_per_block, + sector_count -= sectors_per_block) { + if (SPIEraseBlock(current_sector / sectors_per_block)) { + return 3; + } + } + + for (; current_sector < end; + ++current_sector, --sector_count) { + if (SPIEraseSector(current_sector)) { + return 4; + } + } + + return 0; +} + +int copy_raw(const uint32_t src_addr, + const uint32_t dst_addr, + const uint32_t size) +{ + // require regions to be aligned + if (src_addr & 0xfff != 0 || + dst_addr & 0xfff != 0) { + return 1; + } + + if (erase(dst_addr, size)) { + return 2; + } + + const uint32_t buffer_size = 4096; + uint8_t buffer[buffer_size]; + + const uint32_t end = src_addr + size; + uint32_t saddr = src_addr; + uint32_t daddr = dst_addr; + uint32_t left = size; + while (saddr < end) { + uint32_t will_copy = (left < buffer_size) ? left : buffer_size; + if (SPIRead(saddr, buffer, will_copy)) { + return 3; + } + if (SPIWrite(daddr, buffer, will_copy)) { + return 4; + } + saddr += will_copy; + daddr += will_copy; + left -= will_copy; + } + + return 0; +} + + + void main() { - int res = load_app_from_flash_raw(0); + int res; + struct eboot_command cmd; + + eboot_command_read(&cmd); + + if (cmd.action == ACTION_COPY_RAW) { + res = copy_raw(cmd.args[0], cmd.args[1], cmd.args[2]); + if (res == 0) { + cmd.action = ACTION_LOAD_APP; + } + } + + if (cmd.action == ACTION_LOAD_APP) { + res = load_app_from_flash_raw(0); + } + if (res) { ets_putc('\n'); ets_putc('#'); diff --git a/hardware/esp8266com/esp8266/bootloaders/eboot/eboot.elf b/hardware/esp8266com/esp8266/bootloaders/eboot/eboot.elf index b2381a4098690e025f33c25290a14715934882fe..b7908dfd67b803008b425ac3b0d07ce5d7dd279b 100755 GIT binary patch literal 11738 zcmb_i3v^t?d7im@ceN|69;>x%89%g=t;jak!^Q=f+E|h;V;O^uBtK|vmX)-YWTahr zcjX5aNVs4i7_i}_JmN%#Q%+9^%?Xf}a0r_bMDOl_~xH~{(olf+`Bv6yl%CWQs~PN*9&syZ;Kk1pgvWB!X?BK5fW}O zPXt7P(!Ze_OsLtG_a8<7X;Fi~U5fsByKURFe-8YGF6z8R)Qr8D9#)8>>2$hm=2fC0 zT?l@yX!t>kXb`}x11)mI4UmqUxmYwjJL{M!ioyRXJvxHA_}FW29lCqbX~Tb8#p^|{ zKI(hw?5&^el<%jH3USid)Zr=rdHQ$$1*hNl?+=RV{N>Vr+gW)wAb(E4xsMuuny#03 zpI$qs@xRkmKgcgXoo+mxUNEO>iSe=_)a<$n=);^}#T1*i8LLiiVY+`_-?WtW(d zu8_W}6;B*-iPezL^gdPXfAi4sN6*~)>CWO~b@^kW_}JL1<-SEHjkf}4rN21mT%`PX z`sj(q1wVQ1RO5f1LJ!q``A@Wee&37}|MC2^qoF069{XZH!*+CTqkK{MxcFqjJ12_% z=Y?|?{y7RyH37eD%x|oA34eu$el6aQR{kdMqT}Un2F}RhV@2>lz=zjfee|tE49aQ4 z_f%a)=y&p@%Rf8kogLM#2I<*-ROk1uxT{t^$liNaoNH1tzkJBz@2owwZ^!8!CvLd&=)AJ3Cj7|6Ei*OwEr+(c;Q6hab zB-R*pOG2oZ8mm7{uU+XcJrqxSa)l62!^_({j*Ntc-Oqa5BfIMc22x`cfrF3LO47prxG#wcl`pAg5ZvQ;(U1UWV@|Pk;WGj4Kv^8CRT^efi zwZ&MlZpW(Y%&RIcyZ?h~zx#Z;-k|*BY#`Z-O*AIST4b6V*K~ldI)`F(U6Z@8in1uJ?ew6{LkNQdoja4}|x) z?q%DB7F6_nR@Crt23u!(K_4&(y3cL;z~mQ>NK_%*ytwD2SkqR)L8&k!@&KlwnCLtC z=W*{rn|jnUZT|b~+)28Ow9C^^x;)BKxW2^(6}Nza zy~+gQO3aYRWz_|79*da_)-*u<6%fl{B}zR5<>5{! z@}EH=gCuzse2hYtFfPWSErkQ|q>##T8zhCv0U=ki1J2;WfleV;k$VQWdJL?Fm4FZZ z%Gs2^g1fjBMZsPavVzeu4s8f9Kyn_t`~|2$57`AhU_S#DydASX&yA-b1XEkuREm--Y^046{(qwv1C=QC+LnjsW4Yx2jZ(0S*U?43paVO} zGSQav39{X|1FH$Xh3uWUr!9klCn^6n3OP)BuYt1MzLl^sYHO(7$3e}2lYu0S{3Y3? zWVeyMjqGNyMRgzoFcdgOPxe#(SC9vv$B3B7&%hvuu3_Qf;F!b{P;G+BAx30G$pOgY z=$rD7WxI|=?m8&xdMPJ$0`|mIQq!Mjj}Pj-Ode);g^4I8?ZcG-eFw;kI{T54N4U~l zhsJK1(TGjyGU!gj+)PU46NKImc9saXKsyK{kAp?;@^TTp))qZyi45-?5&Sb-cG8v& z)rpc0TV^#A!KvW)!_-F>hMkMql@M~ul`I8uBYGzq0W7-+K9~jcWC7ZQq98(wQX71^ zS@sYC`2=w8D1a#QAy%fJLPpaTGNEQ6g&fI5Q;spyyIG;&lYWFp)-PbU3eg>gwZ{pmGjcczb%-X~aYfCn) zEm>{yt~aQ6s~ytJWCdug$3H@ri|YOS;uV`=%)wEF_>GHyZKLYC>rusmFkaazX8Nd6SYru+tk zEWZL}sGutee=Amk=0YlA)MOR?xeV;o8$eV+$1%>KbS-B~;6r$`6J62)F5*IyeHRf> zXtESCAS(-kd9H#P1skUYWYIJXd9KLIyCTo!#j2btTm_fs{b^oH5J|G-1(*RrnU_bo zgxr�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 diff --git a/hardware/esp8266com/esp8266/bootloaders/eboot/eboot.h b/hardware/esp8266com/esp8266/bootloaders/eboot/eboot.h index b77f8f45a..973c616a8 100644 --- a/hardware/esp8266com/esp8266/bootloaders/eboot/eboot.h +++ b/hardware/esp8266com/esp8266/bootloaders/eboot/eboot.h @@ -14,6 +14,9 @@ int SPIEraseSector(uint32_t sector); int SPIRead(uint32_t addr, void *dest, size_t size); int SPIWrite(uint32_t addr, void *src, size_t size); + +#define FLASH_SECTOR_SIZE 0x1000 +#define FLASH_BLOCK_SIZE 0x10000 #define APP_START_OFFSET 0x1000 typedef struct { diff --git a/hardware/esp8266com/esp8266/bootloaders/eboot/eboot_command.c b/hardware/esp8266com/esp8266/bootloaders/eboot/eboot_command.c new file mode 100644 index 000000000..1e9cbed2c --- /dev/null +++ b/hardware/esp8266com/esp8266/bootloaders/eboot/eboot_command.c @@ -0,0 +1,47 @@ +#include "eboot_command.h" + +uint32_t crc_update(uint32_t crc, const uint8_t *data, size_t length) +{ + uint32_t i; + bool bit; + uint8_t c; + + while (length--) { + c = *data++; + for (i = 0x80; i > 0; i >>= 1) { + bit = crc & 0x80000000; + if (c & i) { + bit = !bit; + } + crc <<= 1; + if (bit) { + crc ^= 0x04c11db7; + } + } + } + return crc; +} + +uint32_t eboot_command_calculate_crc32(const struct eboot_command* cmd) +{ + return crc_update(0xffffffff, (const uint8_t*) cmd, + offsetof(struct eboot_command, crc32)); +} + +void eboot_command_read(struct eboot_command* cmd) +{ + const uint32_t dw_count = sizeof(struct eboot_command) / sizeof(uint32_t); + uint32_t* dst = (uint32_t *) cmd; + for (uint32_t i = 0; i < dw_count; ++i) { + dst[i] = RTC_MEM[i]; + } + + uint32_t crc32 = eboot_command_calculate_crc32(cmd); + if (cmd->magic & EBOOT_MAGIC_MASK != EBOOT_MAGIC || + cmd->crc32 != crc32) { + + cmd->action = ACTION_LOAD_APP; + cmd->args[0] = 0; + } +} + diff --git a/hardware/esp8266com/esp8266/bootloaders/eboot/eboot_command.h b/hardware/esp8266com/esp8266/bootloaders/eboot/eboot_command.h new file mode 100644 index 000000000..aa0fc11bb --- /dev/null +++ b/hardware/esp8266com/esp8266/bootloaders/eboot/eboot_command.h @@ -0,0 +1,29 @@ +#ifndef EBOOT_COMMAND_H +#define EBOOT_COMMAND_H + +#include +#include +#include + +#define RTC_MEM ((volatile uint32_t*)0x60001200) + +enum action_t { + ACTION_COPY_RAW = 0x00000001, + ACTION_LOAD_APP = 0xffffffff +}; + +#define EBOOT_MAGIC 0xeb001000 +#define EBOOT_MAGIC_MASK 0xfffff000 + +struct eboot_command { + uint32_t magic; + enum action_t action; + uint32_t args[29]; + uint32_t crc32; +}; + + +void eboot_command_read(struct eboot_command* cmd); + + +#endif //EBOOT_COMMAND_H