Revamp deploy.py

Now the script supports more flashing methods:
- JLink (with tockloader)
- OpenOCD (with tockloader)
- pyOCD
- Nordic DFU
- none (will produce an IntelHex file)

Also merged the contributions from:
- Yihui Xiong to support the Makerdiary USB dongle board
- Dennis Geurts to support Nordic DFU

Doc updated accordingly.

Imported 2 patches for Tock kernel:
- 06-add-set_vector_table_offset.patch (upstream tock/tock#1579)
- 07-nrf52-bootloader.patch (upstream tock/tock#1681)
This commit is contained in:
Jean-Michel Picod
2020-03-11 16:51:26 +01:00
parent 8b146440a5
commit e63482af1c
14 changed files with 861 additions and 226 deletions

View File

@@ -1,7 +0,0 @@
# Target configuration for the CTAP2 app on the nRF52840 chip
[target.thumbv7em-none-eabi]
rustflags = [
"-C", "link-arg=-Tnrf52840dk_layout.ld",
"-C", "relocation-model=static",
"-D", "warnings",
]

View File

@@ -19,8 +19,9 @@ successfully tested on the following boards:
## Disclaimer ## Disclaimer
This project is proof-of-concept and a research platform. It's still under This project is **proof-of-concept and a research platform**. It is **NOT**
development and as such comes with a few limitations: meant for a day to day usage. It's still under development and as such comes
with a few limitations:
### FIDO2 ### FIDO2
@@ -53,25 +54,17 @@ For a more detailed guide, please refer to our
./setup.sh ./setup.sh
``` ```
2. If Tock OS is already installed on your board, move to the next step. 2. Next step is to install Tock OS as well as the OpenSK application on your
Otherwise, just run one of the following commands, depending on the board board (**Warning**: it will erase the locally stored credentials). Run:
you have:
```shell ```shell
# Nordic nRF52840-DK board # Nordic nRF52840-DK board
./deploy.py os --board=nrf52840_dk ./deploy.py --board=nrf52840dk --opensk
# Nordic nRF52840-Dongle # Nordic nRF52840-Dongle
./deploy.py os --board=nrf52840_dongle ./deploy.py --board=nrf52840_dongle --opensk
``` ```
3. Next step is to install/update the OpenSK application on your board 3. On Linux, you may want to avoid the need for `root` privileges to interact
(**Warning**: it will erase the locally stored credentials). Run:
```shell
./deploy.py app --opensk
```
4. On Linux, you may want to avoid the need for `root` privileges to interact
with the key. For that purpose we provide a udev rule file that can be with the key. For that purpose we provide a udev rule file that can be
installed with the following command: installed with the following command:

View File

@@ -0,0 +1,30 @@
[package]
name = "nrf52840_dongle_dfu"
version = "0.1.0"
authors = ["Tock Project Developers <tock-dev@googlegroups.com>"]
build = "build.rs"
edition = "2018"
[profile.dev]
panic = "abort"
lto = false
opt-level = "z"
debug = true
[profile.release]
panic = "abort"
lto = true
opt-level = "z"
debug = true
[[bin]]
path = "../../third_party/tock/boards/nordic/nrf52840_dongle/src/main.rs"
name = "nrf52840_dongle_dfu"
[dependencies]
components = { path = "../../third_party/tock/boards/components" }
cortexm4 = { path = "../../third_party/tock/arch/cortex-m4" }
capsules = { path = "../../third_party/tock/capsules" }
kernel = { path = "../../third_party/tock/kernel" }
nrf52840 = { path = "../../third_party/tock/chips/nrf52840" }
nrf52dk_base = { path = "../../third_party/tock/boards/nordic/nrf52dk_base" }

View File

@@ -0,0 +1,4 @@
fn main() {
println!("cargo:rerun-if-changed=layout.ld");
println!("cargo:rerun-if-changed=../../third_party/tock/boards/kernel_layout.ld");
}

View File

@@ -0,0 +1,10 @@
MEMORY
{
rom (rx) : ORIGIN = 0x00001000, LENGTH = 188K
prog (rx) : ORIGIN = 0x00030000, LENGTH = 832K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 256K
}
MPU_MIN_ALIGN = 8K;
INCLUDE ../../third_party/tock/boards/kernel_layout.ld

View File

@@ -0,0 +1,26 @@
[package]
name = "nrf52840_mdk_dfu"
version = "0.1.0"
authors = ["Yihui Xiong <yihui.xiong@hotmail.com>"]
build = "build.rs"
edition = "2018"
[profile.dev]
panic = "abort"
lto = false
opt-level = "z"
debug = true
[profile.release]
panic = "abort"
lto = true
opt-level = "z"
debug = true
[dependencies]
components = { path = "../../third_party/tock/boards/components" }
cortexm4 = { path = "../../third_party/tock/arch/cortex-m4" }
capsules = { path = "../../third_party/tock/capsules" }
kernel = { path = "../../third_party/tock/kernel" }
nrf52840 = { path = "../../third_party/tock/chips/nrf52840" }
nrf52dk_base = { path = "../../third_party/tock/boards/nordic/nrf52dk_base" }

View File

@@ -0,0 +1,4 @@
fn main() {
println!("cargo:rerun-if-changed=layout.ld");
println!("cargo:rerun-if-changed=../../third_party/tock/boards/kernel_layout.ld");
}

View File

@@ -0,0 +1,10 @@
MEMORY
{
rom (rx) : ORIGIN = 0x00001000, LENGTH = 188K
prog (rx) : ORIGIN = 0x00030000, LENGTH = 832K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 256K
}
MPU_MIN_ALIGN = 8K;
INCLUDE ../../third_party/tock/boards/kernel_layout.ld

View File

@@ -0,0 +1,65 @@
use core::fmt::Write;
use core::panic::PanicInfo;
use cortexm4;
use kernel::debug;
use kernel::debug::IoWrite;
use kernel::hil::led;
use kernel::hil::uart::{self, Configure};
use nrf52840::gpio::Pin;
use crate::CHIP;
use crate::PROCESSES;
struct Writer {
initialized: bool,
}
static mut WRITER: Writer = Writer { initialized: false };
impl Write for Writer {
fn write_str(&mut self, s: &str) -> ::core::fmt::Result {
self.write(s.as_bytes());
Ok(())
}
}
impl IoWrite for Writer {
fn write(&mut self, buf: &[u8]) {
let uart = unsafe { &mut nrf52840::uart::UARTE0 };
if !self.initialized {
self.initialized = true;
uart.configure(uart::Parameters {
baud_rate: 115200,
stop_bits: uart::StopBits::One,
parity: uart::Parity::None,
hw_flow_control: false,
width: uart::Width::Eight,
});
}
for &c in buf {
unsafe {
uart.send_byte(c);
}
while !uart.tx_ready() {}
}
}
}
#[cfg(not(test))]
#[no_mangle]
#[panic_handler]
/// Panic handler
pub unsafe extern "C" fn panic_fmt(pi: &PanicInfo) -> ! {
// The nRF52840 Dongle LEDs (see back of board)
const LED1_PIN: Pin = Pin::P0_23;
let led = &mut led::LedLow::new(&mut nrf52840::gpio::PORT[LED1_PIN]);
let writer = &mut WRITER;
debug::panic(
&mut [led],
writer,
pi,
&cortexm4::support::nop,
&PROCESSES,
&CHIP,
)
}

View File

@@ -0,0 +1,123 @@
//! Tock kernel for the Makerdiary nRF52840 MDK USB dongle.
//!
//! It is based on nRF52840 SoC (Cortex M4 core with a BLE transceiver) with
//! many exported I/O and peripherals.
#![no_std]
#![no_main]
#![deny(missing_docs)]
use kernel::component::Component;
#[allow(unused_imports)]
use kernel::{debug, debug_gpio, debug_verbose, static_init};
use nrf52840::gpio::Pin;
use nrf52dk_base::{SpiPins, UartChannel, UartPins};
// The nRF52840 MDK USB Dongle LEDs
const LED1_R_PIN: Pin = Pin::P0_23;
const LED1_G_PIN: Pin = Pin::P0_22;
const LED1_B_PIN: Pin = Pin::P0_24;
// The nRF52840 Dongle button
const BUTTON_PIN: Pin = Pin::P0_18;
const BUTTON_RST_PIN: Pin = Pin::P0_02;
const UART_RTS: Pin = Pin::P0_21;
const UART_TXD: Pin = Pin::P0_20;
const UART_CTS: Pin = Pin::P0_03;
const UART_RXD: Pin = Pin::P0_19;
const SPI_MOSI: Pin = Pin::P0_05;
const SPI_MISO: Pin = Pin::P0_06;
const SPI_CLK: Pin = Pin::P0_07;
/// UART Writer
pub mod io;
// State for loading and holding applications.
// How should the kernel respond when a process faults.
const FAULT_RESPONSE: kernel::procs::FaultResponse = kernel::procs::FaultResponse::Panic;
// Number of concurrent processes this platform supports.
const NUM_PROCS: usize = 8;
// RAM to be shared by all application processes.
#[link_section = ".app_memory"]
static mut APP_MEMORY: [u8; 0x3C000] = [0; 0x3C000];
static mut PROCESSES: [Option<&'static dyn kernel::procs::ProcessType>; NUM_PROCS] =
[None, None, None, None, None, None, None, None];
// Static reference to chip for panic dumps
static mut CHIP: Option<&'static nrf52840::chip::Chip> = None;
/// Dummy buffer that causes the linker to reserve enough space for the stack.
#[no_mangle]
#[link_section = ".stack_buffer"]
pub static mut STACK_MEMORY: [u8; 0x1000] = [0; 0x1000];
/// Entry point in the vector table called on hard reset.
#[no_mangle]
pub unsafe fn reset_handler() {
// Loads relocations and clears BSS
nrf52840::init();
let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(&PROCESSES));
// GPIOs
let gpio = components::gpio::GpioComponent::new(board_kernel).finalize(
components::gpio_component_helper!(
&nrf52840::gpio::PORT[Pin::P0_04],
&nrf52840::gpio::PORT[Pin::P0_05],
&nrf52840::gpio::PORT[Pin::P0_06],
&nrf52840::gpio::PORT[Pin::P0_07],
&nrf52840::gpio::PORT[Pin::P0_08]
),
);
let button = components::button::ButtonComponent::new(board_kernel).finalize(
components::button_component_helper!((
&nrf52840::gpio::PORT[BUTTON_PIN],
capsules::button::GpioMode::LowWhenPressed,
kernel::hil::gpio::FloatingState::PullUp
)),
);
let led = components::led::LedsComponent::new().finalize(components::led_component_helper!(
(
&nrf52840::gpio::PORT[LED1_R_PIN],
capsules::led::ActivationMode::ActiveLow
),
(
&nrf52840::gpio::PORT[LED1_G_PIN],
capsules::led::ActivationMode::ActiveLow
),
(
&nrf52840::gpio::PORT[LED1_B_PIN],
capsules::led::ActivationMode::ActiveLow
)
));
let chip = static_init!(nrf52840::chip::Chip, nrf52840::chip::new());
CHIP = Some(chip);
nrf52dk_base::setup_board(
board_kernel,
BUTTON_RST_PIN,
&nrf52840::gpio::PORT,
gpio,
LED1_R_PIN,
LED1_G_PIN,
LED1_B_PIN,
led,
UartChannel::Pins(UartPins::new(UART_RTS, UART_TXD, UART_CTS, UART_RXD)),
&SpiPins::new(SPI_MOSI, SPI_MISO, SPI_CLK),
&None,
button,
true,
&mut APP_MEMORY,
&mut PROCESSES,
FAULT_RESPONSE,
nrf52840::uicr::Regulator0Output::V3_0,
false,
&Some(&nrf52840::usbd::USBD),
chip,
);
}

589
deploy.py
View File

@@ -20,6 +20,7 @@ from __future__ import division
from __future__ import print_function from __future__ import print_function
import argparse import argparse
import collections
import copy import copy
import os import os
import shutil import shutil
@@ -32,10 +33,115 @@ from tockloader import tbfh
from tockloader import tockloader as loader from tockloader import tockloader as loader
from tockloader.exceptions import TockLoaderException from tockloader.exceptions import TockLoaderException
# This structure allows us in the future to also support out-of-tree boards. PROGRAMMERS = frozenset(("jlink", "openocd", "pyocd", "nordicdfu", "none"))
# This structure allows us to support out-of-tree boards as well as (in the
# future) more achitectures.
OpenSKBoard = collections.namedtuple(
"OpenSKBoard",
[
# Location of the Tock board (where the Makefile file is
"path",
# Targeted architecture (e.g. thumbv7em-none-eabi)
"arch",
# Size of 1 page of flash memory
"page_size",
# Flash address at which the kernel will be written
"kernel_address",
# Set to None is padding is not required for the board
"padding_address",
# Linker script to produce a working app for this board
"app_ldscript",
# Flash address at which the app should be written
"app_address",
# Target name for flashing the board using pyOCD
"pyocd_target",
# The cfg file in OpenOCD board folder
"openocd_board",
# Options to tell Tockloader how to work with OpenOCD
# Default: []
"openocd_options",
# Dictionnary specifying custom commands for OpenOCD
# Default is an empty dict
# Valid keys are: program, read, erase
"openocd_commands",
# Interface to use with JLink (e.g. swd, jtag, etc.)
"jlink_if",
# Device name as supported by JLinkExe
"jlink_device",
# Whether Nordic DFU flashing method is supported
"nordic_dfu",
])
SUPPORTED_BOARDS = { SUPPORTED_BOARDS = {
"nrf52840_dk": "third_party/tock/boards/nordic/nrf52840dk", "nrf52840dk":
"nrf52840_dongle": "third_party/tock/boards/nordic/nrf52840_dongle" OpenSKBoard(
path="third_party/tock/boards/nordic/nrf52840dk",
arch="thumbv7em-none-eabi",
page_size=4096,
kernel_address=0,
padding_address=0x30000,
app_ldscript="nrf52840dk_layout.ld",
app_address=0x40000,
pyocd_target="nrf52840",
openocd_board="nordic_nrf52840_dongle.cfg",
openocd_options=[],
openocd_commands={},
jlink_if="swd",
jlink_device="nrf52840_xxaa",
nordic_dfu=False,
),
"nrf52840_dongle":
OpenSKBoard(
path="third_party/tock/boards/nordic/nrf52840_dongle",
arch="thumbv7em-none-eabi",
page_size=4096,
kernel_address=0,
padding_address=0x30000,
app_ldscript="nrf52840dk_layout.ld",
app_address=0x40000,
pyocd_target="nrf52840",
openocd_board="nordic_nrf52840_dongle.cfg",
openocd_options=[],
openocd_commands={},
jlink_if="swd",
jlink_device="nrf52840_xxaa",
nordic_dfu=False,
),
"nrf52840_dongle_dfu":
OpenSKBoard(
path="boards/nrf52840_dongle_dfu",
arch="thumbv7em-none-eabi",
page_size=4096,
kernel_address=0x1000,
padding_address=0x30000,
app_ldscript="nrf52840dk_layout.ld",
app_address=0x40000,
pyocd_target="nrf52840",
openocd_board="nordic_nrf52840_dongle.cfg",
openocd_options=[],
openocd_commands={},
jlink_if="swd",
jlink_device="nrf52840_xxaa",
nordic_dfu=True,
),
"nrf52840_mdk_dfu":
OpenSKBoard(
path="boards/nrf52840_mdk_dfu",
arch="thumbv7em-none-eabi",
page_size=4096,
kernel_address=0x1000,
padding_address=0x30000,
app_ldscript="nrf52840dk_layout.ld",
app_address=0x40000,
pyocd_target="nrf52840",
openocd_board="nordic_nrf52840_dongle.cfg",
openocd_options=[],
openocd_commands={},
jlink_if="swd",
jlink_device="nrf52840_xxaa",
nordic_dfu=True,
),
} }
# The STACK_SIZE value below must match the one used in the linker script # The STACK_SIZE value below must match the one used in the linker script
@@ -50,9 +156,9 @@ APP_HEAP_SIZE = 90000
def get_supported_boards(): def get_supported_boards():
boards = [] boards = []
for name, root in SUPPORTED_BOARDS.items(): for name, props in SUPPORTED_BOARDS.items():
if all((os.path.exists(os.path.join(root, "Cargo.toml")), if all((os.path.exists(os.path.join(props.path, "Cargo.toml")),
os.path.exists(os.path.join(root, "Makefile")))): (props.app_ldscript and os.path.exists(props.app_ldscript)))):
boards.append(name) boards.append(name)
return tuple(set(boards)) return tuple(set(boards))
@@ -79,9 +185,23 @@ def info(msg):
message=msg)) message=msg))
def assert_mandatory_binary(binary):
if not shutil.which(binary):
fatal(("Couldn't find {} binary. Make sure it is installed and "
"that your PATH is set correctly.").format(binary))
def assert_python_library(module):
try:
__import__(module)
except ModuleNotFoundError:
fatal(("Couldn't load python3 module {name}. "
"Try to run: pip3 install {name}").format(name=module))
class RemoveConstAction(argparse.Action): class RemoveConstAction(argparse.Action):
# pylint: disable=W0622 # pylint: disable=redefined-builtin
def __init__(self, def __init__(self,
option_strings, option_strings,
dest, dest,
@@ -121,28 +241,34 @@ class OpenSKInstaller:
self.args = args self.args = args
# Where all the TAB files should go # Where all the TAB files should go
self.tab_folder = os.path.join("target", "tab") self.tab_folder = os.path.join("target", "tab")
# This is the filename that elf2tab command expects in order board = SUPPORTED_BOARDS[self.args.board]
# to create a working TAB file.
self.target_elf_filename = os.path.join(self.tab_folder, "cortex-m4.elf")
self.tockloader_default_args = argparse.Namespace( self.tockloader_default_args = argparse.Namespace(
arch="cortex-m4", arch=board.arch,
board=getattr(self.args, "board", "nrf52840"), board=self.args.board,
debug=False, debug=False,
force=False, force=False,
jlink=True, jlink=self.args.programmer == "jlink",
jlink_device="nrf52840_xxaa", jlink_device=board.jlink_device,
jlink_if="swd", jlink_if=board.jlink_if,
jlink_speed=1200, jlink_speed=1200,
openocd=self.args.programmer == "openocd",
openocd_board=board.openocd_board,
jtag=False, jtag=False,
no_bootloader_entry=False, no_bootloader_entry=False,
page_size=4096, page_size=board.page_size,
port=None, port=None,
) )
def checked_command_output(self, cmd): def checked_command_output(self, cmd, env=None, cwd=None):
cmd_output = "" cmd_output = ""
try: try:
cmd_output = subprocess.check_output(cmd) cmd_output = subprocess.run(
cmd,
stdout=subprocess.PIPE,
timeout=None,
check=True,
env=env,
cwd=cwd).stdout
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
fatal("Failed to execute {}: {}".format(cmd[0], str(e))) fatal("Failed to execute {}: {}".format(cmd[0], str(e)))
# Unreachable because fatal() will exit # Unreachable because fatal() will exit
@@ -166,38 +292,104 @@ class OpenSKInstaller:
# Need to update # Need to update
self.checked_command_output( self.checked_command_output(
["rustup", "install", target_toolchain_fullstring]) ["rustup", "install", target_toolchain_fullstring])
self.checked_command_output( targets = set([x.arch for _, x in SUPPORTED_BOARDS.items()])
["rustup", "target", "add", "thumbv7em-none-eabi"]) for arch in targets:
self.checked_command_output(["rustup", "target", "add", arch])
info("Rust toolchain up-to-date") info("Rust toolchain up-to-date")
def build_and_install_tockos(self): def search_binary(self, name, start_directory="."):
for root, _, files in os.walk(start_directory):
for fname in files:
if fname == name:
return os.path.join(root, fname)
return None
def build_tockos(self):
info("Building Tock OS for board {}".format(self.args.board))
props = SUPPORTED_BOARDS[self.args.board]
out_directory = os.path.join(props.path, "target", props.arch, "release")
os.makedirs(out_directory, exist_ok=True)
rust_flags = [
"-C",
"link-arg=-Tlayout.ld",
"-C",
"linker=rust-lld",
"-C",
"linker-flavor=ld.lld",
"-C",
"relocation-model=dynamic-no-pic",
"-C",
"link-arg=-zmax-page-size=512",
"--remap-path-prefix={}=".format(os.path.realpath(props.path)),
]
env = os.environ.copy()
env["RUSTFLAGS"] = " ".join(rust_flags)
self.checked_command_output( self.checked_command_output(
["make", "-C", SUPPORTED_BOARDS[self.args.board], "flash"]) ["cargo", "build", "--release", "--target={}".format(props.arch)],
env=env,
def build_and_install_example(self): cwd=props.path)
assert self.args.application info("Converting Tock OS file into a binary")
kernel_name = os.path.basename(props.path)
shutil.copyfile(
os.path.join(out_directory, kernel_name),
os.path.join(out_directory, "{}.elf".format(kernel_name)))
# Find appropriate llvm-objcopy
llvm_dir = self.checked_command_output(["rustc", "--print=sysroot"],
cwd=props.path).strip()
if not llvm_dir:
fatal("Couldn't determine where rustc is installed. "
"This shouldn't happen.")
if not os.path.isdir(llvm_dir):
fatal("Something went wrong while locating llvm-objcopy.")
objcopy = self.search_binary("llvm-objcopy", start_directory=llvm_dir)
if not objcopy:
fatal("Couldn't locate llvm-objcopy binary in your system.")
self.checked_command_output([ self.checked_command_output([
"cargo", "build", "--release", "--target=thumbv7em-none-eabi", objcopy, "--output-target=binary",
"--features={}".format(",".join(self.args.features)), "--example", os.path.join(out_directory, "{}.elf".format(kernel_name)),
self.args.application os.path.join(out_directory, "{}.bin".format(kernel_name))
]) ])
self.install_elf_file(
os.path.join("target/thumbv7em-none-eabi/release/examples",
self.args.application))
def build_and_install_opensk(self): def build_example(self):
assert self.args.application info("Building example {}".format(self.args.application))
self._build_app_or_example(is_example=True)
def build_opensk(self):
info("Building OpenSK application") info("Building OpenSK application")
self.checked_command_output([ self._build_app_or_example(is_example=False)
"cargo",
"build", def _build_app_or_example(self, is_example):
"--release", assert self.args.application
"--target=thumbv7em-none-eabi", # Ideally we would build a TAB file for all boards at once but depending on
"--features={}".format(",".join(self.args.features)), # the chip on the board, the link script could be totally different.
]) # And elf2tab doesn't seem to let us set the boards a TAB file has been
self.install_elf_file( # created for. So at the moment we only build for the selected board.
os.path.join("target/thumbv7em-none-eabi/release", props = SUPPORTED_BOARDS[self.args.board]
self.args.application)) rust_flags = [
"-C",
"link-arg=-T{}".format(props.app_ldscript),
"-C",
"relocation-model=static",
"-D",
"warnings",
"--remap-path-prefix={}=".format(os.getcwd()),
]
env = os.environ.copy()
env["RUSTFLAGS"] = " ".join(rust_flags)
command = [
"cargo", "build", "--release", "--target={}".format(props.arch),
"--features={}".format(",".join(self.args.features))
]
if is_example:
command.extend(["--example", self.args.application])
self.checked_command_output(command, env=env)
app_path = os.path.join("target", props.arch, "release")
if is_example:
app_path = os.path.join(app_path, "examples")
app_path = os.path.join(app_path, self.args.application)
# Create a TAB file
self.create_tab_file({props.arch: app_path})
def generate_crypto_materials(self, force_regenerate): def generate_crypto_materials(self, force_regenerate):
has_error = subprocess.call([ has_error = subprocess.call([
@@ -208,8 +400,11 @@ class OpenSKInstaller:
error(("Something went wrong while trying to generate ECC " error(("Something went wrong while trying to generate ECC "
"key and/or certificate for OpenSK")) "key and/or certificate for OpenSK"))
def install_elf_file(self, elf_path): def create_tab_file(self, binaries):
assert binaries
assert self.args.application assert self.args.application
info("Generating Tock TAB file for application/example {}".format(
self.args.application))
package_parameter = "-n" package_parameter = "-n"
elf2tab_ver = self.checked_command_output(["elf2tab", "--version"]).split( elf2tab_ver = self.checked_command_output(["elf2tab", "--version"]).split(
" ", maxsplit=1)[1] " ", maxsplit=1)[1]
@@ -221,17 +416,26 @@ class OpenSKInstaller:
os.makedirs(self.tab_folder, exist_ok=True) os.makedirs(self.tab_folder, exist_ok=True)
tab_filename = os.path.join(self.tab_folder, tab_filename = os.path.join(self.tab_folder,
"{}.tab".format(self.args.application)) "{}.tab".format(self.args.application))
shutil.copyfile(elf_path, self.target_elf_filename) elf2tab_args = [
self.checked_command_output([ "elf2tab", package_parameter, self.args.application, "-o", tab_filename
"elf2tab", package_parameter, self.args.application, "-o", tab_filename, ]
self.target_elf_filename, "--stack={}".format(STACK_SIZE), for arch, app_file in binaries.items():
"--app-heap={}".format(APP_HEAP_SIZE), "--kernel-heap=1024", dest_file = os.path.join(self.tab_folder, "{}.elf".format(arch))
"--protected-region-size=64" shutil.copyfile(app_file, dest_file)
elf2tab_args.append(dest_file)
elf2tab_args.extend([
"--stack={}".format(STACK_SIZE), "--app-heap={}".format(APP_HEAP_SIZE),
"--kernel-heap=1024", "--protected-region-size=64"
]) ])
self.install_padding() self.checked_command_output(elf2tab_args)
def install_tab_file(self, tab_filename):
assert self.args.application
info("Installing Tock application {}".format(self.args.application)) info("Installing Tock application {}".format(self.args.application))
board_props = SUPPORTED_BOARDS[self.args.board]
args = copy.copy(self.tockloader_default_args) args = copy.copy(self.tockloader_default_args)
setattr(args, "app_address", 0x40000) setattr(args, "app_address", board_props.app_address)
setattr(args, "erase", self.args.clear_apps) setattr(args, "erase", self.args.clear_apps)
setattr(args, "make", False) setattr(args, "make", False)
setattr(args, "no_replace", False) setattr(args, "no_replace", False)
@@ -244,16 +448,38 @@ class OpenSKInstaller:
fatal("Couldn't install Tock application {}: {}".format( fatal("Couldn't install Tock application {}: {}".format(
self.args.application, str(e))) self.args.application, str(e)))
def install_padding(self): def get_padding(self):
fake_header = tbfh.TBFHeader("") fake_header = tbfh.TBFHeader("")
fake_header.version = 2 fake_header.version = 2
fake_header.fields["header_size"] = 0x10 fake_header.fields["header_size"] = 0x10
fake_header.fields["total_size"] = 0x10000 fake_header.fields["total_size"] = (
SUPPORTED_BOARDS[self.args.board].app_address -
SUPPORTED_BOARDS[self.args.board].padding_address)
fake_header.fields["flags"] = 0 fake_header.fields["flags"] = 0
padding = fake_header.get_binary() return fake_header.get_binary()
def install_tock_os(self):
board_props = SUPPORTED_BOARDS[self.args.board]
kernel_file = os.path.join(board_props.path, "target", board_props.arch,
"release", "{}.bin".format(self.args.board))
info("Flashing file {}.".format(kernel_file))
with open(kernel_file, "rb") as f:
kernel = f.read()
args = copy.copy(self.tockloader_default_args)
setattr(args, "address", board_props.app_address)
tock = loader.TockLoader(args)
tock.open(args)
try:
tock.flash_binary(kernel, board_props.kernel_address)
except TockLoaderException as e:
fatal("Couldn't install padding: {}".format(str(e)))
def install_padding(self):
padding = self.get_padding()
board_props = SUPPORTED_BOARDS[self.args.board]
info("Flashing padding application") info("Flashing padding application")
args = copy.copy(self.tockloader_default_args) args = copy.copy(self.tockloader_default_args)
setattr(args, "address", 0x30000) setattr(args, "address", board_props.padding_address)
tock = loader.TockLoader(args) tock = loader.TockLoader(args)
tock.open(args) tock.open(args)
try: try:
@@ -263,7 +489,8 @@ class OpenSKInstaller:
def clear_apps(self): def clear_apps(self):
args = copy.copy(self.tockloader_default_args) args = copy.copy(self.tockloader_default_args)
setattr(args, "app_address", 0x40000) board_props = SUPPORTED_BOARDS[self.args.board]
setattr(args, "app_address", board_props.app_address)
info("Erasing all installed applications") info("Erasing all installed applications")
tock = loader.TockLoader(args) tock = loader.TockLoader(args)
tock.open(args) tock.open(args)
@@ -271,11 +498,13 @@ class OpenSKInstaller:
tock.erase_apps(False) tock.erase_apps(False)
except TockLoaderException as e: except TockLoaderException as e:
# Erasing apps is not critical # Erasing apps is not critical
info(("A non-critical error occured while erasing " info(("A non-critical error occurred while erasing "
"apps: {}".format(str(e)))) "apps: {}".format(str(e))))
# pylint: disable=W0212 # pylint: disable=protected-access
def verify_flashed_app(self, expected_app): def verify_flashed_app(self, expected_app):
if self.args.programmer not in ("jlink", "openocd"):
return False
args = copy.copy(self.tockloader_default_args) args = copy.copy(self.tockloader_default_args)
tock = loader.TockLoader(args) tock = loader.TockLoader(args)
app_found = False app_found = False
@@ -284,51 +513,192 @@ class OpenSKInstaller:
app_found = expected_app in apps app_found = expected_app in apps
return app_found return app_found
def create_hex_file(self, dest_file):
# We produce an intelhex file with everything in it
# pylint: disable=g-import-not-at-top,import-outside-toplevel
import intelhex
board_props = SUPPORTED_BOARDS[self.args.board]
final_hex = intelhex.IntelHex()
if self.args.tockos:
# Process kernel
kernel_path = os.path.join(board_props.path, "target", board_props.arch,
"release", "{}.bin".format(self.args.board))
with open(kernel_path, "rb") as kernel:
kern_hex = intelhex.IntelHex()
kern_hex.frombytes(kernel.read(), offset=board_props.kernel_address)
final_hex.merge(kern_hex, overlap="error")
# Add padding
if board_props.padding_address:
padding_hex = intelhex.IntelHex()
padding_hex.frombytes(
self.get_padding(), offset=board_props.padding_address)
final_hex.merge(padding_hex, overlap="error")
# Now we can add the application from the TAB file
app_tab_path = "target/tab/{}.tab".format(self.args.application)
assert os.path.exists(app_tab_path)
app_tab = tab.TAB(app_tab_path)
if board_props.arch not in app_tab.get_supported_architectures():
fatal(("It seems that the TAB file was not produced for the "
"architecture {}".format(board_props.arch)))
app_hex = intelhex.IntelHex()
app_hex.frombytes(
app_tab.extract_app(board_props.arch).get_binary(),
offset=board_props.app_address)
final_hex.merge(app_hex)
info("Generating all-merged HEX file: {}".format(dest_file))
final_hex.tofile(dest_file, format="hex")
def check_prerequisites(self):
if self.args.programmer == "jlink":
assert_mandatory_binary("JLinkExe")
if self.args.programmer == "openocd":
assert_mandatory_binary("openocd")
if self.args.programmer == "pyocd":
assert_mandatory_binary("pyocd")
assert_python_library("intelhex")
if not SUPPORTED_BOARDS[self.args.board].pyocd_target:
fatal("This board doesn't seem to support flashing through pyocd.")
if self.args.programmer == "nordicdfu":
assert_mandatory_binary("nrfutil")
assert_python_library("intelhex")
assert_python_library("nordicsemi.lister")
if not SUPPORTED_BOARDS[self.args.board].nordic_dfu:
fatal("This board doesn't support flashing over DFU.")
if self.args.programmer == "none":
assert_python_library("intelhex")
def run(self): def run(self):
if self.args.action is None: if self.args.listing == "boards":
# Nothing to do print(os.linesep.join(get_supported_boards()))
return 0 return 0
if self.args.listing == "programmers":
print(os.linesep.join(PROGRAMMERS))
return 0
if self.args.listing:
# Missing check?
fatal("Listing {} is not implemented.".format(self.args.listing))
self.check_prerequisites()
self.update_rustc_if_needed() self.update_rustc_if_needed()
if self.args.action == "os": if self.args.application is None:
info("Installing Tock on board {}".format(self.args.board)) fatal("Please specify an application to be flashed")
self.build_and_install_tockos()
return 0
if self.args.action == "app": # Compile what needs to be compiled
if self.args.application is None: if self.args.tockos:
fatal("Unspecified application") self.build_tockos()
if self.args.application == "ctap2":
self.generate_crypto_materials(self.args.regenerate_keys)
self.build_opensk()
else:
self.build_example()
# Flashing
board_props = SUPPORTED_BOARDS[self.args.board]
if self.args.programmer in ("jlink", "openocd"):
# We rely on Tockloader to do the job
if self.args.clear_apps: if self.args.clear_apps:
self.clear_apps() self.clear_apps()
if self.args.application == "ctap2": if self.args.tockos:
self.generate_crypto_materials(self.args.regenerate_keys) # Install Tock OS
self.build_and_install_opensk() self.install_tock_os()
else: # Install padding and application
self.build_and_install_example() self.install_padding()
self.install_tab_file("target/tab/{}.tab".format(self.args.application))
if self.verify_flashed_app(self.args.application): if self.verify_flashed_app(self.args.application):
info("You're all set!") info("You're all set!")
return 0 return 0
error(("It seems that something went wrong. " error(("It seems that something went wrong. App/example not found "
"App/example not found on your board.")) "on your board. Ensure the connections between the programmer and "
"the board are correct."))
return 1 return 1
if self.args.programmer in ("pyocd", "nordicdfu", "none"):
dest_file = "target/{}_merged.hex".format(self.args.board)
self.create_hex_file(dest_file)
if self.args.programmer == "pyocd":
info("Flashing HEX file")
self.checked_command_output([
"pyocd", "flash", "--target={}".format(board_props.pyocd_target),
"--format=hex", "--erase=auto", dest_file
])
if self.args.programmer == "nordicdfu":
info("Creating DFU package")
dfu_pkg_file = "target/{}_dfu.zip".format(self.args.board)
self.checked_command_output([
"nrfutil", "pkg", "generate", "--hw-version=52", "--sd-req=0",
"--application-version=1", "--application={}".format(dest_file),
dfu_pkg_file
])
info(
"Please insert the dongle and switch it to DFU mode by keeping the "
"button pressed while inserting...")
info("Press [ENTER] when ready.")
_ = input()
# Search for the DFU devices
serial_number = []
# pylint: disable=g-import-not-at-top,import-outside-toplevel
from nordicsemi.lister import device_lister
for device in device_lister.DeviceLister().enumerate():
if device.vendor_id == "1915" and device.product_id == "521F":
serial_number.append(device.serial_number)
if not serial_number:
fatal("Couldn't find any DFU device on your system.")
if len(serial_number) > 1:
fatal("Multiple DFU devices are detected. Please only connect one.")
# Run the command without capturing stdout so that we show progress
info("Flashing device using DFU...")
return subprocess.run(
[
"nrfutil", "dfu", "usb-serial",
"--package={}".format(dfu_pkg_file),
"--serial-number={}".format(serial_number[0])
],
check=False,
timeout=None,
).returncode
return 0 return 0
def main(args): def main(args):
# Make sure the current working directory is the right one before running # Make sure the current working directory is the right one before running
os.chdir(os.path.realpath(os.path.dirname(__file__))) os.chdir(os.path.realpath(os.path.dirname(__file__)))
# Check for pre-requisite executable files.
if not shutil.which("JLinkExe"):
fatal(("Couldn't find JLinkExe binary. Make sure Segger JLink tools "
"are installed and correctly set up."))
OpenSKInstaller(args).run() OpenSKInstaller(args).run()
if __name__ == "__main__": if __name__ == "__main__":
shared_parser = argparse.ArgumentParser(add_help=False) main_parser = argparse.ArgumentParser()
shared_parser.add_argument( action_group = main_parser.add_mutually_exclusive_group(required=True)
action_group.add_argument(
"--list",
metavar="WHAT",
choices=("boards", "programmers"),
default=None,
dest="listing",
help=("List supported boards or programmers, 1 per line and then exit."),
)
action_group.add_argument(
"--board",
metavar="BOARD_NAME",
dest="board",
default=None,
choices=get_supported_boards(),
help="Indicates which board Tock OS will be compiled for.",
)
main_parser.add_argument(
"--dont-clear-apps", "--dont-clear-apps",
action="store_false", action="store_false",
default=True, default=True,
@@ -336,32 +706,26 @@ if __name__ == "__main__":
help=("When installing an application, previously installed " help=("When installing an application, previously installed "
"applications won't be erased from the board."), "applications won't be erased from the board."),
) )
main_parser.add_argument(
main_parser = argparse.ArgumentParser() "--programmer",
commands = main_parser.add_subparsers( metavar="METHOD",
dest="action", dest="programmer",
help=("Indicates which part of the firmware should be compiled and " choices=PROGRAMMERS,
"flashed to the connected board.")) default="jlink",
help=("Sets the method to be used to flash Tock OS or the application "
os_commands = commands.add_parser( "on the target board."),
"os",
parents=[shared_parser],
help=("Compiles and installs Tock OS. The target board must be "
"specified by setting the --board argument."),
) )
os_commands.add_argument(
"--board",
metavar="BOARD_NAME",
dest="board",
choices=get_supported_boards(),
help="Indicates which board Tock OS will be compiled for.",
required=True)
app_commands = commands.add_parser( main_parser.add_argument(
"app", "--no-tockos",
parents=[shared_parser], action="store_false",
help="compiles and installs an application.") default=True,
app_commands.add_argument( dest="tockos",
help=("Only compiles and flash the application/example. "
"Otherwise TockOS will also be bundled and flashed."),
)
main_parser.add_argument(
"--panic-console", "--panic-console",
action="append_const", action="append_const",
const="panic_console", const="panic_console",
@@ -370,7 +734,7 @@ if __name__ == "__main__":
"output messages before starting blinking the LEDs on the " "output messages before starting blinking the LEDs on the "
"board."), "board."),
) )
app_commands.add_argument( main_parser.add_argument(
"--debug-allocations", "--debug-allocations",
action="append_const", action="append_const",
const="debug_allocations", const="debug_allocations",
@@ -378,7 +742,7 @@ if __name__ == "__main__":
help=("The console will be used to output allocator statistics every " help=("The console will be used to output allocator statistics every "
"time an allocation/deallocation happens."), "time an allocation/deallocation happens."),
) )
app_commands.add_argument( main_parser.add_argument(
"--no-u2f", "--no-u2f",
action=RemoveConstAction, action=RemoveConstAction,
const="with_ctap1", const="with_ctap1",
@@ -386,7 +750,7 @@ if __name__ == "__main__":
help=("Compiles the OpenSK application without backward compatible " help=("Compiles the OpenSK application without backward compatible "
"support for U2F/CTAP1 protocol."), "support for U2F/CTAP1 protocol."),
) )
app_commands.add_argument( main_parser.add_argument(
"--regen-keys", "--regen-keys",
action="store_true", action="store_true",
default=False, default=False,
@@ -396,7 +760,7 @@ if __name__ == "__main__":
"This is useful to allow flashing multiple OpenSK authenticators " "This is useful to allow flashing multiple OpenSK authenticators "
"in a row without them being considered clones."), "in a row without them being considered clones."),
) )
app_commands.add_argument( main_parser.add_argument(
"--debug", "--debug",
action="append_const", action="append_const",
const="debug_ctap", const="debug_ctap",
@@ -405,7 +769,7 @@ if __name__ == "__main__":
"(i.e. more debug messages will be sent over the console port " "(i.e. more debug messages will be sent over the console port "
"such as hexdumps of packets)."), "such as hexdumps of packets)."),
) )
app_commands.add_argument( main_parser.add_argument(
"--no-persistent-storage", "--no-persistent-storage",
action="append_const", action="append_const",
const="ram_storage", const="ram_storage",
@@ -413,7 +777,8 @@ if __name__ == "__main__":
help=("Compiles and installs the OpenSK application without persistent " help=("Compiles and installs the OpenSK application without persistent "
"storage (i.e. unplugging the key will reset the key)."), "storage (i.e. unplugging the key will reset the key)."),
) )
apps_group = app_commands.add_mutually_exclusive_group()
apps_group = main_parser.add_mutually_exclusive_group()
apps_group.add_argument( apps_group.add_argument(
"--opensk", "--opensk",
dest="application", dest="application",
@@ -428,6 +793,6 @@ if __name__ == "__main__":
help=("Compiles and installs the crypto_bench example that tests " help=("Compiles and installs the crypto_bench example that tests "
"the performance of the cryptographic algorithms on the board.")) "the performance of the cryptographic algorithms on the board."))
app_commands.set_defaults(features=["with_ctap1"]) main_parser.set_defaults(features=["with_ctap1"])
main(main_parser.parse_args()) main(main_parser.parse_args())

