There exist already many AVR bootloaders. "Why another?" you might ask. Well, even though there do exist a lot, none fit my requirements. What sort of requirements could I have, you might wonder. Well, it had to be USB-based. A few exist that do this. It had to be USB-HID so that no driver would be necessary in Windows. Hm... Well, still a few exist that do this. Oh, and I needed it to dynamically load an appliction and allow it to run under it, while still providing USB comms features and encrypted uploads/updates. You see, most of the existing USB bootloaders for AVR only do USB for bootloading. The actual loaded application has no access to the USB stack the bootloader uses. It has to either not use USB or include its own copy of a USB stack. Neither of those options is a good one, really.

USB Features? Run under It? All valid exclamations. Yes, this bootloader will act like a Mini-OS. It wil dynamically load an application over USB into flash, and provide an API to it. The API is mainly for communications (USB for now, but other protocols are doable, the apps do not depend on it being USB). The dynamic loading and lack of static linking with V-USB (the USB implementation of choice) might also be important to you, of course, for license reasons (as your code is loaded dynamically, it is not a derived work). The API provided to the application is pretty simple, actually. There is a function to see if there is a complete packet that has been RXed yet, and another to get the packet data if so. There is a function to see if there is space in the TX buffer for a packet, and another to send one. There is also one to run various background tasks, and another to jump into the bootloader (to do an update for example). The packet size maximum supported is 135 bytes (but you can adjust this to any size you wish in the source code). The preferred format is an 8-bit packet type, 8-bit CRC, followed by data.

And then there's encrypton... How would you update your application in the field safely without exposing it? With an encrypted update of course. I implemented in AVR assembly the SPECK block cypher decryption code in CBC mode (and the rest in C: encryption, key schedule). I chose the SPECK configuration with 64-bit block and 128-bit keys. It seemed like a reasonable compromise between code size and security for my purposes. But if you want a different config, the SPECK code provided will happily support block sizes of 32, 64, and 128 bits and key sizes of 64, 96, 128, 192, and 256 bits. I only provided an AVR assembly implementation of SPECK-64/128-CBC-decryption, but it is easy to change to all the other variants. Go wild! Encryption in ModulaR is optional. At build time you can include (or not) the key. If no key is included, ModulaR will accept plaintext uploads. If a key is included, only encrypted uploads will be accepted. For speed and codesize, the key included is actually the expanded SPECK keyschedule. This allows us to use SPECK with a 0-byte RAM footprint. Cool, huh? To prevent someone from messing with the cyphertext, a checksum of the decrypted plaintext is computed as it streams in, and the uploaded image is marked as valid only if the checksum matches the expected value (sent encrypted as the last upload block). Marked as valid? Yes. The uploaded code is written to flash, but until it is marked as valid, it will not be run. This prevents partial uploads from trying to run and crashing. For unencrypted uploads, the mark is placed when the "UPLOAD DONE" packet is sent.

What about the PC side of this? I used HIDAPI to interact with the device. It supports userspace HID in Windows and has support for Linux and MacOS too. It really is quite wonderful and simple to use. I wrote a tool that can upload an update to ModulaR and another that will do encryption for you and produce for you the keyschedule needed for includion in ModulaR's source. There is also a hacky decryptor app just for you to double-check results of encryption.

How big it is? Well, I only optimized for size the most egregious of avr-gcc's mistakes, so the while thing is still quite large - 3300 bytes if you include the 108-byte keyschedule for SPECK-64/128. But this is not actually that bad since your actual application code does not need to include another copy of the USB stack - ModulaR provides you with the data in/out APIs already. In reality with some more ASM-work it can be shrunk quite a bit, but this is already good enough for my purposes, so I am leaving this as it is (for now).

How do I use it? Build ModulaR (or use included HEX file if the key 00112233445566778899aabbccddeeff is OK with you :) ) and flash it to an AVR. Wiring is standard VUSB wiring. You can use the provided sample linker script for your app. All interrupt vectors will be passed to you except INT0. That one is reserved for ModulaR and will not be ever passed to your app. Once in a while you'll want to call the usbWork() function. On every boot, ModulaR will wait about 2 seconds for an upload and then boot your application. If no application is found, it will wait forever. If you want to get into the bootloader mode from your application, an API is provided. The included SampleApp demonstrates all the uses. It respondes to a few packet types (Packet 0 echoes back whatever you sent XORed with 0xFF, Packet 1 sends back the sum of all the bytes you sent). To facilitate uploads, if the app detects some of commands reserved for bootloader 0xFC-0xFF, it reboots to the bootloader for easier updates. To encrypt it, run tools/encryptor 00112233445566778899aabbccddeeff < SampleApp.bin > SampleApp.encr.bin. To then upload the resulting file use tools/uploader SampleApp.encr.bin.

License?As required by the V-USB inclusion, the AVR code is GPLv2-licensed. This includes my implementation of SPECK. The PC-side code is BSD-3-clause-licensed (this also includes that same implementation of SPECK). Enjoy. You can download ModulaR here: => [LINK] <=

© 2012-2017