Add CF2 docs and support BIN files in patcher
This commit is contained in:
parent
197180bb25
commit
86e101e3a2
5 changed files with 94 additions and 15 deletions
57
cf2.md
Normal file
57
cf2.md
Normal 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
4
hf2.md
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -198,7 +198,7 @@ const CFG_MAGIC1 = 0x20227a79
|
||||||
|
|
||||||
function configkeysH() {
|
function configkeysH() {
|
||||||
let r = "#ifndef __CONFIGKEYS_H\n#define __CONFIGKEYS_H 1\n\n"
|
let r = "#ifndef __CONFIGKEYS_H\n#define __CONFIGKEYS_H 1\n\n"
|
||||||
|
|
||||||
r += "#define CFG_MAGIC0 0x1e9e10f1\n"
|
r += "#define CFG_MAGIC0 0x1e9e10f1\n"
|
||||||
r += "#define CFG_MAGIC1 0x20227a79\n\n"
|
r += "#define CFG_MAGIC1 0x20227a79\n\n"
|
||||||
|
|
||||||
|
|
@ -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) {
|
||||||
if (read32(buf, off) != UF2_MAGIC_START0 ||
|
let start = 0
|
||||||
read32(buf, off + 4) != UF2_MAGIC_START1) {
|
let payloadLen = 512
|
||||||
err("invalid data at " + off)
|
let addr = off
|
||||||
|
|
||||||
|
if (isUF2) {
|
||||||
|
start = 32
|
||||||
|
if (read32(buf, off) != UF2_MAGIC_START0 ||
|
||||||
|
read32(buf, off + 4) != UF2_MAGIC_START1) {
|
||||||
|
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}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue