Skip to content
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

Provide bootloader-hash tool #1190

Merged
merged 3 commits into from
Nov 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 1 addition & 3 deletions src/urclock.c
Original file line number Diff line number Diff line change
Expand Up @@ -1142,9 +1142,6 @@ static void guessblstart(const PROGRAMMER *pgm, const AVRPART *p) {
{ 2048, 0, 0x12ab8da0, 0xca46a3ca }, // ATmegaBOOT_168_diecimila.hex
{ 2048, 0, 0x3242ddd3, 0xf3e94dba }, // ATmegaBOOT_168_ng.hex
{ 2048, 0, 0x2eed30b3, 0x47d14ffa }, // ATmegaBOOT_168_pro_8MHz.hex
{ 4096, 0, 0xc52edd05, 0xa3371f94 }, // Caterina-LilyPadUSB.hex
{ 4096, 0, 0x663b8f7e, 0x7efdda2b }, // Caterina-Robot-Control.hex
{ 4096, 0, 0x3c6387e7, 0x7e96eea2 }, // Caterina-Robot-Motor.hex
{ 2048, 0, 0x1cef0d75, 0x6cfbac49 }, // LilyPadBOOT_168.hex
{ 1024, 1, 0x6ca0f37b, 0x31bae545 }, // bigboot_328.hex
{ 512, 0, 0x035cbc07, 0x24ba435e }, // optiboot_atmega168.hex
Expand All @@ -1159,6 +1156,7 @@ static void guessblstart(const PROGRAMMER *pgm, const AVRPART *p) {
{ 256, 0, 0xaa62bafc, 0xaa62bafc }, // picobootArduino8v3rc1.hex
{ 256, 0, 0x56263965, 0x56263965 }, // picobootSTK500-168p.hex
{ 512, 0, 0x3242ddd3, 0x5ba5f5f6 }, // picobootSTK500-328p.hex
{ 3072, 0, 0x3242ddd3, 0xd3347c5d }, // optiboot_lgt8f328p.hex
};

uint8_t buf[4096], b128[128];
Expand Down
123 changes: 123 additions & 0 deletions tools/bootloader-hash
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#!/bin/bash

# published under GNU General Public License, version 3 (GPL-3.0)
# author Stefan Rueger, 2022
#
# Recursivly find in the current directory intel .hex files, which are
# presumed to be bootloaders; create their hash table entry for urclock.c
#
# Background. This bash script computes the hash-sum of stk500v1 bootloaders
# to ease the guesswork of AVRDUDE's -c urclock programmer. Urclock is
# compatible with -c arduino, but needs to know the size of the bootloader to
# protect it *externally* from being overwritten. In contrast to urboot,
# optiboot et al binaries do not advertise their size and properties. Hence,
# urclock.c maintains a table with hash-sums of popular bootloaders that are
# out there in the wild, so the user doesn't have to know, let alone specify,
# the size of the bootloader on their devices. This utility computes the
# table entry from a .hex files in the directory.
#
# Example:
# $ git clone git@github.com:MCUdude/optiboot_flash.git
# $ ./bootloader-hash

progname=$(basename $0)

hash srec_cat 2>/dev/null || { echo $progname: package srecord is needed, try apt install srecord; exit; }
hash cc 2>/dev/null || { echo $progname: need a C compiler; exit; }

tmp=$(mktemp "$progname.XXXXXX")
trap "rm -f $tmp $tmp.[ch]" EXIT

cat >$tmp.c <<END
// published under GNU General Public License, version 3 (GPL-3.0)
// meta-autor Stefan Rueger, 2022

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#include "$tmp.h"

// https://en.wikipedia.org/wiki/Jenkins_hash_function
uint32_t jenkins_hash(const uint8_t* key, size_t length) {
size_t i = 0;
uint32_t hash = 0;

while (i != length) {
hash += key[i++];
hash += hash << 10;
hash ^= hash >> 6;
}
hash += hash << 3;
hash ^= hash >> 11;
hash += hash << 15;

return hash;
}


int main(int argc, char **argv) {
unsigned char reverse[4096];

if(argc != 2 || !argv[1])
exit(1);

int len, addr, end, flashsize, bi, ri;
char *base = strrchr(argv[1], '/');
base = base? base+1: argv[1];

memset(reverse, 0, sizeof reverse);

flashsize = bootloader_finish;
while(flashsize & (flashsize-1))
flashsize++;

int N = sizeof bootloader_length_of_sections/sizeof*bootloader_length_of_sections;

ri = 0; // buffer index
bi = sizeof bootloader-1; // index in bootloader[] array, top to bottom
end = flashsize;
for(int i=N-1; i >= 0; i--) {
len = bootloader_length_of_sections[i];
addr = bootloader_address[i];
if(addr == 0)
break;
if(addr + len > end) {
printf("inconsistent %d + %d > %d\n", addr, len, end);
exit(1);
}

int nff = end-addr-len;
if(ri+nff <= (int) sizeof reverse)
memset(reverse+ri, 0xff, nff);
else {
printf("buffer too small %d + %d > %d\n", ri, nff, (int) sizeof reverse);
exit(1);
}
ri += nff;

for(int n=len; n; n--) {
if(ri >= (int) sizeof reverse)
goto done;
reverse[ri] = bootloader[bi];
ri++;
bi--;
}
end = addr;
}

done:
;
printf(" { %4d, %d, 0x%08x, 0x%08x }, // %s\n", ri,
strstr(base, "bigboot") || strstr(base, "BIGBOOT"),
jenkins_hash(reverse, 256), jenkins_hash(reverse, ri), base);
}
END


for hn in $(find . -iname \*.hex -type f); do
srec_cat "$hn" -intel -o "$tmp.h" -c-array bootloader -c_compressed -line_length 96
cc $tmp.c -o $tmp
./$tmp $hn
done