Add CF2 docs and support BIN files in patcher

This commit is contained in:
Michal Moskal 2019-01-06 20:32:34 +00:00
parent 197180bb25
commit 86e101e3a2
5 changed files with 94 additions and 15 deletions

57
cf2.md Normal file
View file

@ -0,0 +1,57 @@
# Binary Bootloader-embedded Config (CF2)
## Motivation
The goal of CF2 is to run the same binary on a number of devices with different
peripheral configuration, but the same MCU.
Typically, this has been achieved by embedding identification components in hardware
(eg. connecting certain MCU pins to GND or 3V) and having the firmware dynamically
detect these.
While simple, this only allows a few bits of configuration data to be stored on device.
Instead, we use the bootloader area for storing device specific configuration data.
Such data is not altered when the device is programmed with new firmware,
and the said firmware can refer to the configuration data in the bootloader area to
alter its behavior.
For example, MakeCode Arcade requires a device with 7 buttons (directions, A, B, and MENU),
a screen from a specific family, and one of the few supported accelerometers.
The exact configuration depends on the manufacturer, but the binary produced by MakeCode
will work on any device with the right MCU, provided it has the right configuration
data in the bootloader area.
Thus, the user only needs to select the type of MCU (which is color coded,
and is assigned a simple user-facing name), and the resulting binary will work
on their device.
Moreover, they can drag the UF2 file between devices, provided they run the same MCU.
Once bootloaders are updated with networking support (wired or wireless), one device with
a given MCU will be able to flash another.
## Configuration data format
Data comes as pairs of 32 bit unsigned integers (in machine byte order).
* first pair is `0x1e9e10f1, 0x20227a79`
* second pair consists of the number of configuration entries, and a zero (reserved)
* then configuration entries follow, where the first element is the configuration
entry key number, and the second is the value (these entries are sorted by key number)
* finally, a number of zeroes follows (typically at least a few hundred),
to store any additional configuration data in future
The file with definitions of key names can be downloaded from the patcher website (see below).
If you require your own key names, please use
[random large key names](https://github.com/Microsoft/uf2#picking-numbers-at-random).
## The Patcher
At https://microsoft.github.io/uf2/patcher/ we provide a tool, which given a UF2 file
and a configuration definition, binary-patches the UF2 file and lets the user download it.
The tool also parses existing configuration information from the UF2 file and show it.
Such tool is to be used by maker of devices.
For example, for MakeCode Arcade, this includes both factories and users who take an existing
multi-purpose board and connect keys and screen.
Such user would then download generic MakeCode Arcade bootloader (either a UF2 file,
which upgrades the bootloader, or a .BIN file with the bootloader) for the given MCU,
and binary patch it with their configuration.
Then, they would update the bootloader, and have a Arcade-compatible device.

4
hf2.md
View file

@ -14,8 +14,8 @@ ones, but be less efficient.
In particular, it is suitable for running over USB HID (Human Interface Device), In particular, it is suitable for running over USB HID (Human Interface Device),
which is widely supported in various operating systems without the need for kernel-space which is widely supported in various operating systems without the need for kernel-space
drivers. It is also possible to run the protocol over a WebUSB link with either a single drivers. It is also possible to run the protocol over a WebUSB link with either a single
interrupt endpoint or two bulk endpoints, allowing direct access from supported interrupt endpoint or two bulk endpoints, as well as using just the control pipe,
browsers. allowing direct access from supported browsers.
## Raw message format ## Raw message format

View file

@ -43,10 +43,12 @@
<a href="#" id="apply" class="btn btn-dl">Apply my patch</a> <a href="#" id="apply" class="btn btn-dl">Apply my patch</a>
<h2>Information</h2> <h2>Information</h2>
<pre><code id="currconfig">Drop UF2 file above to see its config.</code></pre> <pre><code id="currconfig">Drop UF2 or BIN file above to see its config.</code></pre>
<p> <p>
<a href="#" onclick="defines()">Download configkeys.h</a> <a href="https://github.com/Microsoft/uf2/blob/master/cf2.md">Learn more</a>
or
<a href="#" onclick="defines()">download configkeys.h</a>.
</p> </p>
</section> </section>

View file

@ -242,23 +242,43 @@ function readWriteConfig(buf, patch) {
let cfgLen = 0 let cfgLen = 0
if (patch) if (patch)
patch.push(0, 0) patch.push(0, 0)
let isUF2 = false
if (read32(buf, 0) == UF2_MAGIC_START0) {
isUF2 = true
log("# detected UF2 file")
} else {
let stackBase = read32(buf, 0)
if ((stackBase & 0xff0000ff) == 0x20000000 &&
(read32(buf, 4) & 1) == 1) {
log("# detected BIN file")
} else {
err("unknown file format")
}
}
for (let off = 0; off < buf.length; off += 512) { for (let off = 0; off < buf.length; off += 512) {
let start = 0
let payloadLen = 512
let addr = off
if (isUF2) {
start = 32
if (read32(buf, off) != UF2_MAGIC_START0 || if (read32(buf, off) != UF2_MAGIC_START0 ||
read32(buf, off + 4) != UF2_MAGIC_START1) { read32(buf, off + 4) != UF2_MAGIC_START1) {
err("invalid data at " + off) err("invalid data at " + off)
} }
payloadLen = read32(buf, off + 16)
addr = read32(buf, off + 12) - 32
}
const payloadLen = read32(buf, off + 16) for (let i = start; i < start + payloadLen; i += 4) {
for (let i = 32; i < 32 + payloadLen; i += 4) {
if (read32(buf, off + i) == CFG_MAGIC0 && if (read32(buf, off + i) == CFG_MAGIC0 &&
read32(buf, off + i + 4) == CFG_MAGIC1) { read32(buf, off + i + 4) == CFG_MAGIC1) {
let addr = "0x" + (read32(buf, off + 12) + i - 32).toString(16) let addrS = "0x" + (addr + i).toString(16)
if (patchPtr === null) { if (patchPtr === null) {
log(`# Found CFG DATA at ${addr}`) log(`# Found CFG DATA at ${addrS}`)
patchPtr = -4 patchPtr = -4
} else { } else {
log(`# Skipping second CFG DATA at ${addr}`) log(`# Skipping second CFG DATA at ${addrS}`)
} }
} }

View file

@ -54,7 +54,7 @@ function applyPatch() {
let text = document.getElementById("patch") let text = document.getElementById("patch")
let newcfg = text.value.trim() let newcfg = text.value.trim()
if (!currUF2) if (!currUF2)
log("You have to drop a UF2 file with bootloader above before applying patches.") log("You have to drop a UF2 or BIN file with bootloader above before applying patches.")
else if (!newcfg) else if (!newcfg)
log("You didn't give any patch to apply.") log("You didn't give any patch to apply.")
else { else {