Skip to content

Add a CRC32 over progmem and ESP.checkFlashCRC #6566

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Dec 20, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions cores/esp8266/Esp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "MD5Builder.h"
#include "umm_malloc/umm_malloc.h"
#include "cont.h"
#include "coredecls.h"

extern "C" {
#include "user_interface.h"
Expand Down Expand Up @@ -439,6 +440,19 @@ bool EspClass::checkFlashConfig(bool needsEquals) {
return false;
}

bool EspClass::checkFlashCRC() {
uint32_t flashsize = *((uint32_t*)0x40200ff8);
uint32_t flashcrc = *((uint32_t*)0x40200ffc);
uint32_t z[2];
z[0] = z[1] = 0;

uint32_t crc = crc32_P((const void*)0x40200000, 4096-8, 0xffffffff);
crc = crc32_P(z, 8, crc);
crc = crc32_P((const void*)0x40201000, flashsize-4096, crc);
return crc == flashcrc;
}


String EspClass::getResetReason(void) {
char buff[32];
if (resetInfo.reason == REASON_DEFAULT_RST) { // normal startup by power on
Expand Down
2 changes: 2 additions & 0 deletions cores/esp8266/Esp.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,8 @@ class EspClass {

bool checkFlashConfig(bool needsEquals = false);

bool checkFlashCRC();

bool flashEraseSector(uint32_t sector);
bool flashWrite(uint32_t offset, uint32_t *data, size_t size);
bool flashRead(uint32_t offset, uint32_t *data, size_t size);
Expand Down
1 change: 1 addition & 0 deletions cores/esp8266/coredecls.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ void disable_extra4k_at_link_time (void) __attribute__((noinline));

uint32_t sqrt32 (uint32_t n);
uint32_t crc32 (const void* data, size_t length, uint32_t crc = 0xffffffff);
uint32_t crc32_P (const void* data, size_t length, uint32_t crc = 0xffffffff);

#ifdef __cplusplus
}
Expand Down
21 changes: 21 additions & 0 deletions cores/esp8266/crc32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
*/

#include "coredecls.h"
#include "pgmspace.h"

// moved from core_esp8266_eboot_command.cpp
uint32_t crc32 (const void* data, size_t length, uint32_t crc /*= 0xffffffff*/)
Expand All @@ -40,3 +41,23 @@ uint32_t crc32 (const void* data, size_t length, uint32_t crc /*= 0xffffffff*/)
}
return crc;
}


uint32_t crc32_P (const void* data, size_t length, uint32_t crc /*= 0xffffffff*/)
{
const uint8_t* ldata = (const uint8_t*)data;
while (length--)
{
uint8_t c = pgm_read_byte(ldata++);
for (uint32_t i = 0x80; i > 0; i >>= 1)
{
bool bit = crc & 0x80000000;
if (c & i)
bit = !bit;
crc <<= 1;
if (bit)
crc ^= 0x04c11db7;
}
}
return crc;
}
2 changes: 2 additions & 0 deletions doc/libraries.rst
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ Some ESP-specific APIs related to deep sleep, RTC and flash memories are availab

``ESP.getCycleCount()`` returns the cpu instruction cycle count since start as an unsigned 32-bit. This is useful for accurate timing of very short actions like bit banging.

``ESP.checkFlashCRC()`` calculates the CRC of the program memory (not including any filesystems) and compares it to the one embedded in the image. If this call returns ``false`` then the flash has been corrupted.

``ESP.getVcc()`` may be used to measure supply voltage. ESP needs to reconfigure the ADC at startup in order for this feature to be available. Add the following line to the top of your sketch to use ``getVcc``:

.. code:: cpp
Expand Down
6 changes: 4 additions & 2 deletions platform.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ runtime.tools.elf2bin={runtime.platform.path}/tools/elf2bin.py
runtime.tools.sizes={runtime.platform.path}/tools/sizes.py
runtime.tools.makecorever={runtime.platform.path}/tools/makecorever.py
runtime.tools.eboot={runtime.platform.path}/bootloaders/eboot/eboot.elf
runtime.tools.crc={runtime.platform.path}/tools/crc32bin.py

compiler.warning_flags=-w
compiler.warning_flags.none=-w
Expand Down Expand Up @@ -112,8 +113,9 @@ recipe.objcopy.eep.pattern=

## Create hex
recipe.objcopy.hex.1.pattern="{runtime.tools.python3.path}/python3" "{runtime.tools.elf2bin}" --eboot "{runtime.tools.eboot}" --app "{build.path}/{build.project_name}.elf" --flash_mode {build.flash_mode} --flash_freq {build.flash_freq} --flash_size {build.flash_size} --path "{runtime.tools.xtensa-lx106-elf-gcc.path}/bin" --out "{build.path}/{build.project_name}.bin"
recipe.objcopy.hex.2.pattern="{runtime.tools.python3.path}/python3" "{runtime.tools.signing}" --mode sign --privatekey "{build.source.path}/private.key" --bin "{build.path}/{build.project_name}.bin" --out "{build.path}/{build.project_name}.bin.signed" --legacy "{build.path}/{build.project_name}.bin.legacy_sig"
recipe.objcopy.hex.3.pattern="{runtime.tools.python3.path}/python3" "{runtime.tools.sizes}" --elf "{build.path}/{build.project_name}.elf" --path "{runtime.tools.xtensa-lx106-elf-gcc.path}/bin"
recipe.objcopy.hex.2.pattern="{runtime.tools.python3.path}/python3" "{runtime.tools.crc}" --bin "{build.path}/{build.project_name}.bin" --size 4088 --crc 4092
recipe.objcopy.hex.3.pattern="{runtime.tools.python3.path}/python3" "{runtime.tools.signing}" --mode sign --privatekey "{build.source.path}/private.key" --bin "{build.path}/{build.project_name}.bin" --out "{build.path}/{build.project_name}.bin.signed" --legacy "{build.path}/{build.project_name}.bin.legacy_sig"
recipe.objcopy.hex.4.pattern="{runtime.tools.python3.path}/python3" "{runtime.tools.sizes}" --elf "{build.path}/{build.project_name}.elf" --path "{runtime.tools.xtensa-lx106-elf-gcc.path}/bin"

## Save hex
recipe.output.tmp_file={build.project_name}.bin
Expand Down
72 changes: 72 additions & 0 deletions tools/crc32bin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#!/usr/bin/env python3
#
# Place a CRC32 checksum and length in a generated BIN file
#
# Copyright (C) 2019 - Earle F. Philhower, III
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.

from __future__ import print_function
import argparse
import sys

def crc8266(ldata):
crc = 0xffffffff
idx = 0
while idx < len(ldata):
c = int(ldata[idx]);
idx = idx + 1
for i in [0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01]:
bit = crc & 0x80000000;
if (c & i) != 0:
if bit == 0:
bit = 1
else:
bit = 0
crc = int(crc << 1) & 0xffffffff
if bit != 0:
crc = int(crc ^ 0x04c11db7);
return crc

def store_word(raw, offset, val):
raw[offset] = val & 255
raw[offset + 1] = (val >> 8) & 255
raw[offset + 2] = (val >> 16) & 255
raw[offset + 3] = (val >> 24) & 255
return raw

def main():
parser = argparse.ArgumentParser(description='Add a CRC32 and length in a generated flash BIN image.')
parser.add_argument('-b', '--bin', action='store', required=True, help='Path to the Arduino sketch.bin')
parser.add_argument('-s', '--size', action='store', required=True, help='Byte offset in bin to store the size')
parser.add_argument('-c', '--crc', action='store', required=True, help='Byte offset in bin to store the crc32')
args = parser.parse_args()

with open(args.bin, "rb") as binfile:
raw = bytearray(binfile.read())

# Zero out the spots we're going to overwrite to be idempotent
raw = store_word(raw, int(args.size), 0)
raw = store_word(raw, int(args.crc), 0)
crc = crc8266(raw)
raw = store_word(raw, int(args.size), len(raw))
raw = store_word(raw, int(args.crc), int(crc))

with open(args.bin, "wb") as binfile:
binfile.write(raw)

print("Inserted length of " + hex(len(raw)) + " and CRC of " + hex(crc)+ " into " + args.bin)

if __name__ == '__main__':
sys.exit(main())