From cf1b8e067a35bf31ac1f41e9f31163e71c151109 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Sun, 23 Aug 2020 19:33:58 -0700 Subject: [PATCH] Don't overwrite boot sector unless OTA changes it There is a window where the eboot sector is erased and unwritten/partially written. If there's a power cycle at this time, the chip will brick due to eboot being corrupted. Avoid this by checking if the new eboot 4K sector is identical to the one already in flash, and if so don't rewrite it. --- bootloaders/eboot/eboot.c | 26 +++++++++++++++++++------- bootloaders/eboot/eboot.elf | Bin 44468 -> 44900 bytes 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/bootloaders/eboot/eboot.c b/bootloaders/eboot/eboot.c index 6b3b31634..bf8a53115 100644 --- a/bootloaders/eboot/eboot.c +++ b/bootloaders/eboot/eboot.c @@ -159,11 +159,6 @@ int copy_raw(const uint32_t src_addr, gzip = true; } while (left > 0) { - if (!verify) { - if (SPIEraseSector(daddr/buffer_size)) { - return 2; - } - } if (!gzip) { if (SPIRead(saddr, buffer, buffer_size)) { return 3; @@ -190,8 +185,25 @@ int copy_raw(const uint32_t src_addr, return 9; } } else { - if (SPIWrite(daddr, buffer, buffer_size)) { - return 4; + // Special treatment for address 0 (bootloader). Only erase and + // rewrite if the data is different (i.e. very rarely). + bool skip = false; + if (daddr == 0) { + if (SPIRead(daddr, buffer2, buffer_size)) { + return 4; + } + if (!memcmp(buffer2, buffer, buffer_size)) { + ets_putc('B'); // Note we skipped the bootloader in output + skip = true; // And skip erase/write + } + } + if (!skip) { + if (SPIEraseSector(daddr/buffer_size)) { + return 2; + } + if (SPIWrite(daddr, buffer, buffer_size)) { + return 4; + } } } saddr += buffer_size; diff --git a/bootloaders/eboot/eboot.elf b/bootloaders/eboot/eboot.elf index 8c235c2087a1b2e72ba0ebb58ca69d24c202d202..48b3543892c439817ed8ffa358333cf48937c4ef 100755 GIT binary patch delta 15214 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 O9_(e*9T4Ik>i!p3`(;=F delta 14911 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 Fe*-c%5;_0?