diff --git a/.gitignore b/.gitignore index 9d665be..098012e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ build target local_cargo +Cargo.lock diff --git a/arch/bootloader_cortexm/Cargo.toml b/arch/bootloader_cortexm/Cargo.toml index a59fe5e..45f67a0 100644 --- a/arch/bootloader_cortexm/Cargo.toml +++ b/arch/bootloader_cortexm/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["Tock Project Developers "] [dependencies] -kernel = { git = "https://github.com/tock/tock", rev = "405417" } +kernel = { git = "https://github.com/tock/tock", rev = "2ff6868" } #kernel = { path = "../../../tock/kernel" } bootloader = { path = "../../bootloader" } diff --git a/arch/bootloader_cortexm/src/jumper.rs b/arch/bootloader_cortexm/src/jumper.rs index 305689a..7e9c27e 100644 --- a/arch/bootloader_cortexm/src/jumper.rs +++ b/arch/bootloader_cortexm/src/jumper.rs @@ -8,17 +8,18 @@ impl CortexMJumper { impl bootloader::interfaces::Jumper for CortexMJumper { fn jump(&self, address: u32) -> ! { + use core::arch::asm; unsafe { asm!( ".syntax unified \n\ - mov r0, {0} // The address of the payload's .vectors \n\ + mov r0, {address} // The address of the payload's .vectors \n\ ldr r1, =0xe000ed08 // The address of the VTOR register (0xE000E000(SCS) + 0xD00(SCB) + 0x8(VTOR)) \n\ str r0, [r1] // Move the payload's VT address into the VTOR register \n\ ldr r1, [r0] // Move the payload's initial SP into r1 \n\ mov sp, r1 // Set our SP to that \n\ ldr r0, [r0, #4] // Load the payload's ENTRY into r0 \n\ bx r0 // Whoopee", - in(reg) address, + address = in(reg) address, ); } loop {} diff --git a/arch/bootloader_cortexm/src/lib.rs b/arch/bootloader_cortexm/src/lib.rs index c51f58f..c773f34 100644 --- a/arch/bootloader_cortexm/src/lib.rs +++ b/arch/bootloader_cortexm/src/lib.rs @@ -1,4 +1,3 @@ -#![feature(const_fn, asm)] #![no_std] pub mod jumper; diff --git a/boards/Common.mk b/boards/Common.mk index cac6161..6fcfbb6 100644 --- a/boards/Common.mk +++ b/boards/Common.mk @@ -1,3 +1,7 @@ +# Licensed under the Apache License, Version 2.0 or the MIT License. +# SPDX-License-Identifier: Apache-2.0 OR MIT +# Copyright Tock Contributors 2022. + # Force the Shell to be bash as some systems have strange default shells SHELL := bash @@ -13,48 +17,89 @@ MAKEFILE_COMMON_PATH := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) # This is currently the parent directory of MAKEFILE_COMMON_PATH. TOCK_ROOT_DIRECTORY := $(dir $(abspath $(MAKEFILE_COMMON_PATH))) +# The path to the root of the rust installation used for this build. +# Useful for remapping paths and for finding already-installed llvm tools. +RUSTC_SYSROOT := "$(shell rustc --print sysroot)" + # Common defaults that specific boards can override, but likely do not need to. -TOOLCHAIN ?= llvm +# +# The TOOLCHAIN parameter is set to the magic value "llvm-tools", which will +# cause the Makefile to resolve the llvm toolchain installed as part of the +# rustup component "llvm-tools". In case a system toolchain shall be used, this +# can be overridden to specify the toolchain prefix, e.g. "llvm" for +# llvm-{objdump,objcopy,...} or "arm-none-eabi". +TOOLCHAIN ?= llvm-tools CARGO ?= cargo -RUSTUP ?= rustup -# Default location of target directory (relative to board makefile) -# passed to cargo --target_dir +# Not all platforms support the rustup tool. Those that do not can pass +# `NO_RUSTUP=1` to make and then all of the rustup commands will be ignored. +ifeq ($(NO_RUSTUP),) + RUSTUP ?= rustup +else + RUSTUP ?= true +endif + +# Default location of target directory (relative to board makefile) passed to +# cargo `--target_dir`. TARGET_DIRECTORY ?= $(TOCK_ROOT_DIRECTORY)target/ # RUSTC_FLAGS allows boards to define board-specific options. # This will hopefully move into Cargo.toml (or Cargo.toml.local) eventually. -# lld uses the page size to align program sections. It defaults to 4096 and this -# puts a gap between before the .relocate section. `zmax-page-size=512` tells -# lld the actual page size so it doesn't have to be conservative. +# +# - `-Tlayout.ld`: Use the linker script `layout.ld` all boards must provide. +# - `linker=rust-lld`: Tell rustc to use the LLVM linker. This avoids needing +# GCC as a dependency to build the kernel. +# - `linker-flavor=ld.lld`: Use the LLVM lld executable with the `-flavor gnu` +# flag. +# - `relocation-model=static`: See https://github.com/tock/tock/pull/2853 +# - `-nmagic`: lld by default uses a default page size to align program +# sections. Tock expects that program sections are set back-to-back. `-nmagic` +# instructs the linker to not page-align sections. +# - `-icf=all`: Identical Code Folding (ICF) set to all. This tells the linker +# to be more aggressive about removing duplicate code. The default is `safe`, +# and the downside to `all` is that different functions in the code can end up +# with the same address in the binary. However, it can save a fair bit of code +# size. +# - `-C symbol-mangling-version=v0`: Opt-in to Rust v0 symbol mangling scheme. +# See https://github.com/rust-lang/rust/issues/60705 and +# https://github.com/tock/tock/issues/3529. RUSTC_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 \ + -C relocation-model=static \ + -C link-arg=-nmagic \ -C link-arg=-icf=all \ + -C symbol-mangling-version=v0 \ # RISC-V-specific flags. ifneq ($(findstring riscv32i, $(TARGET)),) - # NOTE: This flag causes kernel panics on some ARM cores. Since the - # size benefit is almost exclusively for RISC-V, we only apply it for - # those targets. + # NOTE: This flag causes kernel panics on some ARM cores. Since the size + # benefit is almost exclusively for RISC-V, we only apply it for those + # targets. RUSTC_FLAGS += -C force-frame-pointers=no + # Ensure relocations generated is eligible for linker relaxation. + # This provide huge space savings. + RUSTC_FLAGS += -C target-feature=+relax endif -# RUSTC_FLAGS_TOCK by default extends RUSTC_FLAGS with options -# that are global to all Tock boards. +# RUSTC_FLAGS_TOCK by default extends RUSTC_FLAGS with options that are global +# to all Tock boards. # # We use `remap-path-prefix` to remove user-specific filepath strings for error -# reporting from appearing in the generated binary. +# reporting from appearing in the generated binary. The first line is used for +# remapping the tock directory, and the second line is for remapping paths to +# the source code of the core library, which end up in the binary as a result of +# our use of `-Zbuild-std=core`. RUSTC_FLAGS_TOCK ?= \ $(RUSTC_FLAGS) \ --remap-path-prefix=$(TOCK_ROOT_DIRECTORY)= \ + --remap-path-prefix=$(RUSTC_SYSROOT)/lib/rustlib/src/rust/library/core=/core/ -# Disallow warnings for continuous integration builds. Disallowing them here -# ensures that warnings during testing won't prevent compilation from succeeding. -ifeq ($(CI),true) +# Disallow warnings only for continuous integration builds. Disallowing them +# here using the `RUSTC_FLAGS_TOCK` variable ensures that warnings during +# testing won't prevent compilation from succeeding. +ifeq ($(NOWARNINGS),true) RUSTC_FLAGS_TOCK += -D warnings endif @@ -85,31 +130,53 @@ RUSTC_FLAGS_FOR_BIN ?= \ check_defined = $(strip $(foreach 1,$1,$(if $(value $1),,$(error Undefined variable "$1")))) # Check that we know the basics of what we are compiling for. -# `PLATFORM`: The name of the board that the kernel is being compiled for. -# `TARGET` : The Rust target architecture the kernel is being compiled for. +# - `PLATFORM`: The name of the board that the kernel is being compiled for. +# - `TARGET` : The Rust target architecture the kernel is being compiled for. $(call check_defined, PLATFORM) $(call check_defined, TARGET) -# Location of target-specific build +# Location of target-specific build. TARGET_PATH := $(TARGET_DIRECTORY)$(TARGET) -# If environment variable V is non-empty, be verbose. +# If environment variable V or VERBOSE is non-empty, be verbose. ifneq ($(V),) + VERBOSE_MODE = 1 +else ifneq ($(VERBOSE),) + VERBOSE_MODE = 1 +else + VERBOSE_MODE = +endif + +ifeq ($(VERBOSE_MODE),1) Q = - VERBOSE = --verbose + VERBOSE_FLAGS = --verbose + DEVNULL = else Q = @ - VERBOSE = + VERBOSE_FLAGS = + DEVNULL = > /dev/null endif # Ask git what version of the Tock kernel we are compiling, so we can include # this within the binary. If Tock is not within a git repo then we fallback to # a set string which should be updated with every release. -export TOCK_KERNEL_VERSION := $(shell git describe --tags --always 2> /dev/null || echo "1.4+") +export TOCK_KERNEL_VERSION := $(shell git describe --tags --always 2> /dev/null || echo "2.1+") + +# Allow users to opt out of using rustup. +ifeq ($(NO_RUSTUP),) +# Validate that rustup exists. +RUSTUP_ERROR := $(shell $(RUSTUP) --version > /dev/null 2>&1; echo $$?) +ifneq ($(RUSTUP_ERROR),0) + $(info Error! rustup not found.) + $(info Please follow the instructions at https://rustup.rs/ to install rustup.) + $(info Alternatively, install all required tools and Rust targets and set NO_RUSTUP=1 to disable this check.) + $(info ) + $(error Rustup required to build Tock.) +endif # Validate that rustup is new enough. -MINIMUM_RUSTUP_VERSION := 1.11.0 -RUSTUP_VERSION := $(strip $(word 2, $(shell $(RUSTUP) --version))) +MINIMUM_RUSTUP_VERSION := 1.23.0 +RUSTUP_VERSION := $(strip $(word 2, $(shell $(RUSTUP) --version 2> /dev/null))) ifeq ($(shell $(TOCK_ROOT_DIRECTORY)tools/semver.sh $(RUSTUP_VERSION) \< $(MINIMUM_RUSTUP_VERSION)), true) $(warning Required tool `$(RUSTUP)` is out-of-date.) $(warning Running `$(RUSTUP) update` in 3 seconds (ctrl-c to cancel)) @@ -120,46 +187,63 @@ endif # Verify that various required Rust components are installed. All of these steps # only have to be done once per Rust version, but will take some time when # compiling for the first time. -LLVM_TOOLS_INSTALLED := $(shell $(RUSTUP) component list | grep 'llvm-tools-preview.*(installed)' > /dev/null; echo $$?) -ifeq ($(LLVM_TOOLS_INSTALLED),1) - $(shell $(RUSTUP) component add llvm-tools-preview) -endif -ifneq ($(shell $(RUSTUP) component list | grep rust-src),rust-src (installed)) - $(shell $(RUSTUP) component add rust-src) -endif ifneq ($(shell $(RUSTUP) target list | grep "$(TARGET) (installed)"),$(TARGET) (installed)) - $(shell $(RUSTUP) target add $(TARGET)) + $(warning Request to compile for a missing TARGET, make will install in 5s) + $(warning Consider updating 'targets' in 'rust-toolchain.toml') + $(shell sleep 5s && $(RUSTUP) target add $(TARGET)) endif - -# If the user is using the standard toolchain we need to get the full path. -# rustup should take care of this for us by putting in a proxy in .cargo/bin, -# but until that is setup we workaround it. -ifeq ($(TOOLCHAIN),llvm) - TOOLCHAIN = "$(shell dirname $(shell find `rustc --print sysroot` -name llvm-size))/llvm" +endif # $(NO_RUSTUP) + +# If the user is using the standard toolchain provided as part of the llvm-tools +# rustup component we need to get the full path. rustup should take care of this +# for us by putting in a proxy in .cargo/bin, but until that is setup we +# workaround it. +ifeq ($(TOOLCHAIN),llvm-tools) + TOOLCHAIN = "$(shell dirname $(shell find $(RUSTC_SYSROOT) -name llvm-size))/llvm" endif -# Set variables of the key tools we need to compile a Tock kernel. -SIZE ?= $(TOOLCHAIN)-size -OBJCOPY ?= $(TOOLCHAIN)-objcopy -OBJDUMP ?= $(TOOLCHAIN)-objdump +# Set variables of the key tools we need to compile a Tock kernel. Need to do +# this after we handle if we are using the LLVM tools or not. +SIZE ?= $(TOOLCHAIN)-size +OBJCOPY ?= $(TOOLCHAIN)-objcopy +OBJDUMP ?= $(TOOLCHAIN)-objdump # Set additional flags to produce binary from .elf. -# * --strip-sections prevents enormous binaries when SRAM is below flash. -# * --remove-section .apps prevents the .apps section from being included in the -# kernel binary file. This section is a placeholder for optionally including -# application binaries, and only needs to exist in the .elf. By removing it, -# we prevent the kernel binary from overwriting applications. -OBJCOPY_FLAGS ?= --strip-sections -S --remove-section .apps +# +# - `--strip-sections`: Prevents enormous binaries when SRAM is below flash. +# - `--strip-all`: Remove non-allocated sections outside segments. +# `.gnu.warning*` and `.ARM.attribute` sections are not removed. +# - `--remove-section .apps`: Prevents the .apps section from being included in +# the kernel binary file. This section is a placeholder for optionally +# including application binaries, and only needs to exist in the .elf. By +# removing it, we prevent the kernel binary from overwriting applications. +OBJCOPY_FLAGS ?= --strip-sections --strip-all --remove-section .apps + # This make variable allows board-specific Makefiles to pass down options to # the Cargo build command. For example, in boards//Makefile: # `CARGO_FLAGS += --features=foo` would pass feature `foo` to the top level # Cargo.toml. CARGO_FLAGS ?= -# Add default flags to cargo. Boards can add additional options in CARGO_FLAGS -CARGO_FLAGS_TOCK ?= $(VERBOSE) --target=$(TARGET) --package $(PLATFORM) --target-dir=$(TARGET_DIRECTORY) $(CARGO_FLAGS) + +# Add default flags to cargo. Boards can add additional options in +# `CARGO_FLAGS`. +# +# - `-Z build-std=core,compiler_builtins`: Build the std library from source +# using our optimization settings. This leads to significantly smaller binary +# sizes, and makes debugging easier since debug information for the core +# library is included in the resulting .elf file. See +# https://github.com/tock/tock/pull/2847 for more details. +CARGO_FLAGS_TOCK ?= \ + $(VERBOSE_FLAGS) \ + -Z build-std=core,compiler_builtins \ + --target=$(TARGET) \ + --package $(PLATFORM) \ + --target-dir=$(TARGET_DIRECTORY) $(CARGO_FLAGS) + # Set the default flags we need for objdump to get a .lst file. OBJDUMP_FLAGS ?= --disassemble-all --source --section-headers --demangle -# Set default flags for size + +# Set default flags for size. SIZE_FLAGS ?= # Need an extra flag for OBJDUMP if we are on a thumb platform. @@ -167,49 +251,78 @@ ifneq (,$(findstring thumb,$(TARGET))) OBJDUMP_FLAGS += --arch-name=thumb endif -# Check whether the system already has a sha256sum application -# present, if not use the custom shipped one +# Additional flags that can be passed to cargo bloat via an environment +# variable. Allows users to pass arbitrary flags supported by cargo bloat to +# customize the output. By default, pass an empty string. +CARGO_BLOAT_FLAGS ?= + +# Additional flags that can be passed to print_tock_memory_usage.py via an +# environment variable. By default, pass an empty string. +PTMU_ARGS ?= + +# `cargo bloat` does not support `-Z build-std`, so we must remove it from cargo +# flags. See https://github.com/RazrFalcon/cargo-bloat/issues/62. +CARGO_FLAGS_TOCK_NO_BUILD_STD := $(filter-out -Z build-std=core,$(CARGO_FLAGS_TOCK)) + +# Check whether the system already has a sha256sum or shasum application +# present. If not, use the custom shipped one. ifeq (, $(shell sha256sum --version 2>/dev/null)) - # No system sha256sum available - SHA256SUM := $(CARGO) run --manifest-path $(TOCK_ROOT_DIRECTORY)tools/sha256sum/Cargo.toml -- 2>/dev/null + ifeq (, $(shell shasum --version 2>/dev/null)) + # No system sha256sum available. + SHA256SUM := $(CARGO) run --manifest-path $(TOCK_ROOT_DIRECTORY)tools/sha256sum/Cargo.toml -- 2>/dev/null + else + SHA256SUM := shasum -a 256 + endif else - # Use system sha256sum + # Use system sha256sum. SHA256SUM := sha256sum endif +# virtual-function-elimination reduces the size of binaries, but is still +# experimental and has some possible miscompilation issues. This is only enabled +# for some boards by default, but is exposed via the `VFUNC_ELIM=1` option. +# +# For details on virtual-function-elimination see: https://github.com/rust-lang/rust/pull/96285 +# See https://github.com/rust-lang/rust/issues/68262 for general tracking +ifneq ($(VFUNC_ELIM),) + RUSTC_FLAGS += -C lto -Z virtual-function-elimination +endif + # Dump configuration for verbose builds -ifneq ($(V),) +ifeq ($(VERBOSE_MODE),1) $(info ) $(info *******************************************************) $(info TOCK KERNEL BUILD SYSTEM -- VERBOSE BUILD CONFIGURATION) $(info *******************************************************) - $(info MAKEFILE_COMMON_PATH = $(MAKEFILE_COMMON_PATH)) - $(info TOCK_ROOT_DIRECTORY = $(TOCK_ROOT_DIRECTORY)) - $(info TARGET_DIRECTORY = $(TARGET_DIRECTORY)) + $(info MAKEFILE_COMMON_PATH = $(MAKEFILE_COMMON_PATH)) + $(info TOCK_ROOT_DIRECTORY = $(TOCK_ROOT_DIRECTORY)) + $(info TARGET_DIRECTORY = $(TARGET_DIRECTORY)) $(info ) - $(info PLATFORM = $(PLATFORM)) - $(info TARGET = $(TARGET)) - $(info TOCK_KERNEL_VERSION = $(TOCK_KERNEL_VERSION)) - $(info RUSTC_FLAGS = $(RUSTC_FLAGS)) - $(info RUSTC_FLAGS_TOCK = $(RUSTC_FLAGS_TOCK)) - $(info MAKEFLAGS = $(MAKEFLAGS)) - $(info OBJDUMP_FLAGS = $(OBJDUMP_FLAGS)) - $(info OBJCOPY_FLAGS = $(OBJCOPY_FLAGS)) - $(info CARGO_FLAGS = $(CARGO_FLAGS)) - $(info CARGO_FLAGS_TOCK = $(CARGO_FLAGS_TOCK)) - $(info SIZE_FLAGS = $(SIZE_FLAGS)) + $(info PLATFORM = $(PLATFORM)) + $(info TARGET = $(TARGET)) + $(info TOCK_KERNEL_VERSION = $(TOCK_KERNEL_VERSION)) + $(info RUSTC_FLAGS = $(RUSTC_FLAGS)) + $(info RUSTC_FLAGS_TOCK = $(RUSTC_FLAGS_TOCK)) + $(info MAKEFLAGS = $(MAKEFLAGS)) + $(info OBJDUMP_FLAGS = $(OBJDUMP_FLAGS)) + $(info OBJCOPY_FLAGS = $(OBJCOPY_FLAGS)) + $(info CARGO_FLAGS = $(CARGO_FLAGS)) + $(info CARGO_FLAGS_TOCK = $(CARGO_FLAGS_TOCK)) + $(info CARGO_FLAGS_TOCK_NO_BUILD_STD = $(CARGO_FLAGS_TOCK_NO_BUILD_STD)) + $(info SIZE_FLAGS = $(SIZE_FLAGS)) + $(info CARGO_BLOAT_FLAGS = $(CARGO_BLOAT_FLAGS)) $(info ) - $(info TOOLCHAIN = $(TOOLCHAIN)) - $(info SIZE = $(SIZE)) - $(info OBJCOPY = $(OBJCOPY)) - $(info OBJDUMP = $(OBJDUMP)) - $(info CARGO = $(CARGO)) - $(info RUSTUP = $(RUSTUP)) - $(info SHA256SUM = $(SHA256SUM)) + $(info TOOLCHAIN = $(TOOLCHAIN)) + $(info SIZE = $(SIZE)) + $(info OBJCOPY = $(OBJCOPY)) + $(info OBJDUMP = $(OBJDUMP)) + $(info CARGO = $(CARGO)) + $(info RUSTUP = $(RUSTUP)) + $(info SHA256SUM = $(SHA256SUM)) $(info ) - $(info cargo --version = $(shell $(CARGO) --version)) - $(info rustc --version = $(shell rustc --version)) - $(info rustup --version = $(shell $(RUSTUP) --version)) + $(info cargo --version = $(shell $(CARGO) --version)) + $(info rustc --version = $(shell rustc --version)) + $(info rustup --version = $(shell $(RUSTUP) --version 2>/dev/null)) $(info *******************************************************) $(info ) endif @@ -225,12 +338,12 @@ all: release # binary. This makes checking for Rust errors much faster. .PHONY: check check: - $(Q)$(CARGO) check $(VERBOSE) $(CARGO_FLAGS_TOCK) + $(Q)$(CARGO) check $(VERBOSE_FLAGS) $(CARGO_FLAGS_TOCK) .PHONY: clean clean:: - $(Q)$(CARGO) clean $(VERBOSE) --target-dir=$(TARGET_DIRECTORY) + $(Q)$(CARGO) clean $(VERBOSE_FLAGS) --target-dir=$(TARGET_DIRECTORY) .PHONY: release release: $(TARGET_PATH)/release/$(PLATFORM).bin @@ -245,7 +358,7 @@ debug-lst: $(TARGET_PATH)/debug/$(PLATFORM).lst doc: | target @# This mess is all to work around rustdoc giving no way to return an @# error if there are warnings. This effectively simulates that. - $(Q)RUSTDOCFLAGS='-Z unstable-options --document-hidden-items -D warnings' $(CARGO) --color=always doc $(VERBOSE) --release --package $(PLATFORM) --target-dir=$(TARGET_DIRECTORY) 2>&1 | tee /dev/tty | grep -q warning && (echo "Warnings detected during doc build" && if [[ $$CI == "true" ]]; then echo "Erroring due to CI context" && exit 33; fi) || if [ $$? -eq 33 ]; then exit 1; fi + $(Q)RUSTDOCFLAGS='-Z unstable-options --document-hidden-items -D warnings' $(CARGO) --color=always doc $(VERBOSE_FLAGS) --release --package $(PLATFORM) --target-dir=$(TARGET_DIRECTORY) 2>&1 | grep -C 9999 warning && (echo "Warnings detected during doc build" && if [[ $$NOWARNINGS == "true" ]]; then echo "Erroring due to CI context" && exit 33; fi) || if [ $$? -eq 33 ]; then exit 1; fi .PHONY: lst @@ -257,6 +370,40 @@ lst: $(TARGET_PATH)/release/$(PLATFORM).lst show-target: $(info $(TARGET)) +# This rule is a copy of the rule used to build the release target, but `cargo +# rustc` has been replaced with `cargo bloat`. `cargo bloat` replicates the +# interface of `cargo build`, rather than `cargo rustc`, so we need to move +# `RUSTC_FLAGS_FOR_BIN` into the `RUSTFLAGS` environment variable. This only +# means that cargo cannot reuse built dependencies built using `cargo bloat`. +# See the discussion on `RUSTC_FLAGS_FOR_BIN` above for additional details. To +# pass additional flags to `cargo bloat`, populate the CARGO_BLOAT_FLAGS +# environment variable, e.g. run `CARGO_BLOAT_FLAGS=--crates make cargobloat` +.PHONY: cargobloat +cargobloat: + $(Q)$(CARGO) install cargo-bloat > /dev/null 2>&1 || echo 'Error: Failed to install cargo-bloat' + $(Q)RUSTFLAGS="$(RUSTC_FLAGS_TOCK) $(RUSTC_FLAGS_FOR_BIN)" CARGO_FLAGS="-Z build-std=core" $(CARGO) bloat $(CARGO_FLAGS_TOCK_NO_BUILD_STD) --bin $(PLATFORM) --release $(CARGO_BLOAT_FLAGS) + +# To pass additional flags to `cargo cargobloatnoinline`, populate the +# CARGO_BLOAT_FLAGS environment variable, e.g. run `CARGO_BLOAT_FLAGS=--crates +# make cargobloatnoinline` +.PHONY: cargobloatnoinline +cargobloatnoinline: + $(Q)$(CARGO) install cargo-bloat > \dev\null 2>&1 || echo 'Error: Failed to install cargo-bloat' + $(Q)RUSTFLAGS="$(RUSTC_FLAGS_TOCK) -C inline-threshold=0 $(RUSTC_FLAGS_FOR_BIN)" $(CARGO) bloat $(CARGO_FLAGS_TOCK) --bin $(PLATFORM) --release $(CARGO_BLOAT_FLAGS) + +.PHONY: stack-analysis +#stack_analysis: RUSTC_FLAGS_TOCK += -Z emit-stack-sizes +stack-analysis: + @$ echo $(PLATFORM) + @$ echo ---------------------- + $(Q)$(MAKE) release RUSTC_FLAGS="$(RUSTC_FLAGS) -Z emit-stack-sizes" $(DEVNULL) 2>&1 + $(Q)$(TOCK_ROOT_DIRECTORY)/tools/stack_analysis.sh $(TARGET_PATH)/release/$(PLATFORM).elf + +# Run the `print_tock_memory_usage.py` script for this board. +.PHONY: memory +memory: $(TARGET_PATH)/release/$(PLATFORM).elf + $(TOCK_ROOT_DIRECTORY)tools/print_tock_memory_usage.py --objdump $(OBJDUMP) -w $(PTMU_ARGS) $< + # Support rules target: @@ -269,13 +416,14 @@ target: %.bin: %.elf $(Q)$(OBJCOPY) --output-target=binary $(OBJCOPY_FLAGS) $< $@ + $(Q)$(SHA256SUM) $@ %.lst: %.elf $(Q)$(OBJDUMP) $(OBJDUMP_FLAGS) $< > $@ $(TOCK_ROOT_DIRECTORY)tools/sha256sum/target/debug/sha256sum: - $(Q)$(CARGO) build $(VERBOSE) --manifest-path $(TOCK_ROOT_DIRECTORY)tools/sha256sum/Cargo.toml + $(Q)$(CARGO) build $(VERBOSE_FLAGS) --manifest-path $(TOCK_ROOT_DIRECTORY)tools/sha256sum/Cargo.toml # Cargo-drivers diff --git a/boards/clue_nrf52840-bootloader/Cargo.lock b/boards/clue_nrf52840-bootloader/Cargo.lock deleted file mode 100644 index e37cb50..0000000 --- a/boards/clue_nrf52840-bootloader/Cargo.lock +++ /dev/null @@ -1,181 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "bootloader" -version = "0.1.0" -dependencies = [ - "kernel", - "tock-bootloader-protocol", -] - -[[package]] -name = "bootloader_attributes" -version = "0.1.0" - -[[package]] -name = "bootloader_cortexm" -version = "0.1.0" -dependencies = [ - "bootloader", - "kernel", -] - -[[package]] -name = "bootloader_nrf52" -version = "0.1.0" -dependencies = [ - "bootloader", - "cortexm4", - "kernel", - "nrf52", -] - -[[package]] -name = "byteorder" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b" - -[[package]] -name = "capsules" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" -dependencies = [ - "enum_primitive", - "kernel", - "tickv", -] - -[[package]] -name = "clue_nrf52840-bootloader" -version = "0.1.0" -dependencies = [ - "bootloader", - "bootloader_attributes", - "bootloader_cortexm", - "bootloader_nrf52", - "capsules", - "components", - "cortexm4", - "kernel", - "nrf52", - "nrf52840", - "nrf52_components", -] - -[[package]] -name = "components" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" -dependencies = [ - "capsules", - "kernel", -] - -[[package]] -name = "cortexm" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" -dependencies = [ - "kernel", -] - -[[package]] -name = "cortexm4" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" -dependencies = [ - "cortexm", - "kernel", -] - -[[package]] -name = "enum_primitive" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" - -[[package]] -name = "kernel" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" -dependencies = [ - "tock-cells", - "tock-registers", - "tock-tbf", -] - -[[package]] -name = "nrf52" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" -dependencies = [ - "cortexm4", - "enum_primitive", - "kernel", - "nrf5x", - "tock-rt0", -] - -[[package]] -name = "nrf52840" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" -dependencies = [ - "cortexm4", - "kernel", - "nrf52", - "tock-rt0", -] - -[[package]] -name = "nrf52_components" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" -dependencies = [ - "capsules", - "components", - "cortexm4", - "kernel", - "nrf52", -] - -[[package]] -name = "nrf5x" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" -dependencies = [ - "enum_primitive", - "kernel", -] - -[[package]] -name = "tickv" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" - -[[package]] -name = "tock-bootloader-protocol" -version = "0.2.2" -dependencies = [ - "byteorder", -] - -[[package]] -name = "tock-cells" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" - -[[package]] -name = "tock-registers" -version = "0.6.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" - -[[package]] -name = "tock-rt0" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" - -[[package]] -name = "tock-tbf" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" diff --git a/boards/clue_nrf52840-bootloader/Cargo.toml b/boards/clue_nrf52840-bootloader/Cargo.toml index 847d0fb..dea7b9d 100644 --- a/boards/clue_nrf52840-bootloader/Cargo.toml +++ b/boards/clue_nrf52840-bootloader/Cargo.toml @@ -3,16 +3,17 @@ name = "clue_nrf52840-bootloader" version = "0.1.0" authors = ["Tock Project Developers "] build = "build.rs" -edition = "2018" +edition = "2021" [dependencies] -cortexm4 = { git = "https://github.com/tock/tock", rev = "405417" } -capsules = { git = "https://github.com/tock/tock", rev = "405417" } -kernel = { git = "https://github.com/tock/tock", rev = "405417" } -nrf52 = { git = "https://github.com/tock/tock", rev = "405417" } -nrf52840 = { git = "https://github.com/tock/tock", rev = "405417" } -components = { git = "https://github.com/tock/tock", rev = "405417" } -nrf52_components = { git = "https://github.com/tock/tock", rev = "405417" } +cortexm4 = { git = "https://github.com/tock/tock", rev = "2ff6868" } +capsules-core = { git = "https://github.com/tock/tock", rev = "2ff6868" } +capsules-extra = { git = "https://github.com/tock/tock", rev = "2ff6868" } +kernel = { git = "https://github.com/tock/tock", rev = "2ff6868" } +nrf52 = { git = "https://github.com/tock/tock", rev = "2ff6868" } +nrf52840 = { git = "https://github.com/tock/tock", rev = "2ff6868" } +components = { git = "https://github.com/tock/tock", rev = "2ff6868" } +nrf52_components = { git = "https://github.com/tock/tock", rev = "2ff6868" } # For Development # cortexm4 = { path = "../../../tock/arch/cortex-m4" } diff --git a/boards/clue_nrf52840-bootloader/build.rs b/boards/clue_nrf52840-bootloader/build.rs index d8926f9..337ddfd 100644 --- a/boards/clue_nrf52840-bootloader/build.rs +++ b/boards/clue_nrf52840-bootloader/build.rs @@ -5,7 +5,7 @@ fn main() { println!("cargo:rerun-if-changed=../kernel_layout.ld"); let mut f = bootloader_attributes::get_file(); - bootloader_attributes::write_flags(&mut f, "1.1.0", 0x36000); + bootloader_attributes::write_flags(&mut f, "1.1.3", 0x36000); bootloader_attributes::write_attribute(&mut f, "board", "clue_nrf52840"); bootloader_attributes::write_attribute(&mut f, "arch", "cortex-m4"); bootloader_attributes::write_attribute(&mut f, "appaddr", "0x80000"); diff --git a/boards/clue_nrf52840-bootloader/src/main.rs b/boards/clue_nrf52840-bootloader/src/main.rs index b436497..b01c6e8 100644 --- a/boards/clue_nrf52840-bootloader/src/main.rs +++ b/boards/clue_nrf52840-bootloader/src/main.rs @@ -10,18 +10,20 @@ use core::panic::PanicInfo; use kernel::capabilities; -use kernel::common::dynamic_deferred_call::{DynamicDeferredCall, DynamicDeferredCallClientState}; use kernel::component::Component; use kernel::hil; use kernel::hil::time::Alarm; use kernel::hil::time::Counter; use kernel::hil::usb::Client; -use kernel::mpu::MPU; -use kernel::Chip; -#[allow(unused_imports)] -use kernel::{create_capability, debug, debug_gpio, debug_verbose, static_init}; +use kernel::platform::chip::Chip; +use kernel::platform::mpu::MPU; +use kernel::platform::KernelResources; +use kernel::platform::SyscallDriverLookup; +use kernel::{create_capability, static_init}; -use capsules::virtual_alarm::VirtualMuxAlarm; +use bootloader::null_scheduler::NullScheduler; + +use capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm; use nrf52840::interrupt_service::Nrf52840DefaultPeripherals; @@ -40,7 +42,7 @@ include!(concat!(env!("OUT_DIR"), "/attributes.rs")); // Number of concurrent processes this platform supports. const NUM_PROCS: usize = 0; -static mut PROCESSES: [Option<&'static dyn kernel::procs::ProcessType>; NUM_PROCS] = +static mut PROCESSES: [Option<&'static dyn kernel::process::Process>; NUM_PROCS] = [None; NUM_PROCS]; static mut CHIP: Option<&'static nrf52840::chip::NRF52> = None; @@ -67,28 +69,78 @@ pub struct Platform { >, bootloader::flash_large_to_small::FlashLargeToSmall<'static, nrf52::nvmc::Nvmc>, >, + scheduler: &'static NullScheduler, +} + +impl KernelResources>> + for Platform +{ + type SyscallDriverLookup = Self; + type SyscallFilter = (); + type ProcessFault = (); + type CredentialsCheckingPolicy = (); + type Scheduler = NullScheduler; + type SchedulerTimer = (); + type WatchDog = (); + type ContextSwitchCallback = (); + + fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup { + &self + } + fn syscall_filter(&self) -> &Self::SyscallFilter { + &() + } + fn process_fault(&self) -> &Self::ProcessFault { + &() + } + fn credentials_checking_policy(&self) -> &'static Self::CredentialsCheckingPolicy { + &() + } + fn scheduler(&self) -> &Self::Scheduler { + self.scheduler + } + fn scheduler_timer(&self) -> &Self::SchedulerTimer { + &() + } + fn watchdog(&self) -> &Self::WatchDog { + &() + } + fn context_switch_callback(&self) -> &Self::ContextSwitchCallback { + &() + } } -impl kernel::Platform for Platform { +impl SyscallDriverLookup for Platform { fn with_driver(&self, _driver_num: usize, f: F) -> R where - F: FnOnce(Option<&dyn kernel::Driver>) -> R, + F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R, { f(None) } } +#[inline(never)] +unsafe fn create_peripherals() -> &'static mut Nrf52840DefaultPeripherals<'static> { + let ieee802154_ack_buf = static_init!( + [u8; nrf52840::ieee802154_radio::ACK_BUF_SIZE], + [0; nrf52840::ieee802154_radio::ACK_BUF_SIZE] + ); + // Initialize chip peripheral drivers + let nrf52840_peripherals = static_init!( + Nrf52840DefaultPeripherals, + Nrf52840DefaultPeripherals::new(ieee802154_ack_buf) + ); + + nrf52840_peripherals +} + /// Entry point in the vector table called on hard reset. #[no_mangle] -pub unsafe fn reset_handler() { +pub unsafe fn main() { // Loads relocations and clears BSS nrf52840::init(); - let ppi = static_init!(nrf52840::ppi::Ppi, nrf52840::ppi::Ppi::new()); // Initialize chip peripheral drivers - let nrf52840_peripherals = static_init!( - Nrf52840DefaultPeripherals, - Nrf52840DefaultPeripherals::new(ppi) - ); + let nrf52840_peripherals = create_peripherals(); // set up circular peripheral dependencies nrf52840_peripherals.init(); @@ -146,26 +198,20 @@ pub unsafe fn reset_handler() { let main_loop_capability = create_capability!(capabilities::MainLoopCapability); //-------------------------------------------------------------------------- - // Deferred Call (Dynamic) Setup + // SCHEDULER //-------------------------------------------------------------------------- - let dynamic_deferred_call_clients = - static_init!([DynamicDeferredCallClientState; 2], Default::default()); - let dynamic_deferred_caller = static_init!( - DynamicDeferredCall, - DynamicDeferredCall::new(dynamic_deferred_call_clients) - ); - DynamicDeferredCall::set_global_instance(dynamic_deferred_caller); + let null_scheduler = static_init!(NullScheduler, NullScheduler::new()); //-------------------------------------------------------------------------- // ALARM & TIMER //-------------------------------------------------------------------------- let rtc = &base_peripherals.rtc; - rtc.start(); + let _ = rtc.start(); let mux_alarm = components::alarm::AlarmMuxComponent::new(rtc) - .finalize(components::alarm_mux_component_helper!(nrf52::rtc::Rtc)); + .finalize(components::alarm_mux_component_static!(nrf52::rtc::Rtc)); // //-------------------------------------------------------------------------- // // UART DEBUGGING @@ -209,15 +255,14 @@ pub unsafe fn reset_handler() { let cdc = components::cdc::CdcAcmComponent::new( &nrf52840_peripherals.usbd, - capsules::usb::cdc::MAX_CTRL_PACKET_SIZE_NRF52840, + capsules_extra::usb::cdc::MAX_CTRL_PACKET_SIZE_NRF52840, 0x2341, 0x005a, strings, mux_alarm, - dynamic_deferred_caller, None, ) - .finalize(components::usb_cdc_acm_component_helper!( + .finalize(components::cdc_acm_component_static!( nrf52::usbd::Usbd, nrf52::rtc::Rtc )); @@ -363,7 +408,10 @@ pub unsafe fn reset_handler() { // approach than this. nrf52_components::NrfClockComponent::new(&base_peripherals.clock).finalize(()); - let platform = Platform { bootloader }; + let platform = Platform { + bootloader, + scheduler: null_scheduler, + }; let chip = static_init!( nrf52840::chip::NRF52, @@ -385,13 +433,10 @@ pub unsafe fn reset_handler() { // MAIN LOOP //-------------------------------------------------------------------------- - let scheduler = components::sched::round_robin::RoundRobinComponent::new(&PROCESSES) - .finalize(components::rr_component_helper!(NUM_PROCS)); - board_kernel.kernel_loop::<_, _, _, NUM_PROCS>( + board_kernel.kernel_loop( &platform, chip, - None, - scheduler, + None::<&kernel::ipc::IPC<0>>, &main_loop_capability, ); } diff --git a/boards/microbit_v2-bootloader/Cargo.lock b/boards/microbit_v2-bootloader/Cargo.lock deleted file mode 100644 index 1b89362..0000000 --- a/boards/microbit_v2-bootloader/Cargo.lock +++ /dev/null @@ -1,168 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "bootloader" -version = "0.1.0" -dependencies = [ - "kernel", - "tock-bootloader-protocol", -] - -[[package]] -name = "bootloader_attributes" -version = "0.1.0" - -[[package]] -name = "bootloader_cortexm" -version = "0.1.0" -dependencies = [ - "bootloader", - "kernel", -] - -[[package]] -name = "bootloader_nrf52" -version = "0.1.0" -dependencies = [ - "bootloader", - "cortexm4", - "kernel", - "nrf52", -] - -[[package]] -name = "byteorder" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b" - -[[package]] -name = "capsules" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" -dependencies = [ - "enum_primitive", - "kernel", - "tickv", -] - -[[package]] -name = "components" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" -dependencies = [ - "capsules", - "kernel", -] - -[[package]] -name = "cortexm" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" -dependencies = [ - "kernel", -] - -[[package]] -name = "cortexm4" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" -dependencies = [ - "cortexm", - "kernel", -] - -[[package]] -name = "enum_primitive" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" - -[[package]] -name = "kernel" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" -dependencies = [ - "tock-cells", - "tock-registers", - "tock-tbf", -] - -[[package]] -name = "microbit_v2-bootloader" -version = "0.1.0" -dependencies = [ - "bootloader", - "bootloader_attributes", - "bootloader_cortexm", - "bootloader_nrf52", - "capsules", - "components", - "cortexm4", - "kernel", - "nrf52", - "nrf52833", -] - -[[package]] -name = "nrf52" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" -dependencies = [ - "cortexm4", - "enum_primitive", - "kernel", - "nrf5x", - "tock-rt0", -] - -[[package]] -name = "nrf52833" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" -dependencies = [ - "cortexm4", - "kernel", - "nrf52", - "tock-rt0", -] - -[[package]] -name = "nrf5x" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" -dependencies = [ - "enum_primitive", - "kernel", -] - -[[package]] -name = "tickv" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" - -[[package]] -name = "tock-bootloader-protocol" -version = "0.2.2" -dependencies = [ - "byteorder", -] - -[[package]] -name = "tock-cells" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" - -[[package]] -name = "tock-registers" -version = "0.6.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" - -[[package]] -name = "tock-rt0" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" - -[[package]] -name = "tock-tbf" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" diff --git a/boards/microbit_v2-bootloader/Cargo.toml b/boards/microbit_v2-bootloader/Cargo.toml index 18ae0d6..1c0ce9f 100644 --- a/boards/microbit_v2-bootloader/Cargo.toml +++ b/boards/microbit_v2-bootloader/Cargo.toml @@ -3,15 +3,15 @@ name = "microbit_v2-bootloader" version = "0.1.0" authors = ["Tock Project Developers "] build = "build.rs" -edition = "2018" +edition = "2021" [dependencies] -cortexm4 = { git = "https://github.com/tock/tock", rev = "405417" } -capsules = { git = "https://github.com/tock/tock", rev = "405417" } -kernel = { git = "https://github.com/tock/tock", rev = "405417" } -nrf52 = { git = "https://github.com/tock/tock", rev = "405417" } -nrf52833 = { git = "https://github.com/tock/tock", rev = "405417" } -components = { git = "https://github.com/tock/tock", rev = "405417" } +cortexm4 = { git = "https://github.com/tock/tock", rev = "2ff6868" } +capsules-core = { git = "https://github.com/tock/tock", rev = "2ff6868" } +kernel = { git = "https://github.com/tock/tock", rev = "2ff6868" } +nrf52 = { git = "https://github.com/tock/tock", rev = "2ff6868" } +nrf52833 = { git = "https://github.com/tock/tock", rev = "2ff6868" } +components = { git = "https://github.com/tock/tock", rev = "2ff6868" } # For Development # cortexm4 = { path = "../../../tock/arch/cortex-m4" } diff --git a/boards/microbit_v2-bootloader/build.rs b/boards/microbit_v2-bootloader/build.rs index 826288f..38e39b6 100644 --- a/boards/microbit_v2-bootloader/build.rs +++ b/boards/microbit_v2-bootloader/build.rs @@ -9,7 +9,7 @@ fn main() { let version = if let Ok(v) = env::var("BOOTLOADER_VERSION") { v } else { - String::from("1.1.1") + String::from("1.1.3") }; bootloader_attributes::write_flags(&mut f, &version, 0x8000); bootloader_attributes::write_attribute(&mut f, "board", "microbit_v2"); diff --git a/boards/microbit_v2-bootloader/src/main.rs b/boards/microbit_v2-bootloader/src/main.rs index c35c4e4..447c975 100644 --- a/boards/microbit_v2-bootloader/src/main.rs +++ b/boards/microbit_v2-bootloader/src/main.rs @@ -10,15 +10,17 @@ use core::panic::PanicInfo; use kernel::capabilities; -use kernel::common::dynamic_deferred_call::{DynamicDeferredCall, DynamicDeferredCallClientState}; use kernel::component::Component; use kernel::hil; use kernel::hil::time::Alarm; use kernel::hil::time::Counter; -#[allow(unused_imports)] -use kernel::{create_capability, debug, debug_gpio, debug_verbose, static_init}; +use kernel::platform::KernelResources; +use kernel::platform::SyscallDriverLookup; +use kernel::{create_capability, static_init}; -use capsules::virtual_alarm::VirtualMuxAlarm; +use bootloader::null_scheduler::NullScheduler; + +use capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm; use nrf52833::gpio::Pin; use nrf52833::interrupt_service::Nrf52833DefaultPeripherals; @@ -34,7 +36,7 @@ include!(concat!(env!("OUT_DIR"), "/attributes.rs")); // Number of concurrent processes this platform supports. const NUM_PROCS: usize = 0; -static mut PROCESSES: [Option<&'static dyn kernel::procs::ProcessType>; NUM_PROCS] = +static mut PROCESSES: [Option<&'static dyn kernel::process::Process>; NUM_PROCS] = [None; NUM_PROCS]; static mut CHIP: Option<&'static nrf52833::chip::NRF52> = None; @@ -61,12 +63,51 @@ pub struct Platform { >, bootloader::flash_large_to_small::FlashLargeToSmall<'static, nrf52::nvmc::Nvmc>, >, + scheduler: &'static NullScheduler, +} + +impl KernelResources>> + for Platform +{ + type SyscallDriverLookup = Self; + type SyscallFilter = (); + type ProcessFault = (); + type CredentialsCheckingPolicy = (); + type Scheduler = NullScheduler; + type SchedulerTimer = (); + type WatchDog = (); + type ContextSwitchCallback = (); + + fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup { + &self + } + fn syscall_filter(&self) -> &Self::SyscallFilter { + &() + } + fn process_fault(&self) -> &Self::ProcessFault { + &() + } + fn credentials_checking_policy(&self) -> &'static Self::CredentialsCheckingPolicy { + &() + } + fn scheduler(&self) -> &Self::Scheduler { + self.scheduler + } + fn scheduler_timer(&self) -> &Self::SchedulerTimer { + &() + } + fn watchdog(&self) -> &Self::WatchDog { + &() + } + fn context_switch_callback(&self) -> &Self::ContextSwitchCallback { + &() + } } -impl kernel::Platform for Platform { +impl SyscallDriverLookup for Platform { fn with_driver(&self, _driver_num: usize, f: F) -> R where - F: FnOnce(Option<&dyn kernel::Driver>) -> R, + F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R, { f(None) } @@ -74,14 +115,13 @@ impl kernel::Platform for Platform { /// Entry point in the vector table called on hard reset. #[no_mangle] -pub unsafe fn reset_handler() { +pub unsafe fn main() { // Loads relocations and clears BSS nrf52833::init(); - let ppi = static_init!(nrf52833::ppi::Ppi, nrf52833::ppi::Ppi::new()); // Initialize chip peripheral drivers let nrf52833_peripherals = static_init!( Nrf52833DefaultPeripherals, - Nrf52833DefaultPeripherals::new(ppi) + Nrf52833DefaultPeripherals::new() ); // set up circular peripheral dependencies @@ -139,27 +179,15 @@ pub unsafe fn reset_handler() { // functions. let main_loop_capability = create_capability!(capabilities::MainLoopCapability); - //-------------------------------------------------------------------------- - // Deferred Call (Dynamic) Setup - //-------------------------------------------------------------------------- - - let dynamic_deferred_call_clients = - static_init!([DynamicDeferredCallClientState; 5], Default::default()); - let dynamic_deferred_caller = static_init!( - DynamicDeferredCall, - DynamicDeferredCall::new(dynamic_deferred_call_clients) - ); - DynamicDeferredCall::set_global_instance(dynamic_deferred_caller); - //-------------------------------------------------------------------------- // ALARM & TIMER //-------------------------------------------------------------------------- let rtc = &base_peripherals.rtc; - rtc.start(); + let _ = rtc.start(); let mux_alarm = components::alarm::AlarmMuxComponent::new(rtc) - .finalize(components::alarm_mux_component_helper!(nrf52::rtc::Rtc)); + .finalize(components::alarm_mux_component_static!(nrf52::rtc::Rtc)); // //-------------------------------------------------------------------------- // // UART DEBUGGING @@ -189,6 +217,7 @@ pub unsafe fn reset_handler() { VirtualMuxAlarm<'static, nrf52833::rtc::Rtc>, VirtualMuxAlarm::new(mux_alarm) ); + recv_auto_virtual_alarm.setup(); let recv_auto_uart = static_init!( bootloader::uart_receive_multiple_timeout::UartReceiveMultipleTimeout< @@ -204,7 +233,7 @@ pub unsafe fn reset_handler() { recv_auto_virtual_alarm.set_alarm_client(recv_auto_uart); // Setup the UART pins - &base_peripherals.uarte0.initialize( + let _ = base_peripherals.uarte0.initialize( nrf52833::pinmux::Pinmux::new(UART_TXD as u32), nrf52833::pinmux::Pinmux::new(UART_RXD as u32), None, @@ -250,6 +279,12 @@ pub unsafe fn reset_handler() { hil::uart::Receive::set_receive_client(recv_auto_uart, bootloader); hil::flash::HasClient::set_client(flash_adapter, bootloader); + //-------------------------------------------------------------------------- + // SCHEDULER + //-------------------------------------------------------------------------- + + let null_scheduler = static_init!(NullScheduler, NullScheduler::new()); + //-------------------------------------------------------------------------- // FINAL SETUP AND BOARD BOOT //-------------------------------------------------------------------------- @@ -263,7 +298,10 @@ pub unsafe fn reset_handler() { while !base_peripherals.clock.low_started() {} while !base_peripherals.clock.high_started() {} - let platform = Platform { bootloader }; + let platform = Platform { + bootloader, + scheduler: null_scheduler, + }; let chip = static_init!( nrf52833::chip::NRF52, @@ -278,13 +316,10 @@ pub unsafe fn reset_handler() { // MAIN LOOP //-------------------------------------------------------------------------- - let scheduler = components::sched::round_robin::RoundRobinComponent::new(&PROCESSES) - .finalize(components::rr_component_helper!(NUM_PROCS)); - board_kernel.kernel_loop::<_, _, _, NUM_PROCS>( + board_kernel.kernel_loop( &platform, chip, - None, - scheduler, + None::<&kernel::ipc::IPC<0>>, &main_loop_capability, ); } diff --git a/boards/nano33ble-bootloader/Cargo.lock b/boards/nano33ble-bootloader/Cargo.lock deleted file mode 100644 index 3759d87..0000000 --- a/boards/nano33ble-bootloader/Cargo.lock +++ /dev/null @@ -1,181 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "bootloader" -version = "0.1.0" -dependencies = [ - "kernel", - "tock-bootloader-protocol", -] - -[[package]] -name = "bootloader_attributes" -version = "0.1.0" - -[[package]] -name = "bootloader_cortexm" -version = "0.1.0" -dependencies = [ - "bootloader", - "kernel", -] - -[[package]] -name = "bootloader_nrf52" -version = "0.1.0" -dependencies = [ - "bootloader", - "cortexm4", - "kernel", - "nrf52", -] - -[[package]] -name = "byteorder" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b" - -[[package]] -name = "capsules" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" -dependencies = [ - "enum_primitive", - "kernel", - "tickv", -] - -[[package]] -name = "components" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" -dependencies = [ - "capsules", - "kernel", -] - -[[package]] -name = "cortexm" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" -dependencies = [ - "kernel", -] - -[[package]] -name = "cortexm4" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" -dependencies = [ - "cortexm", - "kernel", -] - -[[package]] -name = "enum_primitive" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" - -[[package]] -name = "kernel" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" -dependencies = [ - "tock-cells", - "tock-registers", - "tock-tbf", -] - -[[package]] -name = "nano33ble-bootloader" -version = "0.1.0" -dependencies = [ - "bootloader", - "bootloader_attributes", - "bootloader_cortexm", - "bootloader_nrf52", - "capsules", - "components", - "cortexm4", - "kernel", - "nrf52", - "nrf52840", - "nrf52_components", -] - -[[package]] -name = "nrf52" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" -dependencies = [ - "cortexm4", - "enum_primitive", - "kernel", - "nrf5x", - "tock-rt0", -] - -[[package]] -name = "nrf52840" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" -dependencies = [ - "cortexm4", - "kernel", - "nrf52", - "tock-rt0", -] - -[[package]] -name = "nrf52_components" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" -dependencies = [ - "capsules", - "components", - "cortexm4", - "kernel", - "nrf52", -] - -[[package]] -name = "nrf5x" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" -dependencies = [ - "enum_primitive", - "kernel", -] - -[[package]] -name = "tickv" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" - -[[package]] -name = "tock-bootloader-protocol" -version = "0.2.2" -dependencies = [ - "byteorder", -] - -[[package]] -name = "tock-cells" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" - -[[package]] -name = "tock-registers" -version = "0.6.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" - -[[package]] -name = "tock-rt0" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" - -[[package]] -name = "tock-tbf" -version = "0.1.0" -source = "git+https://github.com/tock/tock?rev=405417#40541741703ddddbc14e7a7ef6fca0fb9f0b7584" diff --git a/boards/nano33ble-bootloader/Cargo.toml b/boards/nano33ble-bootloader/Cargo.toml index 161afd2..74c5d4a 100644 --- a/boards/nano33ble-bootloader/Cargo.toml +++ b/boards/nano33ble-bootloader/Cargo.toml @@ -3,16 +3,17 @@ name = "nano33ble-bootloader" version = "0.1.0" authors = ["Tock Project Developers "] build = "build.rs" -edition = "2018" +edition = "2021" [dependencies] -cortexm4 = { git = "https://github.com/tock/tock", rev = "405417" } -capsules = { git = "https://github.com/tock/tock", rev = "405417" } -kernel = { git = "https://github.com/tock/tock", rev = "405417" } -nrf52 = { git = "https://github.com/tock/tock", rev = "405417" } -nrf52840 = { git = "https://github.com/tock/tock", rev = "405417" } -components = { git = "https://github.com/tock/tock", rev = "405417" } -nrf52_components = { git = "https://github.com/tock/tock", rev = "405417" } +cortexm4 = { git = "https://github.com/tock/tock", rev = "2ff6868" } +capsules-core = { git = "https://github.com/tock/tock", rev = "2ff6868" } +capsules-extra = { git = "https://github.com/tock/tock", rev = "2ff6868" } +kernel = { git = "https://github.com/tock/tock", rev = "2ff6868" } +nrf52 = { git = "https://github.com/tock/tock", rev = "2ff6868" } +nrf52840 = { git = "https://github.com/tock/tock", rev = "2ff6868" } +components = { git = "https://github.com/tock/tock", rev = "2ff6868" } +nrf52_components = { git = "https://github.com/tock/tock", rev = "2ff6868" } # For Development #cortexm4 = { path = "../../../tock/arch/cortex-m4" } diff --git a/boards/nano33ble-bootloader/build.rs b/boards/nano33ble-bootloader/build.rs index d73f395..20e6b93 100644 --- a/boards/nano33ble-bootloader/build.rs +++ b/boards/nano33ble-bootloader/build.rs @@ -5,7 +5,7 @@ fn main() { println!("cargo:rerun-if-changed=../kernel_layout.ld"); let mut f = bootloader_attributes::get_file(); - bootloader_attributes::write_flags(&mut f, "1.1.0", 0x10000); + bootloader_attributes::write_flags(&mut f, "1.1.3", 0x10000); bootloader_attributes::write_attribute(&mut f, "board", "nano33ble"); bootloader_attributes::write_attribute(&mut f, "arch", "cortex-m4"); bootloader_attributes::write_attribute(&mut f, "appaddr", "0x50000"); diff --git a/boards/nano33ble-bootloader/src/main.rs b/boards/nano33ble-bootloader/src/main.rs index ea1888c..d823c04 100644 --- a/boards/nano33ble-bootloader/src/main.rs +++ b/boards/nano33ble-bootloader/src/main.rs @@ -10,18 +10,20 @@ use core::panic::PanicInfo; use kernel::capabilities; -use kernel::common::dynamic_deferred_call::{DynamicDeferredCall, DynamicDeferredCallClientState}; use kernel::component::Component; use kernel::hil; use kernel::hil::time::Alarm; use kernel::hil::time::Counter; use kernel::hil::usb::Client; -use kernel::mpu::MPU; -use kernel::Chip; -#[allow(unused_imports)] -use kernel::{create_capability, debug, debug_gpio, debug_verbose, static_init}; +use kernel::platform::chip::Chip; +use kernel::platform::mpu::MPU; +use kernel::platform::KernelResources; +use kernel::platform::SyscallDriverLookup; +use kernel::{create_capability, static_init}; -use capsules::virtual_alarm::VirtualMuxAlarm; +use bootloader::null_scheduler::NullScheduler; + +use capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm; use nrf52840::interrupt_service::Nrf52840DefaultPeripherals; @@ -40,7 +42,7 @@ include!(concat!(env!("OUT_DIR"), "/attributes.rs")); // Number of concurrent processes this platform supports. const NUM_PROCS: usize = 0; -static mut PROCESSES: [Option<&'static dyn kernel::procs::ProcessType>; NUM_PROCS] = +static mut PROCESSES: [Option<&'static dyn kernel::process::Process>; NUM_PROCS] = [None; NUM_PROCS]; static mut CHIP: Option<&'static nrf52840::chip::NRF52> = None; @@ -67,28 +69,78 @@ pub struct Platform { >, bootloader::flash_large_to_small::FlashLargeToSmall<'static, nrf52::nvmc::Nvmc>, >, + scheduler: &'static NullScheduler, +} + +impl KernelResources>> + for Platform +{ + type SyscallDriverLookup = Self; + type SyscallFilter = (); + type ProcessFault = (); + type CredentialsCheckingPolicy = (); + type Scheduler = NullScheduler; + type SchedulerTimer = (); + type WatchDog = (); + type ContextSwitchCallback = (); + + fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup { + &self + } + fn syscall_filter(&self) -> &Self::SyscallFilter { + &() + } + fn process_fault(&self) -> &Self::ProcessFault { + &() + } + fn credentials_checking_policy(&self) -> &'static Self::CredentialsCheckingPolicy { + &() + } + fn scheduler(&self) -> &Self::Scheduler { + self.scheduler + } + fn scheduler_timer(&self) -> &Self::SchedulerTimer { + &() + } + fn watchdog(&self) -> &Self::WatchDog { + &() + } + fn context_switch_callback(&self) -> &Self::ContextSwitchCallback { + &() + } } -impl kernel::Platform for Platform { +impl SyscallDriverLookup for Platform { fn with_driver(&self, _driver_num: usize, f: F) -> R where - F: FnOnce(Option<&dyn kernel::Driver>) -> R, + F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R, { f(None) } } +#[inline(never)] +unsafe fn create_peripherals() -> &'static mut Nrf52840DefaultPeripherals<'static> { + let ieee802154_ack_buf = static_init!( + [u8; nrf52840::ieee802154_radio::ACK_BUF_SIZE], + [0; nrf52840::ieee802154_radio::ACK_BUF_SIZE] + ); + // Initialize chip peripheral drivers + let nrf52840_peripherals = static_init!( + Nrf52840DefaultPeripherals, + Nrf52840DefaultPeripherals::new(ieee802154_ack_buf) + ); + + nrf52840_peripherals +} + /// Entry point in the vector table called on hard reset. #[no_mangle] -pub unsafe fn reset_handler() { +pub unsafe fn main() { // Loads relocations and clears BSS nrf52840::init(); - let ppi = static_init!(nrf52840::ppi::Ppi, nrf52840::ppi::Ppi::new()); // Initialize chip peripheral drivers - let nrf52840_peripherals = static_init!( - Nrf52840DefaultPeripherals, - Nrf52840DefaultPeripherals::new(ppi) - ); + let nrf52840_peripherals = create_peripherals(); // set up circular peripheral dependencies nrf52840_peripherals.init(); @@ -145,27 +197,15 @@ pub unsafe fn reset_handler() { // functions. let main_loop_capability = create_capability!(capabilities::MainLoopCapability); - //-------------------------------------------------------------------------- - // Deferred Call (Dynamic) Setup - //-------------------------------------------------------------------------- - - let dynamic_deferred_call_clients = - static_init!([DynamicDeferredCallClientState; 2], Default::default()); - let dynamic_deferred_caller = static_init!( - DynamicDeferredCall, - DynamicDeferredCall::new(dynamic_deferred_call_clients) - ); - DynamicDeferredCall::set_global_instance(dynamic_deferred_caller); - //-------------------------------------------------------------------------- // ALARM & TIMER //-------------------------------------------------------------------------- let rtc = &base_peripherals.rtc; - rtc.start(); + let _ = rtc.start(); let mux_alarm = components::alarm::AlarmMuxComponent::new(rtc) - .finalize(components::alarm_mux_component_helper!(nrf52::rtc::Rtc)); + .finalize(components::alarm_mux_component_static!(nrf52::rtc::Rtc)); // //-------------------------------------------------------------------------- // // UART DEBUGGING @@ -209,15 +249,14 @@ pub unsafe fn reset_handler() { let cdc = components::cdc::CdcAcmComponent::new( &nrf52840_peripherals.usbd, - capsules::usb::cdc::MAX_CTRL_PACKET_SIZE_NRF52840, + capsules_extra::usb::cdc::MAX_CTRL_PACKET_SIZE_NRF52840, 0x2341, 0x005a, strings, mux_alarm, - dynamic_deferred_caller, None, ) - .finalize(components::usb_cdc_acm_component_helper!( + .finalize(components::cdc_acm_component_static!( nrf52::usbd::Usbd, nrf52::rtc::Rtc )); @@ -230,6 +269,7 @@ pub unsafe fn reset_handler() { VirtualMuxAlarm<'static, nrf52::rtc::Rtc>, VirtualMuxAlarm::new(mux_alarm) ); + recv_auto_virtual_alarm.setup(); let recv_auto_cdc = static_init!( bootloader::uart_receive_multiple_timeout::UartReceiveMultipleTimeout< @@ -282,6 +322,12 @@ pub unsafe fn reset_handler() { hil::uart::Receive::set_receive_client(recv_auto_cdc, bootloader); hil::flash::HasClient::set_client(flash_adapter, bootloader); + //-------------------------------------------------------------------------- + // SCHEDULER + //-------------------------------------------------------------------------- + + let null_scheduler = static_init!(NullScheduler, NullScheduler::new()); + //-------------------------------------------------------------------------- // ALTERNATIVE BOOTLOADER STACK // @@ -363,7 +409,10 @@ pub unsafe fn reset_handler() { // approach than this. nrf52_components::NrfClockComponent::new(&base_peripherals.clock).finalize(()); - let platform = Platform { bootloader }; + let platform = Platform { + bootloader, + scheduler: null_scheduler, + }; let chip = static_init!( nrf52840::chip::NRF52, @@ -385,13 +434,10 @@ pub unsafe fn reset_handler() { // MAIN LOOP //-------------------------------------------------------------------------- - let scheduler = components::sched::round_robin::RoundRobinComponent::new(&PROCESSES) - .finalize(components::rr_component_helper!(NUM_PROCS)); - board_kernel.kernel_loop::<_, _, _, NUM_PROCS>( + board_kernel.kernel_loop( &platform, chip, - None, - scheduler, + None::<&kernel::ipc::IPC<0>>, &main_loop_capability, ); } diff --git a/boards/nrf52840dk-bootloader/Cargo.toml b/boards/nrf52840dk-bootloader/Cargo.toml new file mode 100644 index 0000000..091bf2b --- /dev/null +++ b/boards/nrf52840dk-bootloader/Cargo.toml @@ -0,0 +1,44 @@ +[package] +name = "nrf52840dk-bootloader" +version = "0.1.0" +authors = ["Tock Project Developers "] +build = "build.rs" +edition = "2021" + +[dependencies] +cortexm4 = { git = "https://github.com/tock/tock", rev = "2ff6868" } +capsules-core = { git = "https://github.com/tock/tock", rev = "2ff6868" } +capsules-extra = { git = "https://github.com/tock/tock", rev = "2ff6868" } +kernel = { git = "https://github.com/tock/tock", rev = "2ff6868" } +nrf52 = { git = "https://github.com/tock/tock", rev = "2ff6868" } +nrf52840 = { git = "https://github.com/tock/tock", rev = "2ff6868" } +components = { git = "https://github.com/tock/tock", rev = "2ff6868" } +nrf52_components = { git = "https://github.com/tock/tock", rev = "2ff6868" } + +# For Development +# cortexm4 = { path = "../../../tock/arch/cortex-m4" } +# capsules = { path = "../../../tock/capsules" } +# kernel = { path = "../../../tock/kernel" } +# nrf52 = { path = "../../../tock/chips/nrf52" } +# nrf52833 = { path = "../../../tock/chips/nrf52833" } +# components = { path = "../../../tock/boards/components" } + +bootloader = { path = "../../bootloader" } +bootloader_nrf52 = { path = "../../chips/bootloader_nrf52" } +bootloader_cortexm = { path = "../../arch/bootloader_cortexm" } + + +[build-dependencies] +bootloader_attributes = { path = "../../tools/bootloader_attributes" } + +[profile.dev] +panic = "abort" +lto = false +opt-level = "z" +debug = true + +[profile.release] +panic = "abort" +lto = true +opt-level = "z" +debug = false diff --git a/boards/nrf52840dk-bootloader/Makefile b/boards/nrf52840dk-bootloader/Makefile new file mode 100644 index 0000000..ae07206 --- /dev/null +++ b/boards/nrf52840dk-bootloader/Makefile @@ -0,0 +1,21 @@ +# Makefile for building the Tock bootloader for nRF52 platforms over UART. + +TOCK_ARCH=cortex-m4 +TARGET=thumbv7em-none-eabi +PLATFORM=nrf52840dk-bootloader + +include ../Common.mk + +TOCKLOADER=tockloader + +OPENOCD=openocd +OPENOCD_OPTIONS=-f openocd.cfg + +# Upload the kernel over JTAG +.PHONY: flash +flash: $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM).bin + $(OPENOCD) $(OPENOCD_OPTIONS) -c "program $<; verify_image $<; reset; shutdown;" + +.PHONY: flash +flash-debug: $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/debug/$(PLATFORM).bin + $(OPENOCD) $(OPENOCD_OPTIONS) -c "program $<; verify_image $<; reset; shutdown;" diff --git a/boards/nrf52840dk-bootloader/README.md b/boards/nrf52840dk-bootloader/README.md new file mode 100644 index 0000000..f972fdf --- /dev/null +++ b/boards/nrf52840dk-bootloader/README.md @@ -0,0 +1,28 @@ +BBC:MicroBit v2 Tock Bootloader +=================== + +This is the implementation of the Tock bootloader for the BBC:MicroBit v2 +board. The bootloader runs using the Debugger UART. + +Compiling +--------- + +To compile the bootloader, simply run the `make` command. + +``` +make +``` + +Flashing +-------- + +OpenOCD is needed to flash the bootloader. Running `make flash` will compile it and flash it. + +``` +make flash +``` + +Entering +-------- + +Entering the bootloader is done by holding Button A during reset. diff --git a/boards/nrf52840dk-bootloader/build.rs b/boards/nrf52840dk-bootloader/build.rs new file mode 100644 index 0000000..4bef3b0 --- /dev/null +++ b/boards/nrf52840dk-bootloader/build.rs @@ -0,0 +1,24 @@ +extern crate bootloader_attributes; +use std::env; + +fn main() { + println!("cargo:rerun-if-changed=layout.ld"); + println!("cargo:rerun-if-changed=../kernel_layout.ld"); + + let mut f = bootloader_attributes::get_file(); + let version = if let Ok(v) = env::var("BOOTLOADER_VERSION") { + v + } else { + String::from("1.1.3") + }; + bootloader_attributes::write_flags(&mut f, &version, 0x8000); + bootloader_attributes::write_attribute(&mut f, "board", "nrf52840dk"); + bootloader_attributes::write_attribute(&mut f, "arch", "cortex-m4"); + bootloader_attributes::write_attribute(&mut f, "appaddr", "0x40000"); + if let Ok(bootloader) = env::var("BOOTLOADER_HASH") { + bootloader_attributes::write_attribute(&mut f, "boothash", &bootloader); + } + if let Ok(bootloader_kernel) = env::var("BOOTLOADER_KERNEL_HASH") { + bootloader_attributes::write_attribute(&mut f, "kernhash", &bootloader_kernel); + } +} diff --git a/boards/nrf52840dk-bootloader/layout.ld b/boards/nrf52840dk-bootloader/layout.ld new file mode 100644 index 0000000..7a116c2 --- /dev/null +++ b/boards/nrf52840dk-bootloader/layout.ld @@ -0,0 +1,11 @@ +MEMORY +{ + rom (rx) : ORIGIN = 0x00000000, LENGTH = 32K + prog (rx) : ORIGIN = 0x00008000, LENGTH = 480K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K +} + +MPU_MIN_ALIGN = 8K; +PAGE_SIZE = 4K; + +INCLUDE ../kernel_layout.ld diff --git a/boards/nrf52840dk-bootloader/src/main.rs b/boards/nrf52840dk-bootloader/src/main.rs new file mode 100644 index 0000000..b639188 --- /dev/null +++ b/boards/nrf52840dk-bootloader/src/main.rs @@ -0,0 +1,354 @@ +//! Tock kernel for the bootloader on nrf52 over UART. +//! +//! It is based on nRF52840 SoC. + +#![no_std] +// Disable this attribute when documenting, as a workaround for +// https://github.com/rust-lang/rust/issues/62184. +#![cfg_attr(not(doc), no_main)] + +use core::panic::PanicInfo; + +use kernel::capabilities; +use kernel::component::Component; +use kernel::create_capability; +use kernel::hil; +use kernel::hil::time::Alarm; +use kernel::hil::time::Counter; +use kernel::platform::KernelResources; +use kernel::platform::SyscallDriverLookup; +use kernel::static_init; + +use bootloader::null_scheduler::NullScheduler; + +use capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm; + +use nrf52840::gpio::Pin; +use nrf52840::interrupt_service::Nrf52840DefaultPeripherals; + +const UART_TXD: Pin = Pin::P0_06; +const UART_RXD: Pin = Pin::P0_08; +const BUTTON_RST_PIN: Pin = Pin::P0_18; + +const LED_4: Pin = Pin::P0_16; + +#[allow(dead_code)] +const BUTTON_4: Pin = Pin::P0_25; + +include!(concat!(env!("OUT_DIR"), "/attributes.rs")); + +// Number of concurrent processes this platform supports. +const NUM_PROCS: usize = 0; + +static mut PROCESSES: [Option<&'static dyn kernel::process::Process>; NUM_PROCS] = + [None; NUM_PROCS]; + +static mut CHIP: Option<&'static nrf52840::chip::NRF52> = 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; 0x2000] = [0; 0x2000]; + +/// Function to allow the bootloader to exit by reseting the chip. +fn bootloader_exit() { + unsafe { + cortexm4::scb::reset(); + } +} + +/// Supported drivers by the platform +pub struct Platform { + bootloader: &'static bootloader::bootloader::Bootloader< + 'static, + bootloader::uart_receive_multiple_timeout::UartReceiveMultipleTimeout< + 'static, + VirtualMuxAlarm<'static, nrf52::rtc::Rtc<'static>>, + >, + bootloader::flash_large_to_small::FlashLargeToSmall<'static, nrf52::nvmc::Nvmc>, + >, + scheduler: &'static NullScheduler, +} + +impl KernelResources>> + for Platform +{ + type SyscallDriverLookup = Self; + type SyscallFilter = (); + type ProcessFault = (); + type CredentialsCheckingPolicy = (); + type Scheduler = NullScheduler; + type SchedulerTimer = (); + type WatchDog = (); + type ContextSwitchCallback = (); + + fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup { + &self + } + fn syscall_filter(&self) -> &Self::SyscallFilter { + &() + } + fn process_fault(&self) -> &Self::ProcessFault { + &() + } + fn credentials_checking_policy(&self) -> &'static Self::CredentialsCheckingPolicy { + &() + } + fn scheduler(&self) -> &Self::Scheduler { + self.scheduler + } + fn scheduler_timer(&self) -> &Self::SchedulerTimer { + &() + } + fn watchdog(&self) -> &Self::WatchDog { + &() + } + fn context_switch_callback(&self) -> &Self::ContextSwitchCallback { + &() + } +} + +impl SyscallDriverLookup for Platform { + fn with_driver(&self, _driver_num: usize, f: F) -> R + where + F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R, + { + f(None) + } +} + +#[inline(never)] +unsafe fn create_peripherals() -> &'static mut Nrf52840DefaultPeripherals<'static> { + let ieee802154_ack_buf = static_init!( + [u8; nrf52840::ieee802154_radio::ACK_BUF_SIZE], + [0; nrf52840::ieee802154_radio::ACK_BUF_SIZE] + ); + // Initialize chip peripheral drivers + let nrf52840_peripherals = static_init!( + Nrf52840DefaultPeripherals, + Nrf52840DefaultPeripherals::new(ieee802154_ack_buf) + ); + + nrf52840_peripherals +} + +/// Entry point in the vector table called on hard reset. +#[no_mangle] +pub unsafe fn main() { + // Loads relocations and clears BSS + nrf52840::init(); + // Initialize chip peripheral drivers + let nrf52840_peripherals = create_peripherals(); + + // set up circular peripheral dependencies + nrf52840_peripherals.init(); + let base_peripherals = &nrf52840_peripherals.nrf52; + + let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(&PROCESSES)); + + nrf52_components::startup::NrfStartupComponent::new( + false, + BUTTON_RST_PIN, + nrf52840::uicr::Regulator0Output::DEFAULT, + &base_peripherals.nvmc, + ) + .finalize(()); + + //-------------------------------------------------------------------------- + // BOOTLOADER ENTRY + //-------------------------------------------------------------------------- + + // Decide very early if we want to stay in the bootloader so we don't run a + // bunch of init code just to reset into the kernel. + + let bootloader_entry_mode = static_init!( + bootloader_nrf52::bootloader_entry_doublereset::BootloaderEntryDoubleReset, + bootloader_nrf52::bootloader_entry_doublereset::BootloaderEntryDoubleReset::new() + ); + + let bootloader_jumper = static_init!( + bootloader_cortexm::jumper::CortexMJumper, + bootloader_cortexm::jumper::CortexMJumper::new() + ); + + let active_notifier_led = static_init!( + kernel::hil::led::LedLow<'static, nrf52840::gpio::GPIOPin>, + kernel::hil::led::LedLow::new(&nrf52840_peripherals.gpio_port[LED_4]) + ); + + let bootloader_active_notifier = static_init!( + bootloader::active_notifier_ledon::ActiveNotifierLedon, + bootloader::active_notifier_ledon::ActiveNotifierLedon::new(active_notifier_led) + ); + + let bootloader_enterer = static_init!( + bootloader::bootloader::BootloaderEnterer<'static>, + bootloader::bootloader::BootloaderEnterer::new( + bootloader_entry_mode, + bootloader_jumper, + bootloader_active_notifier + ) + ); + + // First decide if we want to actually run the bootloader or not. + bootloader_enterer.check(); + + //-------------------------------------------------------------------------- + // CAPABILITIES + //-------------------------------------------------------------------------- + + // Create capabilities that the board needs to call certain protected kernel + // functions. + let main_loop_capability = create_capability!(capabilities::MainLoopCapability); + + //-------------------------------------------------------------------------- + // ALARM & TIMER + //-------------------------------------------------------------------------- + + let rtc = &base_peripherals.rtc; + let _ = rtc.start(); + + let mux_alarm = components::alarm::AlarmMuxComponent::new(rtc) + .finalize(components::alarm_mux_component_static!(nrf52::rtc::Rtc)); + + // //-------------------------------------------------------------------------- + // // UART DEBUGGING + // //-------------------------------------------------------------------------- + + // let channel = nrf52_components::UartChannelComponent::new( + // UartChannel::Pins(UartPins::new(UART_RTS, UART_TXD, UART_CTS, UART_RXD)), + // mux_alarm, + // &base_peripherals.uarte0, + // ) + // .finalize(()); + + // // Create a shared UART channel for the console and for kernel debug. + // let uart_mux = + // components::console::UartMuxComponent::new(channel, 115200, dynamic_deferred_caller) + // .finalize(()); + + // // Create the debugger object that handles calls to `debug!()`. + // components::debug_writer::DebugWriterComponent::new(uart_mux).finalize(()); + + //-------------------------------------------------------------------------- + // SCHEDULER + //-------------------------------------------------------------------------- + + let null_scheduler = static_init!(NullScheduler, NullScheduler::new()); + + //-------------------------------------------------------------------------- + // BOOTLOADER + //-------------------------------------------------------------------------- + + // Setup receive with timeout. + let recv_auto_virtual_alarm = static_init!( + VirtualMuxAlarm<'static, nrf52840::rtc::Rtc>, + VirtualMuxAlarm::new(mux_alarm) + ); + recv_auto_virtual_alarm.setup(); + + let recv_auto_uart = static_init!( + bootloader::uart_receive_multiple_timeout::UartReceiveMultipleTimeout< + 'static, + VirtualMuxAlarm<'static, nrf52840::rtc::Rtc>, + >, + bootloader::uart_receive_multiple_timeout::UartReceiveMultipleTimeout::new( + &base_peripherals.uarte0, + recv_auto_virtual_alarm, + &mut bootloader::uart_receive_multiple_timeout::BUF + ) + ); + recv_auto_virtual_alarm.set_alarm_client(recv_auto_uart); + + // Setup the UART pins + let _ = base_peripherals.uarte0.initialize( + nrf52840::pinmux::Pinmux::new(UART_TXD as u32), + nrf52840::pinmux::Pinmux::new(UART_RXD as u32), + None, + None, + ); + + let nrfpagebuffer = static_init!(nrf52::nvmc::NrfPage, nrf52::nvmc::NrfPage::default()); + + let flash_adapter = static_init!( + bootloader::flash_large_to_small::FlashLargeToSmall<'static, nrf52840::nvmc::Nvmc>, + bootloader::flash_large_to_small::FlashLargeToSmall::new( + &base_peripherals.nvmc, + nrfpagebuffer, + ) + ); + hil::flash::HasClient::set_client(&base_peripherals.nvmc, flash_adapter); + + let pagebuffer = static_init!( + bootloader::flash_large_to_small::FiveTwelvePage, + bootloader::flash_large_to_small::FiveTwelvePage::default() + ); + + let bootloader = static_init!( + bootloader::bootloader::Bootloader< + 'static, + bootloader::uart_receive_multiple_timeout::UartReceiveMultipleTimeout< + 'static, + VirtualMuxAlarm<'static, nrf52840::rtc::Rtc>, + >, + bootloader::flash_large_to_small::FlashLargeToSmall<'static, nrf52::nvmc::Nvmc>, + >, + bootloader::bootloader::Bootloader::new( + recv_auto_uart, + flash_adapter, + &bootloader_exit, + pagebuffer, + &mut bootloader::bootloader::BUF + ) + ); + + hil::uart::Transmit::set_transmit_client(&base_peripherals.uarte0, bootloader); + hil::uart::Receive::set_receive_client(&base_peripherals.uarte0, recv_auto_uart); + hil::uart::Receive::set_receive_client(recv_auto_uart, bootloader); + hil::flash::HasClient::set_client(flash_adapter, bootloader); + + //-------------------------------------------------------------------------- + // FINAL SETUP AND BOARD BOOT + //-------------------------------------------------------------------------- + + // Start all of the clocks. Low power operation will require a better + // approach than this. + base_peripherals.clock.low_stop(); + base_peripherals.clock.high_stop(); + base_peripherals.clock.low_start(); + base_peripherals.clock.high_start(); + while !base_peripherals.clock.low_started() {} + while !base_peripherals.clock.high_started() {} + + let platform = Platform { + bootloader, + scheduler: null_scheduler, + }; + + let chip = static_init!( + nrf52840::chip::NRF52, + nrf52840::chip::NRF52::new(nrf52840_peripherals) + ); + CHIP = Some(chip); + + // Actually run the bootloader. + platform.bootloader.start(); + + //-------------------------------------------------------------------------- + // MAIN LOOP + //-------------------------------------------------------------------------- + + board_kernel.kernel_loop( + &platform, + chip, + None::<&kernel::ipc::IPC<0>>, + &main_loop_capability, + ); +} + +#[cfg(not(test))] +#[no_mangle] +#[panic_handler] +pub unsafe extern "C" fn panic_fmt(_pi: &PanicInfo) -> ! { + loop {} +} diff --git a/boards/wm1110_dev-bootloader/Cargo.toml b/boards/wm1110_dev-bootloader/Cargo.toml new file mode 100644 index 0000000..1f9e5fc --- /dev/null +++ b/boards/wm1110_dev-bootloader/Cargo.toml @@ -0,0 +1,44 @@ +[package] +name = "wm1110_dev-bootloader" +version = "0.1.0" +authors = ["Tock Project Developers "] +build = "build.rs" +edition = "2021" + +[dependencies] +cortexm4 = { git = "https://github.com/tock/tock", rev = "2ff6868" } +capsules-core = { git = "https://github.com/tock/tock", rev = "2ff6868" } +capsules-extra = { git = "https://github.com/tock/tock", rev = "2ff6868" } +kernel = { git = "https://github.com/tock/tock", rev = "2ff6868" } +nrf52 = { git = "https://github.com/tock/tock", rev = "2ff6868" } +nrf52840 = { git = "https://github.com/tock/tock", rev = "2ff6868" } +components = { git = "https://github.com/tock/tock", rev = "2ff6868" } +nrf52_components = { git = "https://github.com/tock/tock", rev = "2ff6868" } + +# For Development +# cortexm4 = { path = "../../../tock/arch/cortex-m4" } +# capsules = { path = "../../../tock/capsules" } +# kernel = { path = "../../../tock/kernel" } +# nrf52 = { path = "../../../tock/chips/nrf52" } +# nrf52833 = { path = "../../../tock/chips/nrf52833" } +# components = { path = "../../../tock/boards/components" } + +bootloader = { path = "../../bootloader" } +bootloader_nrf52 = { path = "../../chips/bootloader_nrf52" } +bootloader_cortexm = { path = "../../arch/bootloader_cortexm" } + + +[build-dependencies] +bootloader_attributes = { path = "../../tools/bootloader_attributes" } + +[profile.dev] +panic = "abort" +lto = false +opt-level = "z" +debug = true + +[profile.release] +panic = "abort" +lto = true +opt-level = "z" +debug = true diff --git a/boards/wm1110_dev-bootloader/Makefile b/boards/wm1110_dev-bootloader/Makefile new file mode 100644 index 0000000..efd9357 --- /dev/null +++ b/boards/wm1110_dev-bootloader/Makefile @@ -0,0 +1,21 @@ +# Makefile for building the Tock bootloader for nRF52 platforms over UART. + +TOCK_ARCH=cortex-m4 +TARGET=thumbv7em-none-eabi +PLATFORM=wm1110_dev-bootloader + +include ../Common.mk + +TOCKLOADER=tockloader + +OPENOCD=openocd +OPENOCD_OPTIONS=-f openocd.cfg + +# Upload the kernel over JTAG +.PHONY: flash +flash: $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM).bin + $(OPENOCD) $(OPENOCD_OPTIONS) -c "program $<; verify_image $<; reset; shutdown;" + +.PHONY: flash +flash-debug: $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/debug/$(PLATFORM).bin + $(OPENOCD) $(OPENOCD_OPTIONS) -c "program $<; verify_image $<; reset; shutdown;" diff --git a/boards/wm1110_dev-bootloader/README.md b/boards/wm1110_dev-bootloader/README.md new file mode 100644 index 0000000..f972fdf --- /dev/null +++ b/boards/wm1110_dev-bootloader/README.md @@ -0,0 +1,28 @@ +BBC:MicroBit v2 Tock Bootloader +=================== + +This is the implementation of the Tock bootloader for the BBC:MicroBit v2 +board. The bootloader runs using the Debugger UART. + +Compiling +--------- + +To compile the bootloader, simply run the `make` command. + +``` +make +``` + +Flashing +-------- + +OpenOCD is needed to flash the bootloader. Running `make flash` will compile it and flash it. + +``` +make flash +``` + +Entering +-------- + +Entering the bootloader is done by holding Button A during reset. diff --git a/boards/wm1110_dev-bootloader/build.rs b/boards/wm1110_dev-bootloader/build.rs new file mode 100644 index 0000000..e52fcde --- /dev/null +++ b/boards/wm1110_dev-bootloader/build.rs @@ -0,0 +1,24 @@ +extern crate bootloader_attributes; +use std::env; + +fn main() { + println!("cargo:rerun-if-changed=layout.ld"); + println!("cargo:rerun-if-changed=../kernel_layout.ld"); + + let mut f = bootloader_attributes::get_file(); + let version = if let Ok(v) = env::var("BOOTLOADER_VERSION") { + v + } else { + String::from("1.1.3") + }; + bootloader_attributes::write_flags(&mut f, &version, 0x10000); + bootloader_attributes::write_attribute(&mut f, "board", "wm1110_dev"); + bootloader_attributes::write_attribute(&mut f, "arch", "cortex-m4"); + bootloader_attributes::write_attribute(&mut f, "appaddr", "0x50000"); + if let Ok(bootloader) = env::var("BOOTLOADER_HASH") { + bootloader_attributes::write_attribute(&mut f, "boothash", &bootloader); + } + if let Ok(bootloader_kernel) = env::var("BOOTLOADER_KERNEL_HASH") { + bootloader_attributes::write_attribute(&mut f, "kernhash", &bootloader_kernel); + } +} diff --git a/boards/wm1110_dev-bootloader/layout.ld b/boards/wm1110_dev-bootloader/layout.ld new file mode 100644 index 0000000..044e37c --- /dev/null +++ b/boards/wm1110_dev-bootloader/layout.ld @@ -0,0 +1,11 @@ +MEMORY +{ + rom (rx) : ORIGIN = 0x00000000, LENGTH = 64K + prog (rx) : ORIGIN = 0x00010000, LENGTH = 480K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K +} + +MPU_MIN_ALIGN = 8K; +PAGE_SIZE = 4K; + +INCLUDE ../kernel_layout.ld diff --git a/boards/wm1110_dev-bootloader/src/main.rs b/boards/wm1110_dev-bootloader/src/main.rs new file mode 100644 index 0000000..45efa8a --- /dev/null +++ b/boards/wm1110_dev-bootloader/src/main.rs @@ -0,0 +1,359 @@ +//! Tock kernel for the bootloader on nrf52 over UART. +//! +//! It is based on nRF52840 SoC. + +#![no_std] +// Disable this attribute when documenting, as a workaround for +// https://github.com/rust-lang/rust/issues/62184. +#![cfg_attr(not(doc), no_main)] + +use core::panic::PanicInfo; + +use kernel::capabilities; +use kernel::component::Component; +use kernel::create_capability; +use kernel::hil; +use kernel::hil::time::Alarm; +use kernel::hil::time::Counter; +use kernel::platform::KernelResources; +use kernel::platform::SyscallDriverLookup; +use kernel::static_init; + +use bootloader::null_scheduler::NullScheduler; + +use capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm; + +use nrf52840::gpio::Pin; +use nrf52840::interrupt_service::Nrf52840DefaultPeripherals; + +const UART_TXD: Pin = Pin::P0_24; +const UART_RXD: Pin = Pin::P0_22; + +const LED_GREEN: Pin = Pin::P0_13; +#[allow(dead_code)] +const LED_RED: Pin = Pin::P0_14; + +const BUTTON_RST_PIN: Pin = Pin::P0_18; + +#[allow(dead_code)] +const BUTTON_CONFIG: Pin = Pin::P0_25; +#[allow(dead_code)] +const BUTTON_USER: Pin = Pin::P0_23; + +include!(concat!(env!("OUT_DIR"), "/attributes.rs")); + +// Number of concurrent processes this platform supports. +const NUM_PROCS: usize = 0; + +static mut PROCESSES: [Option<&'static dyn kernel::process::Process>; NUM_PROCS] = + [None; NUM_PROCS]; + +static mut CHIP: Option<&'static nrf52840::chip::NRF52> = 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; 0x2000] = [0; 0x2000]; + +/// Function to allow the bootloader to exit by reseting the chip. +fn bootloader_exit() { + unsafe { + cortexm4::scb::reset(); + } +} + +/// Supported drivers by the platform +pub struct Platform { + bootloader: &'static bootloader::bootloader::Bootloader< + 'static, + bootloader::uart_receive_multiple_timeout::UartReceiveMultipleTimeout< + 'static, + VirtualMuxAlarm<'static, nrf52::rtc::Rtc<'static>>, + >, + bootloader::flash_large_to_small::FlashLargeToSmall<'static, nrf52::nvmc::Nvmc>, + >, + scheduler: &'static NullScheduler, +} + +impl KernelResources>> + for Platform +{ + type SyscallDriverLookup = Self; + type SyscallFilter = (); + type ProcessFault = (); + type CredentialsCheckingPolicy = (); + type Scheduler = NullScheduler; + type SchedulerTimer = (); + type WatchDog = (); + type ContextSwitchCallback = (); + + fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup { + &self + } + fn syscall_filter(&self) -> &Self::SyscallFilter { + &() + } + fn process_fault(&self) -> &Self::ProcessFault { + &() + } + fn credentials_checking_policy(&self) -> &'static Self::CredentialsCheckingPolicy { + &() + } + fn scheduler(&self) -> &Self::Scheduler { + self.scheduler + } + fn scheduler_timer(&self) -> &Self::SchedulerTimer { + &() + } + fn watchdog(&self) -> &Self::WatchDog { + &() + } + fn context_switch_callback(&self) -> &Self::ContextSwitchCallback { + &() + } +} + +impl SyscallDriverLookup for Platform { + fn with_driver(&self, _driver_num: usize, f: F) -> R + where + F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R, + { + f(None) + } +} + +#[inline(never)] +unsafe fn create_peripherals() -> &'static mut Nrf52840DefaultPeripherals<'static> { + let ieee802154_ack_buf = static_init!( + [u8; nrf52840::ieee802154_radio::ACK_BUF_SIZE], + [0; nrf52840::ieee802154_radio::ACK_BUF_SIZE] + ); + // Initialize chip peripheral drivers + let nrf52840_peripherals = static_init!( + Nrf52840DefaultPeripherals, + Nrf52840DefaultPeripherals::new(ieee802154_ack_buf) + ); + + nrf52840_peripherals +} + +/// Entry point in the vector table called on hard reset. +#[no_mangle] +pub unsafe fn main() { + // Loads relocations and clears BSS + nrf52840::init(); + // Initialize chip peripheral drivers + let nrf52840_peripherals = create_peripherals(); + + // set up circular peripheral dependencies + nrf52840_peripherals.init(); + let base_peripherals = &nrf52840_peripherals.nrf52; + + let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(&PROCESSES)); + + nrf52_components::startup::NrfStartupComponent::new( + false, + BUTTON_RST_PIN, + nrf52840::uicr::Regulator0Output::DEFAULT, + &base_peripherals.nvmc, + ) + .finalize(()); + + //-------------------------------------------------------------------------- + // BOOTLOADER ENTRY + //-------------------------------------------------------------------------- + + // Decide very early if we want to stay in the bootloader so we don't run a + // bunch of init code just to reset into the kernel. + + let bootloader_entry_mode = static_init!( + bootloader_nrf52::bootloader_entry_doublereset::BootloaderEntryDoubleReset, + bootloader_nrf52::bootloader_entry_doublereset::BootloaderEntryDoubleReset::new() + ); + + let bootloader_jumper = static_init!( + bootloader_cortexm::jumper::CortexMJumper, + bootloader_cortexm::jumper::CortexMJumper::new() + ); + + let active_notifier_led = static_init!( + kernel::hil::led::LedHigh<'static, nrf52840::gpio::GPIOPin>, + kernel::hil::led::LedHigh::new(&nrf52840_peripherals.gpio_port[LED_GREEN]) + ); + + let bootloader_active_notifier = static_init!( + bootloader::active_notifier_ledon::ActiveNotifierLedon, + bootloader::active_notifier_ledon::ActiveNotifierLedon::new(active_notifier_led) + ); + + let bootloader_enterer = static_init!( + bootloader::bootloader::BootloaderEnterer<'static>, + bootloader::bootloader::BootloaderEnterer::new( + bootloader_entry_mode, + bootloader_jumper, + bootloader_active_notifier + ) + ); + + // First decide if we want to actually run the bootloader or not. + bootloader_enterer.check(); + + //-------------------------------------------------------------------------- + // CAPABILITIES + //-------------------------------------------------------------------------- + + // Create capabilities that the board needs to call certain protected kernel + // functions. + let main_loop_capability = create_capability!(capabilities::MainLoopCapability); + + //-------------------------------------------------------------------------- + // ALARM & TIMER + //-------------------------------------------------------------------------- + + let rtc = &base_peripherals.rtc; + let _ = rtc.start(); + + let mux_alarm = components::alarm::AlarmMuxComponent::new(rtc) + .finalize(components::alarm_mux_component_static!(nrf52::rtc::Rtc)); + + // //-------------------------------------------------------------------------- + // // UART DEBUGGING + // //-------------------------------------------------------------------------- + + // let channel = nrf52_components::UartChannelComponent::new( + // UartChannel::Pins(UartPins::new(UART_RTS, UART_TXD, UART_CTS, UART_RXD)), + // mux_alarm, + // &base_peripherals.uarte0, + // ) + // .finalize(()); + + // // Create a shared UART channel for the console and for kernel debug. + // let uart_mux = + // components::console::UartMuxComponent::new(channel, 115200, dynamic_deferred_caller) + // .finalize(()); + + // // Create the debugger object that handles calls to `debug!()`. + // components::debug_writer::DebugWriterComponent::new(uart_mux).finalize(()); + + //-------------------------------------------------------------------------- + // SCHEDULER + //-------------------------------------------------------------------------- + + let null_scheduler = static_init!(NullScheduler, NullScheduler::new()); + + //-------------------------------------------------------------------------- + // BOOTLOADER + //-------------------------------------------------------------------------- + + // Setup receive with timeout. + let recv_auto_virtual_alarm = static_init!( + VirtualMuxAlarm<'static, nrf52840::rtc::Rtc>, + VirtualMuxAlarm::new(mux_alarm) + ); + recv_auto_virtual_alarm.setup(); + + let recv_auto_uart = static_init!( + bootloader::uart_receive_multiple_timeout::UartReceiveMultipleTimeout< + 'static, + VirtualMuxAlarm<'static, nrf52840::rtc::Rtc>, + >, + bootloader::uart_receive_multiple_timeout::UartReceiveMultipleTimeout::new( + &base_peripherals.uarte0, + recv_auto_virtual_alarm, + &mut bootloader::uart_receive_multiple_timeout::BUF + ) + ); + recv_auto_virtual_alarm.set_alarm_client(recv_auto_uart); + + // Setup the UART pins + let _ = base_peripherals.uarte0.initialize( + nrf52840::pinmux::Pinmux::new(UART_TXD as u32), + nrf52840::pinmux::Pinmux::new(UART_RXD as u32), + None, + None, + ); + + let nrfpagebuffer = static_init!(nrf52::nvmc::NrfPage, nrf52::nvmc::NrfPage::default()); + + let flash_adapter = static_init!( + bootloader::flash_large_to_small::FlashLargeToSmall<'static, nrf52840::nvmc::Nvmc>, + bootloader::flash_large_to_small::FlashLargeToSmall::new( + &base_peripherals.nvmc, + nrfpagebuffer, + ) + ); + hil::flash::HasClient::set_client(&base_peripherals.nvmc, flash_adapter); + + let pagebuffer = static_init!( + bootloader::flash_large_to_small::FiveTwelvePage, + bootloader::flash_large_to_small::FiveTwelvePage::default() + ); + + let bootloader = static_init!( + bootloader::bootloader::Bootloader< + 'static, + bootloader::uart_receive_multiple_timeout::UartReceiveMultipleTimeout< + 'static, + VirtualMuxAlarm<'static, nrf52840::rtc::Rtc>, + >, + bootloader::flash_large_to_small::FlashLargeToSmall<'static, nrf52::nvmc::Nvmc>, + >, + bootloader::bootloader::Bootloader::new( + recv_auto_uart, + flash_adapter, + &bootloader_exit, + pagebuffer, + &mut bootloader::bootloader::BUF + ) + ); + + hil::uart::Transmit::set_transmit_client(&base_peripherals.uarte0, bootloader); + hil::uart::Receive::set_receive_client(&base_peripherals.uarte0, recv_auto_uart); + hil::uart::Receive::set_receive_client(recv_auto_uart, bootloader); + hil::flash::HasClient::set_client(flash_adapter, bootloader); + + //-------------------------------------------------------------------------- + // FINAL SETUP AND BOARD BOOT + //-------------------------------------------------------------------------- + + // Start all of the clocks. Low power operation will require a better + // approach than this. + base_peripherals.clock.low_stop(); + base_peripherals.clock.high_stop(); + base_peripherals.clock.low_start(); + base_peripherals.clock.high_start(); + while !base_peripherals.clock.low_started() {} + while !base_peripherals.clock.high_started() {} + + let platform = Platform { + bootloader, + scheduler: null_scheduler, + }; + + let chip = static_init!( + nrf52840::chip::NRF52, + nrf52840::chip::NRF52::new(nrf52840_peripherals) + ); + CHIP = Some(chip); + + // Actually run the bootloader. + platform.bootloader.start(); + + //-------------------------------------------------------------------------- + // MAIN LOOP + //-------------------------------------------------------------------------- + + board_kernel.kernel_loop( + &platform, + chip, + None::<&kernel::ipc::IPC<0>>, + &main_loop_capability, + ); +} + +#[cfg(not(test))] +#[no_mangle] +#[panic_handler] +pub unsafe extern "C" fn panic_fmt(_pi: &PanicInfo) -> ! { + loop {} +} diff --git a/bootloader/Cargo.toml b/bootloader/Cargo.toml index b01a20b..29a1630 100644 --- a/bootloader/Cargo.toml +++ b/bootloader/Cargo.toml @@ -2,9 +2,10 @@ name = "bootloader" version = "0.1.0" authors = ["Tock Project Developers "] +edition = "2021" [dependencies] -kernel = { git = "https://github.com/tock/tock", rev = "405417" } +kernel = { git = "https://github.com/tock/tock", rev = "2ff6868" } #kernel = { path = "../../tock/kernel" } tock-bootloader-protocol = { path = "../protocol" } diff --git a/bootloader/src/active_notifier_ledon.rs b/bootloader/src/active_notifier_ledon.rs index 720eb86..a49b094 100644 --- a/bootloader/src/active_notifier_ledon.rs +++ b/bootloader/src/active_notifier_ledon.rs @@ -9,6 +9,7 @@ pub struct ActiveNotifierLedon<'a> { impl<'a> ActiveNotifierLedon<'a> { pub fn new(led: &'a mut dyn kernel::hil::led::Led) -> ActiveNotifierLedon<'a> { led.init(); + led.off(); ActiveNotifierLedon { led } } } diff --git a/bootloader/src/bootloader.rs b/bootloader/src/bootloader.rs index 1135dcb..a71c814 100644 --- a/bootloader/src/bootloader.rs +++ b/bootloader/src/bootloader.rs @@ -2,14 +2,15 @@ use core::cell::Cell; use core::cmp; +use kernel::ErrorCode; -use kernel::common::cells::TakeCell; -use kernel::common::cells::VolatileCell; -use kernel::common::StaticRef; use kernel::hil; +use kernel::utilities::cells::TakeCell; +use kernel::utilities::cells::VolatileCell; +use kernel::utilities::StaticRef; -use bootloader_crc; -use interfaces; +use crate::bootloader_crc; +use crate::interfaces; // Main buffer that commands are received into and sent from. // Need a buffer big enough for 512 byte pages. @@ -157,7 +158,7 @@ impl<'a, U: hil::uart::UartAdvanced<'a> + 'a, F: hil::flash::Flash + 'a> Bootloa pub fn start(&self) { // Setup UART and start listening. - self.uart.configure(hil::uart::Parameters { + let _ = self.uart.configure(hil::uart::Parameters { baud_rate: 115200, width: hil::uart::Width::Eight, stop_bits: hil::uart::StopBits::One, @@ -166,7 +167,8 @@ impl<'a, U: hil::uart::UartAdvanced<'a> + 'a, F: hil::flash::Flash + 'a> Bootloa }); self.buffer.take().map(|buffer| { - self.uart + let _ = self + .uart .receive_automatic(buffer, buffer.len(), UART_RECEIVE_TIMEOUT); }); } @@ -176,7 +178,7 @@ impl<'a, U: hil::uart::UartAdvanced<'a> + 'a, F: hil::flash::Flash + 'a> Bootloa self.buffer.take().map(|buffer| { buffer[0] = ESCAPE_CHAR; buffer[1] = response; - self.uart.transmit_buffer(buffer, 2); + let _ = self.uart.transmit_buffer(buffer, 2); }); } } @@ -188,9 +190,9 @@ impl<'a, U: hil::uart::UartAdvanced<'a> + 'a, F: hil::flash::Flash + 'a> hil::ua &self, buffer: &'static mut [u8], _tx_len: usize, - error: kernel::ReturnCode, + error: Result<(), ErrorCode>, ) { - if error != kernel::ReturnCode::SUCCESS { + if error.is_err() { // self.led.clear(); } else { match self.state.get() { @@ -205,8 +207,9 @@ impl<'a, U: hil::uart::UartAdvanced<'a> + 'a, F: hil::flash::Flash + 'a> hil::ua // We are either done, or need to setup the next read. if remaining_length == 0 { self.state.set(State::Idle); - self.uart - .receive_automatic(buffer, buffer.len(), UART_RECEIVE_TIMEOUT); + let _ = + self.uart + .receive_automatic(buffer, buffer.len(), UART_RECEIVE_TIMEOUT); } else { self.buffer.replace(buffer); self.page_buffer.take().map(move |page| { @@ -217,7 +220,8 @@ impl<'a, U: hil::uart::UartAdvanced<'a> + 'a, F: hil::flash::Flash + 'a> hil::ua } _ => { - self.uart + let _ = self + .uart .receive_automatic(buffer, buffer.len(), UART_RECEIVE_TIMEOUT); } } @@ -232,10 +236,10 @@ impl<'a, U: hil::uart::UartAdvanced<'a> + 'a, F: hil::flash::Flash + 'a> hil::ua &self, buffer: &'static mut [u8], rx_len: usize, - rval: kernel::ReturnCode, + rval: Result<(), ErrorCode>, _error: hil::uart::Error, ) { - if rval != kernel::ReturnCode::SUCCESS { + if rval.is_err() { return; } @@ -271,8 +275,9 @@ impl<'a, U: hil::uart::UartAdvanced<'a> + 'a, F: hil::flash::Flash + 'a> hil::ua // If there are more bytes in the buffer we want to continue // parsing those. Otherwise, we want to go back to receive. if i == rx_len - 1 { - self.uart - .receive_automatic(buffer, buffer.len(), UART_RECEIVE_TIMEOUT); + let _ = + self.uart + .receive_automatic(buffer, buffer.len(), UART_RECEIVE_TIMEOUT); break; } } @@ -311,7 +316,7 @@ impl<'a, U: hil::uart::UartAdvanced<'a> + 'a, F: hil::flash::Flash + 'a> hil::ua buffer[1] = RES_BADARGS; self.page_buffer.replace(page); self.state.set(State::Idle); - self.uart.transmit_buffer(buffer, 2); + let _ = self.uart.transmit_buffer(buffer, 2); } else if address >= self.bootloader_address && address < self.bootloader_end_address { @@ -322,7 +327,7 @@ impl<'a, U: hil::uart::UartAdvanced<'a> + 'a, F: hil::flash::Flash + 'a> hil::ua buffer[1] = RES_BADADDR; self.page_buffer.replace(page); self.state.set(State::Idle); - self.uart.transmit_buffer(buffer, 2); + let _ = self.uart.transmit_buffer(buffer, 2); } else { // Otherwise copy into page buffer and write to // flash. @@ -521,7 +526,7 @@ impl<'a, U: hil::uart::UartAdvanced<'a> + 'a, F: hil::flash::Flash + 'a> hil::fl } self.page_buffer.replace(pagebuffer); - self.uart.transmit_buffer(buffer, 195); + let _ = self.uart.transmit_buffer(buffer, 195); }); } @@ -553,7 +558,7 @@ impl<'a, U: hil::uart::UartAdvanced<'a> + 'a, F: hil::flash::Flash + 'a> hil::fl } self.page_buffer.replace(pagebuffer); - self.uart.transmit_buffer(buffer, j); + let _ = self.uart.transmit_buffer(buffer, j); }); } @@ -650,7 +655,7 @@ impl<'a, U: hil::uart::UartAdvanced<'a> + 'a, F: hil::flash::Flash + 'a> hil::fl // And send the buffer to the client. self.page_buffer.replace(pagebuffer); - self.uart.transmit_buffer(buffer, index); + let _ = self.uart.transmit_buffer(buffer, index); }); } @@ -694,7 +699,7 @@ impl<'a, U: hil::uart::UartAdvanced<'a> + 'a, F: hil::flash::Flash + 'a> hil::fl buffer[5] = ((new_crc >> 24) & 0xFF) as u8; // And send the buffer to the client. self.page_buffer.replace(pagebuffer); - self.uart.transmit_buffer(buffer, 6); + let _ = self.uart.transmit_buffer(buffer, 6); }); } else { // More CRC to do! @@ -723,7 +728,7 @@ impl<'a, U: hil::uart::UartAdvanced<'a> + 'a, F: hil::flash::Flash + 'a> hil::fl self.buffer.take().map(move |buffer| { buffer[0] = ESCAPE_CHAR; buffer[1] = RES_OK; - self.uart.transmit_buffer(buffer, 2); + let _ = self.uart.transmit_buffer(buffer, 2); }); } @@ -733,7 +738,7 @@ impl<'a, U: hil::uart::UartAdvanced<'a> + 'a, F: hil::flash::Flash + 'a> hil::fl self.buffer.take().map(move |buffer| { buffer[0] = ESCAPE_CHAR; buffer[1] = RES_OK; - self.uart.transmit_buffer(buffer, 2); + let _ = self.uart.transmit_buffer(buffer, 2); }); } @@ -743,13 +748,14 @@ impl<'a, U: hil::uart::UartAdvanced<'a> + 'a, F: hil::flash::Flash + 'a> hil::fl self.buffer.take().map(move |buffer| { buffer[0] = ESCAPE_CHAR; buffer[1] = RES_OK; - self.uart.transmit_buffer(buffer, 2); + let _ = self.uart.transmit_buffer(buffer, 2); }); } _ => { self.buffer.take().map(|buffer| { - self.uart + let _ = self + .uart .receive_automatic(buffer, buffer.len(), UART_RECEIVE_TIMEOUT); }); } @@ -764,13 +770,14 @@ impl<'a, U: hil::uart::UartAdvanced<'a> + 'a, F: hil::flash::Flash + 'a> hil::fl self.buffer.take().map(move |buffer| { buffer[0] = ESCAPE_CHAR; buffer[1] = RES_OK; - self.uart.transmit_buffer(buffer, 2); + let _ = self.uart.transmit_buffer(buffer, 2); }); } _ => { self.buffer.take().map(|buffer| { - self.uart + let _ = self + .uart .receive_automatic(buffer, buffer.len(), UART_RECEIVE_TIMEOUT); }); } diff --git a/bootloader/src/flash_large_to_small.rs b/bootloader/src/flash_large_to_small.rs index 113cb63..ec43e08 100644 --- a/bootloader/src/flash_large_to_small.rs +++ b/bootloader/src/flash_large_to_small.rs @@ -6,9 +6,9 @@ use core::cell::Cell; use core::ops::{Index, IndexMut}; -use kernel::common::cells::{OptionalCell, TakeCell}; use kernel::hil; -use kernel::ReturnCode; +use kernel::utilities::cells::{OptionalCell, TakeCell}; +use kernel::ErrorCode; pub struct FiveTwelvePage(pub [u8; 512 as usize]); impl Default for FiveTwelvePage { @@ -96,7 +96,7 @@ impl<'a, Flarge: hil::flash::Flash> hil::flash::Flash for FlashLargeToSmall<'a, &self, page_number: usize, buf: &'static mut Self::Page, - ) -> Result<(), (ReturnCode, &'static mut Self::Page)> { + ) -> Result<(), (ErrorCode, &'static mut Self::Page)> { // Translate to the large page we need to read. let (index, _) = self.get_large_page_index_offset(page_number); @@ -105,12 +105,12 @@ impl<'a, Flarge: hil::flash::Flash> hil::flash::Flash for FlashLargeToSmall<'a, // Call the underlying flash layer. self.pagebuffer.take().map_or_else( - || Err((ReturnCode::FAIL, self.client_pagebuffer.take().unwrap())), + || Err((ErrorCode::FAIL, self.client_pagebuffer.take().unwrap())), |page| { self.state.set(State::Read { page_number }); self.flash_large.read_page(index, page).map_err(|e| { self.pagebuffer.replace(e.1); - (ReturnCode::FAIL, self.client_pagebuffer.take().unwrap()) + (ErrorCode::FAIL, self.client_pagebuffer.take().unwrap()) }) }, ) @@ -120,7 +120,7 @@ impl<'a, Flarge: hil::flash::Flash> hil::flash::Flash for FlashLargeToSmall<'a, &self, page_number: usize, buf: &'static mut Self::Page, - ) -> Result<(), (ReturnCode, &'static mut Self::Page)> { + ) -> Result<(), (ErrorCode, &'static mut Self::Page)> { // Translate to the large page we need to read. let (index, _) = self.get_large_page_index_offset(page_number); @@ -129,31 +129,31 @@ impl<'a, Flarge: hil::flash::Flash> hil::flash::Flash for FlashLargeToSmall<'a, // Call the underlying flash layer to read the original large page. self.pagebuffer.take().map_or_else( - || Err((ReturnCode::FAIL, self.client_pagebuffer.take().unwrap())), + || Err((ErrorCode::FAIL, self.client_pagebuffer.take().unwrap())), |page| { self.state.set(State::Write { page_number }); self.flash_large.read_page(index, page).map_err(|e| { self.pagebuffer.replace(e.1); - (ReturnCode::FAIL, self.client_pagebuffer.take().unwrap()) + (ErrorCode::FAIL, self.client_pagebuffer.take().unwrap()) }) }, ) } - fn erase_page(&self, page_number: usize) -> ReturnCode { + fn erase_page(&self, page_number: usize) -> Result<(), ErrorCode> { // Translate to the large page we need to read. let (index, _) = self.get_large_page_index_offset(page_number); // Call the underlying flash layer to read the original large page. - self.pagebuffer.take().map_or(ReturnCode::FAIL, |page| { + self.pagebuffer.take().map_or(Err(ErrorCode::FAIL), |page| { self.state.set(State::Erase { page_number }); - self.flash_large.read_page(index, page).map_or_else( - |e| { - self.pagebuffer.replace(e.1); - ReturnCode::FAIL - }, - |_| ReturnCode::SUCCESS, - ) + match self.flash_large.read_page(index, page) { + Err((e, buf)) => { + self.pagebuffer.replace(buf); + Err(e) + } + Ok(()) => Ok(()), + } }) } } diff --git a/bootloader/src/lib.rs b/bootloader/src/lib.rs index a7396ca..6de6a10 100644 --- a/bootloader/src/lib.rs +++ b/bootloader/src/lib.rs @@ -1,12 +1,6 @@ -#![feature(const_fn, asm, assoc_char_funcs)] -#![feature(const_raw_ptr_to_usize_cast)] // #![forbid(unsafe_code)] #![no_std] -#[allow(unused_imports)] -#[macro_use(debug, debug_gpio)] -extern crate kernel; - pub mod active_notifier_ledon; pub mod active_notifier_null; pub mod bootloader; @@ -15,5 +9,6 @@ pub mod bootloader_entry_always; pub mod bootloader_entry_gpio; pub mod flash_large_to_small; pub mod interfaces; +pub mod null_scheduler; pub mod uart_receive_multiple_timeout; pub mod uart_receive_timeout; diff --git a/bootloader/src/null_scheduler.rs b/bootloader/src/null_scheduler.rs new file mode 100644 index 0000000..364286d --- /dev/null +++ b/bootloader/src/null_scheduler.rs @@ -0,0 +1,29 @@ +// Licensed under the Apache License, Version 2.0 or the MIT License. +// SPDX-License-Identifier: Apache-2.0 OR MIT +// Copyright Tock Contributors 2023. + +//! Null scheduler that does not run applications. + +// use crate::collections::list::{List, ListLink, ListNode}; +// use crate::kernel::StoppedExecutingReason; +// use crate::platform::chip::Chip; +// use crate::process::Process; +use kernel::platform::chip::Chip; +use kernel::scheduler; +use kernel::scheduler::SchedulingDecision; + +pub struct NullScheduler {} + +impl<'a> NullScheduler { + pub const fn new() -> NullScheduler { + NullScheduler {} + } +} + +impl<'a, C: Chip> scheduler::Scheduler for NullScheduler { + fn next(&self) -> SchedulingDecision { + scheduler::SchedulingDecision::TrySleep + } + + fn result(&self, _result: kernel::process::StoppedExecutingReason, _: Option) {} +} diff --git a/bootloader/src/uart_receive_multiple_timeout.rs b/bootloader/src/uart_receive_multiple_timeout.rs index d0d82ee..3dcbcb0 100644 --- a/bootloader/src/uart_receive_multiple_timeout.rs +++ b/bootloader/src/uart_receive_multiple_timeout.rs @@ -13,11 +13,12 @@ use core::cell::Cell; use core::cmp; +use kernel::hil::time::ConvertTicks; -use kernel::common::cells::OptionalCell; -use kernel::common::cells::TakeCell; use kernel::hil; -use kernel::ReturnCode; +use kernel::utilities::cells::OptionalCell; +use kernel::utilities::cells::TakeCell; +use kernel::ErrorCode; pub static mut BUF: [u8; 512] = [0; 512]; @@ -58,7 +59,7 @@ impl<'a, A: hil::time::Alarm<'a>> UartReceiveMultipleTimeout<'a, A> { } impl<'a, A: hil::time::Alarm<'a>> hil::uart::Configure for UartReceiveMultipleTimeout<'a, A> { - fn configure(&self, params: hil::uart::Parameters) -> ReturnCode { + fn configure(&self, params: hil::uart::Parameters) -> Result<(), ErrorCode> { self.uart.configure(params) } } @@ -72,15 +73,15 @@ impl<'a, A: hil::time::Alarm<'a>> hil::uart::Receive<'a> for UartReceiveMultiple &self, rx_buffer: &'static mut [u8], rx_len: usize, - ) -> (ReturnCode, Option<&'static mut [u8]>) { + ) -> Result<(), (ErrorCode, &'static mut [u8])> { self.uart.receive_buffer(rx_buffer, rx_len) } - fn receive_word(&self) -> ReturnCode { + fn receive_word(&self) -> Result<(), ErrorCode> { self.uart.receive_word() } - fn receive_abort(&self) -> ReturnCode { + fn receive_abort(&self) -> Result<(), ErrorCode> { self.uart.receive_abort() } } @@ -92,15 +93,15 @@ impl<'a, A: hil::time::Alarm<'a>> hil::uart::Transmit<'a> for UartReceiveMultipl &self, tx_buffer: &'static mut [u8], tx_len: usize, - ) -> (ReturnCode, Option<&'static mut [u8]>) { + ) -> Result<(), (ErrorCode, &'static mut [u8])> { self.uart.transmit_buffer(tx_buffer, tx_len) } - fn transmit_word(&self, word: u32) -> ReturnCode { + fn transmit_word(&self, word: u32) -> Result<(), ErrorCode> { self.uart.transmit_word(word) } - fn transmit_abort(&self) -> ReturnCode { + fn transmit_abort(&self) -> Result<(), ErrorCode> { self.uart.transmit_abort() } } @@ -113,7 +114,7 @@ impl<'a, A: hil::time::Alarm<'a>> hil::uart::ReceiveAdvanced<'a> rx_buffer: &'static mut [u8], _rx_len: usize, _interbyte_timeout: u8, - ) -> (ReturnCode, Option<&'static mut [u8]>) { + ) -> Result<(), (ErrorCode, &'static mut [u8])> { match self.state.get() { State::Idle => { // Nothing is happening with receive right now. So, all we do @@ -132,35 +133,36 @@ impl<'a, A: hil::time::Alarm<'a>> hil::uart::ReceiveAdvanced<'a> .take() .map(|rx| self.uart.receive_buffer(rx, 1)); - (ReturnCode::SUCCESS, None) + Ok(()) } State::Receiving => { // We are in the middle of a receive. We cannot start another // receive at this point. - (ReturnCode::EBUSY, Some(rx_buffer)) + Err((ErrorCode::BUSY, rx_buffer)) } } } } -impl<'a, A: hil::time::Alarm<'a>> hil::uart::UartAdvanced<'a> - for UartReceiveMultipleTimeout<'a, A> -{ -} - impl<'a, A: hil::time::Alarm<'a>> hil::time::AlarmClient for UartReceiveMultipleTimeout<'a, A> { /// If the timer actually fires then we stopped receiving bytes. fn alarm(&self) { // Cancel the receive so that we get the buffer back. - self.uart.receive_abort(); + let _ = self.uart.receive_abort(); } } // Callbacks from the underlying UART driver. impl<'a, A: hil::time::Alarm<'a>> hil::uart::TransmitClient for UartReceiveMultipleTimeout<'a, A> { // Called when the UART TX has finished. - fn transmitted_buffer(&self, _buffer: &'static mut [u8], _tx_len: usize, _rval: ReturnCode) {} + fn transmitted_buffer( + &self, + _buffer: &'static mut [u8], + _tx_len: usize, + _rval: Result<(), ErrorCode>, + ) { + } } // Callbacks from the underlying UART driver. @@ -170,7 +172,7 @@ impl<'a, A: hil::time::Alarm<'a>> hil::uart::ReceiveClient for UartReceiveMultip &self, buffer: &'static mut [u8], rx_len: usize, - rval: ReturnCode, + rval: Result<(), ErrorCode>, _error: hil::uart::Error, ) { match self.state.get() { @@ -198,45 +200,50 @@ impl<'a, A: hil::time::Alarm<'a>> hil::uart::ReceiveClient for UartReceiveMultip }); // If everything is normal then we continue receiving. - if rval == ReturnCode::SUCCESS { - // Next we setup a timer to timeout if the receive has - // finished. Six ms should be enough to receive up to 50 - // bytes. - let interval = A::ticks_from_ms(6); - self.alarm.set_alarm(self.alarm.now(), interval); - - // Then we go back to receiving to see if there is more data - // on its way. - // - // Receive either 50 bytes or half the buffer, whatever is - // lower. We only use half the buffer in case the host sends - // us more than we expect, as can happen with USB where we - // don't have a method for flow control. We receive up to 50 - // so that we don't need a long timeout in case the host is - // only sending us a small number of bytes. - self.uart - .receive_buffer(buffer, cmp::min(buffer.len() / 2, 50)); - } else if rval == ReturnCode::ECANCEL { - // The last receive was aborted meaning the receive has - // finished. - - // Replace our buffer. - self.rx_buffer.replace(buffer); - - // We are no longer receiving. - self.state.set(State::Idle); - - // Call receive complete to the client. - self.rx_client.map(|client| { - self.rx_client_buffer.take().map(|rx_buffer| { - client.received_buffer( - rx_buffer, - self.rx_client_index.get(), - ReturnCode::SUCCESS, - hil::uart::Error::None, - ); + match rval { + Ok(()) => { + // Next we setup a timer to timeout if the receive has + // finished. Six ms should be enough to receive up to 50 + // bytes. + let interval = self.alarm.ticks_from_ms(6); + self.alarm.set_alarm(self.alarm.now(), interval); + + // Then we go back to receiving to see if there is more data + // on its way. + // + // Receive either 50 bytes or half the buffer, whatever is + // lower. We only use half the buffer in case the host sends + // us more than we expect, as can happen with USB where we + // don't have a method for flow control. We receive up to 50 + // so that we don't need a long timeout in case the host is + // only sending us a small number of bytes. + let _ = self + .uart + .receive_buffer(buffer, cmp::min(buffer.len() / 2, 50)); + } + Err(ErrorCode::CANCEL) => { + // The last receive was aborted meaning the receive has + // finished. + + // Replace our buffer. + self.rx_buffer.replace(buffer); + + // We are no longer receiving. + self.state.set(State::Idle); + + // Call receive complete to the client. + self.rx_client.map(|client| { + self.rx_client_buffer.take().map(|rx_buffer| { + client.received_buffer( + rx_buffer, + self.rx_client_index.get(), + Ok(()), + hil::uart::Error::None, + ); + }); }); - }); + } + _ => {} } } } diff --git a/bootloader/src/uart_receive_timeout.rs b/bootloader/src/uart_receive_timeout.rs index b083e71..3aa36a1 100644 --- a/bootloader/src/uart_receive_timeout.rs +++ b/bootloader/src/uart_receive_timeout.rs @@ -35,7 +35,8 @@ //! ``` use kernel::hil; -use kernel::ReturnCode; +use kernel::hil::time::ConvertTicks; +use kernel::ErrorCode; pub struct UartReceiveTimeout<'a, A: hil::time::Alarm<'a> + 'a> { uart: &'a dyn hil::uart::UartData<'a>, @@ -71,15 +72,15 @@ impl<'a, A: hil::time::Alarm<'a>> hil::uart::Transmit<'a> for UartReceiveTimeout &self, tx_buffer: &'static mut [u8], tx_len: usize, - ) -> (ReturnCode, Option<&'static mut [u8]>) { + ) -> Result<(), (ErrorCode, &'static mut [u8])> { self.uart.transmit_buffer(tx_buffer, tx_len) } - fn transmit_word(&self, word: u32) -> ReturnCode { + fn transmit_word(&self, word: u32) -> Result<(), ErrorCode> { self.uart.transmit_word(word) } - fn transmit_abort(&self) -> ReturnCode { + fn transmit_abort(&self) -> Result<(), ErrorCode> { self.uart.transmit_abort() } } @@ -91,15 +92,15 @@ impl<'a, A: hil::time::Alarm<'a>> hil::uart::Receive<'a> for UartReceiveTimeout< &self, rx_buffer: &'static mut [u8], rx_len: usize, - ) -> (ReturnCode, Option<&'static mut [u8]>) { + ) -> Result<(), (ErrorCode, &'static mut [u8])> { self.uart.receive_buffer(rx_buffer, rx_len) } - fn receive_word(&self) -> ReturnCode { + fn receive_word(&self) -> Result<(), ErrorCode> { self.uart.receive_word() } - fn receive_abort(&self) -> ReturnCode { + fn receive_abort(&self) -> Result<(), ErrorCode> { self.uart.receive_abort() } } @@ -110,7 +111,7 @@ impl<'a, A: hil::time::Alarm<'a>> hil::uart::ReceiveAdvanced<'a> for UartReceive rx_buffer: &'static mut [u8], rx_len: usize, _interbyte_timeout: u8, - ) -> (ReturnCode, Option<&'static mut [u8]>) { + ) -> Result<(), (ErrorCode, &'static mut [u8])> { // Just call receive with the entire buffer. self.uart.receive_buffer(rx_buffer, rx_len) } @@ -121,7 +122,7 @@ impl<'a, A: hil::time::Alarm<'a>> hil::gpio::Client for UartReceiveTimeout<'a, A // We start a new timer on every toggle to wait for the end of incoming // RX bytes. fn fired(&self) { - let interval = A::ticks_from_ms(30); + let interval = self.alarm.ticks_from_ms(30); self.alarm.set_alarm(self.alarm.now(), interval); } } @@ -129,14 +130,20 @@ impl<'a, A: hil::time::Alarm<'a>> hil::gpio::Client for UartReceiveTimeout<'a, A impl<'a, A: hil::time::Alarm<'a>> hil::time::AlarmClient for UartReceiveTimeout<'a, A> { /// If the timer actually fires then we stopped receiving bytes. fn alarm(&self) { - self.uart.receive_abort(); + let _ = self.uart.receive_abort(); } } // Callbacks from the underlying UART driver. impl<'a, A: hil::time::Alarm<'a>> hil::uart::TransmitClient for UartReceiveTimeout<'a, A> { // Called when the UART TX has finished. - fn transmitted_buffer(&self, _buffer: &'static mut [u8], _tx_len: usize, _rval: ReturnCode) {} + fn transmitted_buffer( + &self, + _buffer: &'static mut [u8], + _tx_len: usize, + _rval: Result<(), ErrorCode>, + ) { + } } // Callbacks from the underlying UART driver. @@ -146,7 +153,7 @@ impl<'a, A: hil::time::Alarm<'a>> hil::uart::ReceiveClient for UartReceiveTimeou &self, _buffer: &'static mut [u8], _rx_len: usize, - _rval: ReturnCode, + _rval: Result<(), ErrorCode>, _error: hil::uart::Error, ) { } diff --git a/chips/bootloader_nrf52/Cargo.toml b/chips/bootloader_nrf52/Cargo.toml index a83f39d..15900d2 100644 --- a/chips/bootloader_nrf52/Cargo.toml +++ b/chips/bootloader_nrf52/Cargo.toml @@ -2,11 +2,12 @@ name = "bootloader_nrf52" version = "0.1.0" authors = ["Tock Project Developers "] +edition = "2021" [dependencies] -kernel = { git = "https://github.com/tock/tock", rev = "405417" } -nrf52 = { git = "https://github.com/tock/tock", rev = "405417" } -cortexm4 = { git = "https://github.com/tock/tock", rev = "405417" } +kernel = { git = "https://github.com/tock/tock", rev = "2ff6868" } +nrf52 = { git = "https://github.com/tock/tock", rev = "2ff6868" } +cortexm4 = { git = "https://github.com/tock/tock", rev = "2ff6868" } #kernel = { path = "../../../tock/kernel" } #nrf52 = { path = "../../../tock/chips/nrf52" } diff --git a/chips/bootloader_nrf52/src/bootloader_entry_doublereset.rs b/chips/bootloader_nrf52/src/bootloader_entry_doublereset.rs new file mode 100644 index 0000000..6c17117 --- /dev/null +++ b/chips/bootloader_nrf52/src/bootloader_entry_doublereset.rs @@ -0,0 +1,56 @@ +//! Decide to enter bootloader based on checking for rapid double resets. + +use kernel::utilities::cells::VolatileCell; +use kernel::utilities::StaticRef; + +/// Magic value for the double reset memory location indicating we should stay +/// in the bootloader. This value (and name) is taken from the Adafruit nRF52 +/// bootloader. +const DFU_DBL_RESET_MAGIC: u32 = 0x5A1AD5; + +/// Memory location we use as a flag for detecting a double reset. +/// +/// I have no idea why we use address 0x20007F7C, but that is what the Adafruit +/// nRF52 bootloader uses, so I copied it. +const DOUBLE_RESET_MEMORY_LOCATION: StaticRef> = + unsafe { StaticRef::new(0x20007F7C as *const VolatileCell) }; + +pub struct BootloaderEntryDoubleReset { + double_reset: StaticRef>, +} + +impl BootloaderEntryDoubleReset { + pub fn new() -> BootloaderEntryDoubleReset { + BootloaderEntryDoubleReset { + double_reset: DOUBLE_RESET_MEMORY_LOCATION, + } + } +} + +impl bootloader::interfaces::BootloaderEntry for BootloaderEntryDoubleReset { + fn stay_in_bootloader(&self) -> bool { + // If the retention flag is not set, then we check for the double reset + // memory location. If this is set to a magic value, then we got two + // resets in a short amount of time and we want to go into the + // bootloader. + if self.double_reset.get() == DFU_DBL_RESET_MAGIC { + self.double_reset.set(0); + return true; + } + + // If neither magic value is set, then we need to check if we just got + // the first of a double reset. We do this by setting our flag and + // entering a busy loop. If the busy loop finishes then we must not have + // gotten a second reset and we go to the kernel. If the busy loop + // doesn't finish because we got a reset in the middle, then the + // bootloader will restart and the check above should trigger. + self.double_reset.set(DFU_DBL_RESET_MAGIC); + for _ in 0..2000000 { + cortexm4::support::nop(); + } + self.double_reset.set(0); + + // Default to jumping out of the bootloader. + false + } +} diff --git a/chips/bootloader_nrf52/src/bootloader_entry_gpregret.rs b/chips/bootloader_nrf52/src/bootloader_entry_gpregret.rs index e8652ab..36e89fa 100644 --- a/chips/bootloader_nrf52/src/bootloader_entry_gpregret.rs +++ b/chips/bootloader_nrf52/src/bootloader_entry_gpregret.rs @@ -3,8 +3,8 @@ //! On the nRF52 the GPREGRET memory location is preserved on a soft reset. This //! allows the kernel to set this before resetting and resume in the bootloader. -use kernel::common::cells::VolatileCell; -use kernel::common::StaticRef; +use kernel::utilities::cells::VolatileCell; +use kernel::utilities::StaticRef; /// Magic value for the GPREGRET register that tells our bootloader to stay in /// bootloader mode. This value is not the same as the Adafruit nRF52 bootloader diff --git a/chips/bootloader_nrf52/src/lib.rs b/chips/bootloader_nrf52/src/lib.rs index f3fc34e..29aff88 100644 --- a/chips/bootloader_nrf52/src/lib.rs +++ b/chips/bootloader_nrf52/src/lib.rs @@ -1,9 +1,5 @@ -#![feature(const_fn, asm)] // #![forbid(unsafe_code)] #![no_std] -#[allow(unused_imports)] -#[macro_use(debug, debug_gpio)] -extern crate kernel; - +pub mod bootloader_entry_doublereset; pub mod bootloader_entry_gpregret; diff --git a/protocol/Cargo.lock b/protocol/Cargo.lock deleted file mode 100644 index 7a88b9e..0000000 --- a/protocol/Cargo.lock +++ /dev/null @@ -1,14 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "byteorder" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b" - -[[package]] -name = "tock-bootloader-protocol" -version = "0.2.2" -dependencies = [ - "byteorder", -] diff --git a/rust-toolchain b/rust-toolchain index cef4e16..c5295c7 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2021-01-07 +nightly-2023-07-30 diff --git a/tools/bootloader_attributes/Cargo.lock b/tools/bootloader_attributes/Cargo.lock deleted file mode 100644 index ddd1be9..0000000 --- a/tools/bootloader_attributes/Cargo.lock +++ /dev/null @@ -1,5 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "bootloader_attributes" -version = "0.1.0"