View File

@@ -16,8 +16,9 @@ You will need one the following supported boards:
scenarios as the JTAG probe is already on the board. scenarios as the JTAG probe is already on the board.
* [Nordic nRF52840 Dongle](https://www.nordicsemi.com/Software-and-tools/Development-Kits/nRF52840-Dongle) * [Nordic nRF52840 Dongle](https://www.nordicsemi.com/Software-and-tools/Development-Kits/nRF52840-Dongle)
to have a more practical form factor. to have a more practical form factor.
* [Makerdiary nRF52840-MDK USB dongle](https://wiki.makerdiary.com/nrf52840-mdk/).
In the case of the Nordic USB dongle, you will also need the following extra In the case of the Nordic USB dongle, you may also need the following extra
hardware: hardware:
* a [Segger J-Link](https://www.segger.com/products/debug-probes/j-link/) JTAG * a [Segger J-Link](https://www.segger.com/products/debug-probes/j-link/) JTAG
@@ -30,13 +31,18 @@ hardware:
[Tag-Connect TC2050 retainer clip](http://www.tag-connect.com/TC2050-CLIP) [Tag-Connect TC2050 retainer clip](http://www.tag-connect.com/TC2050-CLIP)
to keep the spring loaded connector pressed to the PCB. to keep the spring loaded connector pressed to the PCB.
Although [OpenOCD](http://openocd.org/) should be supported we encountered some Additionnaly, OpenSK supports other ways to flash your board:
issues while trying to flash a firmware with it. Therefore we suggest at the
moment to use a
[Segger J-Link](https://www.segger.com/products/debug-probes/j-link/) probe
instead.
This guide **does not** cover how to setup the JTAG probe on your system. * [OpenOCD](http://openocd.org/).
* [Segger J-Link](https://www.segger.com/products/debug-probes/j-link/)
(default method).
* [pyOCD](https://pypi.org/project/pyocd/).
* [nrfutil](https://pypi.org/project/nrfutil/) for the USB dongle boards that
supports it, which allows you to directly flash a working board over USB
without additional hardware.
This guide **does not** cover how to setup the JTAG probe and their related
tools on your system.
### Software ### Software
@@ -141,17 +147,17 @@ Our build script `build.rs` is responsible for converting `opensk_cert.pem` and
1. Connect a micro USB cable to the JTAG USB port. 1. Connect a micro USB cable to the JTAG USB port.
1. Run our script for compiling/flashing Tock OS on your device (_output may 1. Run our script for compiling/flashing Tock OS and OpenSK on your device
differ_): (_output may differ_):
```shell ```shell
$ ./deploy.py os --board=nrf52840_dk $ ./deploy.py --board=nrf52840dk --opensk
info: Updating rust toolchain to nightly-2020-02-03 info: Updating rust toolchain to nightly-2020-02-03
info: syncing channel updates for 'nightly-2020-02-03-x86_64-unknown-linux-gnu' info: syncing channel updates for 'nightly-2020-02-03-x86_64-unknown-linux-gnu'
info: checking for self-updates info: checking for self-updates
info: component 'rust-std' for target 'thumbv7em-none-eabi' is up to date info: component 'rust-std' for target 'thumbv7em-none-eabi' is up to date
info: Rust toolchain up-to-date info: Rust toolchain up-to-date
info: Installing Tock on board nrf52840_dk info: Building Tock OS for board nrf52840dk
Compiling tock-registers v0.5.0 (./third_party/tock/libraries/tock-register-interface) Compiling tock-registers v0.5.0 (./third_party/tock/libraries/tock-register-interface)
Compiling tock-cells v0.1.0 (./third_party/tock/libraries/tock-cells) Compiling tock-cells v0.1.0 (./third_party/tock/libraries/tock-cells)
Compiling enum_primitive v0.1.0 (./third_party/tock/libraries/enum_primitive) Compiling enum_primitive v0.1.0 (./third_party/tock/libraries/enum_primitive)
@@ -166,47 +172,17 @@ Our build script `build.rs` is responsible for converting `opensk_cert.pem` and
Compiling nrf52840 v0.1.0 (./third_party/tock/chips/nrf52840) Compiling nrf52840 v0.1.0 (./third_party/tock/chips/nrf52840)
Compiling components v0.1.0 (./third_party/tock/boards/components) Compiling components v0.1.0 (./third_party/tock/boards/components)
Compiling nrf52dk_base v0.1.0 (./third_party/tock/boards/nordic/nrf52dk_base) Compiling nrf52dk_base v0.1.0 (./third_party/tock/boards/nordic/nrf52dk_base)
Finished release [optimized + debuginfo] target(s) in 11.97s Finished release [optimized + debuginfo] target(s) in 13.15s
[STATUS ] Flashing binar(y|ies) to board... info: Converting Tock OS file into a binary
[INFO ] Using known arch and jtag-device for known board nrf52dk info: Building OpenSK application
[INFO ] Finished in 0.284 seconds Finished release [optimized] target(s) in 0.02s
``` info: Generating Tock TAB file for application/example ctap2
info: Erasing all installed applications
1. Run our script for compiling/flashing the OpenSK application on your device All apps have been erased.
(_output may differ_): info: Flashing file third_party/tock/boards/nordic/nrf52840dk/target/thumbv7em-none-eabi/release/nrf52840dk.bin.
info: Flashing padding application
```shell info: Installing Tock application ctap2
$ ./deploy.py app --opensk info: You're all set!
info: Updating rust toolchain to nightly-2020-02-03
info: syncing channel updates for 'nightly-2020-02-03-x86_64-unknown-linux-gnu'
info: checking for self-updates
info: component 'rust-std' for target 'thumbv7em-none-eabi' is up to date
info: Rust toolchain up-to-date
info: Erasing all installed applications
All apps have been erased.
info: Building OpenSK application
Compiling autocfg v1.0.0
Compiling pkg-config v0.3.17
Compiling cc v1.0.50
Compiling libc v0.2.66
Compiling bitflags v1.2.1
Compiling foreign-types-shared v0.1.1
Compiling openssl v0.10.28
Compiling cfg-if v0.1.10
Compiling lazy_static v1.4.0
Compiling byteorder v1.3.2
Compiling linked_list_allocator v0.6.6
Compiling arrayref v0.3.6
Compiling cbor v0.1.0 (./libraries/cbor)
Compiling subtle v2.2.2
Compiling foreign-types v0.3.2
Compiling libtock v0.1.0 (./third_party/libtock-rs)
Compiling crypto v0.1.0 (./libraries/crypto)
Compiling openssl-sys v0.9.54
Compiling ctap2 v0.1.0 (.)
Finished release [optimized] target(s) in 15.34s
info: Flashing padding application
info: Installing Tock application ctap2
``` ```
1. Connect a micro USB cable to the device USB port. 1. Connect a micro USB cable to the device USB port.
@@ -217,6 +193,8 @@ the board in order to see your OpenSK device on your system.
#### Nordic nRF52840 Dongle #### Nordic nRF52840 Dongle
##### Using external programmer (JLink, OpenOCD, etc.)
![Nordic dongle](img/dongle_front.jpg) ![Nordic dongle](img/dongle_front.jpg)
1. The JTAG probe used for programming won't provide power to the board. 1. The JTAG probe used for programming won't provide power to the board.
@@ -232,17 +210,18 @@ the board in order to see your OpenSK device on your system.
![Nordic dongle retainer clip](img/dongle_clip.jpg) ![Nordic dongle retainer clip](img/dongle_clip.jpg)
1. Run our script for compiling/flashing Tock OS on your device (_output may 1. Depending on the programmer you're using, you may have to adapt the next
differ_): command line. Run our script for compiling/flashing Tock OS on your device
(_output may differ_):
```shell ```shell
$ ./deploy.py os --board=nrf52840_dongle $ ./deploy.py os --board=nrf52840_dongle --programmer=jlink
info: Updating rust toolchain to nightly-2020-02-03 info: Updating rust toolchain to nightly-2020-02-03
info: syncing channel updates for 'nightly-2020-02-03-x86_64-unknown-linux-gnu' info: syncing channel updates for 'nightly-2020-02-03-x86_64-unknown-linux-gnu'
info: checking for self-updates info: checking for self-updates
info: component 'rust-std' for target 'thumbv7em-none-eabi' is up to date info: component 'rust-std' for target 'thumbv7em-none-eabi' is up to date
info: Rust toolchain up-to-date info: Rust toolchain up-to-date
info: Installing Tock on board nrf52840_dongle info: Building Tock OS for board nrf52840_dongle
Compiling tock-cells v0.1.0 (./third_party/tock/libraries/tock-cells) Compiling tock-cells v0.1.0 (./third_party/tock/libraries/tock-cells)
Compiling tock-registers v0.5.0 (./third_party/tock/libraries/tock-register-interface) Compiling tock-registers v0.5.0 (./third_party/tock/libraries/tock-register-interface)
Compiling enum_primitive v0.1.0 (./third_party/tock/libraries/enum_primitive) Compiling enum_primitive v0.1.0 (./third_party/tock/libraries/enum_primitive)
@@ -258,50 +237,39 @@ the board in order to see your OpenSK device on your system.
Compiling components v0.1.0 (./third_party/tock/boards/components) Compiling components v0.1.0 (./third_party/tock/boards/components)
Compiling nrf52dk_base v0.1.0 (./third_party/tock/boards/nordic/nrf52dk_base) Compiling nrf52dk_base v0.1.0 (./third_party/tock/boards/nordic/nrf52dk_base)
Finished release [optimized + debuginfo] target(s) in 11.72s Finished release [optimized + debuginfo] target(s) in 11.72s
[STATUS ] Flashing binar(y|ies) to board... info: Converting Tock OS file into a binary
[INFO ] Using known arch and jtag-device for known board nrf52dk info: Building OpenSK application
[INFO ] Finished in 0.280 seconds Finished release [optimized] target(s) in 0.02s
``` info: Generating Tock TAB file for application/example ctap2
1. Run our script for compiling/flashing the OpenSK application on your device
(_output may differ_):
```shell
$ ./deploy.py app --opensk
info: Updating rust toolchain to nightly-2020-02-03
info: syncing channel updates for 'nightly-2020-02-03-x86_64-unknown-linux-gnu'
info: checking for self-updates
info: component 'rust-std' for target 'thumbv7em-none-eabi' is up to date
info: Rust toolchain up-to-date
info: Erasing all installed applications info: Erasing all installed applications
All apps have been erased. All apps have been erased.
info: Building OpenSK application info: Flashing file third_party/tock/boards/nordic/nrf52840_dongle/target/thumbv7em-none-eabi/release/nrf52840_dongle.bin.
Compiling autocfg v1.0.0
Compiling pkg-config v0.3.17
Compiling cc v1.0.50
Compiling libc v0.2.66
Compiling bitflags v1.2.1
Compiling foreign-types-shared v0.1.1
Compiling openssl v0.10.28
Compiling cfg-if v0.1.10
Compiling lazy_static v1.4.0
Compiling byteorder v1.3.2
Compiling linked_list_allocator v0.6.6
Compiling arrayref v0.3.6
Compiling cbor v0.1.0 (./libraries/cbor)
Compiling subtle v2.2.2
Compiling foreign-types v0.3.2
Compiling libtock v0.1.0 (./third_party/libtock-rs)
Compiling crypto v0.1.0 (./libraries/crypto)
Compiling openssl-sys v0.9.54
Compiling ctap2 v0.1.0 (.)
Finished release [optimized] target(s) in 15.34s
info: Flashing padding application info: Flashing padding application
info: Installing Tock application ctap2 info: Installing Tock application ctap2
info: You're all set!
``` ```
1. Remove the programming cable and the USB-A extension cable. 1. Remove the programming cable and the USB-A extension cable.
### Advanced installation
Although flashing using a Segger JLink probe is the officially supported way,
our tool, `deploy.py` also supports other methods:
* OpenOCD: `./deploy.py --board=nrf52840_dongle --opensk --programmer=openocd`
* pyOCD: `./deploy.py --board=nrf52840_dongle --opensk --programmer=pyocd`
* Nordic DFU: `./deploy.py --board=nrf52840_dongle --opensk
--programmer=nordicdfu`
* Custom: `./deploy.py --board=nrf52840_dongle --opensk --programmer=none`. In
this case, an IntelHex file will be created and how to program a board is
left to the user.
If your board is already flashed with Tock OS, you may skip installing it:
`./deploy.py --board=nrf52840dk --opensk --no-tockos`
For more options, we invite you to read the help of our `deploy.py` script by
running `./deploy.py --help`.
### Installing the udev rule (Linux only) ### Installing the udev rule (Linux only)
By default on Linux, a USB device will require root privilege in order interact By default on Linux, a USB device will require root privilege in order interact

View File

@@ -0,0 +1,23 @@
diff --git a/arch/cortex-m/src/scb.rs b/arch/cortex-m/src/scb.rs
index 8107f16..a271db9 100644
--- a/arch/cortex-m/src/scb.rs
+++ b/arch/cortex-m/src/scb.rs
@@ -9,7 +9,7 @@ use kernel::common::StaticRef;
struct ScbRegisters {
cpuid: VolatileCell<u32>,
icsr: VolatileCell<u32>,
- vtor: VolatileCell<u32>,
+ vtor: VolatileCell<*const ()>,
aircr: VolatileCell<u32>,
scr: VolatileCell<u32>,
ccr: VolatileCell<u32>,
@@ -54,3 +54,8 @@ pub unsafe fn reset() {
let reset = (0x5FA << 16) | (aircr & (0x7 << 8)) | (1 << 2);
SCB.aircr.set(reset);
}
+
+/// relocate interrupt vector table
+pub unsafe fn set_vector_table_offset(offset: *const ()) {
+ SCB.vtor.set(offset);
+}

View File

@@ -0,0 +1,21 @@
diff --git a/chips/nrf52/src/crt1.rs b/chips/nrf52/src/crt1.rs
index 9703aac..281ceeb 100644
--- a/chips/nrf52/src/crt1.rs
+++ b/chips/nrf52/src/crt1.rs
@@ -1,4 +1,4 @@
-use cortexm4::{generic_isr, hard_fault_handler, nvic, svc_handler, systick_handler};
+use cortexm4::{generic_isr, hard_fault_handler, nvic, scb, svc_handler, systick_handler};
use tock_rt0;
/*
@@ -168,5 +168,9 @@ pub unsafe extern "C" fn init() {
tock_rt0::init_data(&mut _etext, &mut _srelocate, &mut _erelocate);
tock_rt0::zero_bss(&mut _szero, &mut _ezero);
+ // Ensure that we are compatible with a bootloader.
+ // For this we need to offset our vector table
+ scb::set_vector_table_offset(BASE_VECTORS.as_ptr() as *const ());
+
nvic::enable_all();
}