diff options
161 files changed, 9455 insertions, 9860 deletions
@@ -1,9 +1,10 @@ *.a -*.o -*.mo *.bin *.elf *.hex *.lst *.map +*.mo +*.o *~ +libraries/libtfm/tfm.h diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index d3946e7..0000000 --- a/.gitmodules +++ /dev/null @@ -1,9 +0,0 @@ -[submodule "libhal"] - path = libraries/libhal - url = git@git.cryptech.is:sw/libhal.git -[submodule "thirdparty/libtfm"] - path = libraries/thirdparty/libtfm - url = git@git.cryptech.is:sw/thirdparty/libtfm.git -[submodule "libraries/libcli"] - path = libraries/libcli - url = git@git.cryptech.is:user/ft/libcli @@ -1,5 +1,6 @@ -# Copyright (c) 2015-2016, NORDUnet A/S -# All rights reserved. +# Copyright (c) 2015-2017, NORDUnet A/S All rights reserved. +# Copyright: 2020, The Commons Conservancy Cryptech Project +# SPDX-License-Identifier: BSD-3-Clause # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are @@ -11,9 +12,9 @@ # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # -# - Neither the name of the NORDUnet nor the names of its contributors may -# be used to endorse or promote products derived from this software -# without specific prior written permission. +# - Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED @@ -27,27 +28,48 @@ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# A couple features that can be enabled at build time, but are not turned on +# by default: +# DO_PROFILING: Enable gmon profiling. See libraries/libprof/README.md for +# more details. +# DO_TASK_METRICS: Enable task metrics - average/max time between yields. This +# can be helpful when experimentally adding yields to improve responsiveness. +# +# To enable, run `make DO_PROFILING=1 DO_TASK_METRICS=1` +# (or DO_PROFILING=xyzzy - `make` just cares that the symbol is defined) + +# export all variables to child processes by default +.EXPORT_ALL_VARIABLES: + # absolute path, because we're going to be passing things to sub-makes -export TOPLEVEL = $(shell pwd) +TOPLEVEL = $(abspath .) +CRYPTECH_ROOT = $(abspath ../..) # define board: dev-bridge or alpha BOARD = TARGET_CRYPTECH_ALPHA -# Location of the Libraries folder from the STM32F4 Standard Peripheral Library LIBS_DIR = $(TOPLEVEL)/libraries MBED_DIR = $(LIBS_DIR)/mbed CMSIS_DIR = $(MBED_DIR)/targets/cmsis/TARGET_STM/TARGET_STM32F4 BOARD_DIR = $(CMSIS_DIR)/$(BOARD) -RTOS_DIR = $(MBED_DIR)/rtos -export LIBTFM_DIR = $(LIBS_DIR)/thirdparty/libtfm -export LIBHAL_DIR = $(LIBS_DIR)/libhal -export LIBCLI_DIR = $(LIBS_DIR)/libcli -export LIBS = $(MBED_DIR)/libstmf4.a $(RTOS_DIR)/librtos.a +LIBHAL_SRC = $(CRYPTECH_ROOT)/sw/libhal +LIBHAL_BLD = $(LIBS_DIR)/libhal + +LIBCLI_SRC = $(CRYPTECH_ROOT)/user/paul/libcli +LIBCLI_BLD = $(LIBS_DIR)/libcli + +LIBTFM_SRC = $(CRYPTECH_ROOT)/sw/thirdparty/libtfm +LIBTFM_BLD = $(LIBS_DIR)/libtfm + +LIBPROF_SRC = $(LIBS_DIR)/libprof +LIBPROF_BLD = $(LIBS_DIR)/libprof + +LIBS = $(MBED_DIR)/libstmf4.a # linker script -export LDSCRIPT = $(BOARD_DIR)/TOOLCHAIN_GCC_ARM/STM32F429BI.ld -export BOOTLOADER_LDSCRIPT = $(BOARD_DIR)/TOOLCHAIN_GCC_ARM/STM32F429BI_bootloader.ld +LDSCRIPT = $(BOARD_DIR)/TOOLCHAIN_GCC_ARM/STM32F429BI.ld +BOOTLOADER_LDSCRIPT = $(BOARD_DIR)/TOOLCHAIN_GCC_ARM/STM32F429BI_bootloader.ld # board-specific objects, to link into every project BOARD_OBJS = \ @@ -68,35 +90,50 @@ BOARD_OBJS += \ $(TOPLEVEL)/stm-sdram.o \ $(TOPLEVEL)/stm-flash.o endif -export BOARD_OBJS # cross-building tools PREFIX=arm-none-eabi- -export CC=$(PREFIX)gcc -export AS=$(PREFIX)as -export AR=$(PREFIX)ar -export OBJCOPY=$(PREFIX)objcopy -export OBJDUMP=$(PREFIX)objdump -export SIZE=$(PREFIX)size +CC=$(PREFIX)gcc +AS=$(PREFIX)as +AR=$(PREFIX)ar +OBJCOPY=$(PREFIX)objcopy +OBJDUMP=$(PREFIX)objdump +SIZE=$(PREFIX)size + +# The Alpha is a development platform, so set GCC optimization to a +# level suitable for debugging. Recent versions of GCC have a special +# optimization setting -Og for exactly this purpose, so we use it, +# along with the flag to enable gdb symbols. Note that some libraries +# (in particular, libtfm) may need different optimization settings, +# which is why this needs to remain a separate makefile variable. +# +# If you really want optimization without debugging support, try -O2 +# or -O3. + +STM32_CFLAGS_OPTIMIZATION ?= -ggdb -Og # whew, that's a lot of cflags -CFLAGS = -ggdb -O2 -Wall -Warray-bounds #-Wextra +CFLAGS = $(STM32_CFLAGS_OPTIMIZATION) -Wall -Warray-bounds -Wextra CFLAGS += -mcpu=cortex-m4 -mthumb -mlittle-endian -mthumb-interwork CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16 CFLAGS += -DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F429xx CFLAGS += -D__CORTEX_M4 -DTARGET_STM -DTARGET_STM32F4 -DTARGET_STM32F429ZI -DTOOLCHAIN_GCC -D__FPU_PRESENT=1 -D$(BOARD) +CFLAGS += -DENABLE_WEAK_FUNCTIONS CFLAGS += -ffunction-sections -fdata-sections -Wl,--gc-sections CFLAGS += -std=c99 -CFLAGS += -I $(TOPLEVEL) -CFLAGS += -I $(MBED_DIR)/api -CFLAGS += -I $(MBED_DIR)/rtos/rtos -CFLAGS += -I $(MBED_DIR)/rtos/rtx/TARGET_CORTEX_M -CFLAGS += -I $(MBED_DIR)/targets/cmsis -CFLAGS += -I $(MBED_DIR)/targets/cmsis/TARGET_STM/TARGET_STM32F4 -CFLAGS += -I $(MBED_DIR)/targets/cmsis/TARGET_STM/TARGET_STM32F4/$(BOARD) -CFLAGS += -I $(MBED_DIR)/targets/hal/TARGET_STM/TARGET_STM32F4 -CFLAGS += -I $(MBED_DIR)/targets/hal/TARGET_STM/TARGET_STM32F4/$(BOARD) -export CFLAGS +CFLAGS += -I$(TOPLEVEL) +CFLAGS += -I$(MBED_DIR)/api +CFLAGS += -I$(MBED_DIR)/targets/cmsis +CFLAGS += -I$(MBED_DIR)/targets/cmsis/TARGET_STM/TARGET_STM32F4 +CFLAGS += -I$(MBED_DIR)/targets/cmsis/TARGET_STM/TARGET_STM32F4/$(BOARD) +CFLAGS += -I$(MBED_DIR)/targets/hal/TARGET_STM/TARGET_STM32F4 +CFLAGS += -I$(MBED_DIR)/targets/hal/TARGET_STM/TARGET_STM32F4/$(BOARD) +ifdef DO_TASK_METRICS +CFLAGS += -DDO_TASK_METRICS +endif +ifdef DO_TIMING +CFLAGS += -DDO_TIMING +endif %.o : %.c $(CC) $(CFLAGS) -c -o $@ $< @@ -104,59 +141,72 @@ export CFLAGS %.o : %.S $(CC) $(CFLAGS) -c -o $@ $< -all: board-test cli-test libhal-test hsm - -init: - git submodule update --init --recursive --remote +ifdef DO_PROFILING +CFLAGS += -pg -DDO_PROFILING +LIBS += $(LIBPROF_BLD)/libprof.a +all: hsm +else +all: board-test cli-test libhal-test hsm bootloader +endif -$(MBED_DIR)/libstmf4.a: +$(MBED_DIR)/libstmf4.a: .FORCE $(MAKE) -C $(MBED_DIR) -board-test: $(BOARD_OBJS) $(LIBS) +board-test: $(BOARD_OBJS) $(LIBS) .FORCE $(MAKE) -C projects/board-test -cli-test: $(BOARD_OBJS) $(LIBS) $(LIBCLI_DIR)/libcli.a +cli-test: $(BOARD_OBJS) $(LIBS) $(LIBCLI_BLD)/libcli.a $(LIBHAL_BLD)/libhal.a .FORCE $(MAKE) -C projects/cli-test -$(RTOS_DIR)/librtos.a: - $(MAKE) -C $(RTOS_DIR) +$(LIBTFM_BLD)/libtfm.a: .FORCE + $(MAKE) -C $(LIBTFM_BLD) PREFIX=$(PREFIX) -rtos-test: $(RTOS_OBJS) $(LIBS) - $(MAKE) -C projects/rtos-test +$(LIBHAL_BLD)/libhal.a: $(LIBTFM_BLD)/libtfm.a .FORCE + $(MAKE) -C $(LIBHAL_BLD) IO_BUS=fmc RPC_MODE=server RPC_TRANSPORT=serial KS=flash HASH_CORES=yes libhal.a -$(LIBTFM_DIR)/libtfm.a: - $(MAKE) -C $(LIBTFM_DIR) PREFIX=$(PREFIX) +$(LIBCLI_BLD)/libcli.a: .FORCE + $(MAKE) -C $(LIBCLI_BLD) -$(LIBHAL_DIR)/libhal.a: $(LIBTFM_DIR)/libtfm.a - $(MAKE) -C $(LIBHAL_DIR) IO_BUS=fmc RPC_SERVER=yes RPC_TRANSPORT=serial KS=volatile libhal.a +$(LIBPROF_BLD)/libprof.a: .FORCE + $(MAKE) -C $(LIBPROF_BLD) -$(LIBCLI_DIR)/libcli.a: - $(MAKE) -C $(LIBCLI_DIR) - -libhal-test: $(BOARD_OBJS) $(LIBS) $(LIBHAL_DIR)/libhal.a +libhal-test: $(BOARD_OBJS) $(LIBS) $(LIBHAL_BLD)/libhal.a .FORCE $(MAKE) -C projects/libhal-test -hsm: $(BOARD_OBJS) $(LIBS) $(LIBHAL_DIR)/libhal.a +hsm: $(BOARD_OBJS) $(LIBS) $(LIBHAL_BLD)/libhal.a $(LIBCLI_BLD)/libcli.a .FORCE $(MAKE) -C projects/hsm -bootloader: $(BOARD_OBJS) $(LIBS) +bootloader: $(BOARD_OBJS) $(LIBS) $(LIBHAL_BLD)/libhal.a .FORCE $(MAKE) -C projects/bootloader +modexpng-test: $(BOARD_OBJS) $(LIBS) .FORCE + $(MAKE) -C projects/modexpng-test + # don't automatically delete objects, to avoid a lot of unnecessary rebuilding .SECONDARY: $(BOARD_OBJS) -.PHONY: board-test rtos-test libhal-test cli-test +.PHONY: board-test libhal-test cli-test hsm bootloader + +# We don't (and shouldn't) know enough about libraries and projects to +# know whether they need rebuilding or not, so we let their Makefiles +# decide that. Which means we always need to run all the sub-makes. +# We could do this with .PHONY (which is supposedly more "efficient") +# but using a .FORCE target is simpler once one takes inter-library +# dependency specifications into account. + +.FORCE: # (sic) clean: rm -f $(BOARD_OBJS) + $(MAKE) -C $(LIBHAL_BLD) clean $(MAKE) -C projects/board-test clean $(MAKE) -C projects/cli-test clean - $(MAKE) -C projects/rtos-test clean $(MAKE) -C projects/libhal-test clean $(MAKE) -C projects/hsm clean + $(MAKE) -C projects/bootloader clean distclean: clean $(MAKE) -C $(MBED_DIR) clean - $(MAKE) -C $(RTOS_DIR) clean - $(MAKE) -C $(LIBHAL_DIR) clean - $(MAKE) -C $(LIBTFM_DIR) clean + $(MAKE) -C $(LIBTFM_BLD) clean + $(MAKE) -C $(LIBCLI_BLD) clean + $(MAKE) -C $(LIBPROF_BLD) clean @@ -1,80 +1,127 @@ -STM32 software for dev-bridge/Alpha board -========================================= +STM32 firmware for Cryptech Alpha board +======================================= -The dev-bridge board is a daughterboard for the Novena, which talks to the -Novena's FPGA through the high-speed expansion connector. +The Alpha board is our first full prototype for an open-source hardware +security module (HSM). It is a custom board with an STM32 Cortex-M4 +microcontroller and an Artix-7 FPGA, flash-based keystore, separate memory +for the Key Encryption Key, etc. See the `hardware` repository for +schematics and production files. See the wiki for design documents. -The Alpha board is a stand-alone board with an Artix-7 FPGA, a STM32 Cortex-M4 -microcontroller, two USB interfaces etc. - -See user/ft/stm32-dev-bridge/hardware/rev01 for schematics of the bridge -board. There will be more information on the wiki shortly. +The code in this repository builds the firmware that provides the HSM +functionality on the Alpha board. +There is some residual code here to support the "dev-bridge" board, a +daughterboard for the Novena, which talks to the Novena's FPGA through the +high-speed expansion connector. Only a few of these boards were ever made, +and all development/testing ceased as soon as the Alpha became available, +so the dev-bridge should be considered deprecated, and support may be +removed in the future. Copyrights ========== The license for all work done on this in the CrypTech project is a -3-clause BSD license (see LICENSE.txt for details). Some files have -been generated using the STMicroelectronics initialization code -generator STM32CubeMX and thus have additional copyright header(s). +3-clause BSD license. + +Third-party components, as well as code generated using the +STMicroelectronics initialization code generator STM32CubeMX, or adapted +from STM example/support code, may have different licensing, detailed +below. + +Components +========== + +Libraries +--------- + +* `mbed` - A stripped down copy of the ARM CMSIS library, copied from the + mbed github (see `libraries/mbed/README.txt` for details). The bulk of + this library is covered under 3-clause BSD licenses from either ARM or + STMicroelectronics, but one file is covered under an Apache license from + ARM. + +* `libhal` - Build directory for our own Hardware Adaption Library + (hardware-independent Cryptech components). Source is expected to be in + `sw/libhal`. + +* `libtfm` - Build directory for "Tom's Fast Math", which is used heavily + for bignum math in the RSA and ECDSA code. This code is covered under an + unrestricted public domain license, and source is expected to be in + `sw/thirdparty/libtfm`. + +* `libcli` - Build directory for a third-party Command Line Interface + library. The source is not currently under `sw/thirdparty` because the + license is LGPLv2.1; we are negotiating to see if we can get a + BSD-compatible license for it. + +* `libprof` - A port of the `gmon` profiling package, to be used in + development only, not in production code (obviously). The licensing is a + mix of BSD and "Cygwin license", which now seems to be LGPLv3. + +Projects +-------- -The "Noise generator" and "Amplifier" parts of the circuit diagram are -copied from Benedikt Stockebrand's ARRGH project. ARRGH copyright -statement is included in LICENSE.txt. +These directories build different firmware images for the Alpha board. -A stripped down copy of the ARM CMSIS library version 3.20 is included -in the Drivers/CMSIS/ directory. Unused parts (and documentation etc.) -have been removed, but every attempt have been made to keep any -licensing information intact. See in particular the file -Drivers/CMSIS/CMSIS END USER LICENCE AGREEMENT.pdf. +* `hsm` - Firmware providing HSM functionality. Clients communicate via + RPC requests on the USER USB port, or interactively on the MGMT USB + port. -A full copy of the STM32F4xx HAL Drivers is included in the -Drivers/STM32F4xx_HAL_Driver/ directory. +* `bootloader` - The first thing that runs on the device. It either starts + the primary firmware, or installs new firmware. +* `board-test` - Tests of hardware components. + +* `cli-test` - Test of the CLI itself, plus some interactive tests of + hardware components. Duplicates way too much of the HSM CLI. + +* `libhal-test` - A framework for running the libhal component + tests. Hasn't been run in a while, probably still works. Building ======== -The following packages need to be installed (on Ubuntu 14.04): +Our primary build environments are Debian and Ubuntu, but this should work +on any system with Gnu tools installed. - apt-get install gcc-arm-none-eabi gdb-arm-none-eabi openocd +The following packages need to be installed: -To build the source code, issue "make" from the top level directory -(where this file is). The first time, this will build the complete STM -CMSIS library. A subsequent "make clean" will *not* clean away the CMSIS -library, but a "make distclean" will. + $ apt-get install gcc-arm-none-eabi gdb-arm-none-eabi openocd +The Makefile assumes that all Cryptech repositories have been fetched into +a canonical directory structure, e.g. `libhal` and `thirdparty` are +siblings to this directory, under `sw`. + +To build the source code, issue `make` from the top level directory +(where this file is). The first time, this will build the complete STM +CMSIS library. A subsequent `make clean` will *not* clean away the CMSIS +library, but a `make distclean` will. Installing ========== -Do "bin/flash-target" from the top level directory (where this file is) +Do `bin/flash-target` from the top level directory (where this file is) to flash a built image into the microcontroller. See the section ST-LINK below for information about the actual hardware programming device needed. -Example loading the bootloader and the led-test firmware to get some LEDs -flashing: +Example loading the HSM firmware: - $ make bootloader board-test - $ ./bin/flash-target projects/board-test/led-test - $ ./bin/flash-target projects/bootloader/bootloader + $ make hsm + $ ./bin/flash-target projects/hsm/hsm At this point, the STM32 will reset into the bootloader which flashes the -blue LED five times in one second, and then execution of the LED test -firmware will begin. The LED test firmware will flash the green, yellow, -red and blue LEDs in order until the end of time. +blue LED five times in one second, and then jumps to the primary firmware. Once the bootloader is installed, regular firmware can be loaded without an ST-LINK cable like this: - $ ./bin/dfu projects/board-test/led-test.bin + $ cryptech_upload --firmware -i projects/hsm/hsm.bin Then reboot the Alpha board. - ST-LINK -======= +------- + To program the MCU, an ST-LINK adapter is used. The cheapest way to get one is to buy an evaluation board with an ST-LINK integrated, and pinouts to program external chips. This should work with any evaluation board from @@ -86,7 +133,7 @@ printed on the circuit board. The pin-outs is shown on the circuit board (follow the thin white line from J1 to the white box with STM32_SWD written in it). From left to right, the pins are - 3V3, CLK, GND, I/O, NRST and N/C + 3V3, CLK, GND, I/O, NRST and N/C This matches the pin-out on the DISCO and NUCLEO boards we have tried. @@ -94,34 +141,30 @@ First remove the pair of ST-LINK jumpers (CN4 on the DISCO, CN2 on the NUCLEO). Then find the 6-pin SWD header on the left of the STM board (CN2 on the DISCO, CN4 on the NUCLEO), and connect them to the Alpha board: - NUCLEO / DISCO CRYPTECH ALPHA - -------------- -------------- -* 1 VDD_TARGET <-> 3V3 -* 2 SWCLK / T_JTCK <-> CLK -* 3 GND <-> GND -* 4 SWDIO / T_JTMS <-> IO -* 5 NRST / T_NRST <-> NRST - -N/C (pin 6) means Not Connected. + NUCLEO / DISCO CRYPTECH ALPHA + -------------- -------------- + * 1 VDD_TARGET <-> 3V3 + * 2 SWCLK / T_JTCK <-> CLK + * 3 GND <-> GND + * 4 SWDIO / T_JTMS <-> IO + * 5 NRST / T_NRST <-> NRST + * 6 N/C The Alpha board should be powered on before attempting to flash it. - Debugging the firmware -====================== - -This site shows several ways to use various debuggers to debug the -firmware in an STM32: +---------------------- - http://fun-tech.se/stm32/OpenOCD/gdb.php +[This site](http://fun-tech.se/stm32/OpenOCD/gdb.php) shows several ways +to use various debuggers to debug the firmware in an STM32. There is a shell script called 'bin/debug' that starts an OpenOCD server and GDB. Example: - $ ./bin/debug projects/board-test/led-test + $ ./bin/debug projects/hsm/hsm -Once in GDB, issue "monitor reset halt" to reset the STM32 before debugging. +Once in GDB, issue `monitor reset halt` to reset the STM32 before debugging. Remember that the first code to run will be the bootloader, but if you do -e.g. "break main" and "continue" you will end up in led-test main() after -the bootloader has jumped there. +e.g. `break main` and `continue` you will end up in main() after the +bootloader has jumped there. @@ -6,11 +6,21 @@ OPENOCD=openocd OPENOCD_BOARD_DIR=/usr/share/openocd/scripts/board OPENOCD_PROC_FILE=stm32f4discovery.cfg if [ "x`lsusb -d 0483:374b`" != "x" ]; then - OPENOCD_PROC_FILE=st_nucleo_f4.cfg + for fn in st_nucleo_f4.cfg st_nucleo_f401re.cfg; do + if [ -f "$OPENOCD_BOARD_DIR/$fn" ]; then + OPENOCD_PROC_FILE="$fn" + fi + done fi $OPENOCD -f $OPENOCD_BOARD_DIR/$OPENOCD_PROC_FILE & -GDB=arm-none-eabi-gdb +for gdb in gdb-multiarch arm-none-eabi-gdb; do + if command -v $gdb &>/dev/null; then + GDB=$gdb + break + fi +done + $GDB -ex "target remote localhost:3333" -ex "set remote hardware-breakpoint-limit 6" -ex "set remote hardware-watchpoint-limit 4" $PROJ.elf kill -9 $(pidof $OPENOCD) @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # # Copyright (c) 2016, NORDUnet A/S All rights reserved. # @@ -43,7 +43,7 @@ import struct import serial import argparse -from binascii import crc32 +from binascii import crc32, hexlify CHUNK_SIZE = 4096 @@ -77,23 +77,23 @@ def parse_args(): def _write(dst, data): for i in range(len(data)): - dst.write(data[i]) + dst.write(data[i:i+1]) time.sleep(0.1) if len(data) == 4: - print("Wrote 0x{:02x}{:02x}{:02x}{:02x}".format(ord(data[0]), ord(data[1]), ord(data[2]), ord(data[3]))) + print("Wrote 0x{}".format(hexlify(data).decode("ascii"))) else: print("Wrote {!r}".format(data)) def _read(dst, verbose=False): - res = '' + res = b'' while True: x = dst.read(1) if not x: break res += x if res and verbose: - print ("Read {!r}".format(res)) + print("Read {!r}".format(res)) return res @@ -111,7 +111,7 @@ def send_file(filename, args): except serial.SerialException: time.sleep(0.2) continue - dst.write('\r') + dst.write(b'\r') response = _read(dst, args.verbose) if 'OK' in response: dst.timeout=2 @@ -137,7 +137,7 @@ def send_file(filename, args): if len(ack_bytes) == 4: break print('ERROR: Did not receive an ACK, got {!r}'.format(ack_bytes)) - dst.write('\r') # eventually get back to the CLI prompt + dst.write(b'\r') # eventually get back to the CLI prompt ack = struct.unpack('<I', ack_bytes)[0] if ack != counter + 1: print('ERROR: Did not receive the expected counter as ACK (got {!r}/{!r}, not {!r})'.format(ack, ack_bytes, counter)) diff --git a/bin/flash-target b/bin/flash-target index 0d60c85..336bae1 100755 --- a/bin/flash-target +++ b/bin/flash-target @@ -22,7 +22,11 @@ OPENOCD_BOARD_DIR=/usr/share/openocd/scripts/board # OPENOCD_PROC_FILE=stm32f4discovery.cfg if [ "x`lsusb -d 0483:374b`" != "x" ]; then - OPENOCD_PROC_FILE=st_nucleo_f4.cfg + for fn in st_nucleo_f4.cfg st_nucleo_f401re.cfg; do + if [ -f "$OPENOCD_BOARD_DIR/$fn" ]; then + OPENOCD_PROC_FILE="$fn" + fi + done fi $OPENOCD -f $OPENOCD_BOARD_DIR/$OPENOCD_PROC_FILE -c "program $PROJ.elf verify reset exit" @@ -21,7 +21,11 @@ OPENOCD_BOARD_DIR=/usr/share/openocd/scripts/board # OPENOCD_PROC_FILE=stm32f4discovery.cfg if [ "x`lsusb -d 0483:374b`" != "x" ]; then - OPENOCD_PROC_FILE=st_nucleo_f4.cfg + for fn in st_nucleo_f4.cfg st_nucleo_f401re.cfg; do + if [ -f "$OPENOCD_BOARD_DIR/$fn" ]; then + OPENOCD_PROC_FILE="$fn" + fi + done fi $OPENOCD -f $OPENOCD_BOARD_DIR/$OPENOCD_PROC_FILE -c "init" -c "reset run" -c "exit" diff --git a/libraries/libcli b/libraries/libcli deleted file mode 160000 -Subproject 1a5727c568e36b927ef2088b2b02bae4c84933f diff --git a/libraries/libcli/Makefile b/libraries/libcli/Makefile new file mode 100644 index 0000000..6bc805a --- /dev/null +++ b/libraries/libcli/Makefile @@ -0,0 +1,24 @@ +vpath %.c ${LIBCLI_SRC} +vpath %.h ${LIBCLI_SRC} + +CFLAGS += \ + -DDO_CRYPT=0 \ + -DDO_FILE=0 \ + -DDO_FILTER=0 \ + -DDO_IDLE_TIMEOUT=0 \ + -DDO_MALLOC=0 \ + -DDO_PRINT_BUFFERED=0 \ + -DDO_REGULAR=0 \ + -DDO_SOCKET=0 \ + -DDO_TAB_COMPLETION=1 \ + -DDO_TELNET=0 \ + -DCLI_MAX_LINE_WORDS=36 +CFLAGS += -Wno-unused-parameter + +all: libcli.a + +libcli.a: libcli.o + $(AR) rcs $@ $^ + +clean: + rm -f libcli.[ao] diff --git a/libraries/libhal b/libraries/libhal deleted file mode 160000 -Subproject 60cce0124f2fc3eddca03ed3950da9238247a61 diff --git a/libraries/libhal/Makefile b/libraries/libhal/Makefile new file mode 100644 index 0000000..950e620 --- /dev/null +++ b/libraries/libhal/Makefile @@ -0,0 +1,8 @@ +vpath %.c ${LIBHAL_SRC} +vpath %.h ${LIBHAL_SRC} + +CFLAGS += -Wno-missing-field-initializers -Wno-unused-parameter +CFLAGS += -DHAL_STATIC_CLIENT_STATE_BLOCKS=25 +CFLAGS += -DHAL_IO_TIMEOUT=10000000 + +include ${LIBHAL_SRC}/Makefile diff --git a/libraries/libhal/tests/Makefile b/libraries/libhal/tests/Makefile new file mode 100644 index 0000000..e148174 --- /dev/null +++ b/libraries/libhal/tests/Makefile @@ -0,0 +1,4 @@ +vpath %.c ${LIBHAL_SRC}/tests +vpath %.h ${LIBHAL_SRC}/tests + +include ${LIBHAL_SRC}/tests/Makefile diff --git a/libraries/libhal/utils/Makefile b/libraries/libhal/utils/Makefile new file mode 100644 index 0000000..6f21c2f --- /dev/null +++ b/libraries/libhal/utils/Makefile @@ -0,0 +1,4 @@ +vpath %.c ${LIBHAL_SRC}/utils +vpath %.h ${LIBHAL_SRC}/utils + +include ${LIBHAL_SRC}/utils/Makefile diff --git a/libraries/libprof/Makefile b/libraries/libprof/Makefile new file mode 100644 index 0000000..28bedea --- /dev/null +++ b/libraries/libprof/Makefile @@ -0,0 +1,24 @@ +LIB = libprof.a + +OBJS = gmon.o profiler.o memfunc.o + +# Don't profile the profiling code, because that way lies madness (and recursion). +CFLAGS := $(subst -pg,,$(CFLAGS)) + +all: $(LIB) + +# But do profile the mem functions +memfunc.o: memfunc.c + $(CC) $(CFLAGS) -pg -c -o $@ $< + +%.o : %.c + $(CC) $(CFLAGS) -c -o $@ $< + +%.o : %.S + $(CC) $(CFLAGS) -c -o $@ $< + +$(LIB): $(OBJS) + $(AR) -r $@ $^ + +clean: + rm -f $(OBJS) $(LIB) diff --git a/libraries/libprof/README.md b/libraries/libprof/README.md new file mode 100644 index 0000000..d464644 --- /dev/null +++ b/libraries/libprof/README.md @@ -0,0 +1,65 @@ +Profiling the Cryptech Alpha +============================ + +Origin +------ + +This code was copied from https://github.com/ErichStyger/mcuoneclipse.git, +directory `Examples/KDS/FRDM-K64F120M/FRDM-K64F_Profiling/Profiling`, commit +9b7eedddd8b24968128582aedc63be95b61f782c, dated Mon Jan 9 16:56:17 2017 +0100. + +References +---------- + +I recommend reading both of these to understand how the profiling code works. + +1. [Tutorial: Using GNU Profiling (gprof) with ARM Cortex-M](https://mcuoneclipse.com/2015/08/23/tutorial-using-gnu-profiling-gprof-with-arm-cortex-m/) + +2. [Semihosting with ARM, GCC, and OpenOCD](http://bgamari.github.io/posts/2014-10-31-semihosting.html) + +How to build +------------ + +From the top level, run + + $ make DO_PROFILING=1 hsm + +By default, all code is profiled, *except* the profiling code itself, +because that would cause fatal recursion. + +How to run +---------- + +You need to start OpenOCD on the host, and enable semihosting, at least +before you try to use it as a remote file system. + +I recommend executing the following in the `projects/hsm` directory, so that +`gmon.out` ends up in the same directory as `hsm.elf`. + +Start the debugger: + + $ ../../bin/debug hsm + +In another window, connect to OpenOCD: + + $ telnet localhost 4444 + +In the OpenOCD console, enable semihosting: + + > arm semihosting enable + > exit + +Then connect to the Cryptech management console: + + $ cryptech_console + +In the Cryptech console, type `profile start`, then start the unit test or +whatever will be exercising the hsm. Afterwards, in the console, type +`profile stop`. + +After invoking `profile stop`, it can take several minutes to write +`gmon.out` over OpenOCD to the host. + +In the `projects/hsm` directory, run `gprof` to analyse the `gmon.out` file: + + $ gprof hsm.elf >gprof.txt diff --git a/libraries/libprof/gmon.c b/libraries/libprof/gmon.c new file mode 100644 index 0000000..a34f1a2 --- /dev/null +++ b/libraries/libprof/gmon.c @@ -0,0 +1,261 @@ +/*- + * Copyright (c) 1983, 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This file is taken from Cygwin distribution. Please keep it in sync. + * The differences should be within __MINGW32__ guard. + */ + +#include <fcntl.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include "gmon.h" + +#define bzero(ptr,size) memset (ptr, 0, size); +#define ERR(s) write(2, s, sizeof(s)) + +/* profiling frequency. (No larger than 1000) */ +/* Note this doesn't set the frequency, but merely describes it. */ +#define PROF_HZ 1000 + +struct gmonparam _gmonparam = { off, NULL, 0, NULL, 0, NULL, 0, 0, 0, 0, 0}; + +void monstartup(size_t lowpc, size_t highpc) +{ + static char already_setup = 0; + struct gmonparam *p = &_gmonparam; + + if (already_setup) { + /* reinitialize counters and arcs */ + bzero(p->kcount, p->kcountsize); + bzero(p->froms, p->fromssize); + bzero(p->tos, p->tossize); + p->state = on; + return; + } + already_setup = 1; + + /* enable semihosting, for eventual output */ + extern void initialise_monitor_handles(void); + initialise_monitor_handles(); + + /* + * round lowpc and highpc to multiples of the density we're using + * so the rest of the scaling (here and in gprof) stays in ints. + */ + p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER)); + p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER)); + p->textsize = p->highpc - p->lowpc; + p->kcountsize = p->textsize / HISTFRACTION; + p->fromssize = p->textsize / HASHFRACTION; + p->tolimit = p->textsize * ARCDENSITY / 100; + if (p->tolimit < MINARCS) { + p->tolimit = MINARCS; + } else if (p->tolimit > MAXARCS) { + p->tolimit = MAXARCS; + } + p->tossize = p->tolimit * sizeof(struct tostruct); + + extern void *hal_allocate_static_memory(const size_t size); + void *cp = hal_allocate_static_memory(p->kcountsize + p->fromssize + p->tossize); + if (cp == NULL) { + ERR("monstartup: out of memory\n"); + return; + } + + bzero(cp, p->kcountsize + p->fromssize + p->tossize); + p->kcount = (unsigned short *)cp; cp += p->kcountsize; + p->froms = (unsigned short *)cp; cp += p->fromssize; + p->tos = (struct tostruct *)cp; + + p->state = on; +} + +void _mcleanup(void) +{ + static const char gmon_out[] = "gmon.out"; + int fd; + struct gmonparam *p = &_gmonparam; + + if (p->state == err) { + ERR("_mcleanup: tos overflow\n"); + } + + fd = open(gmon_out , O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0666); + if (fd < 0) { + perror( gmon_out ); + return; + } + + struct gmonhdr hdr = { + .lpc = p->lowpc, + .hpc = p->highpc, + .ncnt = p->kcountsize + sizeof(struct gmonhdr), + .version = GMONVERSION, + .profrate = PROF_HZ + }; + write(fd, &hdr, sizeof(hdr)); + + write(fd, p->kcount, p->kcountsize); + + for (size_t fromindex = 0; fromindex < p->fromssize / sizeof(*p->froms); fromindex++) { + size_t frompc = p->lowpc + fromindex * HASHFRACTION * sizeof(*p->froms); + for (size_t toindex = p->froms[fromindex]; toindex != 0; toindex = p->tos[toindex].next) { + struct rawarc arc = { + .frompc = frompc, + .selfpc = p->tos[toindex].selfpc, + .count = p->tos[toindex].count + }; + write(fd, &arc, sizeof(arc)); + } + } + + close(fd); +} + +void _mcount_internal(size_t frompc, size_t selfpc) +{ + register unsigned short *fromptr; + register struct tostruct *top; + register unsigned short toindex; + struct gmonparam *p = &_gmonparam; + + /* + * check that we are profiling and that we aren't recursively invoked. + * check that frompc is a reasonable pc value. + */ + if (p->state != on || (frompc -= p->lowpc) > p->textsize) { + return; + } + + fromptr = &p->froms[frompc / (HASHFRACTION * sizeof(*p->froms))]; + toindex = *fromptr; /* get froms[] value */ + + if (toindex == 0) { /* we haven't seen this caller before */ + toindex = ++p->tos[0].next; /* index of the last used record in the array */ + if (toindex >= p->tolimit) { /* more tos[] entries than we can handle! */ + overflow: + p->state = err; /* halt further profiling */ +#define TOLIMIT "mcount: tos overflow\n" + write (2, TOLIMIT, sizeof(TOLIMIT)); + return; + } + *fromptr = toindex; /* store new 'to' value into froms[] */ + top = &p->tos[toindex]; + top->selfpc = selfpc; + top->count = 1; + top->next = 0; + } + + else { /* we've seen this caller before */ + top = &p->tos[toindex]; + if (top->selfpc == selfpc) { + /* + * arc at front of chain; usual case. + */ + top->count++; + } + + else { + /* + * have to go looking down chain for it. + * top points to what we are looking at, + * prevtop points to previous top. + * we know it is not at the head of the chain. + */ + while (1) { + if (top->next == 0) { + /* + * top is end of the chain and none of the chain + * had top->selfpc == selfpc. + * so we allocate a new tostruct + * and put it at the head of the chain. + */ + toindex = ++p->tos[0].next; + if (toindex >= p->tolimit) { + goto overflow; + } + top = &p->tos[toindex]; + top->selfpc = selfpc; + top->count = 1; + top->next = *fromptr; + *fromptr = toindex; + break; + } + + else { + /* + * otherwise, check the next arc on the chain. + */ + register struct tostruct *prevtop = top; + top = &p->tos[top->next]; + if (top->selfpc == selfpc) { + /* + * there it is. + * increment its count + * move it to the head of the chain. + */ + top->count++; + toindex = prevtop->next; + prevtop->next = top->next; + top->next = *fromptr; + *fromptr = toindex; + break; + } + } + } + } + } + + return; /* normal return restores saved registers */ +} + +#include <stdint.h> +#include "stm32f4xx_hal.h" /* __get_MSP */ + +/* called from the SysTick handler */ +void profil_callback(void) +{ + struct gmonparam *p = &_gmonparam; + + if (p->state == on) { + /* The interrupt mechanism pushes xPSR, PC, LR, R12, and R3-R0 onto the + * stack, so PC is the 6th word from the top at that point. However, the + * normal function entry code pushes registers as well, so the stack + * offset right now depends on the call tree that got us here. + */ + size_t pc = (size_t)((uint32_t *)__get_MSP())[6 + 6]; + if ((pc -= p->lowpc) < p->textsize) { + size_t idx = pc / (HISTFRACTION * sizeof(*p->kcount)); + p->kcount[idx]++; + } + } +} diff --git a/libraries/libprof/gmon.h b/libraries/libprof/gmon.h new file mode 100644 index 0000000..9016502 --- /dev/null +++ b/libraries/libprof/gmon.h @@ -0,0 +1,148 @@ +/* $OpenBSD: gmon.h,v 1.3 1996/04/21 22:31:46 deraadt Exp $ */ +/* $NetBSD: gmon.h,v 1.5 1996/04/09 20:55:30 cgd Exp $ */ + +/*- + * Copyright (c) 1982, 1986, 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)gmon.h 8.2 (Berkeley) 1/4/94 + */ + +/* + * This file is taken from Cygwin distribution. Please keep it in sync. + * The differences should be within __MINGW32__ guard. + */ + +#ifndef _SYS_GMON_H_ +#define _SYS_GMON_H_ + +/* + * Structure prepended to gmon.out profiling data file. + */ +struct gmonhdr { + size_t lpc; /* base pc address of sample buffer */ + size_t hpc; /* max pc address of sampled buffer */ + int ncnt; /* size of sample buffer (plus this header) */ + int version; /* version number */ + int profrate; /* profiling clock rate */ + int spare[3]; /* reserved */ +}; +#define GMONVERSION 0x00051879 + +/* + * histogram counters are unsigned shorts (according to the kernel). + */ +#define HISTCOUNTER unsigned short + +/* + * fraction of text space to allocate for histogram counters here, 1/2 + */ +//#define HISTFRACTION 2 +#define HISTFRACTION 1 + +/* + * Fraction of text space to allocate for from hash buckets. + * The value of HASHFRACTION is based on the minimum number of bytes + * of separation between two subroutine call points in the object code. + * Given MIN_SUBR_SEPARATION bytes of separation the value of + * HASHFRACTION is calculated as: + * + * HASHFRACTION = MIN_SUBR_SEPARATION / (2 * sizeof(short) - 1); + * + * For example, on the VAX, the shortest two call sequence is: + * + * calls $0,(r0) + * calls $0,(r0) + * + * which is separated by only three bytes, thus HASHFRACTION is + * calculated as: + * + * HASHFRACTION = 3 / (2 * 2 - 1) = 1 + * + * Note that the division above rounds down, thus if MIN_SUBR_FRACTION + * is less than three, this algorithm will not work! + * + * In practice, however, call instructions are rarely at a minimal + * distance. Hence, we will define HASHFRACTION to be 2 across all + * architectures. This saves a reasonable amount of space for + * profiling data structures without (in practice) sacrificing + * any granularity. + */ +//#define HASHFRACTION 2 +#define HASHFRACTION 1 + +/* + * percent of text space to allocate for tostructs with a minimum. + */ +#define ARCDENSITY 2 /* this is in percentage, relative to text size! */ +#define MINARCS 50 +#define MAXARCS ((1 << (8 * sizeof(HISTCOUNTER))) - 2) + +struct tostruct { + size_t selfpc; /* callee address. The caller address is in froms[] array which points to tos[] array */ + unsigned long count; /* how many times it has been called */ + unsigned short next; /* next entry in hash table. For tos[0] this is the index of the last used entry */ + unsigned short pad; /* additional padding bytes, to have entries 4byte aligned */ +}; + +/* + * a raw arc, with pointers to the calling site and + * the called site and a count. + */ +struct rawarc { + size_t frompc; + size_t selfpc; + long count; +}; + +/* + * general rounding functions. + */ +#define ROUNDDOWN(x,y) (((x)/(y))*(y)) +#define ROUNDUP(x,y) ((((x)+(y)-1)/(y))*(y)) + +/* + * The profiling data structures are housed in this structure. + */ +struct gmonparam { + enum { off, on, err } state; + unsigned short *kcount; /* histogram PC sample array */ + size_t kcountsize; /* size of kcount[] array in bytes */ + unsigned short *froms; /* array of hashed 'from' addresses. The 16bit value is an index into the tos[] array */ + size_t fromssize; /* size of froms[] array in bytes */ + struct tostruct *tos; /* to struct, contains arc counters */ + size_t tossize; /* size of tos[] array in bytes */ + size_t tolimit; + size_t lowpc; /* low program counter of area */ + size_t highpc; /* high program counter */ + size_t textsize; /* code size */ +}; +extern struct gmonparam _gmonparam; + +void _mcleanup(void); /* routine to be called to write gmon.out file */ + +#endif /* !_SYS_GMONH_ */ diff --git a/libraries/libprof/memfunc.c b/libraries/libprof/memfunc.c new file mode 100644 index 0000000..fc908e1 --- /dev/null +++ b/libraries/libprof/memfunc.c @@ -0,0 +1,127 @@ +#include <stdint.h> +#include <string.h> + +/* + * Profilable substitutes for mem*(), lacking libc_p.a + * + * This code was written with reference to newlib, and was recently + * brought closer into line with newlib, to make profiling more accurate. + * + * Newlib is maintained by Cygwin, which is Red Hat. There is no copyright + * statement in the corresponding newlib source files, nor is there a + * COPYING file in newlib/libc/string or newlib/libc. Consider this file + * to be covered under one or more of the 50 copyright notices in + * newlib/COPYING, most of which are BSD. In any case, this file is only + * used for profiling, and is not used in production builds. + */ + +#define is_word_aligned(x) (((size_t)(x) & 3) == 0) + +void *memcpy(void *dst, const void *src, size_t n) +{ + uint8_t *d8 = (uint8_t *)dst; + uint8_t *s8 = (uint8_t *)src; + + if (n >= sizeof(uint32_t) && is_word_aligned(src) && is_word_aligned(dst)) { + uint32_t *d32 = (uint32_t *)dst; + uint32_t *s32 = (uint32_t *)src; + while (n >= 4 * sizeof(uint32_t)) { + *d32++ = *s32++; + *d32++ = *s32++; + *d32++ = *s32++; + *d32++ = *s32++; + n -= 4 * sizeof(uint32_t); + } + while (n >= sizeof(uint32_t)) { + *d32++ = *s32++; + n -= sizeof(uint32_t); + } + d8 = (uint8_t *)d32; + s8 = (uint8_t *)s32; + } + while (n-- > 0) { + *d8++ = *s8++; + } + + return dst; +} + +void *memset(void *dst, int c, size_t n) +{ + uint8_t *d8 = (uint8_t *)dst; + uint8_t c8 = (uint8_t)c; + + while (!is_word_aligned(d8)) { + if (n--) + *d8++ = c8; + else + return dst; + } + if (n >= sizeof(uint32_t)) { + uint32_t *d32 = (uint32_t *)d8; + uint32_t c32 = (c8 << 24) | (c8 << 16) | (c8 << 8) | (c8); + while (n >= 4 * sizeof(uint32_t)) { + *d32++ = c32; + *d32++ = c32; + *d32++ = c32; + *d32++ = c32; + n -= 4 * sizeof(uint32_t); + } + while (n >= sizeof(uint32_t)) { + *d32++ = c32; + n -= sizeof(uint32_t); + } + d8 = (uint8_t *)d32; + } + while (n-- > 0) { + *d8++ = c8; + } + + return dst; +} + +int memcmp(const void *dst, const void *src, size_t n) +{ + uint8_t *d8 = (uint8_t *)dst; + uint8_t *s8 = (uint8_t *)src; + + if (n >= sizeof(uint32_t) && is_word_aligned(src) && is_word_aligned(dst)) { + uint32_t *d32 = (uint32_t *)dst; + uint32_t *s32 = (uint32_t *)src; + while (n >= sizeof(uint32_t)) { + if (*d32 != *s32) + break; + d32++; + s32++; + n -= sizeof(uint32_t); + } + d8 = (uint8_t *)d32; + s8 = (uint8_t *)s32; + } + while (n-- > 0) { + if (*d8 != *s8) + return (*d8 - *s8); + d8++; + s8++; + } + + return 0; +} + +void *memmove(void *dst, const void *src, size_t n) +{ + uint8_t *d8 = (uint8_t *)dst; + uint8_t *s8 = (uint8_t *)src; + + if ((s8 < d8) && (d8 < s8 + n)) { + /* Destructive overlap...have to copy backwards */ + s8 += n; + d8 += n; + while (n-- > 0) { + *--d8 = *--s8; + } + return dst; + } + + return memcpy(dst, src, n); +} diff --git a/libraries/libprof/profile-runner.py b/libraries/libprof/profile-runner.py new file mode 100755 index 0000000..b96d6b6 --- /dev/null +++ b/libraries/libprof/profile-runner.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python3 + +""" +Tool to run some test code under the profiler on the Cryptech Alpha. + +This assumes that the HSM code was built with DO_PROFILING=1, and +requires an ST-LINK programmer and the Python pexpect package. +""" + +import subprocess +import argparse +import pexpect +import atexit +import time +import sys +import os + +parser = argparse.ArgumentParser(description = __doc__, + formatter_class = argparse.ArgumentDefaultsHelpFormatter) +parser.add_argument("--hsm-elf", + default = os.path.expanduser("~/git.cryptech.is/sw/stm32/projects/hsm/hsm.elf"), + help = "where you keep the profiled hsm.elf binary") +parser.add_argument("--openocd-config", + default = "/usr/share/openocd/scripts/board/st_nucleo_f401re.cfg", + help = "OpenOCD ST-LINK configuration file ") +parser.add_argument("--gmon-output", + default = "profile-runner.gmon", + help = "where to leave raw profiler output") +parser.add_argument("--gprof-output", type = argparse.FileType("w"), + default = "profile-runner.gprof", + help = "where to leave profiler output after processing with gprof") +parser.add_argument("--user", + default = "wheel", + help = "user name for logging in on the HSM console") +parser.add_argument("--pin", + default = "fnord", + help = "PIN for logging in on the HSM console") +parser.add_argument("command", nargs = 1, + help = "test program to run with profiling") +parser.add_argument("arguments", nargs = argparse.REMAINDER, + help = argparse.SUPPRESS) +args = parser.parse_args() + +openocd = subprocess.Popen(("openocd", "-f", args.openocd_config)) +atexit.register(openocd.terminate) + +time.sleep(5) + +telnet = pexpect.spawn("telnet localhost 4444") +telnet.expect(">") +telnet.sendline("arm semihosting enable") +telnet.expect(">") +telnet.sendline("exit") + +console = pexpect.spawn("cryptech_console") +console.sendline("") +if console.expect(["cryptech>", "Username:"]): + console.sendline(args.user) + console.expect("Password:") + console.sendline(args.pin) + console.expect("cryptech>") +console.sendline("profile start") +console.expect("cryptech>") + +cmd = args.command + args.arguments +sys.stderr.write("Running command: {}\n".format(" ".join(cmd))) +subprocess.check_call(cmd) + +console.sendline("profile stop") +console.expect("cryptech>", timeout = 900) +os.rename("gmon.out", args.gmon_output) + +subprocess.check_call(("gprof", args.hsm_elf, args.gmon_output), stdout = args.gprof_output) diff --git a/libraries/libprof/profiler.S b/libraries/libprof/profiler.S new file mode 100644 index 0000000..1aa5c97 --- /dev/null +++ b/libraries/libprof/profiler.S @@ -0,0 +1,28 @@ +/* + * profiler.S + * Implements the gprof profiler arc counting function. + * Created on: 06.08.2015 + * Author: Erich Styger + */ + + .syntax unified + .arch armv7-m + +.globl __gnu_mcount_nc +.type __gnu_mcount_nc, %function + +__gnu_mcount_nc: +#if 0 /* dummy version, doing nothing */ + mov ip, lr + pop { lr } + bx ip +#else + push {r0, r1, r2, r3, lr} /* save registers */ + bic r1, lr, #1 /* R1 contains callee address, with thumb bit cleared */ + ldr r0, [sp, #20] /* R0 contains caller address */ + bic r0, r0, #1 /* clear thumb bit */ + bl _mcount_internal /* jump to internal _mcount() implementation */ + pop {r0, r1, r2, r3, ip, lr} /* restore saved registers */ + bx ip /* return to caller */ +#endif + diff --git a/libraries/libtfm/Makefile b/libraries/libtfm/Makefile new file mode 100644 index 0000000..aa5031f --- /dev/null +++ b/libraries/libtfm/Makefile @@ -0,0 +1,71 @@ + +# This duplicates more of sw/thirdparty/libtfm/Makefile than I +# would like, but it does the job. Prettier makefiles can wait for another day. + +# vpath %.c ${LIBTFM_SRC} +# vpath %.h ${LIBTFM_SRC} + +BITS := 4096 + +HDR := ${LIBTFM_SRC}/tomsfastmath/src/headers/tfm.h +LIB := tomsfastmath/libtfm.a + +# See sw/thirdparty/libtfm/Makefile for compilation options. Note +# that libtfm platform-specific assembly code has opinions on the +# optimization level (and appears to be best tested with -O3). + +# Using $(subst...) here is a kludge. A cleaner approach might be for +# sw/stm32/Makefile to build up the non-variant parts of CFLAGS in a +# different variable before merging the variant and non-variant parts +# into CFLAGS, which would give us a clean copy of the non-variant +# parts to use when constructing our own CFLAGS. Later. + +# The ARM assembly code in libtfm still generates a lot of warnings of the form: +# +# warning: matching constraint does not allow a register [enabled by default] +# +# This is just a warning, the resulting library appears to work +# correctly, and the fix appears to require a nasty intervention in +# the guts of the libtfm assembly code, so we live with the warning +# for now, at least until we confirm that it hasn't already been fixed +# in a newer version of libtfm. + +ifdef DO_PROFILING +# arm-none-eabi-gcc: error: -pg and -fomit-frame-pointer are incompatible +STM32_LIBTFM_CFLAGS_OPTIMIZATION := -O3 -funroll-loops +else +STM32_LIBTFM_CFLAGS_OPTIMIZATION := -O3 -funroll-loops -fomit-frame-pointer +endif + +CFLAGS := $(subst ${STM32_CFLAGS_OPTIMIZATION},${STM32_LIBTFM_CFLAGS_OPTIMIZATION},${CFLAGS}) +CFLAGS += -DTFM_ARM -DENDIAN_LITTLE -Dasm=__asm__ -Wa,-mimplicit-it=thumb +CFLAGS += -I${LIBTFM_SRC}/tomsfastmath/src/headers +CFLAGS += -DFP_MAX_SIZE="(${BITS}*2+(8*DIGIT_BIT))" +CFLAGS += -Wall -W -Wshadow -Wno-uninitialized + +TARGETS := $(notdir ${HDR} ${LIB}) + +REPLACE = fp_to_unsigned_bin.o + +all: ${TARGETS} + +clean: + rm -rf ${TARGETS} $(notdir ${HDR}.tmp) ${LIB} tomsfastmath/src ${REPLACE} + +distclean: clean + rm -f TAGS + +$(notdir ${HDR}): ${HDR} + echo >$@.tmp '/* Configure size of largest bignum we want to handle -- see notes in tfm.pdf */' + echo >>$@.tmp '#define FP_MAX_SIZE (${BITS}*2+(8*DIGIT_BIT))' + echo >>$@.tmp '' + cat >>$@.tmp $^ + mv -f $@.tmp $@ + +$(notdir ${LIB}): ${LIB} + ln -f $^ $@ + +${LIB}: ${HDR} ${REPLACE} + (cd ${LIBTFM_SRC} && find tomsfastmath/src -type d) | xargs mkdir -p + cd tomsfastmath; ${MAKE} CFLAGS='${CFLAGS}' + ar r ${LIB} ${REPLACE} diff --git a/libraries/libtfm/fp_to_unsigned_bin.c b/libraries/libtfm/fp_to_unsigned_bin.c new file mode 100644 index 0000000..618167d --- /dev/null +++ b/libraries/libtfm/fp_to_unsigned_bin.c @@ -0,0 +1,62 @@ +/* TomsFastMath, a fast ISO C bignum library. + * + * This project is meant to fill in where LibTomMath + * falls short. That is speed ;-) + * + * This project is public domain and free for all purposes. + * + * Tom St Denis, tomstdenis@gmail.com + */ +#include <tfm_private.h> + +void fp_to_unsigned_bin(fp_int *a, unsigned char *b) +{ + /* If we know the endianness of this architecture, and we're using + 32-bit fp_digits, we can optimize this */ +#if (defined(ENDIAN_LITTLE) || defined(ENDIAN_BIG)) && !defined(FP_64BIT) + /* But not for both simultaneously */ +#if defined(ENDIAN_LITTLE) && defined(ENDIAN_BIG) +#error Both ENDIAN_LITTLE and ENDIAN_BIG defined. +#endif + { + int c = fp_unsigned_bin_size(a); + unsigned char *pd = (unsigned char *)a->dp; + + /* read the bytes out */ +#ifdef ENDIAN_BIG + { + /* Use Duff's device to unroll the loop. */ + int idx = (c - 1) & ~3; + switch (c % 4) { + case 0: do { b[idx+0] = *pd++; + case 3: b[idx+1] = *pd++; + case 2: b[idx+2] = *pd++; + case 1: b[idx+3] = *pd++; + idx -= 4; + } while ((c -= 4) > 0); + } + } +#else + for (c -= 1; c >= 0; c -= 1) { + b[c] = *pd++; + } +#endif + } +#else + int x; + fp_int t; + + fp_init_copy(&t, a); + + x = 0; + while (fp_iszero (&t) == FP_NO) { + b[x++] = (unsigned char) (t.dp[0] & 255); + fp_div_2d (&t, 8, &t, NULL); + } + fp_reverse (b, x); +#endif +} + +/* $Source$ */ +/* $Revision$ */ +/* $Date$ */ diff --git a/libraries/libtfm/tomsfastmath/Makefile b/libraries/libtfm/tomsfastmath/Makefile new file mode 100644 index 0000000..695aa92 --- /dev/null +++ b/libraries/libtfm/tomsfastmath/Makefile @@ -0,0 +1,4 @@ +vpath %.c ${LIBTFM_SRC}/tomsfastmath +vpath %.h ${LIBTFM_SRC}/tomsfastmath + +include ${LIBTFM_SRC}/tomsfastmath/makefile diff --git a/libraries/mbed/Makefile b/libraries/mbed/Makefile index 9d68e92..eb2bd2b 100644 --- a/libraries/mbed/Makefile +++ b/libraries/mbed/Makefile @@ -1,9 +1,11 @@ CC=arm-none-eabi-gcc AR=arm-none-eabi-ar +CFLAGS += -Wno-unused-parameter + ########################################### -vpath %.c targets/cmsis/TARGET_STM/TARGET_STM32F4 targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_DEV_BRIDGE +vpath %.c $(CMSIS_DIR) $(BOARD_DIR) SRCS = stm32f4xx_hal.c \ stm32f4xx_hal_adc.c \ diff --git a/libraries/mbed/rtos/Makefile b/libraries/mbed/rtos/Makefile deleted file mode 100644 index 496791c..0000000 --- a/libraries/mbed/rtos/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -CC=arm-none-eabi-gcc -AR=arm-none-eabi-ar - -########################################### - -vpath %.c rtx/TARGET_CORTEX_M -vpath %.S rtx/TARGET_CORTEX_M/TARGET_RTOS_M4_M7/TOOLCHAIN_GCC - -SRCS = rtos/rtos_idle.c \ - HAL_CM.c \ - rt_CMSIS.c \ - rt_Event.c \ - rt_List.c \ - rt_Mailbox.c \ - rt_MemBox.c \ - rt_Mutex.c \ - rt_Robin.c \ - rt_Semaphore.c \ - rt_System.c \ - rt_Task.c \ - rt_Time.c \ - RTX_Conf_CM.c \ - HAL_CM4.S \ - SVC_Table.S - -OBJS = $(patsubst %.S,%.o, $(patsubst %.c,%.o, $(SRCS))) - -all: librtos.a - -%.o : %.c - $(CC) $(CFLAGS) -c -o $@ $< - -%.o : %.S - $(CC) $(CFLAGS) -c -o $@ $< - -librtos.a: $(OBJS) - $(AR) -r $@ $(OBJS) - -clean: - rm -f $(OBJS) librtos.a diff --git a/libraries/mbed/rtos/rtos/rtos_idle.c b/libraries/mbed/rtos/rtos/rtos_idle.c deleted file mode 100644 index 1edef6e..0000000 --- a/libraries/mbed/rtos/rtos/rtos_idle.c +++ /dev/null @@ -1,51 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2006-2012 ARM Limited - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include "rtos_idle.h" - -static void default_idle_hook(void) -{ - /* Sleep: ideally, we should put the chip to sleep. - Unfortunately, this usually requires disconnecting the interface chip (debugger). - This can be done, but it would break the local file system. - */ - // sleep(); -} -static void (*idle_hook_fptr)(void) = &default_idle_hook; - -void rtos_attach_idle_hook(void (*fptr)(void)) -{ - //Attach the specified idle hook, or the default idle hook in case of a NULL pointer - if (fptr != NULL) { - idle_hook_fptr = fptr; - } else { - idle_hook_fptr = default_idle_hook; - } -} - -void rtos_idle_loop(void) -{ - //Continuously call the idle hook function pointer - while (1) { - idle_hook_fptr(); - } -} diff --git a/libraries/mbed/rtos/rtos/rtos_idle.h b/libraries/mbed/rtos/rtos/rtos_idle.h deleted file mode 100644 index 851f5f7..0000000 --- a/libraries/mbed/rtos/rtos/rtos_idle.h +++ /dev/null @@ -1,37 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2006-2012 ARM Limited - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef RTOS_IDLE_H -#define RTOS_IDLE_H - -#include <stddef.h> - -#ifdef __cplusplus -extern "C" { -#endif - -void rtos_attach_idle_hook(void (*fptr)(void)); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/HAL_CM.c b/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/HAL_CM.c deleted file mode 100644 index efbe04c..0000000 --- a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/HAL_CM.c +++ /dev/null @@ -1,170 +0,0 @@ -/*---------------------------------------------------------------------------- - * RL-ARM - RTX - *---------------------------------------------------------------------------- - * Name: HAL_CM.C - * Purpose: Hardware Abstraction Layer for Cortex-M - * Rev.: V4.60 - *---------------------------------------------------------------------------- - * - * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - Neither the name of ARM nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - *---------------------------------------------------------------------------*/ - -#include "rt_TypeDef.h" -#include "RTX_Conf.h" -#include "rt_HAL_CM.h" - - -/*---------------------------------------------------------------------------- - * Global Variables - *---------------------------------------------------------------------------*/ - -#ifdef DBG_MSG -BIT dbg_msg; -#endif - -/*---------------------------------------------------------------------------- - * Functions - *---------------------------------------------------------------------------*/ - - -/*--------------------------- rt_init_stack ---------------------------------*/ - -void rt_init_stack (P_TCB p_TCB, FUNCP task_body) { - /* Prepare TCB and saved context for a first time start of a task. */ - U32 *stk,i,size; - - /* Prepare a complete interrupt frame for first task start */ - size = p_TCB->priv_stack >> 2; - - /* Write to the top of stack. */ - stk = &p_TCB->stack[size]; - - /* Auto correct to 8-byte ARM stack alignment. */ - if ((U32)stk & 0x04) { - stk--; - } - - stk -= 16; - - /* Default xPSR and initial PC */ - stk[15] = INITIAL_xPSR; - stk[14] = (U32)task_body; - - /* Clear R4-R11,R0-R3,R12,LR registers. */ - for (i = 0; i < 14; i++) { - stk[i] = 0; - } - - /* Assign a void pointer to R0. */ - stk[8] = (U32)p_TCB->msg; - - /* Initial Task stack pointer. */ - p_TCB->tsk_stack = (U32)stk; - - /* Task entry point. */ - p_TCB->ptask = task_body; - - /* Set a magic word for checking of stack overflow. - For the main thread (ID: 0x01) the stack is in a memory area shared with the - heap, therefore the last word of the stack is a moving target. - We want to do stack/heap collision detection instead. - */ - if (p_TCB->task_id != 0x01) - p_TCB->stack[0] = MAGIC_WORD; -} - - -/*--------------------------- rt_ret_val ----------------------------------*/ - -static __inline U32 *rt_ret_regs (P_TCB p_TCB) { - /* Get pointer to task return value registers (R0..R3) in Stack */ -#if (__TARGET_FPU_VFP) - if (p_TCB->stack_frame) { - /* Extended Stack Frame: R4-R11,S16-S31,R0-R3,R12,LR,PC,xPSR,S0-S15,FPSCR */ - return (U32 *)(p_TCB->tsk_stack + 8*4 + 16*4); - } else { - /* Basic Stack Frame: R4-R11,R0-R3,R12,LR,PC,xPSR */ - return (U32 *)(p_TCB->tsk_stack + 8*4); - } -#else - /* Stack Frame: R4-R11,R0-R3,R12,LR,PC,xPSR */ - return (U32 *)(p_TCB->tsk_stack + 8*4); -#endif -} - -void rt_ret_val (P_TCB p_TCB, U32 v0) { - U32 *ret; - - ret = rt_ret_regs(p_TCB); - ret[0] = v0; -} - -void rt_ret_val2(P_TCB p_TCB, U32 v0, U32 v1) { - U32 *ret; - - ret = rt_ret_regs(p_TCB); - ret[0] = v0; - ret[1] = v1; -} - - -/*--------------------------- dbg_init --------------------------------------*/ - -#ifdef DBG_MSG -void dbg_init (void) { - if ((DEMCR & DEMCR_TRCENA) && - (ITM_CONTROL & ITM_ITMENA) && - (ITM_ENABLE & (1UL << 31))) { - dbg_msg = __TRUE; - } -} -#endif - -/*--------------------------- dbg_task_notify -------------------------------*/ - -#ifdef DBG_MSG -void dbg_task_notify (P_TCB p_tcb, BOOL create) { - while (ITM_PORT31_U32 == 0); - ITM_PORT31_U32 = (U32)p_tcb->ptask; - while (ITM_PORT31_U32 == 0); - ITM_PORT31_U16 = (create << 8) | p_tcb->task_id; -} -#endif - -/*--------------------------- dbg_task_switch -------------------------------*/ - -#ifdef DBG_MSG -void dbg_task_switch (U32 task_id) { - while (ITM_PORT31_U32 == 0); - ITM_PORT31_U8 = task_id; -} -#endif - - -/*---------------------------------------------------------------------------- - * end of file - *---------------------------------------------------------------------------*/ - diff --git a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h b/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h deleted file mode 100755 index 23697ef..0000000 --- a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h +++ /dev/null @@ -1,537 +0,0 @@ -/*---------------------------------------------------------------------------- - * RL-ARM - RTX - *---------------------------------------------------------------------------- - * Name: RTX_CM_LIB.H - * Purpose: RTX Kernel System Configuration - * Rev.: V4.60 - *---------------------------------------------------------------------------- - * - * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - Neither the name of ARM nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - *---------------------------------------------------------------------------*/ -#include "mbed_error.h" - -#if defined (__CC_ARM) -#pragma O3 -#define __USED __attribute__((used)) -#elif defined (__GNUC__) -#pragma GCC optimize ("O3") -#define __USED __attribute__((used)) -#elif defined (__ICCARM__) -#define __USED __root -#endif - - -/*---------------------------------------------------------------------------- - * Definitions - *---------------------------------------------------------------------------*/ - -#define _declare_box(pool,size,cnt) uint32_t pool[(((size)+3)/4)*(cnt) + 3] -#define _declare_box8(pool,size,cnt) uint64_t pool[(((size)+7)/8)*(cnt) + 2] - -#define OS_TCB_SIZE 48 -#define OS_TMR_SIZE 8 - -#if defined (__CC_ARM) && !defined (__MICROLIB) - -typedef void *OS_ID; -typedef uint32_t OS_TID; -typedef uint32_t OS_MUT[3]; -typedef uint32_t OS_RESULT; - -#define runtask_id() rt_tsk_self() -#define mutex_init(m) rt_mut_init(m) -#define mutex_wait(m) os_mut_wait(m,0xFFFF) -#define mutex_rel(m) os_mut_release(m) - -extern OS_TID rt_tsk_self (void); -extern void rt_mut_init (OS_ID mutex); -extern OS_RESULT rt_mut_release (OS_ID mutex); -extern OS_RESULT rt_mut_wait (OS_ID mutex, uint16_t timeout); - -#define os_mut_wait(mutex,timeout) _os_mut_wait((uint32_t)rt_mut_wait,mutex,timeout) -#define os_mut_release(mutex) _os_mut_release((uint32_t)rt_mut_release,mutex) - -OS_RESULT _os_mut_release (uint32_t p, OS_ID mutex) __svc_indirect(0); -OS_RESULT _os_mut_wait (uint32_t p, OS_ID mutex, uint16_t timeout) __svc_indirect(0); - -#endif - - -/*---------------------------------------------------------------------------- - * Global Variables - *---------------------------------------------------------------------------*/ - -#if (OS_TIMERS != 0) -#define OS_TASK_CNT (OS_TASKCNT + 1) -#else -#define OS_TASK_CNT OS_TASKCNT -#endif - -uint16_t const os_maxtaskrun = OS_TASK_CNT; -uint32_t const os_rrobin = (OS_ROBIN << 16) | OS_ROBINTOUT; -uint32_t const os_trv = OS_TRV; -uint8_t const os_flags = OS_RUNPRIV; - -/* Export following defines to uVision debugger. */ -__USED uint32_t const os_clockrate = OS_TICK; -__USED uint32_t const os_timernum = 0; - -/* Stack for the os_idle_demon */ -unsigned int idle_task_stack[OS_IDLESTKSIZE]; -unsigned short const idle_task_stack_size = OS_IDLESTKSIZE; - -#ifndef OS_FIFOSZ - #define OS_FIFOSZ 16 -#endif - -/* Fifo Queue buffer for ISR requests.*/ -uint32_t os_fifo[OS_FIFOSZ*2+1]; -uint8_t const os_fifo_size = OS_FIFOSZ; - -/* An array of Active task pointers. */ -void *os_active_TCB[OS_TASK_CNT]; - -/* User Timers Resources */ -#if (OS_TIMERS != 0) -extern void osTimerThread (void const *argument); -osThreadDef(osTimerThread, (osPriority)(OS_TIMERPRIO-3), 4*OS_TIMERSTKSZ); -osThreadId osThreadId_osTimerThread; -osMessageQDef(osTimerMessageQ, OS_TIMERCBQS, void *); -osMessageQId osMessageQId_osTimerMessageQ; -#else -osThreadDef_t os_thread_def_osTimerThread = { NULL }; -osThreadId osThreadId_osTimerThread; -osMessageQDef(osTimerMessageQ, 0, void *); -osMessageQId osMessageQId_osTimerMessageQ; -#endif - - -/*---------------------------------------------------------------------------- - * RTX Optimizations (empty functions) - *---------------------------------------------------------------------------*/ - -#if OS_ROBIN == 0 - void rt_init_robin (void) {;} - void rt_chk_robin (void) {;} -#endif - -#if OS_STKCHECK == 0 - void rt_stk_check (void) {;} -#endif - - -/*---------------------------------------------------------------------------- - * Standard Library multithreading interface - *---------------------------------------------------------------------------*/ - -#if defined (__CC_ARM) && !defined (__MICROLIB) - static OS_MUT std_libmutex[OS_MUTEXCNT]; - static uint32_t nr_mutex; - - /*--------------------------- _mutex_initialize -----------------------------*/ - -int _mutex_initialize (OS_ID *mutex) { - /* Allocate and initialize a system mutex. */ - - if (nr_mutex >= OS_MUTEXCNT) { - /* If you are here, you need to increase the number OS_MUTEXCNT. */ - error("Not enough stdlib mutexes\n"); - } - *mutex = &std_libmutex[nr_mutex++]; - mutex_init (*mutex); - return (1); -} - - -/*--------------------------- _mutex_acquire --------------------------------*/ - -__attribute__((used)) void _mutex_acquire (OS_ID *mutex) { - /* Acquire a system mutex, lock stdlib resources. */ - if (runtask_id ()) { - /* RTX running, acquire a mutex. */ - mutex_wait (*mutex); - } -} - - -/*--------------------------- _mutex_release --------------------------------*/ - -__attribute__((used)) void _mutex_release (OS_ID *mutex) { - /* Release a system mutex, unlock stdlib resources. */ - if (runtask_id ()) { - /* RTX running, release a mutex. */ - mutex_rel (*mutex); - } -} - -#endif - - -/*---------------------------------------------------------------------------- - * RTX Startup - *---------------------------------------------------------------------------*/ - -/* Main Thread definition */ -extern int main (void); -osThreadDef_t os_thread_def_main = {(os_pthread)main, osPriorityNormal, 0, NULL}; - -// This define should be probably moved to the CMSIS layer -#if defined(TARGET_LPC1768) -#define INITIAL_SP (0x10008000UL) - -#elif defined(TARGET_LPC11U24) -#define INITIAL_SP (0x10002000UL) - -#elif defined(TARGET_LPC11U35_401) || defined(TARGET_LPC11U35_501) || defined(TARGET_LPCCAPPUCCINO) -#define INITIAL_SP (0x10002000UL) - -#elif defined(TARGET_LPC1114) -#define INITIAL_SP (0x10001000UL) - -#elif defined(TARGET_LPC812) -#define INITIAL_SP (0x10001000UL) - -#elif defined(TARGET_LPC824) || defined(TARGET_SSCI824) -#define INITIAL_SP (0x10002000UL) - -#elif defined(TARGET_KL25Z) -#define INITIAL_SP (0x20003000UL) - -#elif defined(TARGET_KL26Z) -#define INITIAL_SP (0x20003000UL) - -#elif defined(TARGET_K64F) -#define INITIAL_SP (0x20030000UL) - -#elif defined(TARGET_K22F) -#define INITIAL_SP (0x20010000UL) - -#elif defined(TARGET_KL46Z) -#define INITIAL_SP (0x20006000UL) - -#elif defined(TARGET_KL43Z) -#define INITIAL_SP (0x20006000UL) - -#elif defined(TARGET_KL05Z) -#define INITIAL_SP (0x20000C00UL) - -#elif defined(TARGET_LPC4088) || defined(TARGET_LPC4088_DM) -#define INITIAL_SP (0x10010000UL) - -#elif defined(TARGET_LPC4330) -#define INITIAL_SP (0x10008000UL) - -#elif defined(TARGET_LPC4337) -#define INITIAL_SP (0x10008000UL) - -#elif defined(TARGET_LPC1347) -#define INITIAL_SP (0x10002000UL) - -#elif defined(TARGET_STM32F100RB) || defined(TARGET_STM32F051R8) -#define INITIAL_SP (0x20002000UL) - -#elif defined(TARGET_DISCO_F303VC) -#define INITIAL_SP (0x2000A000UL) - -#elif defined(TARGET_STM32F407) || defined(TARGET_F407VG) -#define INITIAL_SP (0x20020000UL) - -#elif defined(TARGET_STM32F401RE) -#define INITIAL_SP (0x20018000UL) - -#elif defined(TARGET_LPC1549) -#define INITIAL_SP (0x02009000UL) - -#elif defined(TARGET_LPC11U68) -#define INITIAL_SP (0x10008000UL) - -#elif defined(TARGET_STM32F411RE) -#define INITIAL_SP (0x20020000UL) - -#elif defined(TARGET_STM32F410RB) -#define INITIAL_SP (0x20008000UL) - -#elif defined(TARGET_STM32F103RB) || defined(TARGET_STM32L073RZ) -#define INITIAL_SP (0x20005000UL) - -#elif defined(TARGET_STM32F302R8) -#define INITIAL_SP (0x20004000UL) - -#elif defined(TARGET_STM32F334R8) -#define INITIAL_SP (0x20003000UL) - -#elif defined(TARGET_STM32F334C8) -#define INITIAL_SP (0x20003000UL) - -#elif defined(TARGET_STM32F405RG) -#define INITIAL_SP (0x20020000UL) - -#elif defined(TARGET_STM32F429ZI) -#define INITIAL_SP (0x20030000UL) - -#elif defined(TARGET_STM32L053R8) || defined(TARGET_STM32L053C8) -#define INITIAL_SP (0x20002000UL) - -#elif defined(TARGET_STM32F072RB) -#define INITIAL_SP (0x20004000UL) - -#elif defined(TARGET_STM32F091RC) -#define INITIAL_SP (0x20008000UL) - -#elif defined(TARGET_STM32F401VC) -#define INITIAL_SP (0x20010000UL) - -#elif defined(TARGET_STM32F303RE) -#define INITIAL_SP (0x20010000UL) - -#elif defined(TARGET_STM32F303K8) -#define INITIAL_SP (0x20003000UL) - -#elif (defined(TARGET_STM32F746NG) || defined(TARGET_STM32F746ZG)) -#define INITIAL_SP (0x20050000UL) - -#elif defined(TARGET_MAX32610) || defined(TARGET_MAX32600) -#define INITIAL_SP (0x20008000UL) - -#elif defined(TARGET_TEENSY3_1) -#define INITIAL_SP (0x20008000UL) - -#elif defined(TARGET_STM32L152RE) -#define INITIAL_SP (0x20014000UL) - -#elif defined(TARGET_NZ32_SC151) -#define INITIAL_SP (0x20008000UL) - -#elif (defined(TARGET_STM32F446RE) || defined(TARGET_STM32F446VE)) -#define INITIAL_SP (0x20020000UL) - -#elif defined(TARGET_STM32F070RB) || defined(TARGET_STM32F030R8) -#define INITIAL_SP (0x20002000UL) - -#elif defined(TARGET_STM32L476VG) -#define INITIAL_SP (0x20018000UL) - -#elif defined(TARGET_STM32L476RG) -#define INITIAL_SP (0x20018000UL) - -#elif defined(TARGET_STM32F469NI) -#define INITIAL_SP (0x20050000UL) - -#elif defined(TARGET_STM32L152RC) -#define INITIAL_SP (0x20008000UL) - - -#else -#error "no target defined" - -#endif - -#ifdef __CC_ARM -extern uint32_t Image$$RW_IRAM1$$ZI$$Limit[]; -#define HEAP_START (Image$$RW_IRAM1$$ZI$$Limit) -#elif defined(__GNUC__) -extern uint32_t __end__[]; -#define HEAP_START (__end__) -#elif defined(__ICCARM__) -#pragma section="HEAP" -#define HEAP_START (void *)__section_begin("HEAP") -#endif - -void set_main_stack(void) { - // That is the bottom of the main stack block: no collision detection - os_thread_def_main.stack_pointer = HEAP_START; - - // Leave OS_SCHEDULERSTKSIZE words for the scheduler and interrupts - os_thread_def_main.stacksize = (INITIAL_SP - (unsigned int)HEAP_START) - (OS_SCHEDULERSTKSIZE * 4); -} - -#if defined (__CC_ARM) -#ifdef __MICROLIB -void _main_init (void) __attribute__((section(".ARM.Collect$$$$000000FF"))); -void _main_init (void) { - osKernelInitialize(); - set_main_stack(); - osThreadCreate(&os_thread_def_main, NULL); - osKernelStart(); - for (;;); -} -#else - -/* The single memory model is checking for stack collision at run time, verifing - that the heap pointer is underneath the stack pointer. - - With the RTOS there is not only one stack above the heap, there are multiple - stacks and some of them are underneath the heap pointer. -*/ -#pragma import(__use_two_region_memory) - -__asm void __rt_entry (void) { - - IMPORT __user_setup_stackheap - IMPORT __rt_lib_init - IMPORT os_thread_def_main - IMPORT osKernelInitialize - IMPORT set_main_stack - IMPORT osKernelStart - IMPORT osThreadCreate - IMPORT exit - - BL __user_setup_stackheap - MOV R1,R2 - BL __rt_lib_init - BL osKernelInitialize - BL set_main_stack - LDR R0,=os_thread_def_main - MOVS R1,#0 - BL osThreadCreate - BL osKernelStart - BL exit - - ALIGN -} -#endif - -#elif defined (__GNUC__) - -#ifdef __CS3__ - -/* CS3 start_c routine. - * - * Copyright (c) 2006, 2007 CodeSourcery Inc - * - * The authors hereby grant permission to use, copy, modify, distribute, - * and license this software and its documentation for any purpose, provided - * that existing copyright notices are retained in all copies and that this - * notice is included verbatim in any distributions. No written agreement, - * license, or royalty fee is required for any of the authorized uses. - * Modifications to this software may be copyrighted by their authors - * and need not follow the licensing terms described here, provided that - * the new terms are clearly indicated on the first page of each file where - * they apply. - */ - -#include "cs3.h" - -extern void __libc_init_array (void); - -__attribute ((noreturn)) void __cs3_start_c (void){ - unsigned regions = __cs3_region_num; - const struct __cs3_region *rptr = __cs3_regions; - - /* Initialize memory */ - for (regions = __cs3_region_num, rptr = __cs3_regions; regions--; rptr++) { - long long *src = (long long *)rptr->init; - long long *dst = (long long *)rptr->data; - unsigned limit = rptr->init_size; - unsigned count; - - if (src != dst) - for (count = 0; count != limit; count += sizeof (long long)) - *dst++ = *src++; - else - dst = (long long *)((char *)dst + limit); - limit = rptr->zero_size; - for (count = 0; count != limit; count += sizeof (long long)) - *dst++ = 0; - } - - /* Run initializers. */ - __libc_init_array (); - - osKernelInitialize(); - set_main_stack(); - osThreadCreate(&os_thread_def_main, NULL); - osKernelStart(); - for (;;); -} - -#else - -__attribute__((naked)) void software_init_hook (void) { - __asm ( - ".syntax unified\n" - ".thumb\n" - "movs r0,#0\n" - "movs r1,#0\n" - "mov r4,r0\n" - "mov r5,r1\n" - "ldr r0,= __libc_fini_array\n" - "bl atexit\n" - "bl __libc_init_array\n" - "mov r0,r4\n" - "mov r1,r5\n" - "bl osKernelInitialize\n" - "bl set_main_stack\n" - "ldr r0,=os_thread_def_main\n" - "movs r1,#0\n" - "bl osThreadCreate\n" - "bl osKernelStart\n" - "bl exit\n" - ); -} - -#endif - -#elif defined (__ICCARM__) - -extern void* __vector_table; -extern int __low_level_init(void); -extern void __iar_data_init3(void); -extern __weak void __iar_init_core( void ); -extern __weak void __iar_init_vfp( void ); -extern void __iar_dynamic_initialization(void); -extern void mbed_sdk_init(void); -extern void exit(int arg); - -#pragma required=__vector_table -void __iar_program_start( void ) -{ - __iar_init_core(); - __iar_init_vfp(); - - int a; - - if (__low_level_init() != 0) { - __iar_data_init3(); - mbed_sdk_init(); - __iar_dynamic_initialization(); - } - osKernelInitialize(); - set_main_stack(); - osThreadCreate(&os_thread_def_main, NULL); - a = osKernelStart(); - exit(a); - -} - -#endif - - -/*---------------------------------------------------------------------------- - * end of file - *---------------------------------------------------------------------------*/ - - diff --git a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/RTX_Conf.h b/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/RTX_Conf.h deleted file mode 100644 index 0b0d461..0000000 --- a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/RTX_Conf.h +++ /dev/null @@ -1,72 +0,0 @@ -/*---------------------------------------------------------------------------- - * RL-ARM - RTX - *---------------------------------------------------------------------------- - * Name: RTX_CONFIG.H - * Purpose: Exported functions of RTX_Config.c - * Rev.: V4.60 - *---------------------------------------------------------------------------- - * - * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - Neither the name of ARM nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - *---------------------------------------------------------------------------*/ - - -/* Error Codes */ -#define OS_ERR_STK_OVF 1 -#define OS_ERR_FIFO_OVF 2 -#define OS_ERR_MBX_OVF 3 - -/* Definitions */ -#define BOX_ALIGN_8 0x80000000 -#define _declare_box(pool,size,cnt) U32 pool[(((size)+3)/4)*(cnt) + 3] -#define _declare_box8(pool,size,cnt) U64 pool[(((size)+7)/8)*(cnt) + 2] -#define _init_box8(pool,size,bsize) _init_box (pool,size,(bsize) | BOX_ALIGN_8) - -/* Variables */ -extern U32 idle_task_stack[]; -extern U32 os_fifo[]; -extern void *os_active_TCB[]; - -/* Constants */ -extern U16 const os_maxtaskrun; -extern U32 const os_trv; -extern U8 const os_flags; -extern U32 const os_rrobin; -extern U32 const os_clockrate; -extern U32 const os_timernum; -extern U16 const idle_task_stack_size; - -extern U8 const os_fifo_size; - -/* Functions */ -extern void os_idle_demon (void); -extern int os_tick_init (void); -extern void os_tick_irqack (void); -extern void os_tmr_call (U16 info); -extern void os_error (U32 err_code); - -/*---------------------------------------------------------------------------- - * end of file - *---------------------------------------------------------------------------*/ diff --git a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/RTX_Conf_CM.c b/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/RTX_Conf_CM.c deleted file mode 100755 index 788edfd..0000000 --- a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/RTX_Conf_CM.c +++ /dev/null @@ -1,342 +0,0 @@ -/*---------------------------------------------------------------------------- - * RL-ARM - RTX - *---------------------------------------------------------------------------- - * Name: RTX_Conf_CM.C - * Purpose: Configuration of CMSIS RTX Kernel for Cortex-M - * Rev.: V4.60 - *---------------------------------------------------------------------------- - * - * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - Neither the name of ARM nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - *---------------------------------------------------------------------------*/ - -#include "cmsis_os.h" - - -/*---------------------------------------------------------------------------- - * RTX User configuration part BEGIN - *---------------------------------------------------------------------------*/ - -//-------- <<< Use Configuration Wizard in Context Menu >>> ----------------- -// -// <h>Thread Configuration -// ======================= -// -// <o>Number of concurrent running threads <0-250> -// <i> Defines max. number of threads that will run at the same time. -// counting "main", but not counting "osTimerThread" -// <i> Default: 6 -#ifndef OS_TASKCNT -# if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) || defined(TARGET_LPC4088) || defined(TARGET_LPC4088_DM) || defined(TARGET_LPC4330) || defined(TARGET_LPC4337) || defined(TARGET_LPC1347) || defined(TARGET_K64F) || defined(TARGET_STM32F401RE)\ - || defined(TARGET_STM32F410RB) || defined(TARGET_KL46Z) || defined(TARGET_KL43Z) || defined(TARGET_STM32F407) || defined(TARGET_F407VG) || defined(TARGET_STM32F303VC) || defined(TARGET_LPC1549) || defined(TARGET_LPC11U68) \ - || defined(TARGET_STM32F411RE) || defined(TARGET_STM32F405RG) || defined(TARGET_K22F) || defined(TARGET_STM32F429ZI) || defined(TARGET_STM32F401VC) || defined(TARGET_MAX32610) || defined(TARGET_MAX32600) || defined(TARGET_TEENSY3_1) \ - || defined(TARGET_STM32L152RE) || defined(TARGET_STM32F446RE) || defined(TARGET_STM32F446VE) || defined(TARGET_STM32L476VG) || defined(TARGET_STM32L476RG) || defined(TARGET_STM32F469NI) || defined(TARGET_STM32F746NG) || defined(TARGET_STM32F746ZG) || defined(TARGET_STM32L152RC) -# define OS_TASKCNT 14 -# elif defined(TARGET_LPC11U24) || defined(TARGET_STM32F303RE) || defined(TARGET_STM32F303K8) || defined(TARGET_LPC11U35_401) || defined(TARGET_LPC11U35_501) || defined(TARGET_LPCCAPPUCCINO) || defined(TARGET_LPC1114) \ - || defined(TARGET_LPC812) || defined(TARGET_KL25Z) || defined(TARGET_KL26Z) || defined(TARGET_KL05Z) || defined(TARGET_STM32F100RB) || defined(TARGET_STM32F051R8) \ - || defined(TARGET_STM32F103RB) || defined(TARGET_LPC824) || defined(TARGET_STM32F302R8) || defined(TARGET_STM32F334R8) || defined(TARGET_STM32F334C8) \ - || defined(TARGET_STM32L053R8) || defined(TARGET_STM32L053C8) || defined(TARGET_STM32L073RZ) || defined(TARGET_STM32F072RB) || defined(TARGET_STM32F091RC) || defined(TARGET_NZ32_SC151) \ - || defined(TARGET_SSCI824) || defined(TARGET_STM32F030R8) || defined(TARGET_STM32F070RB) -# define OS_TASKCNT 6 -# else -# error "no target defined" -# endif -#endif - -// <o>Scheduler (+ interrupts) stack size [bytes] <64-4096:8><#/4> -#ifndef OS_SCHEDULERSTKSIZE -# if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) || defined(TARGET_LPC4088) || defined(TARGET_LPC4088_DM) || defined(TARGET_LPC4330) || defined(TARGET_LPC4337) || defined(TARGET_LPC1347) || defined(TARGET_K64F) || defined(TARGET_STM32F401RE)\ - || defined(TARGET_STM32F410RB) || defined(TARGET_KL46Z) || defined(TARGET_KL43Z) || defined(TARGET_STM32F407) || defined(TARGET_F407VG) || defined(TARGET_STM32F303VC) || defined(TARGET_LPC1549) || defined(TARGET_LPC11U68) \ - || defined(TARGET_STM32F411RE) || defined(TARGET_STM32F405RG) || defined(TARGET_K22F) || defined(TARGET_STM32F429ZI) || defined(TARGET_STM32F401VC) || defined(TARGET_MAX32610) || defined(TARGET_MAX32600) || defined(TARGET_TEENSY3_1) \ - || defined(TARGET_STM32L152RE) || defined(TARGET_STM32F446RE) || defined(TARGET_STM32F446VE) || defined(TARGET_STM32L476VG) || defined(TARGET_STM32L476RG) || defined(TARGET_STM32F469NI) || defined(TARGET_STM32F746NG) || defined(TARGET_STM32F746ZG) || defined(TARGET_STM32L152RC) -# define OS_SCHEDULERSTKSIZE 256 -# elif defined(TARGET_LPC11U24) || defined(TARGET_LPC11U35_401) || defined(TARGET_LPC11U35_501) || defined(TARGET_LPCCAPPUCCINO) || defined(TARGET_LPC1114) \ - || defined(TARGET_LPC812) || defined(TARGET_KL25Z) || defined(TARGET_KL26Z) || defined(TARGET_KL05Z) || defined(TARGET_STM32F100RB) || defined(TARGET_STM32F051R8) \ - || defined(TARGET_STM32F103RB) || defined(TARGET_LPC824) || defined(TARGET_STM32F302R8) || defined(TARGET_STM32F072RB) || defined(TARGET_STM32F091RC) || defined(TARGET_NZ32_SC151) \ - || defined(TARGET_SSCI824) || defined(TARGET_STM32F030R8) || defined(TARGET_STM32F070RB) -# define OS_SCHEDULERSTKSIZE 128 -# elif defined(TARGET_STM32F334R8) || defined(TARGET_STM32F303RE) || defined(TARGET_STM32F303K8) || defined(TARGET_STM32F334C8) || defined(TARGET_STM32L053R8) || defined(TARGET_STM32L053C8) || defined(TARGET_STM32L073RZ) -# define OS_SCHEDULERSTKSIZE 112 -# else -# error "no target defined" -# endif -#endif - -// <o>Idle stack size [bytes] <64-4096:8><#/4> -// <i> Defines default stack size for the Idle thread. -#ifndef OS_IDLESTKSIZE - #define OS_IDLESTKSIZE 128 -#endif - -// <o>Timer Thread stack size [bytes] <64-4096:8><#/4> -// <i> Defines stack size for Timer thread. -// <i> Default: 200 -#ifndef OS_TIMERSTKSZ - #define OS_TIMERSTKSZ WORDS_STACK_SIZE -#endif - -// <q>Check for stack overflow -// <i> Includes the stack checking code for stack overflow. -// <i> Note that additional code reduces the Kernel performance. -#ifndef OS_STKCHECK - #define OS_STKCHECK 1 -#endif - -// <o>Processor mode for thread execution -// <0=> Unprivileged mode -// <1=> Privileged mode -// <i> Default: Privileged mode -#ifndef OS_RUNPRIV - #define OS_RUNPRIV 1 -#endif - -// </h> -// <h>SysTick Timer Configuration -// ============================== -// -// <o>Timer clock value [Hz] <1-1000000000> -// <i> Defines the timer clock value. -// <i> Default: 6000000 (6MHz) -#ifndef OS_CLOCK -# if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) || defined(TARGET_TEENSY3_1) -# define OS_CLOCK 96000000 - -# elif defined(TARGET_LPC1347) || defined(TARGET_STM32F303VC) || defined(TARGET_LPC1549) || defined(TARGET_STM32F334R8) || defined(TARGET_STM32F334C8) || defined(TARGET_STM32F303RE) -# define OS_CLOCK 72000000 - -# elif defined(TARGET_STM32F303K8) -# define OS_CLOCK 64000000 - -# elif defined(TARGET_LPC11U24) || defined(TARGET_LPC11U35_401) || defined(TARGET_LPC11U35_501) || defined(TARGET_LPCCAPPUCCINO) || defined(TARGET_LPC1114) || defined(TARGET_KL25Z) \ - || defined(TARGET_KL26Z) || defined(TARGET_KL05Z) || defined(TARGET_KL46Z) || defined(TARGET_KL43Z) || defined(TARGET_STM32F051R8) || defined(TARGET_LPC11U68) || defined(TARGET_STM32F072RB) || defined(TARGET_STM32F091RC) -# define OS_CLOCK 48000000 - -# elif defined(TARGET_LPC812) -# define OS_CLOCK 36000000 - -# elif defined(TARGET_LPC824) || defined(TARGET_SSCI824) -# define OS_CLOCK 30000000 - -# elif defined(TARGET_STM32F100RB) -# define OS_CLOCK 24000000 - -# elif defined(TARGET_LPC4088) || defined(TARGET_LPC4088_DM) || defined(TARGET_K64F) || defined(TARGET_K22F) -# define OS_CLOCK 120000000 - -# elif defined(TARGET_LPC4330) -# define OS_CLOCK 204000000 - -# elif defined(TARGET_LPC4337) -# define OS_CLOCK 204000000 - -# elif defined(TARGET_STM32F407) || defined(TARGET_F407VG) -# define OS_CLOCK 168000000 - -# elif defined(TARGET_STM32F401RE) -# define OS_CLOCK 84000000 - -# elif defined(TARGET_STM32F411RE) -# define OS_CLOCK 100000000 - -# elif defined(TARGET_STM32F410RB) -# define OS_CLOCK 100000000 - -#elif defined(TARGET_STM32F103RB) -# define OS_CLOCK 72000000 - -#elif defined(TARGET_STM32F429ZI) -# define OS_CLOCK 168000000 - -#elif defined(TARGET_STM32F302R8) -# define OS_CLOCK 72000000 - -#elif defined(TARGET_STM32L053R8) || defined(TARGET_STM32L053C8) || defined(TARGET_STM32L073RZ) -# define OS_CLOCK 32000000 - -#elif defined(TARGET_STM32F401VC) -# define OS_CLOCK 84000000 - -# elif defined(TARGET_STM32F746NG) || defined(TARGET_STM32F746ZG) -# define OS_CLOCK 216000000 - -#elif defined(TARGET_MAX32610) || defined(TARGET_MAX32600) -# define OS_CLOCK 24000000 - -#elif defined(TARGET_NZ32_SC151) -# define OS_CLOCK 32000000 - -#elif defined(TARGET_STM32L152RE) -# define OS_CLOCK 24000000 - -#elif (defined(TARGET_STM32F446RE) || defined(TARGET_STM32F446VE)) -# define OS_CLOCK 180000000 - -#elif defined(TARGET_STM32F030R8) -# define OS_CLOCK 48000000 - -#elif defined(TARGET_STM32F070RB) -# define OS_CLOCK 48000000 - -#elif defined(TARGET_STM32L476VG) || defined(TARGET_STM32L476RG) -# define OS_CLOCK 80000000 - -#elif defined(TARGET_STM32F469NI) -# define OS_CLOCK 168000000 - -#elif defined(TARGET_STM32L152RC) -# define OS_CLOCK 24000000 - -# else -# error "no target defined" -# endif -#endif - -// <o>Timer tick value [us] <1-1000000> -// <i> Defines the timer tick value. -// <i> Default: 1000 (1ms) -#ifndef OS_TICK - #define OS_TICK 1000 -#endif - -// </h> - -// <h>System Configuration -// ======================= -// -// <e>Round-Robin Thread switching -// =============================== -// -// <i> Enables Round-Robin Thread switching. -#ifndef OS_ROBIN - #define OS_ROBIN 1 -#endif - -// <o>Round-Robin Timeout [ticks] <1-1000> -// <i> Defines how long a thread will execute before a thread switch. -// <i> Default: 5 -#ifndef OS_ROBINTOUT - #define OS_ROBINTOUT 5 -#endif - -// </e> - -// <e>User Timers -// ============== -// <i> Enables user Timers -#ifndef OS_TIMERS - #define OS_TIMERS 1 -#endif - -// <o>Timer Thread Priority -// <1=> Low -// <2=> Below Normal -// <3=> Normal -// <4=> Above Normal -// <5=> High -// <6=> Realtime (highest) -// <i> Defines priority for Timer Thread -// <i> Default: High -#ifndef OS_TIMERPRIO - #define OS_TIMERPRIO 5 -#endif - -// <o>Timer Callback Queue size <1-32> -// <i> Number of concurrent active timer callback functions. -// <i> Default: 4 -#ifndef OS_TIMERCBQSZ - #define OS_TIMERCBQS 4 -#endif - -// </e> - -// <o>ISR FIFO Queue size<4=> 4 entries <8=> 8 entries -// <12=> 12 entries <16=> 16 entries -// <24=> 24 entries <32=> 32 entries -// <48=> 48 entries <64=> 64 entries -// <96=> 96 entries -// <i> ISR functions store requests to this buffer, -// <i> when they are called from the interrupt handler. -// <i> Default: 16 entries -#ifndef OS_FIFOSZ - #define OS_FIFOSZ 16 -#endif - -// </h> - -//------------- <<< end of configuration section >>> ----------------------- - -// Standard library system mutexes -// =============================== -// Define max. number system mutexes that are used to protect -// the arm standard runtime library. For microlib they are not used. -#ifndef OS_MUTEXCNT - #define OS_MUTEXCNT 12 -#endif - -/*---------------------------------------------------------------------------- - * RTX User configuration part END - *---------------------------------------------------------------------------*/ - -#define OS_TRV ((uint32_t)(((double)OS_CLOCK*(double)OS_TICK)/1E6)-1) - - -/*---------------------------------------------------------------------------- - * OS Idle daemon - *---------------------------------------------------------------------------*/ -extern void rtos_idle_loop(void); - -void os_idle_demon (void) { - /* The idle demon is a system thread, running when no other thread is */ - /* ready to run. */ - rtos_idle_loop(); -} - -/*---------------------------------------------------------------------------- - * RTX Errors - *---------------------------------------------------------------------------*/ -extern void mbed_die(void); - -void os_error (uint32_t err_code) { - /* This function is called when a runtime error is detected. Parameter */ - /* 'err_code' holds the runtime error code (defined in RTX_Conf.h). */ - mbed_die(); -} - -void sysThreadError(osStatus status) { - if (status != osOK) { - mbed_die(); - } -} - -/*---------------------------------------------------------------------------- - * RTX Configuration Functions - *---------------------------------------------------------------------------*/ - -#include "RTX_CM_lib.h" - -/*---------------------------------------------------------------------------- - * end of file - *---------------------------------------------------------------------------*/ - diff --git a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/TARGET_RTOS_M4_M7/TOOLCHAIN_GCC/HAL_CM4.S b/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/TARGET_RTOS_M4_M7/TOOLCHAIN_GCC/HAL_CM4.S deleted file mode 100644 index ce3242b..0000000 --- a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/TARGET_RTOS_M4_M7/TOOLCHAIN_GCC/HAL_CM4.S +++ /dev/null @@ -1,405 +0,0 @@ -/*---------------------------------------------------------------------------- - * RL-ARM - RTX - *---------------------------------------------------------------------------- - * Name: HAL_CM4.S - * Purpose: Hardware Abstraction Layer for Cortex-M4 - * Rev.: V4.70 - *---------------------------------------------------------------------------- - * - * Copyright (c) 1999-2009 KEIL, 2009-2013 ARM Germany GmbH - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - Neither the name of ARM nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - *---------------------------------------------------------------------------*/ - - .file "HAL_CM4.S" - .syntax unified - - .equ TCB_STACKF, 32 - .equ TCB_TSTACK, 40 - - -/*---------------------------------------------------------------------------- - * Functions - *---------------------------------------------------------------------------*/ - - .thumb - - .section ".text" - .align 2 - - -/*--------------------------- rt_set_PSP ------------------------------------*/ - -# void rt_set_PSP (U32 stack); - - .thumb_func - .type rt_set_PSP, %function - .global rt_set_PSP -rt_set_PSP: - .fnstart - .cantunwind - - MSR PSP,R0 - BX LR - - .fnend - .size rt_set_PSP, .-rt_set_PSP - - -/*--------------------------- rt_get_PSP ------------------------------------*/ - -# U32 rt_get_PSP (void); - - .thumb_func - .type rt_get_PSP, %function - .global rt_get_PSP -rt_get_PSP: - .fnstart - .cantunwind - - MRS R0,PSP - BX LR - - .fnend - .size rt_get_PSP, .-rt_get_PSP - - -/*--------------------------- os_set_env ------------------------------------*/ - -# void os_set_env (void); - /* Switch to Unprivileged/Privileged Thread mode, use PSP. */ - - .thumb_func - .type os_set_env, %function - .global os_set_env -os_set_env: - .fnstart - .cantunwind - - MOV R0,SP /* PSP = MSP */ - MSR PSP,R0 - LDR R0,=os_flags - LDRB R0,[R0] - LSLS R0,#31 - ITE NE - MOVNE R0,#0x02 /* Privileged Thread mode, use PSP */ - MOVEQ R0,#0x03 /* Unprivileged Thread mode, use PSP */ - MSR CONTROL,R0 - BX LR - - .fnend - .size os_set_env, .-os_set_env - - -/*--------------------------- _alloc_box ------------------------------------*/ - -# void *_alloc_box (void *box_mem); - /* Function wrapper for Unprivileged/Privileged mode. */ - - .thumb_func - .type _alloc_box, %function - .global _alloc_box -_alloc_box: - .fnstart - .cantunwind - - LDR R12,=rt_alloc_box - MRS R3,IPSR - LSLS R3,#24 - IT NE - BXNE R12 - MRS R3,CONTROL - LSLS R3,#31 - IT EQ - BXEQ R12 - SVC 0 - BX LR - - .fnend - .size _alloc_box, .-_alloc_box - - -/*--------------------------- _free_box -------------------------------------*/ - -# int _free_box (void *box_mem, void *box); - /* Function wrapper for Unprivileged/Privileged mode. */ - - .thumb_func - .type _free_box, %function - .global _free_box -_free_box: - .fnstart - .cantunwind - - LDR R12,=rt_free_box - MRS R3,IPSR - LSLS R3,#24 - IT NE - BXNE R12 - MRS R3,CONTROL - LSLS R3,#31 - IT EQ - BXEQ R12 - SVC 0 - BX LR - - .fnend - .size _free_box, .-_free_box - - -/*-------------------------- SVC_Handler ------------------------------------*/ - -# void SVC_Handler (void); - - .thumb_func - .type SVC_Handler, %function - .global SVC_Handler -SVC_Handler: - .ifdef IFX_XMC4XXX - .global SVC_Handler_Veneer -SVC_Handler_Veneer: - .endif - .fnstart - .cantunwind - - MRS R0,PSP /* Read PSP */ - LDR R1,[R0,#24] /* Read Saved PC from Stack */ - LDRB R1,[R1,#-2] /* Load SVC Number */ - CBNZ R1,SVC_User - - LDM R0,{R0-R3,R12} /* Read R0-R3,R12 from stack */ - PUSH {R4,LR} /* Save EXC_RETURN */ - BLX R12 /* Call SVC Function */ - POP {R4,LR} /* Restore EXC_RETURN */ - - MRS R12,PSP /* Read PSP */ - STM R12,{R0-R2} /* Store return values */ - - LDR R3,=os_tsk - LDM R3,{R1,R2} /* os_tsk.run, os_tsk.new */ - CMP R1,R2 - .ifdef IFX_XMC4XXX - ITT EQ - PUSHEQ {LR} - POPEQ {PC} - .else - IT EQ - BXEQ LR /* RETI, no task switch */ - .endif - - CBZ R1,SVC_Next /* Runtask deleted? */ - TST LR,#0x10 /* is it extended frame? */ - #ifdef __FPU_PRESENT - ITTE EQ - VSTMDBEQ R12!,{S16-S31} /* yes, stack also VFP hi-regs */ - #else - ITE EQ - #endif - MOVEQ R0,#0x01 /* os_tsk->stack_frame val */ - MOVNE R0,#0x00 - STRB R0,[R1,#TCB_STACKF] /* os_tsk.run->stack_frame = val */ - STMDB R12!,{R4-R11} /* Save Old context */ - STR R12,[R1,#TCB_TSTACK] /* Update os_tsk.run->tsk_stack */ - - PUSH {R2,R3} - BL rt_stk_check /* Check for Stack overflow */ - POP {R2,R3} - -SVC_Next: - STR R2,[R3] /* os_tsk.run = os_tsk.new */ - - LDR R12,[R2,#TCB_TSTACK] /* os_tsk.new->tsk_stack */ - LDMIA R12!,{R4-R11} /* Restore New Context */ - LDRB R0,[R2,#TCB_STACKF] /* Stack Frame */ - CMP R0,#0 /* Basic/Extended Stack Frame */ - #ifdef __FPU_PRESENT - ITTE NE - VLDMIANE R12!,{S16-S31} /* restore VFP hi-registers */ - #else - ITE NE - #endif - MVNNE LR,#~0xFFFFFFED /* set EXC_RETURN value */ - MVNEQ LR,#~0xFFFFFFFD - MSR PSP,R12 /* Write PSP */ - -SVC_Exit: - .ifdef IFX_XMC4XXX - PUSH {LR} - POP {PC} - .else - BX LR - .endif - - /*------------------- User SVC ------------------------------*/ - -SVC_User: - PUSH {R4,LR} /* Save Registers */ - LDR R2,=SVC_Count - LDR R2,[R2] - CMP R1,R2 - BHI SVC_Done /* Overflow */ - - LDR R4,=SVC_Table-4 - LDR R4,[R4,R1,LSL #2] /* Load SVC Function Address */ - - LDM R0,{R0-R3,R12} /* Read R0-R3,R12 from stack */ - BLX R4 /* Call SVC Function */ - - MRS R12,PSP - STM R12,{R0-R3} /* Function return values */ -SVC_Done: - POP {R4,PC} /* RETI */ - - .fnend - .size SVC_Handler, .-SVC_Handler - - -/*-------------------------- PendSV_Handler ---------------------------------*/ - -# void PendSV_Handler (void); - - .thumb_func - .type PendSV_Handler, %function - .global PendSV_Handler - .global Sys_Switch -PendSV_Handler: - .ifdef IFX_XMC4XXX - .global PendSV_Handler_Veneer -PendSV_Handler_Veneer: - .endif - .fnstart - .cantunwind - - PUSH {R4,LR} /* Save EXC_RETURN */ - BL rt_pop_req - -Sys_Switch: - POP {R4,LR} /* Restore EXC_RETURN */ - - LDR R3,=os_tsk - LDM R3,{R1,R2} /* os_tsk.run, os_tsk.new */ - CMP R1,R2 - .ifdef IFX_XMC4XXX - ITT EQ - PUSHEQ {LR} - POPEQ {PC} - .else - IT EQ - BXEQ LR /* RETI, no task switch */ - .endif - - MRS R12,PSP /* Read PSP */ - TST LR,#0x10 /* is it extended frame? */ - #ifdef __FPU_PRESENT - ITTE EQ - VSTMDBEQ R12!,{S16-S31} /* yes, stack also VFP hi-regs */ - #else - ITE EQ - #endif - MOVEQ R0,#0x01 /* os_tsk->stack_frame val */ - MOVNE R0,#0x00 - STRB R0,[R1,#TCB_STACKF] /* os_tsk.run->stack_frame = val */ - STMDB R12!,{R4-R11} /* Save Old context */ - STR R12,[R1,#TCB_TSTACK] /* Update os_tsk.run->tsk_stack */ - - PUSH {R2,R3} - BL rt_stk_check /* Check for Stack overflow */ - POP {R2,R3} - - STR R2,[R3] /* os_tsk.run = os_tsk.new */ - - LDR R12,[R2,#TCB_TSTACK] /* os_tsk.new->tsk_stack */ - LDMIA R12!,{R4-R11} /* Restore New Context */ - LDRB R0,[R2,#TCB_STACKF] /* Stack Frame */ - CMP R0,#0 /* Basic/Extended Stack Frame */ - #ifdef __FPU_PRESENT - ITTE NE - VLDMIANE R12!,{S16-S31} /* restore VFP hi-registers */ - #else - ITE NE - #endif - MVNNE LR,#~0xFFFFFFED /* set EXC_RETURN value */ - MVNEQ LR,#~0xFFFFFFFD - MSR PSP,R12 /* Write PSP */ - -Sys_Exit: - .ifdef IFX_XMC4XXX - PUSH {LR} - POP {PC} - .else - BX LR /* Return to Thread Mode */ - .endif - - .fnend - .size PendSV_Handler, .-PendSV_Handler - - -/*-------------------------- SysTick_Handler --------------------------------*/ - -# void SysTick_Handler (void); - - .thumb_func - .type SysTick_Handler, %function - .global SysTick_Handler -SysTick_Handler: - .ifdef IFX_XMC4XXX - .global SysTick_Handler_Veneer -SysTick_Handler_Veneer: - .endif - .fnstart - .cantunwind - - PUSH {R4,LR} /* Save EXC_RETURN */ - BL rt_systick - B Sys_Switch - - .fnend - .size SysTick_Handler, .-SysTick_Handler - - -/*-------------------------- OS_Tick_Handler --------------------------------*/ - -# void OS_Tick_Handler (void); - - .thumb_func - .type OS_Tick_Handler, %function - .global OS_Tick_Handler -OS_Tick_Handler: - .fnstart - .cantunwind - - PUSH {R4,LR} /* Save EXC_RETURN */ - BL os_tick_irqack - BL rt_systick - B Sys_Switch - - .fnend - .size OS_Tick_Handler, .-OS_Tick_Handler - - - .end - -/*---------------------------------------------------------------------------- - * end of file - *---------------------------------------------------------------------------*/ diff --git a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/TARGET_RTOS_M4_M7/TOOLCHAIN_GCC/SVC_Table.S b/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/TARGET_RTOS_M4_M7/TOOLCHAIN_GCC/SVC_Table.S deleted file mode 100644 index 2b99321..0000000 --- a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/TARGET_RTOS_M4_M7/TOOLCHAIN_GCC/SVC_Table.S +++ /dev/null @@ -1,56 +0,0 @@ -;/*---------------------------------------------------------------------------- -; * RL-ARM - RTX -; *---------------------------------------------------------------------------- -; * Name: SVC_TABLE.S -; * Purpose: Pre-defined SVC Table for Cortex-M -; * Rev.: V4.70 -; *---------------------------------------------------------------------------- -; * -; * Copyright (c) 1999-2009 KEIL, 2009-2013 ARM Germany GmbH -; * All rights reserved. -; * Redistribution and use in source and binary forms, with or without -; * modification, are permitted provided that the following conditions are met: -; * - Redistributions of source code must retain the above copyright -; * notice, this list of conditions and the following disclaimer. -; * - Redistributions in binary form must reproduce the above copyright -; * notice, this list of conditions and the following disclaimer in the -; * documentation and/or other materials provided with the distribution. -; * - Neither the name of ARM nor the names of its contributors may be used -; * to endorse or promote products derived from this software without -; * specific prior written permission. -; * -; * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -; * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -; * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -; * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE -; * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -; * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -; * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -; * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -; * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -; * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -; * POSSIBILITY OF SUCH DAMAGE. -; *---------------------------------------------------------------------------*/ - - - .file "SVC_Table.S" - - - .section ".svc_table" - - .global SVC_Table -SVC_Table: -/* Insert user SVC functions here. SVC 0 used by RTL Kernel. */ -# .long __SVC_1 /* user SVC function */ -SVC_End: - - .global SVC_Count -SVC_Count: - .long (SVC_End-SVC_Table)/4 - - - .end - -/*---------------------------------------------------------------------------- - * end of file - *---------------------------------------------------------------------------*/ diff --git a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/cmsis_os.h b/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/cmsis_os.h deleted file mode 100644 index d1e7198..0000000 --- a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/cmsis_os.h +++ /dev/null @@ -1,774 +0,0 @@ -/* ---------------------------------------------------------------------- - * Copyright (C) 2012 ARM Limited. All rights reserved. - * - * $Date: 5. June 2012 - * $Revision: V1.01 - * - * Project: CMSIS-RTOS API - * Title: cmsis_os.h RTX header file - * - * Version 0.02 - * Initial Proposal Phase - * Version 0.03 - * osKernelStart added, optional feature: main started as thread - * osSemaphores have standard behavior - * osTimerCreate does not start the timer, added osTimerStart - * osThreadPass is renamed to osThreadYield - * Version 1.01 - * Support for C++ interface - * - const attribute removed from the osXxxxDef_t typedef's - * - const attribute added to the osXxxxDef macros - * Added: osTimerDelete, osMutexDelete, osSemaphoreDelete - * Added: osKernelInitialize - * -------------------------------------------------------------------- */ - -/** -\page cmsis_os_h Header File Template: cmsis_os.h - -The file \b cmsis_os.h is a template header file for a CMSIS-RTOS compliant Real-Time Operating System (RTOS). -Each RTOS that is compliant with CMSIS-RTOS shall provide a specific \b cmsis_os.h header file that represents -its implementation. - -The file cmsis_os.h contains: - - CMSIS-RTOS API function definitions - - struct definitions for parameters and return types - - status and priority values used by CMSIS-RTOS API functions - - macros for defining threads and other kernel objects - - -<b>Name conventions and header file modifications</b> - -All definitions are prefixed with \b os to give an unique name space for CMSIS-RTOS functions. -Definitions that are prefixed \b os_ are not used in the application code but local to this header file. -All definitions and functions that belong to a module are grouped and have a common prefix, i.e. \b osThread. - -Definitions that are marked with <b>CAN BE CHANGED</b> can be adapted towards the needs of the actual CMSIS-RTOS implementation. -These definitions can be specific to the underlying RTOS kernel. - -Definitions that are marked with <b>MUST REMAIN UNCHANGED</b> cannot be altered. Otherwise the CMSIS-RTOS implementation is no longer -compliant to the standard. Note that some functions are optional and need not to be provided by every CMSIS-RTOS implementation. - - -<b>Function calls from interrupt service routines</b> - -The following CMSIS-RTOS functions can be called from threads and interrupt service routines (ISR): - - \ref osSignalSet - - \ref osSemaphoreRelease - - \ref osPoolAlloc, \ref osPoolCAlloc, \ref osPoolFree - - \ref osMessagePut, \ref osMessageGet - - \ref osMailAlloc, \ref osMailCAlloc, \ref osMailGet, \ref osMailPut, \ref osMailFree - -Functions that cannot be called from an ISR are verifying the interrupt status and return in case that they are called -from an ISR context the status code \b osErrorISR. In some implementations this condition might be caught using the HARD FAULT vector. - -Some CMSIS-RTOS implementations support CMSIS-RTOS function calls from multiple ISR at the same time. -If this is impossible, the CMSIS-RTOS rejects calls by nested ISR functions with the status code \b osErrorISRRecursive. - - -<b>Define and reference object definitions</b> - -With <b>\#define osObjectsExternal</b> objects are defined as external symbols. This allows to create a consistent header file -that is used throughout a project as shown below: - -<i>Header File</i> -\code -#include <cmsis_os.h> // CMSIS RTOS header file - -// Thread definition -extern void thread_sample (void const *argument); // function prototype -osThreadDef (thread_sample, osPriorityBelowNormal, 1, 100); - -// Pool definition -osPoolDef(MyPool, 10, long); -\endcode - - -This header file defines all objects when included in a C/C++ source file. When <b>\#define osObjectsExternal</b> is -present before the header file, the objects are defined as external symbols. A single consistent header file can therefore be -used throughout the whole project. - -<i>Example</i> -\code -#include "osObjects.h" // Definition of the CMSIS-RTOS objects -\endcode - -\code -#define osObjectExternal // Objects will be defined as external symbols -#include "osObjects.h" // Reference to the CMSIS-RTOS objects -\endcode - -*/ - -#ifndef _CMSIS_OS_H -#define _CMSIS_OS_H - -/// \note MUST REMAIN UNCHANGED: \b osCMSIS identifies the CMSIS-RTOS API version. -#define osCMSIS 0x10001 ///< API version (main [31:16] .sub [15:0]) - -/// \note CAN BE CHANGED: \b osCMSIS_KERNEL identifies the underlying RTOS kernel and version number. -#define osCMSIS_RTX ((4<<16)|61) ///< RTOS identification and version (main [31:16] .sub [15:0]) - -/// \note MUST REMAIN UNCHANGED: \b osKernelSystemId shall be consistent in every CMSIS-RTOS. -#define osKernelSystemId "RTX V4.61" ///< RTOS identification string - - -#define CMSIS_OS_RTX - -// The stack space occupied is mainly dependent on the underling C standard library -#if defined(TOOLCHAIN_GCC) || defined(TOOLCHAIN_ARM_STD) || defined(TOOLCHAIN_IAR) -# define WORDS_STACK_SIZE 512 -#elif defined(TOOLCHAIN_ARM_MICRO) -# define WORDS_STACK_SIZE 128 -#endif - -#define DEFAULT_STACK_SIZE (WORDS_STACK_SIZE*4) - - -/// \note MUST REMAIN UNCHANGED: \b osFeature_xxx shall be consistent in every CMSIS-RTOS. -#define osFeature_MainThread 1 ///< main thread 1=main can be thread, 0=not available -#define osFeature_Pool 1 ///< Memory Pools: 1=available, 0=not available -#define osFeature_MailQ 1 ///< Mail Queues: 1=available, 0=not available -#define osFeature_MessageQ 1 ///< Message Queues: 1=available, 0=not available -#define osFeature_Signals 16 ///< maximum number of Signal Flags available per thread -#define osFeature_Semaphore 65535 ///< maximum count for \ref osSemaphoreCreate function -#define osFeature_Wait 0 ///< osWait function: 1=available, 0=not available - -#if defined (__CC_ARM) -#define os_InRegs __value_in_regs // Compiler specific: force struct in registers -#elif defined (__ICCARM__) -#define os_InRegs __value_in_regs // Compiler specific: force struct in registers -#else -#define os_InRegs -#endif - -#include <stdint.h> -#include <stddef.h> - -#ifdef __cplusplus -extern "C" -{ -#endif - -#include "os_tcb.h" - -// ==== Enumeration, structures, defines ==== - -/// Priority used for thread control. -/// \note MUST REMAIN UNCHANGED: \b osPriority shall be consistent in every CMSIS-RTOS. -typedef enum { - osPriorityIdle = -3, ///< priority: idle (lowest) - osPriorityLow = -2, ///< priority: low - osPriorityBelowNormal = -1, ///< priority: below normal - osPriorityNormal = 0, ///< priority: normal (default) - osPriorityAboveNormal = +1, ///< priority: above normal - osPriorityHigh = +2, ///< priority: high - osPriorityRealtime = +3, ///< priority: realtime (highest) - osPriorityError = 0x84 ///< system cannot determine priority or thread has illegal priority -} osPriority; - -/// Timeout value. -/// \note MUST REMAIN UNCHANGED: \b osWaitForever shall be consistent in every CMSIS-RTOS. -#define osWaitForever 0xFFFFFFFF ///< wait forever timeout value - -/// Status code values returned by CMSIS-RTOS functions. -/// \note MUST REMAIN UNCHANGED: \b osStatus shall be consistent in every CMSIS-RTOS. -typedef enum { - osOK = 0, ///< function completed; no error or event occurred. - osEventSignal = 0x08, ///< function completed; signal event occurred. - osEventMessage = 0x10, ///< function completed; message event occurred. - osEventMail = 0x20, ///< function completed; mail event occurred. - osEventTimeout = 0x40, ///< function completed; timeout occurred. - osErrorParameter = 0x80, ///< parameter error: a mandatory parameter was missing or specified an incorrect object. - osErrorResource = 0x81, ///< resource not available: a specified resource was not available. - osErrorTimeoutResource = 0xC1, ///< resource not available within given time: a specified resource was not available within the timeout period. - osErrorISR = 0x82, ///< not allowed in ISR context: the function cannot be called from interrupt service routines. - osErrorISRRecursive = 0x83, ///< function called multiple times from ISR with same object. - osErrorPriority = 0x84, ///< system cannot determine priority or thread has illegal priority. - osErrorNoMemory = 0x85, ///< system is out of memory: it was impossible to allocate or reserve memory for the operation. - osErrorValue = 0x86, ///< value of a parameter is out of range. - osErrorOS = 0xFF, ///< unspecified RTOS error: run-time error but no other error message fits. - os_status_reserved = 0x7FFFFFFF ///< prevent from enum down-size compiler optimization. -} osStatus; - - -/// Timer type value for the timer definition. -/// \note MUST REMAIN UNCHANGED: \b os_timer_type shall be consistent in every CMSIS-RTOS. -typedef enum { - osTimerOnce = 0, ///< one-shot timer - osTimerPeriodic = 1 ///< repeating timer -} os_timer_type; - -/// Entry point of a thread. -/// \note MUST REMAIN UNCHANGED: \b os_pthread shall be consistent in every CMSIS-RTOS. -typedef void (*os_pthread) (void const *argument); - -/// Entry point of a timer call back function. -/// \note MUST REMAIN UNCHANGED: \b os_ptimer shall be consistent in every CMSIS-RTOS. -typedef void (*os_ptimer) (void const *argument); - -// >>> the following data type definitions may shall adapted towards a specific RTOS - -/// Thread ID identifies the thread (pointer to a thread control block). -/// \note CAN BE CHANGED: \b os_thread_cb is implementation specific in every CMSIS-RTOS. -typedef struct os_thread_cb *osThreadId; - -/// Timer ID identifies the timer (pointer to a timer control block). -/// \note CAN BE CHANGED: \b os_timer_cb is implementation specific in every CMSIS-RTOS. -typedef struct os_timer_cb *osTimerId; - -/// Mutex ID identifies the mutex (pointer to a mutex control block). -/// \note CAN BE CHANGED: \b os_mutex_cb is implementation specific in every CMSIS-RTOS. -typedef struct os_mutex_cb *osMutexId; - -/// Semaphore ID identifies the semaphore (pointer to a semaphore control block). -/// \note CAN BE CHANGED: \b os_semaphore_cb is implementation specific in every CMSIS-RTOS. -typedef struct os_semaphore_cb *osSemaphoreId; - -/// Pool ID identifies the memory pool (pointer to a memory pool control block). -/// \note CAN BE CHANGED: \b os_pool_cb is implementation specific in every CMSIS-RTOS. -typedef struct os_pool_cb *osPoolId; - -/// Message ID identifies the message queue (pointer to a message queue control block). -/// \note CAN BE CHANGED: \b os_messageQ_cb is implementation specific in every CMSIS-RTOS. -typedef struct os_messageQ_cb *osMessageQId; - -/// Mail ID identifies the mail queue (pointer to a mail queue control block). -/// \note CAN BE CHANGED: \b os_mailQ_cb is implementation specific in every CMSIS-RTOS. -typedef struct os_mailQ_cb *osMailQId; - - -/// Thread Definition structure contains startup information of a thread. -/// \note CAN BE CHANGED: \b os_thread_def is implementation specific in every CMSIS-RTOS. -typedef struct os_thread_def { - os_pthread pthread; ///< start address of thread function - osPriority tpriority; ///< initial thread priority - uint32_t stacksize; ///< stack size requirements in bytes - uint32_t *stack_pointer; ///< pointer to the stack memory block - struct OS_TCB tcb; -} osThreadDef_t; - -/// Timer Definition structure contains timer parameters. -/// \note CAN BE CHANGED: \b os_timer_def is implementation specific in every CMSIS-RTOS. -typedef struct os_timer_def { - os_ptimer ptimer; ///< start address of a timer function - void *timer; ///< pointer to internal data -} osTimerDef_t; - -/// Mutex Definition structure contains setup information for a mutex. -/// \note CAN BE CHANGED: \b os_mutex_def is implementation specific in every CMSIS-RTOS. -typedef struct os_mutex_def { - void *mutex; ///< pointer to internal data -} osMutexDef_t; - -/// Semaphore Definition structure contains setup information for a semaphore. -/// \note CAN BE CHANGED: \b os_semaphore_def is implementation specific in every CMSIS-RTOS. -typedef struct os_semaphore_def { - void *semaphore; ///< pointer to internal data -} osSemaphoreDef_t; - -/// Definition structure for memory block allocation. -/// \note CAN BE CHANGED: \b os_pool_def is implementation specific in every CMSIS-RTOS. -typedef struct os_pool_def { - uint32_t pool_sz; ///< number of items (elements) in the pool - uint32_t item_sz; ///< size of an item - void *pool; ///< pointer to memory for pool -} osPoolDef_t; - -/// Definition structure for message queue. -/// \note CAN BE CHANGED: \b os_messageQ_def is implementation specific in every CMSIS-RTOS. -typedef struct os_messageQ_def { - uint32_t queue_sz; ///< number of elements in the queue - void *pool; ///< memory array for messages -} osMessageQDef_t; - -/// Definition structure for mail queue. -/// \note CAN BE CHANGED: \b os_mailQ_def is implementation specific in every CMSIS-RTOS. -typedef struct os_mailQ_def { - uint32_t queue_sz; ///< number of elements in the queue - uint32_t item_sz; ///< size of an item - void *pool; ///< memory array for mail -} osMailQDef_t; - -/// Event structure contains detailed information about an event. -/// \note MUST REMAIN UNCHANGED: \b os_event shall be consistent in every CMSIS-RTOS. -/// However the struct may be extended at the end. -typedef struct { - osStatus status; ///< status code: event or error information - union { - uint32_t v; ///< message as 32-bit value - void *p; ///< message or mail as void pointer - int32_t signals; ///< signal flags - } value; ///< event value - union { - osMailQId mail_id; ///< mail id obtained by \ref osMailCreate - osMessageQId message_id; ///< message id obtained by \ref osMessageCreate - } def; ///< event definition -} osEvent; - - -// ==== Kernel Control Functions ==== - -/// Initialize the RTOS Kernel for creating objects. -/// \return status code that indicates the execution status of the function. -/// \note MUST REMAIN UNCHANGED: \b osKernelInitialize shall be consistent in every CMSIS-RTOS. -osStatus osKernelInitialize (void); - -/// Start the RTOS Kernel. -/// \return status code that indicates the execution status of the function. -/// \note MUST REMAIN UNCHANGED: \b osKernelStart shall be consistent in every CMSIS-RTOS. -osStatus osKernelStart (void); - -/// Check if the RTOS kernel is already started. -/// \note MUST REMAIN UNCHANGED: \b osKernelRunning shall be consistent in every CMSIS-RTOS. -/// \return 0 RTOS is not started, 1 RTOS is started. -int32_t osKernelRunning(void); - - -// ==== Thread Management ==== - -/// Create a Thread Definition with function, priority, and stack requirements. -/// \param name name of the thread function. -/// \param priority initial priority of the thread function. -/// \param stacksz stack size (in bytes) requirements for the thread function. -/// \note CAN BE CHANGED: The parameters to \b osThreadDef shall be consistent but the -/// macro body is implementation specific in every CMSIS-RTOS. -#if defined (osObjectsExternal) // object is external -#define osThreadDef(name, priority, stacksz) \ -extern osThreadDef_t os_thread_def_##name -#else // define the object -#define osThreadDef(name, priority, stacksz) \ -uint32_t os_thread_def_stack_##name [stacksz / sizeof(uint32_t)]; \ -osThreadDef_t os_thread_def_##name = \ -{ (name), (priority), (stacksz), (os_thread_def_stack_##name)} -#endif - -/// Access a Thread definition. -/// \param name name of the thread definition object. -/// \note CAN BE CHANGED: The parameter to \b osThread shall be consistent but the -/// macro body is implementation specific in every CMSIS-RTOS. -#define osThread(name) \ -&os_thread_def_##name - -/// Create a thread and add it to Active Threads and set it to state READY. -/// \param[in] thread_def thread definition referenced with \ref osThread. -/// \param[in] argument pointer that is passed to the thread function as start argument. -/// \return thread ID for reference by other functions or NULL in case of error. -/// \note MUST REMAIN UNCHANGED: \b osThreadCreate shall be consistent in every CMSIS-RTOS. -osThreadId osThreadCreate (osThreadDef_t *thread_def, void *argument); - -/// Return the thread ID of the current running thread. -/// \return thread ID for reference by other functions or NULL in case of error. -/// \note MUST REMAIN UNCHANGED: \b osThreadGetId shall be consistent in every CMSIS-RTOS. -osThreadId osThreadGetId (void); - -/// Terminate execution of a thread and remove it from Active Threads. -/// \param[in] thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId. -/// \return status code that indicates the execution status of the function. -/// \note MUST REMAIN UNCHANGED: \b osThreadTerminate shall be consistent in every CMSIS-RTOS. -osStatus osThreadTerminate (osThreadId thread_id); - -/// Pass control to next thread that is in state \b READY. -/// \return status code that indicates the execution status of the function. -/// \note MUST REMAIN UNCHANGED: \b osThreadYield shall be consistent in every CMSIS-RTOS. -osStatus osThreadYield (void); - -/// Change priority of an active thread. -/// \param[in] thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId. -/// \param[in] priority new priority value for the thread function. -/// \return status code that indicates the execution status of the function. -/// \note MUST REMAIN UNCHANGED: \b osThreadSetPriority shall be consistent in every CMSIS-RTOS. -osStatus osThreadSetPriority (osThreadId thread_id, osPriority priority); - -/// Get current priority of an active thread. -/// \param[in] thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId. -/// \return current priority value of the thread function. -/// \note MUST REMAIN UNCHANGED: \b osThreadGetPriority shall be consistent in every CMSIS-RTOS. -osPriority osThreadGetPriority (osThreadId thread_id); - - -// ==== Generic Wait Functions ==== - -/// Wait for Timeout (Time Delay). -/// \param[in] millisec time delay value -/// \return status code that indicates the execution status of the function. -osStatus osDelay (uint32_t millisec); - -#if (defined (osFeature_Wait) && (osFeature_Wait != 0)) // Generic Wait available - -/// Wait for Signal, Message, Mail, or Timeout. -/// \param[in] millisec timeout value or 0 in case of no time-out -/// \return event that contains signal, message, or mail information or error code. -/// \note MUST REMAIN UNCHANGED: \b osWait shall be consistent in every CMSIS-RTOS. -os_InRegs osEvent osWait (uint32_t millisec); - -#endif // Generic Wait available - - -// ==== Timer Management Functions ==== -/// Define a Timer object. -/// \param name name of the timer object. -/// \param function name of the timer call back function. -/// \note CAN BE CHANGED: The parameter to \b osTimerDef shall be consistent but the -/// macro body is implementation specific in every CMSIS-RTOS. -#if defined (osObjectsExternal) // object is external -#define osTimerDef(name, function) \ -extern osTimerDef_t os_timer_def_##name -#else // define the object -#define osTimerDef(name, function) \ -uint32_t os_timer_cb_##name[5]; \ -osTimerDef_t os_timer_def_##name = \ -{ (function), (os_timer_cb_##name) } -#endif - -/// Access a Timer definition. -/// \param name name of the timer object. -/// \note CAN BE CHANGED: The parameter to \b osTimer shall be consistent but the -/// macro body is implementation specific in every CMSIS-RTOS. -#define osTimer(name) \ -&os_timer_def_##name - -/// Create a timer. -/// \param[in] timer_def timer object referenced with \ref osTimer. -/// \param[in] type osTimerOnce for one-shot or osTimerPeriodic for periodic behavior. -/// \param[in] argument argument to the timer call back function. -/// \return timer ID for reference by other functions or NULL in case of error. -/// \note MUST REMAIN UNCHANGED: \b osTimerCreate shall be consistent in every CMSIS-RTOS. -osTimerId osTimerCreate (osTimerDef_t *timer_def, os_timer_type type, void *argument); - -/// Start or restart a timer. -/// \param[in] timer_id timer ID obtained by \ref osTimerCreate. -/// \param[in] millisec time delay value of the timer. -/// \return status code that indicates the execution status of the function. -/// \note MUST REMAIN UNCHANGED: \b osTimerStart shall be consistent in every CMSIS-RTOS. -osStatus osTimerStart (osTimerId timer_id, uint32_t millisec); - -/// Stop the timer. -/// \param[in] timer_id timer ID obtained by \ref osTimerCreate. -/// \return status code that indicates the execution status of the function. -/// \note MUST REMAIN UNCHANGED: \b osTimerStop shall be consistent in every CMSIS-RTOS. -osStatus osTimerStop (osTimerId timer_id); - -/// Delete a timer that was created by \ref osTimerCreate. -/// \param[in] timer_id timer ID obtained by \ref osTimerCreate. -/// \return status code that indicates the execution status of the function. -/// \note MUST REMAIN UNCHANGED: \b osTimerDelete shall be consistent in every CMSIS-RTOS. -osStatus osTimerDelete (osTimerId timer_id); - - -// ==== Signal Management ==== - -/// Set the specified Signal Flags of an active thread. -/// \param[in] thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId. -/// \param[in] signals specifies the signal flags of the thread that should be set. -/// \return previous signal flags of the specified thread or 0x80000000 in case of incorrect parameters. -/// \note MUST REMAIN UNCHANGED: \b osSignalSet shall be consistent in every CMSIS-RTOS. -int32_t osSignalSet (osThreadId thread_id, int32_t signals); - -/// Clear the specified Signal Flags of an active thread. -/// \param[in] thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId. -/// \param[in] signals specifies the signal flags of the thread that shall be cleared. -/// \return previous signal flags of the specified thread or 0x80000000 in case of incorrect parameters. -/// \note MUST REMAIN UNCHANGED: \b osSignalClear shall be consistent in every CMSIS-RTOS. -int32_t osSignalClear (osThreadId thread_id, int32_t signals); - -/// Get Signal Flags status of an active thread. -/// \param[in] thread_id thread ID obtained by \ref osThreadCreate or \ref osThreadGetId. -/// \return previous signal flags of the specified thread or 0x80000000 in case of incorrect parameters. -/// \note MUST REMAIN UNCHANGED: \b osSignalGet shall be consistent in every CMSIS-RTOS. -int32_t osSignalGet (osThreadId thread_id); - -/// Wait for one or more Signal Flags to become signaled for the current \b RUNNING thread. -/// \param[in] signals wait until all specified signal flags set or 0 for any single signal flag. -/// \param[in] millisec timeout value or 0 in case of no time-out. -/// \return event flag information or error code. -/// \note MUST REMAIN UNCHANGED: \b osSignalWait shall be consistent in every CMSIS-RTOS. -os_InRegs osEvent osSignalWait (int32_t signals, uint32_t millisec); - - -// ==== Mutex Management ==== - -/// Define a Mutex. -/// \param name name of the mutex object. -/// \note CAN BE CHANGED: The parameter to \b osMutexDef shall be consistent but the -/// macro body is implementation specific in every CMSIS-RTOS. -#if defined (osObjectsExternal) // object is external -#define osMutexDef(name) \ -extern osMutexDef_t os_mutex_def_##name -#else // define the object -#define osMutexDef(name) \ -uint32_t os_mutex_cb_##name[3]; \ -osMutexDef_t os_mutex_def_##name = { (os_mutex_cb_##name) } -#endif - -/// Access a Mutex definition. -/// \param name name of the mutex object. -/// \note CAN BE CHANGED: The parameter to \b osMutex shall be consistent but the -/// macro body is implementation specific in every CMSIS-RTOS. -#define osMutex(name) \ -&os_mutex_def_##name - -/// Create and Initialize a Mutex object. -/// \param[in] mutex_def mutex definition referenced with \ref osMutex. -/// \return mutex ID for reference by other functions or NULL in case of error. -/// \note MUST REMAIN UNCHANGED: \b osMutexCreate shall be consistent in every CMSIS-RTOS. -osMutexId osMutexCreate (osMutexDef_t *mutex_def); - -/// Wait until a Mutex becomes available. -/// \param[in] mutex_id mutex ID obtained by \ref osMutexCreate. -/// \param[in] millisec timeout value or 0 in case of no time-out. -/// \return status code that indicates the execution status of the function. -/// \note MUST REMAIN UNCHANGED: \b osMutexWait shall be consistent in every CMSIS-RTOS. -osStatus osMutexWait (osMutexId mutex_id, uint32_t millisec); - -/// Release a Mutex that was obtained by \ref osMutexWait. -/// \param[in] mutex_id mutex ID obtained by \ref osMutexCreate. -/// \return status code that indicates the execution status of the function. -/// \note MUST REMAIN UNCHANGED: \b osMutexRelease shall be consistent in every CMSIS-RTOS. -osStatus osMutexRelease (osMutexId mutex_id); - -/// Delete a Mutex that was created by \ref osMutexCreate. -/// \param[in] mutex_id mutex ID obtained by \ref osMutexCreate. -/// \return status code that indicates the execution status of the function. -/// \note MUST REMAIN UNCHANGED: \b osMutexDelete shall be consistent in every CMSIS-RTOS. -osStatus osMutexDelete (osMutexId mutex_id); - - -// ==== Semaphore Management Functions ==== - -#if (defined (osFeature_Semaphore) && (osFeature_Semaphore != 0)) // Semaphore available - -/// Define a Semaphore object. -/// \param name name of the semaphore object. -/// \note CAN BE CHANGED: The parameter to \b osSemaphoreDef shall be consistent but the -/// macro body is implementation specific in every CMSIS-RTOS. -#if defined (osObjectsExternal) // object is external -#define osSemaphoreDef(name) \ -extern osSemaphoreDef_t os_semaphore_def_##name -#else // define the object -#define osSemaphoreDef(name) \ -uint32_t os_semaphore_cb_##name[2]; \ -osSemaphoreDef_t os_semaphore_def_##name = { (os_semaphore_cb_##name) } -#endif - -/// Access a Semaphore definition. -/// \param name name of the semaphore object. -/// \note CAN BE CHANGED: The parameter to \b osSemaphore shall be consistent but the -/// macro body is implementation specific in every CMSIS-RTOS. -#define osSemaphore(name) \ -&os_semaphore_def_##name - -/// Create and Initialize a Semaphore object used for managing resources. -/// \param[in] semaphore_def semaphore definition referenced with \ref osSemaphore. -/// \param[in] count number of available resources. -/// \return semaphore ID for reference by other functions or NULL in case of error. -/// \note MUST REMAIN UNCHANGED: \b osSemaphoreCreate shall be consistent in every CMSIS-RTOS. -osSemaphoreId osSemaphoreCreate (osSemaphoreDef_t *semaphore_def, int32_t count); - -/// Wait until a Semaphore token becomes available. -/// \param[in] semaphore_id semaphore object referenced with \ref osSemaphoreCreate. -/// \param[in] millisec timeout value or 0 in case of no time-out. -/// \return number of available tokens, or -1 in case of incorrect parameters. -/// \note MUST REMAIN UNCHANGED: \b osSemaphoreWait shall be consistent in every CMSIS-RTOS. -int32_t osSemaphoreWait (osSemaphoreId semaphore_id, uint32_t millisec); - -/// Release a Semaphore token. -/// \param[in] semaphore_id semaphore object referenced with \ref osSemaphoreCreate. -/// \return status code that indicates the execution status of the function. -/// \note MUST REMAIN UNCHANGED: \b osSemaphoreRelease shall be consistent in every CMSIS-RTOS. -osStatus osSemaphoreRelease (osSemaphoreId semaphore_id); - -/// Delete a Semaphore that was created by \ref osSemaphoreCreate. -/// \param[in] semaphore_id semaphore object referenced with \ref osSemaphoreCreate. -/// \return status code that indicates the execution status of the function. -/// \note MUST REMAIN UNCHANGED: \b osSemaphoreDelete shall be consistent in every CMSIS-RTOS. -osStatus osSemaphoreDelete (osSemaphoreId semaphore_id); - -#endif // Semaphore available - - -// ==== Memory Pool Management Functions ==== - -#if (defined (osFeature_Pool) && (osFeature_Pool != 0)) // Memory Pool Management available - -/// \brief Define a Memory Pool. -/// \param name name of the memory pool. -/// \param no maximum number of blocks (objects) in the memory pool. -/// \param type data type of a single block (object). -/// \note CAN BE CHANGED: The parameter to \b osPoolDef shall be consistent but the -/// macro body is implementation specific in every CMSIS-RTOS. -#if defined (osObjectsExternal) // object is external -#define osPoolDef(name, no, type) \ -extern osPoolDef_t os_pool_def_##name -#else // define the object -#define osPoolDef(name, no, type) \ -uint32_t os_pool_m_##name[3+((sizeof(type)+3)/4)*(no)]; \ -osPoolDef_t os_pool_def_##name = \ -{ (no), sizeof(type), (os_pool_m_##name) } -#endif - -/// \brief Access a Memory Pool definition. -/// \param name name of the memory pool -/// \note CAN BE CHANGED: The parameter to \b osPool shall be consistent but the -/// macro body is implementation specific in every CMSIS-RTOS. -#define osPool(name) \ -&os_pool_def_##name - -/// Create and Initialize a memory pool. -/// \param[in] pool_def memory pool definition referenced with \ref osPool. -/// \return memory pool ID for reference by other functions or NULL in case of error. -/// \note MUST REMAIN UNCHANGED: \b osPoolCreate shall be consistent in every CMSIS-RTOS. -osPoolId osPoolCreate (osPoolDef_t *pool_def); - -/// Allocate a memory block from a memory pool. -/// \param[in] pool_id memory pool ID obtain referenced with \ref osPoolCreate. -/// \return address of the allocated memory block or NULL in case of no memory available. -/// \note MUST REMAIN UNCHANGED: \b osPoolAlloc shall be consistent in every CMSIS-RTOS. -void *osPoolAlloc (osPoolId pool_id); - -/// Allocate a memory block from a memory pool and set memory block to zero. -/// \param[in] pool_id memory pool ID obtain referenced with \ref osPoolCreate. -/// \return address of the allocated memory block or NULL in case of no memory available. -/// \note MUST REMAIN UNCHANGED: \b osPoolCAlloc shall be consistent in every CMSIS-RTOS. -void *osPoolCAlloc (osPoolId pool_id); - -/// Return an allocated memory block back to a specific memory pool. -/// \param[in] pool_id memory pool ID obtain referenced with \ref osPoolCreate. -/// \param[in] block address of the allocated memory block that is returned to the memory pool. -/// \return status code that indicates the execution status of the function. -/// \note MUST REMAIN UNCHANGED: \b osPoolFree shall be consistent in every CMSIS-RTOS. -osStatus osPoolFree (osPoolId pool_id, void *block); - -#endif // Memory Pool Management available - - -// ==== Message Queue Management Functions ==== - -#if (defined (osFeature_MessageQ) && (osFeature_MessageQ != 0)) // Message Queues available - -/// \brief Create a Message Queue Definition. -/// \param name name of the queue. -/// \param queue_sz maximum number of messages in the queue. -/// \param type data type of a single message element (for debugger). -/// \note CAN BE CHANGED: The parameter to \b osMessageQDef shall be consistent but the -/// macro body is implementation specific in every CMSIS-RTOS. -#if defined (osObjectsExternal) // object is external -#define osMessageQDef(name, queue_sz, type) \ -extern osMessageQDef_t os_messageQ_def_##name -#else // define the object -#define osMessageQDef(name, queue_sz, type) \ -uint32_t os_messageQ_q_##name[4+(queue_sz)]; \ -osMessageQDef_t os_messageQ_def_##name = \ -{ (queue_sz), (os_messageQ_q_##name) } -#endif - -/// \brief Access a Message Queue Definition. -/// \param name name of the queue -/// \note CAN BE CHANGED: The parameter to \b osMessageQ shall be consistent but the -/// macro body is implementation specific in every CMSIS-RTOS. -#define osMessageQ(name) \ -&os_messageQ_def_##name - -/// Create and Initialize a Message Queue. -/// \param[in] queue_def queue definition referenced with \ref osMessageQ. -/// \param[in] thread_id thread ID (obtained by \ref osThreadCreate or \ref osThreadGetId) or NULL. -/// \return message queue ID for reference by other functions or NULL in case of error. -/// \note MUST REMAIN UNCHANGED: \b osMessageCreate shall be consistent in every CMSIS-RTOS. -osMessageQId osMessageCreate (osMessageQDef_t *queue_def, osThreadId thread_id); - -/// Put a Message to a Queue. -/// \param[in] queue_id message queue ID obtained with \ref osMessageCreate. -/// \param[in] info message information. -/// \param[in] millisec timeout value or 0 in case of no time-out. -/// \return status code that indicates the execution status of the function. -/// \note MUST REMAIN UNCHANGED: \b osMessagePut shall be consistent in every CMSIS-RTOS. -osStatus osMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec); - -/// Get a Message or Wait for a Message from a Queue. -/// \param[in] queue_id message queue ID obtained with \ref osMessageCreate. -/// \param[in] millisec timeout value or 0 in case of no time-out. -/// \return event information that includes status code. -/// \note MUST REMAIN UNCHANGED: \b osMessageGet shall be consistent in every CMSIS-RTOS. -os_InRegs osEvent osMessageGet (osMessageQId queue_id, uint32_t millisec); - -#endif // Message Queues available - - -// ==== Mail Queue Management Functions ==== - -#if (defined (osFeature_MailQ) && (osFeature_MailQ != 0)) // Mail Queues available - -/// \brief Create a Mail Queue Definition. -/// \param name name of the queue -/// \param queue_sz maximum number of messages in queue -/// \param type data type of a single message element -/// \note CAN BE CHANGED: The parameter to \b osMailQDef shall be consistent but the -/// macro body is implementation specific in every CMSIS-RTOS. -#if defined (osObjectsExternal) // object is external -#define osMailQDef(name, queue_sz, type) \ -extern osMailQDef_t os_mailQ_def_##name -#else // define the object -#define osMailQDef(name, queue_sz, type) \ -uint32_t os_mailQ_q_##name[4+(queue_sz)]; \ -uint32_t os_mailQ_m_##name[3+((sizeof(type)+3)/4)*(queue_sz)]; \ -void * os_mailQ_p_##name[2] = { (os_mailQ_q_##name), os_mailQ_m_##name }; \ -osMailQDef_t os_mailQ_def_##name = \ -{ (queue_sz), sizeof(type), (os_mailQ_p_##name) } -#endif - -/// \brief Access a Mail Queue Definition. -/// \param name name of the queue -/// \note CAN BE CHANGED: The parameter to \b osMailQ shall be consistent but the -/// macro body is implementation specific in every CMSIS-RTOS. -#define osMailQ(name) \ -&os_mailQ_def_##name - -/// Create and Initialize mail queue. -/// \param[in] queue_def reference to the mail queue definition obtain with \ref osMailQ -/// \param[in] thread_id thread ID (obtained by \ref osThreadCreate or \ref osThreadGetId) or NULL. -/// \return mail queue ID for reference by other functions or NULL in case of error. -/// \note MUST REMAIN UNCHANGED: \b osMailCreate shall be consistent in every CMSIS-RTOS. -osMailQId osMailCreate (osMailQDef_t *queue_def, osThreadId thread_id); - -/// Allocate a memory block from a mail. -/// \param[in] queue_id mail queue ID obtained with \ref osMailCreate. -/// \param[in] millisec timeout value or 0 in case of no time-out -/// \return pointer to memory block that can be filled with mail or NULL in case of error. -/// \note MUST REMAIN UNCHANGED: \b osMailAlloc shall be consistent in every CMSIS-RTOS. -void *osMailAlloc (osMailQId queue_id, uint32_t millisec); - -/// Allocate a memory block from a mail and set memory block to zero. -/// \param[in] queue_id mail queue ID obtained with \ref osMailCreate. -/// \param[in] millisec timeout value or 0 in case of no time-out -/// \return pointer to memory block that can be filled with mail or NULL in case of error. -/// \note MUST REMAIN UNCHANGED: \b osMailCAlloc shall be consistent in every CMSIS-RTOS. -void *osMailCAlloc (osMailQId queue_id, uint32_t millisec); - -/// Put a mail to a queue. -/// \param[in] queue_id mail queue ID obtained with \ref osMailCreate. -/// \param[in] mail memory block previously allocated with \ref osMailAlloc or \ref osMailCAlloc. -/// \return status code that indicates the execution status of the function. -/// \note MUST REMAIN UNCHANGED: \b osMailPut shall be consistent in every CMSIS-RTOS. -osStatus osMailPut (osMailQId queue_id, void *mail); - -/// Get a mail from a queue. -/// \param[in] queue_id mail queue ID obtained with \ref osMailCreate. -/// \param[in] millisec timeout value or 0 in case of no time-out -/// \return event that contains mail information or error code. -/// \note MUST REMAIN UNCHANGED: \b osMailGet shall be consistent in every CMSIS-RTOS. -os_InRegs osEvent osMailGet (osMailQId queue_id, uint32_t millisec); - -/// Free a memory block from a mail. -/// \param[in] queue_id mail queue ID obtained with \ref osMailCreate. -/// \param[in] mail pointer to the memory block that was obtained with \ref osMailGet. -/// \return status code that indicates the execution status of the function. -/// \note MUST REMAIN UNCHANGED: \b osMailFree shall be consistent in every CMSIS-RTOS. -osStatus osMailFree (osMailQId queue_id, void *mail); - -#endif // Mail Queues available - - -#ifdef __cplusplus -} -#endif - -#endif // _CMSIS_OS_H diff --git a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/os_tcb.h b/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/os_tcb.h deleted file mode 100644 index 800f7f5..0000000 --- a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/os_tcb.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef OS_TCB_H -#define OS_TCB_H - -/* Types */ -typedef char S8; -typedef unsigned char U8; -typedef short S16; -typedef unsigned short U16; -typedef int S32; -typedef unsigned int U32; -typedef long long S64; -typedef unsigned long long U64; -typedef unsigned char BIT; -typedef unsigned int BOOL; -typedef void (*FUNCP)(void); - -typedef struct OS_TCB { - /* General part: identical for all implementations. */ - U8 cb_type; /* Control Block Type */ - U8 state; /* Task state */ - U8 prio; /* Execution priority */ - U8 task_id; /* Task ID value for optimized TCB access */ - struct OS_TCB *p_lnk; /* Link pointer for ready/sem. wait list */ - struct OS_TCB *p_rlnk; /* Link pointer for sem./mbx lst backwards */ - struct OS_TCB *p_dlnk; /* Link pointer for delay list */ - struct OS_TCB *p_blnk; /* Link pointer for delay list backwards */ - U16 delta_time; /* Time until time out */ - U16 interval_time; /* Time interval for periodic waits */ - U16 events; /* Event flags */ - U16 waits; /* Wait flags */ - void **msg; /* Direct message passing when task waits */ - - /* Hardware dependant part: specific for CM processor */ - U8 stack_frame; /* Stack frame: 0=Basic, 1=Extended */ - U8 reserved1; - U16 reserved2; - U32 priv_stack; /* Private stack size in bytes */ - U32 tsk_stack; /* Current task Stack pointer (R13) */ - U32 *stack; /* Pointer to Task Stack memory block */ - - /* Library dependant part */ -#if defined (__CC_ARM) && !defined (__MICROLIB) - /* A memory space for arm standard library. */ - U32 std_libspace[96/4]; -#endif - - /* Task entry point used for uVision debugger */ - FUNCP ptask; /* Task entry address */ -} *P_TCB; - -#endif diff --git a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_CMSIS.c b/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_CMSIS.c deleted file mode 100644 index a747caf..0000000 --- a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_CMSIS.c +++ /dev/null @@ -1,1887 +0,0 @@ -/*---------------------------------------------------------------------------- - * RL-ARM - RTX - *---------------------------------------------------------------------------- - * Name: rt_CMSIS.c - * Purpose: CMSIS RTOS API - * Rev.: V4.60 - *---------------------------------------------------------------------------- - * - * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - Neither the name of ARM nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - *---------------------------------------------------------------------------*/ - -#define __CMSIS_GENERIC - -#if defined (__CORTEX_M4) || defined (__CORTEX_M4F) - #include "core_cm4.h" -#elif defined (__CORTEX_M7) || defined (__CORTEX_M7F) - #include "core_cm7.h" -#elif defined (__CORTEX_M3) - #include "core_cm3.h" -#elif defined (__CORTEX_M0) - #include "core_cm0.h" -#elif defined (__CORTEX_M0PLUS) - #include "core_cm0plus.h" -#else - #error "Missing __CORTEX_Mx definition" -#endif - -#include "rt_TypeDef.h" -#include "RTX_Conf.h" -#include "rt_System.h" -#include "rt_Task.h" -#include "rt_Event.h" -#include "rt_List.h" -#include "rt_Time.h" -#include "rt_Mutex.h" -#include "rt_Semaphore.h" -#include "rt_Mailbox.h" -#include "rt_MemBox.h" -#include "rt_HAL_CM.h" - -#define os_thread_cb OS_TCB - -#include "cmsis_os.h" - -#if (osFeature_Signals != 16) -#error Invalid "osFeature_Signals" value! -#endif -#if (osFeature_Semaphore > 65535) -#error Invalid "osFeature_Semaphore" value! -#endif -#if (osFeature_Wait != 0) -#error osWait not supported! -#endif - - -// ==== Enumeration, structures, defines ==== - -// Service Calls defines - -#if defined (__CC_ARM) /* ARM Compiler */ - -#define __NO_RETURN __declspec(noreturn) - -#define osEvent_type osEvent -#define osEvent_ret_status ret -#define osEvent_ret_value ret -#define osEvent_ret_msg ret -#define osEvent_ret_mail ret - -#define osCallback_type osCallback -#define osCallback_ret ret - -#define SVC_0_1(f,t,...) \ -__svc_indirect(0) t _##f (t(*)()); \ - t f (void); \ -__attribute__((always_inline)) \ -static __inline t __##f (void) { \ - return _##f(f); \ -} - -#define SVC_1_1(f,t,t1,...) \ -__svc_indirect(0) t _##f (t(*)(t1),t1); \ - t f (t1 a1); \ -__attribute__((always_inline)) \ -static __inline t __##f (t1 a1) { \ - return _##f(f,a1); \ -} - -#define SVC_2_1(f,t,t1,t2,...) \ -__svc_indirect(0) t _##f (t(*)(t1,t2),t1,t2); \ - t f (t1 a1, t2 a2); \ -__attribute__((always_inline)) \ -static __inline t __##f (t1 a1, t2 a2) { \ - return _##f(f,a1,a2); \ -} - -#define SVC_3_1(f,t,t1,t2,t3,...) \ -__svc_indirect(0) t _##f (t(*)(t1,t2,t3),t1,t2,t3); \ - t f (t1 a1, t2 a2, t3 a3); \ -__attribute__((always_inline)) \ -static __inline t __##f (t1 a1, t2 a2, t3 a3) { \ - return _##f(f,a1,a2,a3); \ -} - -#define SVC_4_1(f,t,t1,t2,t3,t4,...) \ -__svc_indirect(0) t _##f (t(*)(t1,t2,t3,t4),t1,t2,t3,t4); \ - t f (t1 a1, t2 a2, t3 a3, t4 a4); \ -__attribute__((always_inline)) \ -static __inline t __##f (t1 a1, t2 a2, t3 a3, t4 a4) { \ - return _##f(f,a1,a2,a3,a4); \ -} - -#define SVC_1_2 SVC_1_1 -#define SVC_1_3 SVC_1_1 -#define SVC_2_3 SVC_2_1 - -#elif defined (__GNUC__) /* GNU Compiler */ - -#define __NO_RETURN __attribute__((noreturn)) - -typedef uint32_t __attribute__((vector_size(8))) ret64; -typedef uint32_t __attribute__((vector_size(16))) ret128; - -#define RET_pointer __r0 -#define RET_int32_t __r0 -#define RET_osStatus __r0 -#define RET_osPriority __r0 -#define RET_osEvent {(osStatus)__r0, {(uint32_t)__r1}, {(void *)__r2}} -#define RET_osCallback {(void *)__r0, (void *)__r1} - -#define osEvent_type ret128 -#define osEvent_ret_status (ret128){ret.status} -#define osEvent_ret_value (ret128){ret.status, ret.value.v} -#define osEvent_ret_msg (ret128){ret.status, ret.value.v, (uint32_t)ret.def.message_id} -#define osEvent_ret_mail (ret128){ret.status, ret.value.v, (uint32_t)ret.def.mail_id} - -#define osCallback_type ret64 -#define osCallback_ret (ret64) {(uint32_t)ret.fp, (uint32_t)ret.arg} - -#define SVC_ArgN(n) \ - register int __r##n __asm("r"#n); - -#define SVC_ArgR(n,t,a) \ - register t __r##n __asm("r"#n) = a; - -#define SVC_Arg0() \ - SVC_ArgN(0) \ - SVC_ArgN(1) \ - SVC_ArgN(2) \ - SVC_ArgN(3) - -#define SVC_Arg1(t1) \ - SVC_ArgR(0,t1,a1) \ - SVC_ArgN(1) \ - SVC_ArgN(2) \ - SVC_ArgN(3) - -#define SVC_Arg2(t1,t2) \ - SVC_ArgR(0,t1,a1) \ - SVC_ArgR(1,t2,a2) \ - SVC_ArgN(2) \ - SVC_ArgN(3) - -#define SVC_Arg3(t1,t2,t3) \ - SVC_ArgR(0,t1,a1) \ - SVC_ArgR(1,t2,a2) \ - SVC_ArgR(2,t3,a3) \ - SVC_ArgN(3) - -#define SVC_Arg4(t1,t2,t3,t4) \ - SVC_ArgR(0,t1,a1) \ - SVC_ArgR(1,t2,a2) \ - SVC_ArgR(2,t3,a3) \ - SVC_ArgR(3,t4,a4) - -#if (defined (__CORTEX_M0)) || defined (__CORTEX_M0PLUS) -#define SVC_Call(f) \ - __asm volatile \ - ( \ - "ldr r7,="#f"\n\t" \ - "mov r12,r7\n\t" \ - "svc 0" \ - : "=r" (__r0), "=r" (__r1), "=r" (__r2), "=r" (__r3) \ - : "r" (__r0), "r" (__r1), "r" (__r2), "r" (__r3) \ - : "r7", "r12", "lr", "cc" \ - ); -#else -#define SVC_Call(f) \ - __asm volatile \ - ( \ - "ldr r12,="#f"\n\t" \ - "svc 0" \ - : "=r" (__r0), "=r" (__r1), "=r" (__r2), "=r" (__r3) \ - : "r" (__r0), "r" (__r1), "r" (__r2), "r" (__r3) \ - : "r12", "lr", "cc" \ - ); -#endif - -#define SVC_0_1(f,t,rv) \ -__attribute__((always_inline)) \ -static inline t __##f (void) { \ - SVC_Arg0(); \ - SVC_Call(f); \ - return (t) rv; \ -} - -#define SVC_1_1(f,t,t1,rv) \ -__attribute__((always_inline)) \ -static inline t __##f (t1 a1) { \ - SVC_Arg1(t1); \ - SVC_Call(f); \ - return (t) rv; \ -} - -#define SVC_2_1(f,t,t1,t2,rv) \ -__attribute__((always_inline)) \ -static inline t __##f (t1 a1, t2 a2) { \ - SVC_Arg2(t1,t2); \ - SVC_Call(f); \ - return (t) rv; \ -} - -#define SVC_3_1(f,t,t1,t2,t3,rv) \ -__attribute__((always_inline)) \ -static inline t __##f (t1 a1, t2 a2, t3 a3) { \ - SVC_Arg3(t1,t2,t3); \ - SVC_Call(f); \ - return (t) rv; \ -} - -#define SVC_4_1(f,t,t1,t2,t3,t4,rv) \ -__attribute__((always_inline)) \ -static inline t __##f (t1 a1, t2 a2, t3 a3, t4 a4) { \ - SVC_Arg4(t1,t2,t3,t4); \ - SVC_Call(f); \ - return (t) rv; \ -} - -#define SVC_1_2 SVC_1_1 -#define SVC_1_3 SVC_1_1 -#define SVC_2_3 SVC_2_1 - -#elif defined (__ICCARM__) /* IAR Compiler */ - -#define __NO_RETURN __noreturn - -#define osEvent_type osEvent -#define osEvent_ret_status ret -#define osEvent_ret_value ret -#define osEvent_ret_msg ret -#define osEvent_ret_mail ret - -#define osCallback_type osCallback -#define osCallback_ret ret - -#define RET_osEvent osEvent -#define RET_osCallback osCallback - -#define SVC_Setup(f) \ - __asm( \ - "mov r12,%0\n" \ - :: "r"(&f): "r12" \ - ); - - -#define SVC_0_1(f,t,...) \ -t f (void); \ -_Pragma("swi_number=0") __swi t _##f (void); \ -static inline t __##f (void) { \ - SVC_Setup(f); \ - return _##f(); \ -} - -#define SVC_1_1(f,t,t1,...) \ -t f (t1 a1); \ -_Pragma("swi_number=0") __swi t _##f (t1 a1); \ -static inline t __##f (t1 a1) { \ - SVC_Setup(f); \ - return _##f(a1); \ -} - -#define SVC_2_1(f,t,t1,t2,...) \ -t f (t1 a1, t2 a2); \ -_Pragma("swi_number=0") __swi t _##f (t1 a1, t2 a2); \ -static inline t __##f (t1 a1, t2 a2) { \ - SVC_Setup(f); \ - return _##f(a1,a2); \ -} - -#define SVC_3_1(f,t,t1,t2,t3,...) \ -t f (t1 a1, t2 a2, t3 a3); \ -_Pragma("swi_number=0") __swi t _##f (t1 a1, t2 a2, t3 a3); \ -static inline t __##f (t1 a1, t2 a2, t3 a3) { \ - SVC_Setup(f); \ - return _##f(a1,a2,a3); \ -} - -#define SVC_4_1(f,t,t1,t2,t3,t4,...) \ -t f (t1 a1, t2 a2, t3 a3, t4 a4); \ -_Pragma("swi_number=0") __swi t _##f (t1 a1, t2 a2, t3 a3, t4 a4); \ -static inline t __##f (t1 a1, t2 a2, t3 a3, t4 a4) { \ - SVC_Setup(f); \ - return _##f(a1,a2,a3,a4); \ -} - -#define SVC_1_2 SVC_1_1 -#define SVC_1_3 SVC_1_1 -#define SVC_2_3 SVC_2_1 - -#endif - - -// Callback structure -typedef struct { - void *fp; // Function pointer - void *arg; // Function argument -} osCallback; - - -// OS Section definitions -#ifdef OS_SECTIONS_LINK_INFO -extern const uint32_t os_section_id$$Base; -extern const uint32_t os_section_id$$Limit; -#endif - -// OS Timers external resources -extern osThreadDef_t os_thread_def_osTimerThread; -extern osThreadId osThreadId_osTimerThread; -extern osMessageQDef_t os_messageQ_def_osTimerMessageQ; -extern osMessageQId osMessageQId_osTimerMessageQ; - - -// ==== Helper Functions ==== - -/// Convert timeout in millisec to system ticks -static uint32_t rt_ms2tick (uint32_t millisec) { - uint32_t tick; - - if (millisec == osWaitForever) return 0xFFFF; // Indefinite timeout - if (millisec > 4000000) return 0xFFFE; // Max ticks supported - - tick = ((1000 * millisec) + os_clockrate - 1) / os_clockrate; - if (tick > 0xFFFE) return 0xFFFE; - - return tick; -} - -/// Convert Thread ID to TCB pointer -static P_TCB rt_tid2ptcb (osThreadId thread_id) { - P_TCB ptcb; - - if (thread_id == NULL) return NULL; - - if ((uint32_t)thread_id & 3) return NULL; - -#ifdef OS_SECTIONS_LINK_INFO - if ((os_section_id$$Base != 0) && (os_section_id$$Limit != 0)) { - if (thread_id < (osThreadId)os_section_id$$Base) return NULL; - if (thread_id >= (osThreadId)os_section_id$$Limit) return NULL; - } -#endif - - ptcb = thread_id; - - if (ptcb->cb_type != TCB) return NULL; - - return ptcb; -} - -/// Convert ID pointer to Object pointer -static void *rt_id2obj (void *id) { - - if ((uint32_t)id & 3) return NULL; - -#ifdef OS_SECTIONS_LINK_INFO - if ((os_section_id$$Base != 0) && (os_section_id$$Limit != 0)) { - if (id < (void *)os_section_id$$Base) return NULL; - if (id >= (void *)os_section_id$$Limit) return NULL; - } -#endif - - return id; -} - - -// ==== Kernel Control ==== - -uint8_t os_initialized; // Kernel Initialized flag -uint8_t os_running; // Kernel Running flag - -// Kernel Control Service Calls declarations -SVC_0_1(svcKernelInitialize, osStatus, RET_osStatus) -SVC_0_1(svcKernelStart, osStatus, RET_osStatus) -SVC_0_1(svcKernelRunning, int32_t, RET_int32_t) - -extern void sysThreadError (osStatus status); -osThreadId svcThreadCreate (osThreadDef_t *thread_def, void *argument); -osMessageQId svcMessageCreate (osMessageQDef_t *queue_def, osThreadId thread_id); - -// Kernel Control Service Calls - -/// Initialize the RTOS Kernel for creating objects -osStatus svcKernelInitialize (void) { - if (os_initialized) return osOK; - - rt_sys_init(); // RTX System Initialization - os_tsk.run->prio = 255; // Highest priority - - sysThreadError(osOK); - - os_initialized = 1; - - return osOK; -} - -/// Start the RTOS Kernel -osStatus svcKernelStart (void) { - - if (os_running) return osOK; - - // Create OS Timers resources (Message Queue & Thread) - osMessageQId_osTimerMessageQ = svcMessageCreate (&os_messageQ_def_osTimerMessageQ, NULL); - osThreadId_osTimerThread = svcThreadCreate(&os_thread_def_osTimerThread, NULL); - - rt_tsk_prio(0, 0); // Lowest priority - __set_PSP(os_tsk.run->tsk_stack + 8*4); // New context - os_tsk.run = NULL; // Force context switch - - rt_sys_start(); - - os_running = 1; - - return osOK; -} - -/// Check if the RTOS kernel is already started -int32_t svcKernelRunning(void) { - return os_running; -} - -// Kernel Control Public API - -/// Initialize the RTOS Kernel for creating objects -osStatus osKernelInitialize (void) { - if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR - if ((__get_CONTROL() & 1) == 0) { // Privileged mode - return svcKernelInitialize(); - } else { - return __svcKernelInitialize(); - } -} - -/// Start the RTOS Kernel -osStatus osKernelStart (void) { - uint32_t stack[8]; - - if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR - switch (__get_CONTROL() & 0x03) { - case 0x00: // Privileged Thread mode & MSP - __set_PSP((uint32_t)(stack + 8)); // Initial PSP - if (os_flags & 1) { - __set_CONTROL(0x02); // Set Privileged Thread mode & PSP - } else { - __set_CONTROL(0x03); // Set Unprivileged Thread mode & PSP - } - __DSB(); - __ISB(); - break; - case 0x01: // Unprivileged Thread mode & MSP - return osErrorOS; - case 0x02: // Privileged Thread mode & PSP - if ((os_flags & 1) == 0) { // Unprivileged Thread mode requested - __set_CONTROL(0x03); // Set Unprivileged Thread mode & PSP - __DSB(); - __ISB(); - } - break; - case 0x03: // Unprivileged Thread mode & PSP - if (os_flags & 1) return osErrorOS; // Privileged Thread mode requested - break; - } - return __svcKernelStart(); -} - -/// Check if the RTOS kernel is already started -int32_t osKernelRunning(void) { - if ((__get_IPSR() != 0) || ((__get_CONTROL() & 1) == 0)) { - // in ISR or Privileged - return os_running; - } else { - return __svcKernelRunning(); - } -} - - -// ==== Thread Management ==== - -__NO_RETURN void osThreadExit (void); - -// Thread Service Calls declarations -SVC_2_1(svcThreadCreate, osThreadId, osThreadDef_t *, void *, RET_pointer) -SVC_0_1(svcThreadGetId, osThreadId, RET_pointer) -SVC_1_1(svcThreadTerminate, osStatus, osThreadId, RET_osStatus) -SVC_0_1(svcThreadYield, osStatus, RET_osStatus) -SVC_2_1(svcThreadSetPriority, osStatus, osThreadId, osPriority, RET_osStatus) -SVC_1_1(svcThreadGetPriority, osPriority, osThreadId, RET_osPriority) - -// Thread Service Calls -extern OS_TID rt_get_TID (void); -extern void rt_init_context (P_TCB p_TCB, U8 priority, FUNCP task_body); - -/// Create a thread and add it to Active Threads and set it to state READY -osThreadId svcThreadCreate (osThreadDef_t *thread_def, void *argument) { - P_TCB ptcb; - - if ((thread_def == NULL) || - (thread_def->pthread == NULL) || - (thread_def->tpriority < osPriorityIdle) || - (thread_def->tpriority > osPriorityRealtime) || - (thread_def->stacksize == 0) || - (thread_def->stack_pointer == NULL) ) { - sysThreadError(osErrorParameter); - return NULL; - } - - U8 priority = thread_def->tpriority - osPriorityIdle + 1; - P_TCB task_context = &thread_def->tcb; - - /* Utilize the user provided stack. */ - task_context->stack = (U32*)thread_def->stack_pointer; - task_context->priv_stack = thread_def->stacksize; - /* Find a free entry in 'os_active_TCB' table. */ - OS_TID tsk = rt_get_TID (); - os_active_TCB[tsk-1] = task_context; - task_context->task_id = tsk; - /* Pass parameter 'argv' to 'rt_init_context' */ - task_context->msg = argument; - /* Initialize thread context structure, including the thread's stack. */ - rt_init_context (task_context, priority, (FUNCP)thread_def->pthread); - - /* Dispatch this task to the scheduler for execution. */ - DBG_TASK_NOTIFY(task_context, __TRUE); - rt_dispatch (task_context); - - ptcb = (P_TCB)os_active_TCB[tsk - 1]; // TCB pointer - - *((uint32_t *)ptcb->tsk_stack + 13) = (uint32_t)osThreadExit; - - return ptcb; -} - -/// Return the thread ID of the current running thread -osThreadId svcThreadGetId (void) { - OS_TID tsk; - - tsk = rt_tsk_self(); - if (tsk == 0) return NULL; - return (P_TCB)os_active_TCB[tsk - 1]; -} - -/// Terminate execution of a thread and remove it from ActiveThreads -osStatus svcThreadTerminate (osThreadId thread_id) { - OS_RESULT res; - P_TCB ptcb; - - ptcb = rt_tid2ptcb(thread_id); // Get TCB pointer - if (ptcb == NULL) return osErrorParameter; - - res = rt_tsk_delete(ptcb->task_id); // Delete task - - if (res == OS_R_NOK) return osErrorResource; // Delete task failed - - return osOK; -} - -/// Pass control to next thread that is in state READY -osStatus svcThreadYield (void) { - rt_tsk_pass(); // Pass control to next task - return osOK; -} - -/// Change priority of an active thread -osStatus svcThreadSetPriority (osThreadId thread_id, osPriority priority) { - OS_RESULT res; - P_TCB ptcb; - - ptcb = rt_tid2ptcb(thread_id); // Get TCB pointer - if (ptcb == NULL) return osErrorParameter; - - if ((priority < osPriorityIdle) || (priority > osPriorityRealtime)) { - return osErrorValue; - } - - res = rt_tsk_prio( // Change task priority - ptcb->task_id, // Task ID - priority - osPriorityIdle + 1 // New task priority - ); - - if (res == OS_R_NOK) return osErrorResource; // Change task priority failed - - return osOK; -} - -/// Get current priority of an active thread -osPriority svcThreadGetPriority (osThreadId thread_id) { - P_TCB ptcb; - - ptcb = rt_tid2ptcb(thread_id); // Get TCB pointer - if (ptcb == NULL) return osPriorityError; - - return (osPriority)(ptcb->prio - 1 + osPriorityIdle); -} - - -// Thread Public API - -/// Create a thread and add it to Active Threads and set it to state READY -osThreadId osThreadCreate (osThreadDef_t *thread_def, void *argument) { - if (__get_IPSR() != 0) return NULL; // Not allowed in ISR - if (((__get_CONTROL() & 1) == 0) && (os_running == 0)) { - // Privileged and not running - return svcThreadCreate(thread_def, argument); - } else { - return __svcThreadCreate(thread_def, argument); - } -} - -/// Return the thread ID of the current running thread -osThreadId osThreadGetId (void) { - if (__get_IPSR() != 0) return NULL; // Not allowed in ISR - return __svcThreadGetId(); -} - -/// Terminate execution of a thread and remove it from ActiveThreads -osStatus osThreadTerminate (osThreadId thread_id) { - if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR - return __svcThreadTerminate(thread_id); -} - -/// Pass control to next thread that is in state READY -osStatus osThreadYield (void) { - if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR - return __svcThreadYield(); -} - -/// Change priority of an active thread -osStatus osThreadSetPriority (osThreadId thread_id, osPriority priority) { - if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR - return __svcThreadSetPriority(thread_id, priority); -} - -/// Get current priority of an active thread -osPriority osThreadGetPriority (osThreadId thread_id) { - if (__get_IPSR() != 0) return osPriorityError;// Not allowed in ISR - return __svcThreadGetPriority(thread_id); -} - -/// INTERNAL - Not Public -/// Auto Terminate Thread on exit (used implicitly when thread exists) -__NO_RETURN void osThreadExit (void) { - __svcThreadTerminate(__svcThreadGetId()); - for (;;); // Should never come here -} - - -// ==== Generic Wait Functions ==== - -// Generic Wait Service Calls declarations -SVC_1_1(svcDelay, osStatus, uint32_t, RET_osStatus) -#if osFeature_Wait != 0 -SVC_1_3(svcWait, os_InRegs osEvent, uint32_t, RET_osEvent) -#endif - -// Generic Wait Service Calls - -/// Wait for Timeout (Time Delay) -osStatus svcDelay (uint32_t millisec) { - if (millisec == 0) return osOK; - rt_dly_wait(rt_ms2tick(millisec)); - return osEventTimeout; -} - -/// Wait for Signal, Message, Mail, or Timeout -#if osFeature_Wait != 0 -os_InRegs osEvent_type svcWait (uint32_t millisec) { - osEvent ret; - - if (millisec == 0) { - ret.status = osOK; - return osEvent_ret_status; - } - - /* To Do: osEventSignal, osEventMessage, osEventMail */ - rt_dly_wait(rt_ms2tick(millisec)); - ret.status = osEventTimeout; - - return osEvent_ret_status; -} -#endif - - -// Generic Wait API - -/// Wait for Timeout (Time Delay) -osStatus osDelay (uint32_t millisec) { - if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR - return __svcDelay(millisec); -} - -/// Wait for Signal, Message, Mail, or Timeout -os_InRegs osEvent osWait (uint32_t millisec) { - osEvent ret; - -#if osFeature_Wait == 0 - ret.status = osErrorOS; - return ret; -#else - if (__get_IPSR() != 0) { // Not allowed in ISR - ret.status = osErrorISR; - return ret; - } - return __svcWait(millisec); -#endif -} - - -// ==== Timer Management ==== - -// Timer definitions -#define osTimerInvalid 0 -#define osTimerStopped 1 -#define osTimerRunning 2 - -// Timer structures - -typedef struct os_timer_cb_ { // Timer Control Block - struct os_timer_cb_ *next; // Pointer to next active Timer - uint8_t state; // Timer State - uint8_t type; // Timer Type (Periodic/One-shot) - uint16_t reserved; // Reserved - uint16_t tcnt; // Timer Delay Count - uint16_t icnt; // Timer Initial Count - void *arg; // Timer Function Argument - osTimerDef_t *timer; // Pointer to Timer definition -} os_timer_cb; - -// Timer variables -os_timer_cb *os_timer_head; // Pointer to first active Timer - - -// Timer Helper Functions - -// Insert Timer into the list sorted by time -static void rt_timer_insert (os_timer_cb *pt, uint32_t tcnt) { - os_timer_cb *p, *prev; - - prev = NULL; - p = os_timer_head; - while (p != NULL) { - if (tcnt < p->tcnt) break; - tcnt -= p->tcnt; - prev = p; - p = p->next; - } - pt->next = p; - pt->tcnt = (uint16_t)tcnt; - if (p != NULL) { - p->tcnt -= pt->tcnt; - } - if (prev != NULL) { - prev->next = pt; - } else { - os_timer_head = pt; - } -} - -// Remove Timer from the list -static int rt_timer_remove (os_timer_cb *pt) { - os_timer_cb *p, *prev; - - prev = NULL; - p = os_timer_head; - while (p != NULL) { - if (p == pt) break; - prev = p; - p = p->next; - } - if (p == NULL) return -1; - if (prev != NULL) { - prev->next = pt->next; - } else { - os_timer_head = pt->next; - } - if (pt->next != NULL) { - pt->next->tcnt += pt->tcnt; - } - - return 0; -} - - -// Timer Service Calls declarations -SVC_3_1(svcTimerCreate, osTimerId, osTimerDef_t *, os_timer_type, void *, RET_pointer) -SVC_2_1(svcTimerStart, osStatus, osTimerId, uint32_t, RET_osStatus) -SVC_1_1(svcTimerStop, osStatus, osTimerId, RET_osStatus) -SVC_1_1(svcTimerDelete, osStatus, osTimerId, RET_osStatus) -SVC_1_2(svcTimerCall, os_InRegs osCallback, osTimerId, RET_osCallback) - -// Timer Management Service Calls - -/// Create timer -osTimerId svcTimerCreate (osTimerDef_t *timer_def, os_timer_type type, void *argument) { - os_timer_cb *pt; - - if ((timer_def == NULL) || (timer_def->ptimer == NULL)) { - sysThreadError(osErrorParameter); - return NULL; - } - - pt = timer_def->timer; - if (pt == NULL) { - sysThreadError(osErrorParameter); - return NULL; - } - - if ((type != osTimerOnce) && (type != osTimerPeriodic)) { - sysThreadError(osErrorValue); - return NULL; - } - - if (osThreadId_osTimerThread == NULL) { - sysThreadError(osErrorResource); - return NULL; - } - - if (pt->state != osTimerInvalid){ - sysThreadError(osErrorResource); - return NULL; - } - - pt->state = osTimerStopped; - pt->type = (uint8_t)type; - pt->arg = argument; - pt->timer = timer_def; - - return (osTimerId)pt; -} - -/// Start or restart timer -osStatus svcTimerStart (osTimerId timer_id, uint32_t millisec) { - os_timer_cb *pt; - uint32_t tcnt; - - pt = rt_id2obj(timer_id); - if (pt == NULL) return osErrorParameter; - - tcnt = rt_ms2tick(millisec); - if (tcnt == 0) return osErrorValue; - - switch (pt->state) { - case osTimerRunning: - if (rt_timer_remove(pt) != 0) { - return osErrorResource; - } - break; - case osTimerStopped: - pt->state = osTimerRunning; - pt->icnt = (uint16_t)tcnt; - break; - default: - return osErrorResource; - } - - rt_timer_insert(pt, tcnt); - - return osOK; -} - -/// Stop timer -osStatus svcTimerStop (osTimerId timer_id) { - os_timer_cb *pt; - - pt = rt_id2obj(timer_id); - if (pt == NULL) return osErrorParameter; - - if (pt->state != osTimerRunning) return osErrorResource; - - pt->state = osTimerStopped; - - if (rt_timer_remove(pt) != 0) { - return osErrorResource; - } - - return osOK; -} - -/// Delete timer -osStatus svcTimerDelete (osTimerId timer_id) { - os_timer_cb *pt; - - pt = rt_id2obj(timer_id); - if (pt == NULL) return osErrorParameter; - - switch (pt->state) { - case osTimerRunning: - rt_timer_remove(pt); - break; - case osTimerStopped: - break; - default: - return osErrorResource; - } - - pt->state = osTimerInvalid; - - return osOK; -} - -/// Get timer callback parameters -os_InRegs osCallback_type svcTimerCall (osTimerId timer_id) { - os_timer_cb *pt; - osCallback ret; - - pt = rt_id2obj(timer_id); - if (pt == NULL) { - ret.fp = NULL; - ret.arg = NULL; - return osCallback_ret; - } - - ret.fp = (void *)pt->timer->ptimer; - ret.arg = pt->arg; - - return osCallback_ret; -} - -static __INLINE osStatus isrMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec); - -/// Timer Tick (called each SysTick) -void sysTimerTick (void) { - os_timer_cb *pt, *p; - - p = os_timer_head; - if (p == NULL) return; - - p->tcnt--; - while ((p != NULL) && (p->tcnt == 0)) { - pt = p; - p = p->next; - os_timer_head = p; - isrMessagePut(osMessageQId_osTimerMessageQ, (uint32_t)pt, 0); - if (pt->type == osTimerPeriodic) { - rt_timer_insert(pt, pt->icnt); - } else { - pt->state = osTimerStopped; - } - } -} - - -// Timer Management Public API - -/// Create timer -osTimerId osTimerCreate (osTimerDef_t *timer_def, os_timer_type type, void *argument) { - if (__get_IPSR() != 0) return NULL; // Not allowed in ISR - if (((__get_CONTROL() & 1) == 0) && (os_running == 0)) { - // Privileged and not running - return svcTimerCreate(timer_def, type, argument); - } else { - return __svcTimerCreate(timer_def, type, argument); - } -} - -/// Start or restart timer -osStatus osTimerStart (osTimerId timer_id, uint32_t millisec) { - if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR - return __svcTimerStart(timer_id, millisec); -} - -/// Stop timer -osStatus osTimerStop (osTimerId timer_id) { - if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR - return __svcTimerStop(timer_id); -} - -/// Delete timer -osStatus osTimerDelete (osTimerId timer_id) { - if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR - return __svcTimerDelete(timer_id); -} - -/// INTERNAL - Not Public -/// Get timer callback parameters (used by OS Timer Thread) -os_InRegs osCallback osTimerCall (osTimerId timer_id) { - return __svcTimerCall(timer_id); -} - - -// Timer Thread -__NO_RETURN void osTimerThread (void const *argument) { - osCallback cb; - osEvent evt; - - for (;;) { - evt = osMessageGet(osMessageQId_osTimerMessageQ, osWaitForever); - if (evt.status == osEventMessage) { - cb = osTimerCall(evt.value.p); - if (cb.fp != NULL) { - (*(os_ptimer)cb.fp)(cb.arg); - } - } - } -} - - -// ==== Signal Management ==== - -// Signal Service Calls declarations -SVC_2_1(svcSignalSet, int32_t, osThreadId, int32_t, RET_int32_t) -SVC_2_1(svcSignalClear, int32_t, osThreadId, int32_t, RET_int32_t) -SVC_1_1(svcSignalGet, int32_t, osThreadId, RET_int32_t) -SVC_2_3(svcSignalWait, os_InRegs osEvent, int32_t, uint32_t, RET_osEvent) - -// Signal Service Calls - -/// Set the specified Signal Flags of an active thread -int32_t svcSignalSet (osThreadId thread_id, int32_t signals) { - P_TCB ptcb; - int32_t sig; - - ptcb = rt_tid2ptcb(thread_id); // Get TCB pointer - if (ptcb == NULL) return 0x80000000; - - if (signals & (0xFFFFFFFF << osFeature_Signals)) return 0x80000000; - - sig = ptcb->events; // Previous signal flags - - rt_evt_set(signals, ptcb->task_id); // Set event flags - - return sig; -} - -/// Clear the specified Signal Flags of an active thread -int32_t svcSignalClear (osThreadId thread_id, int32_t signals) { - P_TCB ptcb; - int32_t sig; - - ptcb = rt_tid2ptcb(thread_id); // Get TCB pointer - if (ptcb == NULL) return 0x80000000; - - if (signals & (0xFFFFFFFF << osFeature_Signals)) return 0x80000000; - - sig = ptcb->events; // Previous signal flags - - rt_evt_clr(signals, ptcb->task_id); // Clear event flags - - return sig; -} - -/// Get Signal Flags status of an active thread -int32_t svcSignalGet (osThreadId thread_id) { - P_TCB ptcb; - - ptcb = rt_tid2ptcb(thread_id); // Get TCB pointer - if (ptcb == NULL) return 0x80000000; - - return ptcb->events; // Return event flags -} - -/// Wait for one or more Signal Flags to become signaled for the current RUNNING thread -os_InRegs osEvent_type svcSignalWait (int32_t signals, uint32_t millisec) { - OS_RESULT res; - osEvent ret; - - if (signals & (0xFFFFFFFF << osFeature_Signals)) { - ret.status = osErrorValue; - return osEvent_ret_status; - } - - if (signals != 0) { // Wait for all specified signals - res = rt_evt_wait(signals, rt_ms2tick(millisec), __TRUE); - } else { // Wait for any signal - res = rt_evt_wait(0xFFFF, rt_ms2tick(millisec), __FALSE); - } - - if (res == OS_R_EVT) { - ret.status = osEventSignal; - ret.value.signals = signals ? signals : os_tsk.run->waits; - } else { - ret.status = millisec ? osEventTimeout : osOK; - ret.value.signals = 0; - } - - return osEvent_ret_value; -} - - -// Signal ISR Calls - -/// Set the specified Signal Flags of an active thread -static __INLINE int32_t isrSignalSet (osThreadId thread_id, int32_t signals) { - P_TCB ptcb; - int32_t sig; - - ptcb = rt_tid2ptcb(thread_id); // Get TCB pointer - if (ptcb == NULL) return 0x80000000; - - if (signals & (0xFFFFFFFF << osFeature_Signals)) return 0x80000000; - - sig = ptcb->events; // Previous signal flags - - isr_evt_set(signals, ptcb->task_id); // Set event flags - - return sig; -} - - -// Signal Public API - -/// Set the specified Signal Flags of an active thread -int32_t osSignalSet (osThreadId thread_id, int32_t signals) { - if (__get_IPSR() != 0) { // in ISR - return isrSignalSet(thread_id, signals); - } else { // in Thread - return __svcSignalSet(thread_id, signals); - } -} - -/// Clear the specified Signal Flags of an active thread -int32_t osSignalClear (osThreadId thread_id, int32_t signals) { - if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR - return __svcSignalClear(thread_id, signals); -} - -/// Get Signal Flags status of an active thread -int32_t osSignalGet (osThreadId thread_id) { - if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR - return __svcSignalGet(thread_id); -} - -/// Wait for one or more Signal Flags to become signaled for the current RUNNING thread -os_InRegs osEvent osSignalWait (int32_t signals, uint32_t millisec) { - osEvent ret; - - if (__get_IPSR() != 0) { // Not allowed in ISR - ret.status = osErrorISR; - return ret; - } - return __svcSignalWait(signals, millisec); -} - - -// ==== Mutex Management ==== - -// Mutex Service Calls declarations -SVC_1_1(svcMutexCreate, osMutexId, osMutexDef_t *, RET_pointer) -SVC_2_1(svcMutexWait, osStatus, osMutexId, uint32_t, RET_osStatus) -SVC_1_1(svcMutexRelease, osStatus, osMutexId, RET_osStatus) -SVC_1_1(svcMutexDelete, osStatus, osMutexId, RET_osStatus) - -// Mutex Service Calls - -/// Create and Initialize a Mutex object -osMutexId svcMutexCreate (osMutexDef_t *mutex_def) { - OS_ID mut; - - if (mutex_def == NULL) { - sysThreadError(osErrorParameter); - return NULL; - } - - mut = mutex_def->mutex; - if (mut == NULL) { - sysThreadError(osErrorParameter); - return NULL; - } - - if (((P_MUCB)mut)->cb_type != 0) { - sysThreadError(osErrorParameter); - return NULL; - } - - rt_mut_init(mut); // Initialize Mutex - - return mut; -} - -/// Wait until a Mutex becomes available -osStatus svcMutexWait (osMutexId mutex_id, uint32_t millisec) { - OS_ID mut; - OS_RESULT res; - - mut = rt_id2obj(mutex_id); - if (mut == NULL) return osErrorParameter; - - if (((P_MUCB)mut)->cb_type != MUCB) return osErrorParameter; - - res = rt_mut_wait(mut, rt_ms2tick(millisec)); // Wait for Mutex - - if (res == OS_R_TMO) { - return (millisec ? osErrorTimeoutResource : osErrorResource); - } - - return osOK; -} - -/// Release a Mutex that was obtained with osMutexWait -osStatus svcMutexRelease (osMutexId mutex_id) { - OS_ID mut; - OS_RESULT res; - - mut = rt_id2obj(mutex_id); - if (mut == NULL) return osErrorParameter; - - if (((P_MUCB)mut)->cb_type != MUCB) return osErrorParameter; - - res = rt_mut_release(mut); // Release Mutex - - if (res == OS_R_NOK) return osErrorResource; // Thread not owner or Zero Counter - - return osOK; -} - -/// Delete a Mutex that was created by osMutexCreate -osStatus svcMutexDelete (osMutexId mutex_id) { - OS_ID mut; - - mut = rt_id2obj(mutex_id); - if (mut == NULL) return osErrorParameter; - - if (((P_MUCB)mut)->cb_type != MUCB) return osErrorParameter; - - rt_mut_delete(mut); // Release Mutex - - return osOK; -} - - -// Mutex Public API - -/// Create and Initialize a Mutex object -osMutexId osMutexCreate (osMutexDef_t *mutex_def) { - if (__get_IPSR() != 0) return NULL; // Not allowed in ISR - if (((__get_CONTROL() & 1) == 0) && (os_running == 0)) { - // Privileged and not running - return svcMutexCreate(mutex_def); - } else { - return __svcMutexCreate(mutex_def); - } -} - -/// Wait until a Mutex becomes available -osStatus osMutexWait (osMutexId mutex_id, uint32_t millisec) { - if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR - return __svcMutexWait(mutex_id, millisec); -} - -/// Release a Mutex that was obtained with osMutexWait -osStatus osMutexRelease (osMutexId mutex_id) { - if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR - return __svcMutexRelease(mutex_id); -} - -/// Delete a Mutex that was created by osMutexCreate -osStatus osMutexDelete (osMutexId mutex_id) { - if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR - return __svcMutexDelete(mutex_id); -} - - -// ==== Semaphore Management ==== - -// Semaphore Service Calls declarations -SVC_2_1(svcSemaphoreCreate, osSemaphoreId, const osSemaphoreDef_t *, int32_t, RET_pointer) -SVC_2_1(svcSemaphoreWait, int32_t, osSemaphoreId, uint32_t, RET_int32_t) -SVC_1_1(svcSemaphoreRelease, osStatus, osSemaphoreId, RET_osStatus) -SVC_1_1(svcSemaphoreDelete, osStatus, osSemaphoreId, RET_osStatus) - -// Semaphore Service Calls - -/// Create and Initialize a Semaphore object -osSemaphoreId svcSemaphoreCreate (const osSemaphoreDef_t *semaphore_def, int32_t count) { - OS_ID sem; - - if (semaphore_def == NULL) { - sysThreadError(osErrorParameter); - return NULL; - } - - sem = semaphore_def->semaphore; - if (sem == NULL) { - sysThreadError(osErrorParameter); - return NULL; - } - - if (((P_SCB)sem)->cb_type != 0) { - sysThreadError(osErrorParameter); - return NULL; - } - - if (count > osFeature_Semaphore) { - sysThreadError(osErrorValue); - return NULL; - } - - rt_sem_init(sem, count); // Initialize Semaphore - - return sem; -} - -/// Wait until a Semaphore becomes available -int32_t svcSemaphoreWait (osSemaphoreId semaphore_id, uint32_t millisec) { - OS_ID sem; - OS_RESULT res; - - sem = rt_id2obj(semaphore_id); - if (sem == NULL) return -1; - - if (((P_SCB)sem)->cb_type != SCB) return -1; - - res = rt_sem_wait(sem, rt_ms2tick(millisec)); // Wait for Semaphore - - if (res == OS_R_TMO) return 0; // Timeout - - return (((P_SCB)sem)->tokens + 1); -} - -/// Release a Semaphore -osStatus svcSemaphoreRelease (osSemaphoreId semaphore_id) { - OS_ID sem; - - sem = rt_id2obj(semaphore_id); - if (sem == NULL) return osErrorParameter; - - if (((P_SCB)sem)->cb_type != SCB) return osErrorParameter; - - if (((P_SCB)sem)->tokens == osFeature_Semaphore) return osErrorResource; - - rt_sem_send(sem); // Release Semaphore - - return osOK; -} - -/// Delete a Semaphore that was created by osSemaphoreCreate -osStatus svcSemaphoreDelete (osSemaphoreId semaphore_id) { - OS_ID sem; - - sem = rt_id2obj(semaphore_id); - if (sem == NULL) return osErrorParameter; - - if (((P_SCB)sem)->cb_type != SCB) return osErrorParameter; - - rt_sem_delete(sem); // Delete Semaphore - - return osOK; -} - - -// Semaphore ISR Calls - -/// Release a Semaphore -static __INLINE osStatus isrSemaphoreRelease (osSemaphoreId semaphore_id) { - OS_ID sem; - - sem = rt_id2obj(semaphore_id); - if (sem == NULL) return osErrorParameter; - - if (((P_SCB)sem)->cb_type != SCB) return osErrorParameter; - - if (((P_SCB)sem)->tokens == osFeature_Semaphore) return osErrorResource; - - isr_sem_send(sem); // Release Semaphore - - return osOK; -} - - -// Semaphore Public API - -/// Create and Initialize a Semaphore object -osSemaphoreId osSemaphoreCreate (osSemaphoreDef_t *semaphore_def, int32_t count) { - if (__get_IPSR() != 0) return NULL; // Not allowed in ISR - if (((__get_CONTROL() & 1) == 0) && (os_running == 0)) { - // Privileged and not running - return svcSemaphoreCreate(semaphore_def, count); - } else { - return __svcSemaphoreCreate(semaphore_def, count); - } -} - -/// Wait until a Semaphore becomes available -int32_t osSemaphoreWait (osSemaphoreId semaphore_id, uint32_t millisec) { - if (__get_IPSR() != 0) return -1; // Not allowed in ISR - return __svcSemaphoreWait(semaphore_id, millisec); -} - -/// Release a Semaphore -osStatus osSemaphoreRelease (osSemaphoreId semaphore_id) { - if (__get_IPSR() != 0) { // in ISR - return isrSemaphoreRelease(semaphore_id); - } else { // in Thread - return __svcSemaphoreRelease(semaphore_id); - } -} - -/// Delete a Semaphore that was created by osSemaphoreCreate -osStatus osSemaphoreDelete (osSemaphoreId semaphore_id) { - if (__get_IPSR() != 0) return osErrorISR; // Not allowed in ISR - return __svcSemaphoreDelete(semaphore_id); -} - - -// ==== Memory Management Functions ==== - -// Memory Management Helper Functions - -// Clear Memory Box (Zero init) -static void rt_clr_box (void *box_mem, void *box) { - uint32_t *p, n; - - if (box) { - p = box; - for (n = ((P_BM)box_mem)->blk_size; n; n -= 4) { - *p++ = 0; - } - } -} - -// Memory Management Service Calls declarations -SVC_1_1(svcPoolCreate, osPoolId, const osPoolDef_t *, RET_pointer) -SVC_2_1(sysPoolAlloc, void *, osPoolId, uint32_t, RET_pointer) -SVC_2_1(sysPoolFree, osStatus, osPoolId, void *, RET_osStatus) - -// Memory Management Service & ISR Calls - -/// Create and Initialize memory pool -osPoolId svcPoolCreate (const osPoolDef_t *pool_def) { - uint32_t blk_sz; - - if ((pool_def == NULL) || - (pool_def->pool_sz == 0) || - (pool_def->item_sz == 0) || - (pool_def->pool == NULL)) { - sysThreadError(osErrorParameter); - return NULL; - } - - blk_sz = (pool_def->item_sz + 3) & ~3; - - _init_box(pool_def->pool, sizeof(struct OS_BM) + pool_def->pool_sz * blk_sz, blk_sz); - - return pool_def->pool; -} - -/// Allocate a memory block from a memory pool -void *sysPoolAlloc (osPoolId pool_id, uint32_t clr) { - void *ptr; - - if (pool_id == NULL) return NULL; - - ptr = rt_alloc_box(pool_id); - if (clr) { - rt_clr_box(pool_id, ptr); - } - - return ptr; -} - -/// Return an allocated memory block back to a specific memory pool -osStatus sysPoolFree (osPoolId pool_id, void *block) { - int32_t res; - - if (pool_id == NULL) return osErrorParameter; - - res = rt_free_box(pool_id, block); - if (res != 0) return osErrorValue; - - return osOK; -} - - -// Memory Management Public API - -/// Create and Initialize memory pool -osPoolId osPoolCreate (osPoolDef_t *pool_def) { - if (__get_IPSR() != 0) return NULL; // Not allowed in ISR - if (((__get_CONTROL() & 1) == 0) && (os_running == 0)) { - // Privileged and not running - return svcPoolCreate(pool_def); - } else { - return __svcPoolCreate(pool_def); - } -} - -/// Allocate a memory block from a memory pool -void *osPoolAlloc (osPoolId pool_id) { - if ((__get_IPSR() != 0) || ((__get_CONTROL() & 1) == 0)) { // in ISR or Privileged - return sysPoolAlloc(pool_id, 0); - } else { // in Thread - return __sysPoolAlloc(pool_id, 0); - } -} - -/// Allocate a memory block from a memory pool and set memory block to zero -void *osPoolCAlloc (osPoolId pool_id) { - if ((__get_IPSR() != 0) || ((__get_CONTROL() & 1) == 0)) { // in ISR or Privileged - return sysPoolAlloc(pool_id, 1); - } else { // in Thread - return __sysPoolAlloc(pool_id, 1); - } -} - -/// Return an allocated memory block back to a specific memory pool -osStatus osPoolFree (osPoolId pool_id, void *block) { - if ((__get_IPSR() != 0) || ((__get_CONTROL() & 1) == 0)) { // in ISR or Privileged - return sysPoolFree(pool_id, block); - } else { // in Thread - return __sysPoolFree(pool_id, block); - } -} - - -// ==== Message Queue Management Functions ==== - -// Message Queue Management Service Calls declarations -SVC_2_1(svcMessageCreate, osMessageQId, osMessageQDef_t *, osThreadId, RET_pointer) -SVC_3_1(svcMessagePut, osStatus, osMessageQId, uint32_t, uint32_t, RET_osStatus) -SVC_2_3(svcMessageGet, os_InRegs osEvent, osMessageQId, uint32_t, RET_osEvent) - -// Message Queue Service Calls - -/// Create and Initialize Message Queue -osMessageQId svcMessageCreate (osMessageQDef_t *queue_def, osThreadId thread_id) { - - if ((queue_def == NULL) || - (queue_def->queue_sz == 0) || - (queue_def->pool == NULL)) { - sysThreadError(osErrorParameter); - return NULL; - } - - if (((P_MCB)queue_def->pool)->cb_type != 0) { - sysThreadError(osErrorParameter); - return NULL; - } - - rt_mbx_init(queue_def->pool, 4*(queue_def->queue_sz + 4)); - - return queue_def->pool; -} - -/// Put a Message to a Queue -osStatus svcMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec) { - OS_RESULT res; - - if (queue_id == NULL) return osErrorParameter; - - if (((P_MCB)queue_id)->cb_type != MCB) return osErrorParameter; - - res = rt_mbx_send(queue_id, (void *)info, rt_ms2tick(millisec)); - - if (res == OS_R_TMO) { - return (millisec ? osErrorTimeoutResource : osErrorResource); - } - - return osOK; -} - -/// Get a Message or Wait for a Message from a Queue -os_InRegs osEvent_type svcMessageGet (osMessageQId queue_id, uint32_t millisec) { - OS_RESULT res; - osEvent ret; - - if (queue_id == NULL) { - ret.status = osErrorParameter; - return osEvent_ret_status; - } - - if (((P_MCB)queue_id)->cb_type != MCB) { - ret.status = osErrorParameter; - return osEvent_ret_status; - } - - res = rt_mbx_wait(queue_id, &ret.value.p, rt_ms2tick(millisec)); - - if (res == OS_R_TMO) { - ret.status = millisec ? osEventTimeout : osOK; - return osEvent_ret_value; - } - - ret.status = osEventMessage; - - return osEvent_ret_value; -} - - -// Message Queue ISR Calls - -/// Put a Message to a Queue -static __INLINE osStatus isrMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec) { - - if ((queue_id == NULL) || (millisec != 0)) { - return osErrorParameter; - } - - if (((P_MCB)queue_id)->cb_type != MCB) return osErrorParameter; - - if (rt_mbx_check(queue_id) == 0) { // Check if Queue is full - return osErrorResource; - } - - isr_mbx_send(queue_id, (void *)info); - - return osOK; -} - -/// Get a Message or Wait for a Message from a Queue -static __INLINE os_InRegs osEvent isrMessageGet (osMessageQId queue_id, uint32_t millisec) { - OS_RESULT res; - osEvent ret; - - if ((queue_id == NULL) || (millisec != 0)) { - ret.status = osErrorParameter; - return ret; - } - - if (((P_MCB)queue_id)->cb_type != MCB) { - ret.status = osErrorParameter; - return ret; - } - - res = isr_mbx_receive(queue_id, &ret.value.p); - - if (res != OS_R_MBX) { - ret.status = osOK; - return ret; - } - - ret.status = osEventMessage; - - return ret; -} - - -// Message Queue Management Public API - -/// Create and Initialize Message Queue -osMessageQId osMessageCreate (osMessageQDef_t *queue_def, osThreadId thread_id) { - if (__get_IPSR() != 0) return NULL; // Not allowed in ISR - if (((__get_CONTROL() & 1) == 0) && (os_running == 0)) { - // Privileged and not running - return svcMessageCreate(queue_def, thread_id); - } else { - return __svcMessageCreate(queue_def, thread_id); - } -} - -/// Put a Message to a Queue -osStatus osMessagePut (osMessageQId queue_id, uint32_t info, uint32_t millisec) { - if (__get_IPSR() != 0) { // in ISR - return isrMessagePut(queue_id, info, millisec); - } else { // in Thread - return __svcMessagePut(queue_id, info, millisec); - } -} - -/// Get a Message or Wait for a Message from a Queue -os_InRegs osEvent osMessageGet (osMessageQId queue_id, uint32_t millisec) { - if (__get_IPSR() != 0) { // in ISR - return isrMessageGet(queue_id, millisec); - } else { // in Thread - return __svcMessageGet(queue_id, millisec); - } -} - - -// ==== Mail Queue Management Functions ==== - -// Mail Queue Management Service Calls declarations -SVC_2_1(svcMailCreate, osMailQId, osMailQDef_t *, osThreadId, RET_pointer) -SVC_4_1(sysMailAlloc, void *, osMailQId, uint32_t, uint32_t, uint32_t, RET_pointer) -SVC_3_1(sysMailFree, osStatus, osMailQId, void *, uint32_t, RET_osStatus) - -// Mail Queue Management Service & ISR Calls - -/// Create and Initialize mail queue -osMailQId svcMailCreate (osMailQDef_t *queue_def, osThreadId thread_id) { - uint32_t blk_sz; - P_MCB pmcb; - void *pool; - - if ((queue_def == NULL) || - (queue_def->queue_sz == 0) || - (queue_def->item_sz == 0) || - (queue_def->pool == NULL)) { - sysThreadError(osErrorParameter); - return NULL; - } - - pmcb = *(((void **)queue_def->pool) + 0); - pool = *(((void **)queue_def->pool) + 1); - - if ((pool == NULL) || (pmcb == NULL) || (pmcb->cb_type != 0)) { - sysThreadError(osErrorParameter); - return NULL; - } - - blk_sz = (queue_def->item_sz + 3) & ~3; - - _init_box(pool, sizeof(struct OS_BM) + queue_def->queue_sz * blk_sz, blk_sz); - - rt_mbx_init(pmcb, 4*(queue_def->queue_sz + 4)); - - - return queue_def->pool; -} - -/// Allocate a memory block from a mail -void *sysMailAlloc (osMailQId queue_id, uint32_t millisec, uint32_t isr, uint32_t clr) { - P_MCB pmcb; - void *pool; - void *mem; - - if (queue_id == NULL) return NULL; - - pmcb = *(((void **)queue_id) + 0); - pool = *(((void **)queue_id) + 1); - - if ((pool == NULL) || (pmcb == NULL)) return NULL; - - if (isr && (millisec != 0)) return NULL; - - mem = rt_alloc_box(pool); - if (clr) { - rt_clr_box(pool, mem); - } - - if ((mem == NULL) && (millisec != 0)) { - // Put Task to sleep when Memory not available - if (pmcb->p_lnk != NULL) { - rt_put_prio((P_XCB)pmcb, os_tsk.run); - } else { - pmcb->p_lnk = os_tsk.run; - os_tsk.run->p_lnk = NULL; - os_tsk.run->p_rlnk = (P_TCB)pmcb; - // Task is waiting to allocate a message - pmcb->state = 3; - } - rt_block(rt_ms2tick(millisec), WAIT_MBX); - } - - return mem; -} - -/// Free a memory block from a mail -osStatus sysMailFree (osMailQId queue_id, void *mail, uint32_t isr) { - P_MCB pmcb; - P_TCB ptcb; - void *pool; - void *mem; - int32_t res; - - if (queue_id == NULL) return osErrorParameter; - - pmcb = *(((void **)queue_id) + 0); - pool = *(((void **)queue_id) + 1); - - if ((pmcb == NULL) || (pool == NULL)) return osErrorParameter; - - res = rt_free_box(pool, mail); - - if (res != 0) return osErrorValue; - - if (pmcb->state == 3) { - // Task is waiting to allocate a message - if (isr) { - rt_psq_enq (pmcb, (U32)pool); - rt_psh_req (); - } else { - mem = rt_alloc_box(pool); - if (mem != NULL) { - ptcb = rt_get_first((P_XCB)pmcb); - if (pmcb->p_lnk == NULL) { - pmcb->state = 0; - } - rt_ret_val(ptcb, (U32)mem); - rt_rmv_dly(ptcb); - rt_dispatch(ptcb); - } - } - } - - return osOK; -} - - -// Mail Queue Management Public API - -/// Create and Initialize mail queue -osMailQId osMailCreate (osMailQDef_t *queue_def, osThreadId thread_id) { - if (__get_IPSR() != 0) return NULL; // Not allowed in ISR - if (((__get_CONTROL() & 1) == 0) && (os_running == 0)) { - // Privileged and not running - return svcMailCreate(queue_def, thread_id); - } else { - return __svcMailCreate(queue_def, thread_id); - } -} - -/// Allocate a memory block from a mail -void *osMailAlloc (osMailQId queue_id, uint32_t millisec) { - if (__get_IPSR() != 0) { // in ISR - return sysMailAlloc(queue_id, millisec, 1, 0); - } else { // in Thread - return __sysMailAlloc(queue_id, millisec, 0, 0); - } -} - -/// Allocate a memory block from a mail and set memory block to zero -void *osMailCAlloc (osMailQId queue_id, uint32_t millisec) { - if (__get_IPSR() != 0) { // in ISR - return sysMailAlloc(queue_id, millisec, 1, 1); - } else { // in Thread - return __sysMailAlloc(queue_id, millisec, 0, 1); - } -} - -/// Free a memory block from a mail -osStatus osMailFree (osMailQId queue_id, void *mail) { - if (__get_IPSR() != 0) { // in ISR - return sysMailFree(queue_id, mail, 1); - } else { // in Thread - return __sysMailFree(queue_id, mail, 0); - } -} - -/// Put a mail to a queue -osStatus osMailPut (osMailQId queue_id, void *mail) { - if (queue_id == NULL) return osErrorParameter; - if (mail == NULL) return osErrorValue; - return osMessagePut(*((void **)queue_id), (uint32_t)mail, 0); -} - -#ifdef __CC_ARM -#pragma push -#pragma Ospace -#endif // __arm__ -/// Get a mail from a queue -os_InRegs osEvent osMailGet (osMailQId queue_id, uint32_t millisec) { - osEvent ret; - - if (queue_id == NULL) { - ret.status = osErrorParameter; - return ret; - } - - ret = osMessageGet(*((void **)queue_id), millisec); - if (ret.status == osEventMessage) ret.status = osEventMail; - - return ret; -} -#ifdef __CC_ARM -#pragma pop -#endif // __arm__ diff --git a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Event.c b/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Event.c deleted file mode 100644 index acd8ccc..0000000 --- a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Event.c +++ /dev/null @@ -1,190 +0,0 @@ -/*---------------------------------------------------------------------------- - * RL-ARM - RTX - *---------------------------------------------------------------------------- - * Name: RT_EVENT.C - * Purpose: Implements waits and wake-ups for event flags - * Rev.: V4.60 - *---------------------------------------------------------------------------- - * - * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - Neither the name of ARM nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - *---------------------------------------------------------------------------*/ - -#include "rt_TypeDef.h" -#include "RTX_Conf.h" -#include "rt_System.h" -#include "rt_Event.h" -#include "rt_List.h" -#include "rt_Task.h" -#include "rt_HAL_CM.h" - - -/*---------------------------------------------------------------------------- - * Functions - *---------------------------------------------------------------------------*/ - - -/*--------------------------- rt_evt_wait -----------------------------------*/ - -OS_RESULT rt_evt_wait (U16 wait_flags, U16 timeout, BOOL and_wait) { - /* Wait for one or more event flags with optional time-out. */ - /* "wait_flags" identifies the flags to wait for. */ - /* "timeout" is the time-out limit in system ticks (0xffff if no time-out) */ - /* "and_wait" specifies the AND-ing of "wait_flags" as condition to be met */ - /* to complete the wait. (OR-ing if set to 0). */ - U32 block_state; - - if (and_wait) { - /* Check for AND-connected events */ - if ((os_tsk.run->events & wait_flags) == wait_flags) { - os_tsk.run->events &= ~wait_flags; - return (OS_R_EVT); - } - block_state = WAIT_AND; - } - else { - /* Check for OR-connected events */ - if (os_tsk.run->events & wait_flags) { - os_tsk.run->waits = os_tsk.run->events & wait_flags; - os_tsk.run->events &= ~wait_flags; - return (OS_R_EVT); - } - block_state = WAIT_OR; - } - /* Task has to wait */ - os_tsk.run->waits = wait_flags; - rt_block (timeout, (U8)block_state); - return (OS_R_TMO); -} - - -/*--------------------------- rt_evt_set ------------------------------------*/ - -void rt_evt_set (U16 event_flags, OS_TID task_id) { - /* Set one or more event flags of a selectable task. */ - P_TCB p_tcb; - - p_tcb = os_active_TCB[task_id-1]; - if (p_tcb == NULL) { - return; - } - p_tcb->events |= event_flags; - event_flags = p_tcb->waits; - /* If the task is not waiting for an event, it should not be put */ - /* to ready state. */ - if (p_tcb->state == WAIT_AND) { - /* Check for AND-connected events */ - if ((p_tcb->events & event_flags) == event_flags) { - goto wkup; - } - } - if (p_tcb->state == WAIT_OR) { - /* Check for OR-connected events */ - if (p_tcb->events & event_flags) { - p_tcb->waits &= p_tcb->events; -wkup: p_tcb->events &= ~event_flags; - rt_rmv_dly (p_tcb); - p_tcb->state = READY; -#ifdef __CMSIS_RTOS - rt_ret_val2(p_tcb, 0x08/*osEventSignal*/, p_tcb->waits); -#else - rt_ret_val (p_tcb, OS_R_EVT); -#endif - rt_dispatch (p_tcb); - } - } -} - - -/*--------------------------- rt_evt_clr ------------------------------------*/ - -void rt_evt_clr (U16 clear_flags, OS_TID task_id) { - /* Clear one or more event flags (identified by "clear_flags") of a */ - /* selectable task (identified by "task"). */ - P_TCB task = os_active_TCB[task_id-1]; - - if (task == NULL) { - return; - } - task->events &= ~clear_flags; -} - - -/*--------------------------- isr_evt_set -----------------------------------*/ - -void isr_evt_set (U16 event_flags, OS_TID task_id) { - /* Same function as "os_evt_set", but to be called by ISRs. */ - P_TCB p_tcb = os_active_TCB[task_id-1]; - - if (p_tcb == NULL) { - return; - } - rt_psq_enq (p_tcb, event_flags); - rt_psh_req (); -} - - -/*--------------------------- rt_evt_get ------------------------------------*/ - -U16 rt_evt_get (void) { - /* Get events of a running task after waiting for OR connected events. */ - return (os_tsk.run->waits); -} - - -/*--------------------------- rt_evt_psh ------------------------------------*/ - -void rt_evt_psh (P_TCB p_CB, U16 set_flags) { - /* Check if task has to be waken up */ - U16 event_flags; - - p_CB->events |= set_flags; - event_flags = p_CB->waits; - if (p_CB->state == WAIT_AND) { - /* Check for AND-connected events */ - if ((p_CB->events & event_flags) == event_flags) { - goto rdy; - } - } - if (p_CB->state == WAIT_OR) { - /* Check for OR-connected events */ - if (p_CB->events & event_flags) { - p_CB->waits &= p_CB->events; -rdy: p_CB->events &= ~event_flags; - rt_rmv_dly (p_CB); - p_CB->state = READY; -#ifdef __CMSIS_RTOS - rt_ret_val2(p_CB, 0x08/*osEventSignal*/, p_CB->waits); -#else - rt_ret_val (p_CB, OS_R_EVT); -#endif - rt_put_prio (&os_rdy, p_CB); - } - } -} - -/*---------------------------------------------------------------------------- - * end of file - *---------------------------------------------------------------------------*/ diff --git a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Event.h b/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Event.h deleted file mode 100644 index 8b92f3c..0000000 --- a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Event.h +++ /dev/null @@ -1,46 +0,0 @@ -/*---------------------------------------------------------------------------- - * RL-ARM - RTX - *---------------------------------------------------------------------------- - * Name: RT_EVENT.H - * Purpose: Implements waits and wake-ups for event flags - * Rev.: V4.60 - *---------------------------------------------------------------------------- - * - * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - Neither the name of ARM nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - *---------------------------------------------------------------------------*/ - -/* Functions */ -extern OS_RESULT rt_evt_wait (U16 wait_flags, U16 timeout, BOOL and_wait); -extern void rt_evt_set (U16 event_flags, OS_TID task_id); -extern void rt_evt_clr (U16 clear_flags, OS_TID task_id); -extern void isr_evt_set (U16 event_flags, OS_TID task_id); -extern U16 rt_evt_get (void); -extern void rt_evt_psh (P_TCB p_CB, U16 set_flags); - -/*---------------------------------------------------------------------------- - * end of file - *---------------------------------------------------------------------------*/ - diff --git a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_HAL_CM.h b/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_HAL_CM.h deleted file mode 100644 index 2ab4b36..0000000 --- a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_HAL_CM.h +++ /dev/null @@ -1,276 +0,0 @@ -/*---------------------------------------------------------------------------- - * RL-ARM - RTX - *---------------------------------------------------------------------------- - * Name: RT_HAL_CM.H - * Purpose: Hardware Abstraction Layer for Cortex-M definitions - * Rev.: V4.60 - *---------------------------------------------------------------------------- - * - * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - Neither the name of ARM nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - *---------------------------------------------------------------------------*/ - -/* Definitions */ -#define INITIAL_xPSR 0x01000000 -#define DEMCR_TRCENA 0x01000000 -#define ITM_ITMENA 0x00000001 -#define MAGIC_WORD 0xE25A2EA5 - -#if defined (__CC_ARM) /* ARM Compiler */ - -#if ((__TARGET_ARCH_7_M || __TARGET_ARCH_7E_M) && !NO_EXCLUSIVE_ACCESS) - #define __USE_EXCLUSIVE_ACCESS -#else - #undef __USE_EXCLUSIVE_ACCESS -#endif - -#elif defined (__GNUC__) /* GNU Compiler */ - -#undef __USE_EXCLUSIVE_ACCESS - -#if defined (__CORTEX_M0) || defined (__CORTEX_M0PLUS) -#define __TARGET_ARCH_6S_M 1 -#else -#define __TARGET_ARCH_6S_M 0 -#endif - -#if defined (__VFP_FP__) && !defined(__SOFTFP__) -#define __TARGET_FPU_VFP 1 -#else -#define __TARGET_FPU_VFP 0 -#endif - -#define __inline inline -#define __weak __attribute__((weak)) - -#ifndef __CMSIS_GENERIC - -__attribute__((always_inline)) static inline void __enable_irq(void) -{ - __asm volatile ("cpsie i"); -} - -__attribute__((always_inline)) static inline U32 __disable_irq(void) -{ - U32 result; - - __asm volatile ("mrs %0, primask" : "=r" (result)); - __asm volatile ("cpsid i"); - return(result & 1); -} - -#endif - -__attribute__(( always_inline)) static inline U8 __clz(U32 value) -{ - U8 result; - - __asm volatile ("clz %0, %1" : "=r" (result) : "r" (value)); - return(result); -} - -#elif defined (__ICCARM__) /* IAR Compiler */ - -#undef __USE_EXCLUSIVE_ACCESS - -#if (__CORE__ == __ARM6M__) -#define __TARGET_ARCH_6S_M 1 -#else -#define __TARGET_ARCH_6S_M 0 -#endif - -#if defined __ARMVFP__ -#define __TARGET_FPU_VFP 1 -#else -#define __TARGET_FPU_VFP 0 -#endif - -#define __inline inline - -#ifndef __CMSIS_GENERIC - -static inline void __enable_irq(void) -{ - __asm volatile ("cpsie i"); -} - -static inline U32 __disable_irq(void) -{ - U32 result; - - __asm volatile ("mrs %0, primask" : "=r" (result)); - __asm volatile ("cpsid i"); - return(result & 1); -} - -#endif - -static inline U8 __clz(U32 value) -{ - U8 result; - - __asm volatile ("clz %0, %1" : "=r" (result) : "r" (value)); - return(result); -} - -#endif - -/* NVIC registers */ -#define NVIC_ST_CTRL (*((volatile U32 *)0xE000E010)) -#define NVIC_ST_RELOAD (*((volatile U32 *)0xE000E014)) -#define NVIC_ST_CURRENT (*((volatile U32 *)0xE000E018)) -#define NVIC_ISER ((volatile U32 *)0xE000E100) -#define NVIC_ICER ((volatile U32 *)0xE000E180) -#if (__TARGET_ARCH_6S_M) -#define NVIC_IP ((volatile U32 *)0xE000E400) -#else -#define NVIC_IP ((volatile U8 *)0xE000E400) -#endif -#define NVIC_INT_CTRL (*((volatile U32 *)0xE000ED04)) -#define NVIC_AIR_CTRL (*((volatile U32 *)0xE000ED0C)) -#define NVIC_SYS_PRI2 (*((volatile U32 *)0xE000ED1C)) -#define NVIC_SYS_PRI3 (*((volatile U32 *)0xE000ED20)) - -#define OS_PEND_IRQ() NVIC_INT_CTRL = (1<<28) -#define OS_PENDING ((NVIC_INT_CTRL >> 26) & (1<<2 | 1)) -#define OS_UNPEND(fl) NVIC_INT_CTRL = (*fl = OS_PENDING) << 25 -#define OS_PEND(fl,p) NVIC_INT_CTRL = (fl | p<<2) << 26 -#define OS_LOCK() NVIC_ST_CTRL = 0x0005 -#define OS_UNLOCK() NVIC_ST_CTRL = 0x0007 - -#define OS_X_PENDING ((NVIC_INT_CTRL >> 28) & 1) -#define OS_X_UNPEND(fl) NVIC_INT_CTRL = (*fl = OS_X_PENDING) << 27 -#define OS_X_PEND(fl,p) NVIC_INT_CTRL = (fl | p) << 28 -#if (__TARGET_ARCH_6S_M) -#define OS_X_INIT(n) NVIC_IP[n>>2] |= 0xFF << (8*(n & 0x03)); \ - NVIC_ISER[n>>5] = 1 << (n & 0x1F) -#else -#define OS_X_INIT(n) NVIC_IP[n] = 0xFF; \ - NVIC_ISER[n>>5] = 1 << (n & 0x1F) -#endif -#define OS_X_LOCK(n) NVIC_ICER[n>>5] = 1 << (n & 0x1F) -#define OS_X_UNLOCK(n) NVIC_ISER[n>>5] = 1 << (n & 0x1F) - -/* Core Debug registers */ -#define DEMCR (*((volatile U32 *)0xE000EDFC)) - -/* ITM registers */ -#define ITM_CONTROL (*((volatile U32 *)0xE0000E80)) -#define ITM_ENABLE (*((volatile U32 *)0xE0000E00)) -#define ITM_PORT30_U32 (*((volatile U32 *)0xE0000078)) -#define ITM_PORT31_U32 (*((volatile U32 *)0xE000007C)) -#define ITM_PORT31_U16 (*((volatile U16 *)0xE000007C)) -#define ITM_PORT31_U8 (*((volatile U8 *)0xE000007C)) - -/* Variables */ -extern BIT dbg_msg; - -/* Functions */ -#ifdef __USE_EXCLUSIVE_ACCESS - #define rt_inc(p) while(__strex((__ldrex(p)+1),p)) - #define rt_dec(p) while(__strex((__ldrex(p)-1),p)) -#else - #define rt_inc(p) __disable_irq();(*p)++;__enable_irq(); - #define rt_dec(p) __disable_irq();(*p)--;__enable_irq(); -#endif - -__inline static U32 rt_inc_qi (U32 size, U8 *count, U8 *first) { - U32 cnt,c2; -#ifdef __USE_EXCLUSIVE_ACCESS - do { - if ((cnt = __ldrex(count)) == size) { - __clrex(); - return (cnt); } - } while (__strex(cnt+1, count)); - do { - c2 = (cnt = __ldrex(first)) + 1; - if (c2 == size) c2 = 0; - } while (__strex(c2, first)); -#else - __disable_irq(); - if ((cnt = *count) < size) { - *count = cnt+1; - c2 = (cnt = *first) + 1; - if (c2 == size) c2 = 0; - *first = c2; - } - __enable_irq (); -#endif - return (cnt); -} - -__inline static void rt_systick_init (void) { - NVIC_ST_RELOAD = os_trv; - NVIC_ST_CURRENT = 0; - NVIC_ST_CTRL = 0x0007; - NVIC_SYS_PRI3 |= 0xFF000000; -} - -__inline static void rt_svc_init (void) { -#if !(__TARGET_ARCH_6S_M) - int sh,prigroup; -#endif - NVIC_SYS_PRI3 |= 0x00FF0000; -#if (__TARGET_ARCH_6S_M) - NVIC_SYS_PRI2 |= (NVIC_SYS_PRI3<<(8+1)) & 0xFC000000; -#else - sh = 8 - __clz (~((NVIC_SYS_PRI3 << 8) & 0xFF000000)); - prigroup = ((NVIC_AIR_CTRL >> 8) & 0x07); - if (prigroup >= sh) { - sh = prigroup + 1; - } - NVIC_SYS_PRI2 = ((0xFEFFFFFF << sh) & 0xFF000000) | (NVIC_SYS_PRI2 & 0x00FFFFFF); -#endif -} - -extern void rt_set_PSP (U32 stack); -extern U32 rt_get_PSP (void); -extern void os_set_env (void); -extern void *_alloc_box (void *box_mem); -extern int _free_box (void *box_mem, void *box); - -extern void rt_init_stack (P_TCB p_TCB, FUNCP task_body); -extern void rt_ret_val (P_TCB p_TCB, U32 v0); -extern void rt_ret_val2 (P_TCB p_TCB, U32 v0, U32 v1); - -extern void dbg_init (void); -extern void dbg_task_notify (P_TCB p_tcb, BOOL create); -extern void dbg_task_switch (U32 task_id); - -#ifdef DBG_MSG -#define DBG_INIT() dbg_init() -#define DBG_TASK_NOTIFY(p_tcb,create) if (dbg_msg) dbg_task_notify(p_tcb,create) -#define DBG_TASK_SWITCH(task_id) if (dbg_msg && (os_tsk.new_tsk != os_tsk.run)) \ - dbg_task_switch(task_id) -#else -#define DBG_INIT() -#define DBG_TASK_NOTIFY(p_tcb,create) -#define DBG_TASK_SWITCH(task_id) -#endif - -/*---------------------------------------------------------------------------- - * end of file - *---------------------------------------------------------------------------*/ - diff --git a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_List.c b/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_List.c deleted file mode 100644 index 2134d14..0000000 --- a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_List.c +++ /dev/null @@ -1,320 +0,0 @@ -/*---------------------------------------------------------------------------- - * RL-ARM - RTX - *---------------------------------------------------------------------------- - * Name: RT_LIST.C - * Purpose: Functions for the management of different lists - * Rev.: V4.60 - *---------------------------------------------------------------------------- - * - * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - Neither the name of ARM nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - *---------------------------------------------------------------------------*/ - -#include "rt_TypeDef.h" -#include "RTX_Conf.h" -#include "rt_System.h" -#include "rt_List.h" -#include "rt_Task.h" -#include "rt_Time.h" -#include "rt_HAL_CM.h" - -/*---------------------------------------------------------------------------- - * Global Variables - *---------------------------------------------------------------------------*/ - -/* List head of chained ready tasks */ -struct OS_XCB os_rdy; -/* List head of chained delay tasks */ -struct OS_XCB os_dly; - - -/*---------------------------------------------------------------------------- - * Functions - *---------------------------------------------------------------------------*/ - - -/*--------------------------- rt_put_prio -----------------------------------*/ - -void rt_put_prio (P_XCB p_CB, P_TCB p_task) { - /* Put task identified with "p_task" into list ordered by priority. */ - /* "p_CB" points to head of list; list has always an element at end with */ - /* a priority less than "p_task->prio". */ - P_TCB p_CB2; - U32 prio; - BOOL sem_mbx = __FALSE; - - if (p_CB->cb_type == SCB || p_CB->cb_type == MCB || p_CB->cb_type == MUCB) { - sem_mbx = __TRUE; - } - prio = p_task->prio; - p_CB2 = p_CB->p_lnk; - /* Search for an entry in the list */ - while (p_CB2 != NULL && prio <= p_CB2->prio) { - p_CB = (P_XCB)p_CB2; - p_CB2 = p_CB2->p_lnk; - } - /* Entry found, insert the task into the list */ - p_task->p_lnk = p_CB2; - p_CB->p_lnk = p_task; - if (sem_mbx) { - if (p_CB2 != NULL) { - p_CB2->p_rlnk = p_task; - } - p_task->p_rlnk = (P_TCB)p_CB; - } - else { - p_task->p_rlnk = NULL; - } -} - - -/*--------------------------- rt_get_first ----------------------------------*/ - -P_TCB rt_get_first (P_XCB p_CB) { - /* Get task at head of list: it is the task with highest priority. */ - /* "p_CB" points to head of list. */ - P_TCB p_first; - - p_first = p_CB->p_lnk; - p_CB->p_lnk = p_first->p_lnk; - if (p_CB->cb_type == SCB || p_CB->cb_type == MCB || p_CB->cb_type == MUCB) { - if (p_first->p_lnk != NULL) { - p_first->p_lnk->p_rlnk = (P_TCB)p_CB; - p_first->p_lnk = NULL; - } - p_first->p_rlnk = NULL; - } - else { - p_first->p_lnk = NULL; - } - return (p_first); -} - - -/*--------------------------- rt_put_rdy_first ------------------------------*/ - -void rt_put_rdy_first (P_TCB p_task) { - /* Put task identified with "p_task" at the head of the ready list. The */ - /* task must have at least a priority equal to highest priority in list. */ - p_task->p_lnk = os_rdy.p_lnk; - p_task->p_rlnk = NULL; - os_rdy.p_lnk = p_task; -} - - -/*--------------------------- rt_get_same_rdy_prio --------------------------*/ - -P_TCB rt_get_same_rdy_prio (void) { - /* Remove a task of same priority from ready list if any exists. Other- */ - /* wise return NULL. */ - P_TCB p_first; - - p_first = os_rdy.p_lnk; - if (p_first->prio == os_tsk.run->prio) { - os_rdy.p_lnk = os_rdy.p_lnk->p_lnk; - return (p_first); - } - return (NULL); -} - - -/*--------------------------- rt_resort_prio --------------------------------*/ - -void rt_resort_prio (P_TCB p_task) { - /* Re-sort ordered lists after the priority of 'p_task' has changed. */ - P_TCB p_CB; - - if (p_task->p_rlnk == NULL) { - if (p_task->state == READY) { - /* Task is chained into READY list. */ - p_CB = (P_TCB)&os_rdy; - goto res; - } - } - else { - p_CB = p_task->p_rlnk; - while (p_CB->cb_type == TCB) { - /* Find a header of this task chain list. */ - p_CB = p_CB->p_rlnk; - } -res:rt_rmv_list (p_task); - rt_put_prio ((P_XCB)p_CB, p_task); - } -} - - -/*--------------------------- rt_put_dly ------------------------------------*/ - -void rt_put_dly (P_TCB p_task, U16 delay) { - /* Put a task identified with "p_task" into chained delay wait list using */ - /* a delay value of "delay". */ - P_TCB p; - U32 delta,idelay = delay; - - p = (P_TCB)&os_dly; - if (p->p_dlnk == NULL) { - /* Delay list empty */ - delta = 0; - goto last; - } - delta = os_dly.delta_time; - while (delta < idelay) { - if (p->p_dlnk == NULL) { - /* End of list found */ -last: p_task->p_dlnk = NULL; - p->p_dlnk = p_task; - p_task->p_blnk = p; - p->delta_time = (U16)(idelay - delta); - p_task->delta_time = 0; - return; - } - p = p->p_dlnk; - delta += p->delta_time; - } - /* Right place found */ - p_task->p_dlnk = p->p_dlnk; - p->p_dlnk = p_task; - p_task->p_blnk = p; - if (p_task->p_dlnk != NULL) { - p_task->p_dlnk->p_blnk = p_task; - } - p_task->delta_time = (U16)(delta - idelay); - p->delta_time -= p_task->delta_time; -} - - -/*--------------------------- rt_dec_dly ------------------------------------*/ - -void rt_dec_dly (void) { - /* Decrement delta time of list head: remove tasks having a value of zero.*/ - P_TCB p_rdy; - - if (os_dly.p_dlnk == NULL) { - return; - } - os_dly.delta_time--; - while ((os_dly.delta_time == 0) && (os_dly.p_dlnk != NULL)) { - p_rdy = os_dly.p_dlnk; - if (p_rdy->p_rlnk != NULL) { - /* Task is really enqueued, remove task from semaphore/mailbox */ - /* timeout waiting list. */ - p_rdy->p_rlnk->p_lnk = p_rdy->p_lnk; - if (p_rdy->p_lnk != NULL) { - p_rdy->p_lnk->p_rlnk = p_rdy->p_rlnk; - p_rdy->p_lnk = NULL; - } - p_rdy->p_rlnk = NULL; - } - rt_put_prio (&os_rdy, p_rdy); - os_dly.delta_time = p_rdy->delta_time; - if (p_rdy->state == WAIT_ITV) { - /* Calculate the next time for interval wait. */ - p_rdy->delta_time = p_rdy->interval_time + (U16)os_time; - } - p_rdy->state = READY; - os_dly.p_dlnk = p_rdy->p_dlnk; - if (p_rdy->p_dlnk != NULL) { - p_rdy->p_dlnk->p_blnk = (P_TCB)&os_dly; - p_rdy->p_dlnk = NULL; - } - p_rdy->p_blnk = NULL; - } -} - - -/*--------------------------- rt_rmv_list -----------------------------------*/ - -void rt_rmv_list (P_TCB p_task) { - /* Remove task identified with "p_task" from ready, semaphore or mailbox */ - /* waiting list if enqueued. */ - P_TCB p_b; - - if (p_task->p_rlnk != NULL) { - /* A task is enqueued in semaphore / mailbox waiting list. */ - p_task->p_rlnk->p_lnk = p_task->p_lnk; - if (p_task->p_lnk != NULL) { - p_task->p_lnk->p_rlnk = p_task->p_rlnk; - } - return; - } - - p_b = (P_TCB)&os_rdy; - while (p_b != NULL) { - /* Search the ready list for task "p_task" */ - if (p_b->p_lnk == p_task) { - p_b->p_lnk = p_task->p_lnk; - return; - } - p_b = p_b->p_lnk; - } -} - - -/*--------------------------- rt_rmv_dly ------------------------------------*/ - -void rt_rmv_dly (P_TCB p_task) { - /* Remove task identified with "p_task" from delay list if enqueued. */ - P_TCB p_b; - - p_b = p_task->p_blnk; - if (p_b != NULL) { - /* Task is really enqueued */ - p_b->p_dlnk = p_task->p_dlnk; - if (p_task->p_dlnk != NULL) { - /* 'p_task' is in the middle of list */ - p_b->delta_time += p_task->delta_time; - p_task->p_dlnk->p_blnk = p_b; - p_task->p_dlnk = NULL; - } - else { - /* 'p_task' is at the end of list */ - p_b->delta_time = 0; - } - p_task->p_blnk = NULL; - } -} - - -/*--------------------------- rt_psq_enq ------------------------------------*/ - -void rt_psq_enq (OS_ID entry, U32 arg) { - /* Insert post service request "entry" into ps-queue. */ - U32 idx; - - idx = rt_inc_qi (os_psq->size, &os_psq->count, &os_psq->first); - if (idx < os_psq->size) { - os_psq->q[idx].id = entry; - os_psq->q[idx].arg = arg; - } - else { - os_error (OS_ERR_FIFO_OVF); - } -} - - -/*---------------------------------------------------------------------------- - * end of file - *---------------------------------------------------------------------------*/ - diff --git a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_List.h b/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_List.h deleted file mode 100644 index cb3008e..0000000 --- a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_List.h +++ /dev/null @@ -1,67 +0,0 @@ -/*---------------------------------------------------------------------------- - * RL-ARM - RTX - *---------------------------------------------------------------------------- - * Name: RT_LIST.H - * Purpose: Functions for the management of different lists - * Rev.: V4.60 - *---------------------------------------------------------------------------- - * - * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - Neither the name of ARM nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - *---------------------------------------------------------------------------*/ - -/* Definitions */ - -/* Values for 'cb_type' */ -#define TCB 0 -#define MCB 1 -#define SCB 2 -#define MUCB 3 -#define HCB 4 - -/* Variables */ -extern struct OS_XCB os_rdy; -extern struct OS_XCB os_dly; - -/* Functions */ -extern void rt_put_prio (P_XCB p_CB, P_TCB p_task); -extern P_TCB rt_get_first (P_XCB p_CB); -extern void rt_put_rdy_first (P_TCB p_task); -extern P_TCB rt_get_same_rdy_prio (void); -extern void rt_resort_prio (P_TCB p_task); -extern void rt_put_dly (P_TCB p_task, U16 delay); -extern void rt_dec_dly (void); -extern void rt_rmv_list (P_TCB p_task); -extern void rt_rmv_dly (P_TCB p_task); -extern void rt_psq_enq (OS_ID entry, U32 arg); - -/* This is a fast macro generating in-line code */ -#define rt_rdy_prio(void) (os_rdy.p_lnk->prio) - - -/*---------------------------------------------------------------------------- - * end of file - *---------------------------------------------------------------------------*/ - diff --git a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Mailbox.c b/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Mailbox.c deleted file mode 100644 index ef28b76..0000000 --- a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Mailbox.c +++ /dev/null @@ -1,292 +0,0 @@ -/*---------------------------------------------------------------------------- - * RL-ARM - RTX - *---------------------------------------------------------------------------- - * Name: RT_MAILBOX.C - * Purpose: Implements waits and wake-ups for mailbox messages - * Rev.: V4.60 - *---------------------------------------------------------------------------- - * - * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - Neither the name of ARM nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - *---------------------------------------------------------------------------*/ - -#include "rt_TypeDef.h" -#include "RTX_Conf.h" -#include "rt_System.h" -#include "rt_List.h" -#include "rt_Mailbox.h" -#include "rt_MemBox.h" -#include "rt_Task.h" -#include "rt_HAL_CM.h" - - -/*---------------------------------------------------------------------------- - * Functions - *---------------------------------------------------------------------------*/ - - -/*--------------------------- rt_mbx_init -----------------------------------*/ - -void rt_mbx_init (OS_ID mailbox, U16 mbx_size) { - /* Initialize a mailbox */ - P_MCB p_MCB = mailbox; - - p_MCB->cb_type = MCB; - p_MCB->state = 0; - p_MCB->isr_st = 0; - p_MCB->p_lnk = NULL; - p_MCB->first = 0; - p_MCB->last = 0; - p_MCB->count = 0; - p_MCB->size = (mbx_size + sizeof(void *) - sizeof(struct OS_MCB)) / - (U32)sizeof (void *); -} - - -/*--------------------------- rt_mbx_send -----------------------------------*/ - -OS_RESULT rt_mbx_send (OS_ID mailbox, void *p_msg, U16 timeout) { - /* Send message to a mailbox */ - P_MCB p_MCB = mailbox; - P_TCB p_TCB; - - if ((p_MCB->p_lnk != NULL) && (p_MCB->state == 1)) { - /* A task is waiting for message */ - p_TCB = rt_get_first ((P_XCB)p_MCB); -#ifdef __CMSIS_RTOS - rt_ret_val2(p_TCB, 0x10/*osEventMessage*/, (U32)p_msg); -#else - *p_TCB->msg = p_msg; - rt_ret_val (p_TCB, OS_R_MBX); -#endif - rt_rmv_dly (p_TCB); - rt_dispatch (p_TCB); - } - else { - /* Store message in mailbox queue */ - if (p_MCB->count == p_MCB->size) { - /* No free message entry, wait for one. If message queue is full, */ - /* then no task is waiting for message. The 'p_MCB->p_lnk' list */ - /* pointer can now be reused for send message waits task list. */ - if (timeout == 0) { - return (OS_R_TMO); - } - if (p_MCB->p_lnk != NULL) { - rt_put_prio ((P_XCB)p_MCB, os_tsk.run); - } - else { - p_MCB->p_lnk = os_tsk.run; - os_tsk.run->p_lnk = NULL; - os_tsk.run->p_rlnk = (P_TCB)p_MCB; - /* Task is waiting to send a message */ - p_MCB->state = 2; - } - os_tsk.run->msg = p_msg; - rt_block (timeout, WAIT_MBX); - return (OS_R_TMO); - } - /* Yes, there is a free entry in a mailbox. */ - p_MCB->msg[p_MCB->first] = p_msg; - rt_inc (&p_MCB->count); - if (++p_MCB->first == p_MCB->size) { - p_MCB->first = 0; - } - } - return (OS_R_OK); -} - - -/*--------------------------- rt_mbx_wait -----------------------------------*/ - -OS_RESULT rt_mbx_wait (OS_ID mailbox, void **message, U16 timeout) { - /* Receive a message; possibly wait for it */ - P_MCB p_MCB = mailbox; - P_TCB p_TCB; - - /* If a message is available in the fifo buffer */ - /* remove it from the fifo buffer and return. */ - if (p_MCB->count) { - *message = p_MCB->msg[p_MCB->last]; - if (++p_MCB->last == p_MCB->size) { - p_MCB->last = 0; - } - if ((p_MCB->p_lnk != NULL) && (p_MCB->state == 2)) { - /* A task is waiting to send message */ - p_TCB = rt_get_first ((P_XCB)p_MCB); -#ifdef __CMSIS_RTOS - rt_ret_val(p_TCB, 0/*osOK*/); -#else - rt_ret_val(p_TCB, OS_R_OK); -#endif - p_MCB->msg[p_MCB->first] = p_TCB->msg; - if (++p_MCB->first == p_MCB->size) { - p_MCB->first = 0; - } - rt_rmv_dly (p_TCB); - rt_dispatch (p_TCB); - } - else { - rt_dec (&p_MCB->count); - } - return (OS_R_OK); - } - /* No message available: wait for one */ - if (timeout == 0) { - return (OS_R_TMO); - } - if (p_MCB->p_lnk != NULL) { - rt_put_prio ((P_XCB)p_MCB, os_tsk.run); - } - else { - p_MCB->p_lnk = os_tsk.run; - os_tsk.run->p_lnk = NULL; - os_tsk.run->p_rlnk = (P_TCB)p_MCB; - /* Task is waiting to receive a message */ - p_MCB->state = 1; - } - rt_block(timeout, WAIT_MBX); -#ifndef __CMSIS_RTOS - os_tsk.run->msg = message; -#endif - return (OS_R_TMO); -} - - -/*--------------------------- rt_mbx_check ----------------------------------*/ - -OS_RESULT rt_mbx_check (OS_ID mailbox) { - /* Check for free space in a mailbox. Returns the number of messages */ - /* that can be stored to a mailbox. It returns 0 when mailbox is full. */ - P_MCB p_MCB = mailbox; - - return (p_MCB->size - p_MCB->count); -} - - -/*--------------------------- isr_mbx_send ----------------------------------*/ - -void isr_mbx_send (OS_ID mailbox, void *p_msg) { - /* Same function as "os_mbx_send", but to be called by ISRs. */ - P_MCB p_MCB = mailbox; - - rt_psq_enq (p_MCB, (U32)p_msg); - rt_psh_req (); -} - - -/*--------------------------- isr_mbx_receive -------------------------------*/ - -OS_RESULT isr_mbx_receive (OS_ID mailbox, void **message) { - /* Receive a message in the interrupt function. The interrupt function */ - /* should not wait for a message since this would block the rtx os. */ - P_MCB p_MCB = mailbox; - - if (p_MCB->count) { - /* A message is available in the fifo buffer. */ - *message = p_MCB->msg[p_MCB->last]; - if (p_MCB->state == 2) { - /* A task is locked waiting to send message */ - rt_psq_enq (p_MCB, 0); - rt_psh_req (); - } - rt_dec (&p_MCB->count); - if (++p_MCB->last == p_MCB->size) { - p_MCB->last = 0; - } - return (OS_R_MBX); - } - return (OS_R_OK); -} - - -/*--------------------------- rt_mbx_psh ------------------------------------*/ - -void rt_mbx_psh (P_MCB p_CB, void *p_msg) { - /* Store the message to the mailbox queue or pass it to task directly. */ - P_TCB p_TCB; - void *mem; - - if (p_CB->p_lnk != NULL) switch (p_CB->state) { -#ifdef __CMSIS_RTOS - case 3: - /* Task is waiting to allocate memory, remove it from the waiting list */ - mem = rt_alloc_box(p_msg); - if (mem == NULL) break; - p_TCB = rt_get_first ((P_XCB)p_CB); - rt_ret_val(p_TCB, (U32)mem); - p_TCB->state = READY; - rt_rmv_dly (p_TCB); - rt_put_prio (&os_rdy, p_TCB); - break; -#endif - case 2: - /* Task is waiting to send a message, remove it from the waiting list */ - p_TCB = rt_get_first ((P_XCB)p_CB); -#ifdef __CMSIS_RTOS - rt_ret_val(p_TCB, 0/*osOK*/); -#else - rt_ret_val(p_TCB, OS_R_OK); -#endif - p_CB->msg[p_CB->first] = p_TCB->msg; - rt_inc (&p_CB->count); - if (++p_CB->first == p_CB->size) { - p_CB->first = 0; - } - p_TCB->state = READY; - rt_rmv_dly (p_TCB); - rt_put_prio (&os_rdy, p_TCB); - break; - case 1: - /* Task is waiting for a message, pass the message to the task directly */ - p_TCB = rt_get_first ((P_XCB)p_CB); -#ifdef __CMSIS_RTOS - rt_ret_val2(p_TCB, 0x10/*osEventMessage*/, (U32)p_msg); -#else - *p_TCB->msg = p_msg; - rt_ret_val (p_TCB, OS_R_MBX); -#endif - p_TCB->state = READY; - rt_rmv_dly (p_TCB); - rt_put_prio (&os_rdy, p_TCB); - break; - } else { - /* No task is waiting for a message, store it to the mailbox queue */ - if (p_CB->count < p_CB->size) { - p_CB->msg[p_CB->first] = p_msg; - rt_inc (&p_CB->count); - if (++p_CB->first == p_CB->size) { - p_CB->first = 0; - } - } - else { - os_error (OS_ERR_MBX_OVF); - } - } -} - -/*---------------------------------------------------------------------------- - * end of file - *---------------------------------------------------------------------------*/ - diff --git a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Mailbox.h b/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Mailbox.h deleted file mode 100644 index 0c8e2f3..0000000 --- a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Mailbox.h +++ /dev/null @@ -1,48 +0,0 @@ -/*---------------------------------------------------------------------------- - * RL-ARM - RTX - *---------------------------------------------------------------------------- - * Name: RT_MAILBOX.H - * Purpose: Implements waits and wake-ups for mailbox messages - * Rev.: V4.60 - *---------------------------------------------------------------------------- - * - * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - Neither the name of ARM nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - *---------------------------------------------------------------------------*/ - -/* Functions */ -extern void rt_mbx_init (OS_ID mailbox, U16 mbx_size); -extern OS_RESULT rt_mbx_send (OS_ID mailbox, void *p_msg, U16 timeout); -extern OS_RESULT rt_mbx_wait (OS_ID mailbox, void **message, U16 timeout); -extern OS_RESULT rt_mbx_check (OS_ID mailbox); -extern void isr_mbx_send (OS_ID mailbox, void *p_msg); -extern OS_RESULT isr_mbx_receive (OS_ID mailbox, void **message); -extern void rt_mbx_psh (P_MCB p_CB, void *p_msg); - - -/*---------------------------------------------------------------------------- - * end of file - *---------------------------------------------------------------------------*/ - diff --git a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_MemBox.c b/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_MemBox.c deleted file mode 100644 index 5b96ae0..0000000 --- a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_MemBox.c +++ /dev/null @@ -1,166 +0,0 @@ -/*---------------------------------------------------------------------------- - * RL-ARM - RTX - *---------------------------------------------------------------------------- - * Name: RT_MEMBOX.C - * Purpose: Interface functions for fixed memory block management system - * Rev.: V4.60 - *---------------------------------------------------------------------------- - * - * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - Neither the name of ARM nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - *---------------------------------------------------------------------------*/ - -#include "rt_TypeDef.h" -#include "RTX_Conf.h" -#include "rt_System.h" -#include "rt_MemBox.h" -#include "rt_HAL_CM.h" - -/*---------------------------------------------------------------------------- - * Global Functions - *---------------------------------------------------------------------------*/ - - -/*--------------------------- _init_box -------------------------------------*/ - -int _init_box (void *box_mem, U32 box_size, U32 blk_size) { - /* Initialize memory block system, returns 0 if OK, 1 if fails. */ - void *end; - void *blk; - void *next; - U32 sizeof_bm; - - /* Create memory structure. */ - if (blk_size & BOX_ALIGN_8) { - /* Memory blocks 8-byte aligned. */ - blk_size = ((blk_size & ~BOX_ALIGN_8) + 7) & ~7; - sizeof_bm = (sizeof (struct OS_BM) + 7) & ~7; - } - else { - /* Memory blocks 4-byte aligned. */ - blk_size = (blk_size + 3) & ~3; - sizeof_bm = sizeof (struct OS_BM); - } - if (blk_size == 0) { - return (1); - } - if ((blk_size + sizeof_bm) > box_size) { - return (1); - } - /* Create a Memory structure. */ - blk = ((U8 *) box_mem) + sizeof_bm; - ((P_BM) box_mem)->free = blk; - end = ((U8 *) box_mem) + box_size; - ((P_BM) box_mem)->end = end; - ((P_BM) box_mem)->blk_size = blk_size; - - /* Link all free blocks using offsets. */ - end = ((U8 *) end) - blk_size; - while (1) { - next = ((U8 *) blk) + blk_size; - if (next > end) break; - *((void **)blk) = next; - blk = next; - } - /* end marker */ - *((void **)blk) = 0; - return (0); -} - -/*--------------------------- rt_alloc_box ----------------------------------*/ - -void *rt_alloc_box (void *box_mem) { - /* Allocate a memory block and return start address. */ - void **free; -#ifndef __USE_EXCLUSIVE_ACCESS - int irq_dis; - - irq_dis = __disable_irq (); - free = ((P_BM) box_mem)->free; - if (free) { - ((P_BM) box_mem)->free = *free; - } - if (!irq_dis) __enable_irq (); -#else - do { - if ((free = (void **)__ldrex(&((P_BM) box_mem)->free)) == 0) { - __clrex(); - break; - } - } while (__strex((U32)*free, &((P_BM) box_mem)->free)); -#endif - return (free); -} - - -/*--------------------------- _calloc_box -----------------------------------*/ - -void *_calloc_box (void *box_mem) { - /* Allocate a 0-initialized memory block and return start address. */ - void *free; - U32 *p; - U32 i; - - free = _alloc_box (box_mem); - if (free) { - p = free; - for (i = ((P_BM) box_mem)->blk_size; i; i -= 4) { - *p = 0; - p++; - } - } - return (free); -} - - -/*--------------------------- rt_free_box -----------------------------------*/ - -int rt_free_box (void *box_mem, void *box) { - /* Free a memory block, returns 0 if OK, 1 if box does not belong to box_mem */ -#ifndef __USE_EXCLUSIVE_ACCESS - int irq_dis; -#endif - - if (box < box_mem || box >= ((P_BM) box_mem)->end) { - return (1); - } - -#ifndef __USE_EXCLUSIVE_ACCESS - irq_dis = __disable_irq (); - *((void **)box) = ((P_BM) box_mem)->free; - ((P_BM) box_mem)->free = box; - if (!irq_dis) __enable_irq (); -#else - do { - *((void **)box) = (void *)__ldrex(&((P_BM) box_mem)->free); - } while (__strex ((U32)box, &((P_BM) box_mem)->free)); -#endif - return (0); -} - -/*---------------------------------------------------------------------------- - * end of file - *---------------------------------------------------------------------------*/ - diff --git a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_MemBox.h b/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_MemBox.h deleted file mode 100644 index c10a1cb..0000000 --- a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_MemBox.h +++ /dev/null @@ -1,46 +0,0 @@ -/*---------------------------------------------------------------------------- - * RL-ARM - RTX - *---------------------------------------------------------------------------- - * Name: RT_MEMBOX.H - * Purpose: Interface functions for fixed memory block management system - * Rev.: V4.60 - *---------------------------------------------------------------------------- - * - * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - Neither the name of ARM nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - *---------------------------------------------------------------------------*/ - -/* Functions */ -#define rt_init_box _init_box -#define rt_calloc_box _calloc_box -extern int _init_box (void *box_mem, U32 box_size, U32 blk_size); -extern void *rt_alloc_box (void *box_mem); -extern void * _calloc_box (void *box_mem); -extern int rt_free_box (void *box_mem, void *box); - -/*---------------------------------------------------------------------------- - * end of file - *---------------------------------------------------------------------------*/ - diff --git a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Mutex.c b/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Mutex.c deleted file mode 100644 index c7a996b..0000000 --- a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Mutex.c +++ /dev/null @@ -1,197 +0,0 @@ -/*---------------------------------------------------------------------------- - * RL-ARM - RTX - *---------------------------------------------------------------------------- - * Name: RT_MUTEX.C - * Purpose: Implements mutex synchronization objects - * Rev.: V4.60 - *---------------------------------------------------------------------------- - * - * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - Neither the name of ARM nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - *---------------------------------------------------------------------------*/ - -#include "rt_TypeDef.h" -#include "RTX_Conf.h" -#include "rt_List.h" -#include "rt_Task.h" -#include "rt_Mutex.h" -#include "rt_HAL_CM.h" - - -/*---------------------------------------------------------------------------- - * Functions - *---------------------------------------------------------------------------*/ - - -/*--------------------------- rt_mut_init -----------------------------------*/ - -void rt_mut_init (OS_ID mutex) { - /* Initialize a mutex object */ - P_MUCB p_MCB = mutex; - - p_MCB->cb_type = MUCB; - p_MCB->prio = 0; - p_MCB->level = 0; - p_MCB->p_lnk = NULL; - p_MCB->owner = NULL; -} - - -/*--------------------------- rt_mut_delete ---------------------------------*/ - -#ifdef __CMSIS_RTOS -OS_RESULT rt_mut_delete (OS_ID mutex) { - /* Delete a mutex object */ - P_MUCB p_MCB = mutex; - P_TCB p_TCB; - - /* Restore owner task's priority. */ - if (p_MCB->level != 0) { - p_MCB->owner->prio = p_MCB->prio; - if (p_MCB->owner != os_tsk.run) { - rt_resort_prio (p_MCB->owner); - } - } - - while (p_MCB->p_lnk != NULL) { - /* A task is waiting for mutex. */ - p_TCB = rt_get_first ((P_XCB)p_MCB); - rt_ret_val(p_TCB, 0/*osOK*/); - rt_rmv_dly(p_TCB); - p_TCB->state = READY; - rt_put_prio (&os_rdy, p_TCB); - } - - if (os_rdy.p_lnk && (os_rdy.p_lnk->prio > os_tsk.run->prio)) { - /* preempt running task */ - rt_put_prio (&os_rdy, os_tsk.run); - os_tsk.run->state = READY; - rt_dispatch (NULL); - } - - p_MCB->cb_type = 0; - - return (OS_R_OK); -} -#endif - - -/*--------------------------- rt_mut_release --------------------------------*/ - -OS_RESULT rt_mut_release (OS_ID mutex) { - /* Release a mutex object */ - P_MUCB p_MCB = mutex; - P_TCB p_TCB; - - if (p_MCB->level == 0 || p_MCB->owner != os_tsk.run) { - /* Unbalanced mutex release or task is not the owner */ - return (OS_R_NOK); - } - if (--p_MCB->level != 0) { - return (OS_R_OK); - } - /* Restore owner task's priority. */ - os_tsk.run->prio = p_MCB->prio; - if (p_MCB->p_lnk != NULL) { - /* A task is waiting for mutex. */ - p_TCB = rt_get_first ((P_XCB)p_MCB); -#ifdef __CMSIS_RTOS - rt_ret_val(p_TCB, 0/*osOK*/); -#else - rt_ret_val(p_TCB, OS_R_MUT); -#endif - rt_rmv_dly (p_TCB); - /* A waiting task becomes the owner of this mutex. */ - p_MCB->level = 1; - p_MCB->owner = p_TCB; - p_MCB->prio = p_TCB->prio; - /* Priority inversion, check which task continues. */ - if (os_tsk.run->prio >= rt_rdy_prio()) { - rt_dispatch (p_TCB); - } - else { - /* Ready task has higher priority than running task. */ - rt_put_prio (&os_rdy, os_tsk.run); - rt_put_prio (&os_rdy, p_TCB); - os_tsk.run->state = READY; - p_TCB->state = READY; - rt_dispatch (NULL); - } - } - else { - /* Check if own priority raised by priority inversion. */ - if (rt_rdy_prio() > os_tsk.run->prio) { - rt_put_prio (&os_rdy, os_tsk.run); - os_tsk.run->state = READY; - rt_dispatch (NULL); - } - } - return (OS_R_OK); -} - - -/*--------------------------- rt_mut_wait -----------------------------------*/ - -OS_RESULT rt_mut_wait (OS_ID mutex, U16 timeout) { - /* Wait for a mutex, continue when mutex is free. */ - P_MUCB p_MCB = mutex; - - if (p_MCB->level == 0) { - p_MCB->owner = os_tsk.run; - p_MCB->prio = os_tsk.run->prio; - goto inc; - } - if (p_MCB->owner == os_tsk.run) { - /* OK, running task is the owner of this mutex. */ -inc:p_MCB->level++; - return (OS_R_OK); - } - /* Mutex owned by another task, wait until released. */ - if (timeout == 0) { - return (OS_R_TMO); - } - /* Raise the owner task priority if lower than current priority. */ - /* This priority inversion is called priority inheritance. */ - if (p_MCB->prio < os_tsk.run->prio) { - p_MCB->owner->prio = os_tsk.run->prio; - rt_resort_prio (p_MCB->owner); - } - if (p_MCB->p_lnk != NULL) { - rt_put_prio ((P_XCB)p_MCB, os_tsk.run); - } - else { - p_MCB->p_lnk = os_tsk.run; - os_tsk.run->p_lnk = NULL; - os_tsk.run->p_rlnk = (P_TCB)p_MCB; - } - rt_block(timeout, WAIT_MUT); - return (OS_R_TMO); -} - - -/*---------------------------------------------------------------------------- - * end of file - *---------------------------------------------------------------------------*/ - diff --git a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Mutex.h b/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Mutex.h deleted file mode 100644 index bf15c4d..0000000 --- a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Mutex.h +++ /dev/null @@ -1,44 +0,0 @@ -/*---------------------------------------------------------------------------- - * RL-ARM - RTX - *---------------------------------------------------------------------------- - * Name: RT_MUTEX.H - * Purpose: Implements mutex synchronization objects - * Rev.: V4.60 - *---------------------------------------------------------------------------- - * - * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - Neither the name of ARM nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - *---------------------------------------------------------------------------*/ - -/* Functions */ -extern void rt_mut_init (OS_ID mutex); -extern OS_RESULT rt_mut_delete (OS_ID mutex); -extern OS_RESULT rt_mut_release (OS_ID mutex); -extern OS_RESULT rt_mut_wait (OS_ID mutex, U16 timeout); - -/*---------------------------------------------------------------------------- - * end of file - *---------------------------------------------------------------------------*/ - diff --git a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Robin.c b/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Robin.c deleted file mode 100644 index d693dc6..0000000 --- a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Robin.c +++ /dev/null @@ -1,84 +0,0 @@ -/*---------------------------------------------------------------------------- - * RL-ARM - RTX - *---------------------------------------------------------------------------- - * Name: RT_ROBIN.C - * Purpose: Round Robin Task switching - * Rev.: V4.60 - *---------------------------------------------------------------------------- - * - * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - Neither the name of ARM nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - *---------------------------------------------------------------------------*/ - -#include "rt_TypeDef.h" -#include "RTX_Conf.h" -#include "rt_List.h" -#include "rt_Task.h" -#include "rt_Time.h" -#include "rt_Robin.h" -#include "rt_HAL_CM.h" - -/*---------------------------------------------------------------------------- - * Global Variables - *---------------------------------------------------------------------------*/ - -struct OS_ROBIN os_robin; - - -/*---------------------------------------------------------------------------- - * Global Functions - *---------------------------------------------------------------------------*/ - -/*--------------------------- rt_init_robin ---------------------------------*/ - -__weak void rt_init_robin (void) { - /* Initialize Round Robin variables. */ - os_robin.task = NULL; - os_robin.tout = (U16)os_rrobin; -} - -/*--------------------------- rt_chk_robin ----------------------------------*/ - -__weak void rt_chk_robin (void) { - /* Check if Round Robin timeout expired and switch to the next ready task.*/ - P_TCB p_new; - - if (os_robin.task != os_rdy.p_lnk) { - /* New task was suspended, reset Round Robin timeout. */ - os_robin.task = os_rdy.p_lnk; - os_robin.time = (U16)os_time + os_robin.tout - 1; - } - if (os_robin.time == (U16)os_time) { - /* Round Robin timeout has expired, swap Robin tasks. */ - os_robin.task = NULL; - p_new = rt_get_first (&os_rdy); - rt_put_prio ((P_XCB)&os_rdy, p_new); - } -} - -/*---------------------------------------------------------------------------- - * end of file - *---------------------------------------------------------------------------*/ - diff --git a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Robin.h b/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Robin.h deleted file mode 100644 index 3ccbffc..0000000 --- a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Robin.h +++ /dev/null @@ -1,45 +0,0 @@ -/*---------------------------------------------------------------------------- - * RL-ARM - RTX - *---------------------------------------------------------------------------- - * Name: RT_ROBIN.H - * Purpose: Round Robin Task switching definitions - * Rev.: V4.60 - *---------------------------------------------------------------------------- - * - * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - Neither the name of ARM nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - *---------------------------------------------------------------------------*/ - -/* Variables */ -extern struct OS_ROBIN os_robin; - -/* Functions */ -extern void rt_init_robin (void); -extern void rt_chk_robin (void); - -/*---------------------------------------------------------------------------- - * end of file - *---------------------------------------------------------------------------*/ - diff --git a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Semaphore.c b/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Semaphore.c deleted file mode 100644 index 93ff2bf..0000000 --- a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Semaphore.c +++ /dev/null @@ -1,183 +0,0 @@ -/*---------------------------------------------------------------------------- - * RL-ARM - RTX - *---------------------------------------------------------------------------- - * Name: RT_SEMAPHORE.C - * Purpose: Implements binary and counting semaphores - * Rev.: V4.60 - *---------------------------------------------------------------------------- - * - * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - Neither the name of ARM nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - *---------------------------------------------------------------------------*/ - -#include "rt_TypeDef.h" -#include "RTX_Conf.h" -#include "rt_System.h" -#include "rt_List.h" -#include "rt_Task.h" -#include "rt_Semaphore.h" -#include "rt_HAL_CM.h" - - -/*---------------------------------------------------------------------------- - * Functions - *---------------------------------------------------------------------------*/ - - -/*--------------------------- rt_sem_init -----------------------------------*/ - -void rt_sem_init (OS_ID semaphore, U16 token_count) { - /* Initialize a semaphore */ - P_SCB p_SCB = semaphore; - - p_SCB->cb_type = SCB; - p_SCB->p_lnk = NULL; - p_SCB->tokens = token_count; -} - - -/*--------------------------- rt_sem_delete ---------------------------------*/ - -#ifdef __CMSIS_RTOS -OS_RESULT rt_sem_delete (OS_ID semaphore) { - /* Delete semaphore */ - P_SCB p_SCB = semaphore; - P_TCB p_TCB; - - while (p_SCB->p_lnk != NULL) { - /* A task is waiting for token */ - p_TCB = rt_get_first ((P_XCB)p_SCB); - rt_ret_val(p_TCB, 0); - rt_rmv_dly(p_TCB); - p_TCB->state = READY; - rt_put_prio (&os_rdy, p_TCB); - } - - if (os_rdy.p_lnk && (os_rdy.p_lnk->prio > os_tsk.run->prio)) { - /* preempt running task */ - rt_put_prio (&os_rdy, os_tsk.run); - os_tsk.run->state = READY; - rt_dispatch (NULL); - } - - p_SCB->cb_type = 0; - - return (OS_R_OK); -} -#endif - - -/*--------------------------- rt_sem_send -----------------------------------*/ - -OS_RESULT rt_sem_send (OS_ID semaphore) { - /* Return a token to semaphore */ - P_SCB p_SCB = semaphore; - P_TCB p_TCB; - - if (p_SCB->p_lnk != NULL) { - /* A task is waiting for token */ - p_TCB = rt_get_first ((P_XCB)p_SCB); -#ifdef __CMSIS_RTOS - rt_ret_val(p_TCB, 1); -#else - rt_ret_val(p_TCB, OS_R_SEM); -#endif - rt_rmv_dly (p_TCB); - rt_dispatch (p_TCB); - } - else { - /* Store token. */ - p_SCB->tokens++; - } - return (OS_R_OK); -} - - -/*--------------------------- rt_sem_wait -----------------------------------*/ - -OS_RESULT rt_sem_wait (OS_ID semaphore, U16 timeout) { - /* Obtain a token; possibly wait for it */ - P_SCB p_SCB = semaphore; - - if (p_SCB->tokens) { - p_SCB->tokens--; - return (OS_R_OK); - } - /* No token available: wait for one */ - if (timeout == 0) { - return (OS_R_TMO); - } - if (p_SCB->p_lnk != NULL) { - rt_put_prio ((P_XCB)p_SCB, os_tsk.run); - } - else { - p_SCB->p_lnk = os_tsk.run; - os_tsk.run->p_lnk = NULL; - os_tsk.run->p_rlnk = (P_TCB)p_SCB; - } - rt_block(timeout, WAIT_SEM); - return (OS_R_TMO); -} - - -/*--------------------------- isr_sem_send ----------------------------------*/ - -void isr_sem_send (OS_ID semaphore) { - /* Same function as "os_sem"send", but to be called by ISRs */ - P_SCB p_SCB = semaphore; - - rt_psq_enq (p_SCB, 0); - rt_psh_req (); -} - - -/*--------------------------- rt_sem_psh ------------------------------------*/ - -void rt_sem_psh (P_SCB p_CB) { - /* Check if task has to be waken up */ - P_TCB p_TCB; - - if (p_CB->p_lnk != NULL) { - /* A task is waiting for token */ - p_TCB = rt_get_first ((P_XCB)p_CB); - rt_rmv_dly (p_TCB); - p_TCB->state = READY; -#ifdef __CMSIS_RTOS - rt_ret_val(p_TCB, 1); -#else - rt_ret_val(p_TCB, OS_R_SEM); -#endif - rt_put_prio (&os_rdy, p_TCB); - } - else { - /* Store token */ - p_CB->tokens++; - } -} - -/*---------------------------------------------------------------------------- - * end of file - *---------------------------------------------------------------------------*/ - diff --git a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Semaphore.h b/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Semaphore.h deleted file mode 100644 index ec45480..0000000 --- a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Semaphore.h +++ /dev/null @@ -1,46 +0,0 @@ -/*---------------------------------------------------------------------------- - * RL-ARM - RTX - *---------------------------------------------------------------------------- - * Name: RT_SEMAPHORE.H - * Purpose: Implements binary and counting semaphores - * Rev.: V4.60 - *---------------------------------------------------------------------------- - * - * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - Neither the name of ARM nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - *---------------------------------------------------------------------------*/ - -/* Functions */ -extern void rt_sem_init (OS_ID semaphore, U16 token_count); -extern OS_RESULT rt_sem_delete(OS_ID semaphore); -extern OS_RESULT rt_sem_send (OS_ID semaphore); -extern OS_RESULT rt_sem_wait (OS_ID semaphore, U16 timeout); -extern void isr_sem_send (OS_ID semaphore); -extern void rt_sem_psh (P_SCB p_CB); - -/*---------------------------------------------------------------------------- - * end of file - *---------------------------------------------------------------------------*/ - diff --git a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_System.c b/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_System.c deleted file mode 100644 index f48b67b..0000000 --- a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_System.c +++ /dev/null @@ -1,299 +0,0 @@ -/*---------------------------------------------------------------------------- - * RL-ARM - RTX - *---------------------------------------------------------------------------- - * Name: RT_SYSTEM.C - * Purpose: System Task Manager - * Rev.: V4.60 - *---------------------------------------------------------------------------- - * - * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - Neither the name of ARM nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - *---------------------------------------------------------------------------*/ - -#include "rt_TypeDef.h" -#include "RTX_Conf.h" -#include "rt_Task.h" -#include "rt_System.h" -#include "rt_Event.h" -#include "rt_List.h" -#include "rt_Mailbox.h" -#include "rt_Semaphore.h" -#include "rt_Time.h" -#include "rt_Robin.h" -#include "rt_HAL_CM.h" - -/*---------------------------------------------------------------------------- - * Global Variables - *---------------------------------------------------------------------------*/ - -int os_tick_irqn; - -/*---------------------------------------------------------------------------- - * Local Variables - *---------------------------------------------------------------------------*/ - -static volatile BIT os_lock; -static volatile BIT os_psh_flag; -static U8 pend_flags; - -/*---------------------------------------------------------------------------- - * Global Functions - *---------------------------------------------------------------------------*/ - -#if defined (__CC_ARM) -__asm void $$RTX$$version (void) { - /* Export a version number symbol for a version control. */ - - EXPORT __RL_RTX_VER - -__RL_RTX_VER EQU 0x450 -} -#endif - - -/*--------------------------- rt_suspend ------------------------------------*/ -U32 rt_suspend (void) { - /* Suspend OS scheduler */ - U32 delta = 0xFFFF; - - rt_tsk_lock(); - - if (os_dly.p_dlnk) { - delta = os_dly.delta_time; - } -#ifndef __CMSIS_RTOS - if (os_tmr.next) { - if (os_tmr.tcnt < delta) delta = os_tmr.tcnt; - } -#endif - - return (delta); -} - - -/*--------------------------- rt_resume -------------------------------------*/ -void rt_resume (U32 sleep_time) { - /* Resume OS scheduler after suspend */ - P_TCB next; - U32 delta; - - os_tsk.run->state = READY; - rt_put_rdy_first (os_tsk.run); - - os_robin.task = NULL; - - /* Update delays. */ - if (os_dly.p_dlnk) { - delta = sleep_time; - if (delta >= os_dly.delta_time) { - delta -= os_dly.delta_time; - os_time += os_dly.delta_time; - os_dly.delta_time = 1; - while (os_dly.p_dlnk) { - rt_dec_dly(); - if (delta == 0) break; - delta--; - os_time++; - } - } else { - os_time += delta; - os_dly.delta_time -= delta; - } - } else { - os_time += sleep_time; - } - -#ifndef __CMSIS_RTOS - /* Check the user timers. */ - if (os_tmr.next) { - delta = sleep_time; - if (delta >= os_tmr.tcnt) { - delta -= os_tmr.tcnt; - os_tmr.tcnt = 1; - while (os_tmr.next) { - rt_tmr_tick(); - if (delta == 0) break; - delta--; - } - } else { - os_tmr.tcnt -= delta; - } - } -#endif - - /* Switch back to highest ready task */ - next = rt_get_first (&os_rdy); - rt_switch_req (next); - - rt_tsk_unlock(); -} - - -/*--------------------------- rt_tsk_lock -----------------------------------*/ - -void rt_tsk_lock (void) { - /* Prevent task switching by locking out scheduler */ - if (os_tick_irqn < 0) { - OS_LOCK(); - os_lock = __TRUE; - OS_UNPEND (&pend_flags); - } else { - OS_X_LOCK(os_tick_irqn); - os_lock = __TRUE; - OS_X_UNPEND (&pend_flags); - } -} - - -/*--------------------------- rt_tsk_unlock ---------------------------------*/ - -void rt_tsk_unlock (void) { - /* Unlock scheduler and re-enable task switching */ - if (os_tick_irqn < 0) { - OS_UNLOCK(); - os_lock = __FALSE; - OS_PEND (pend_flags, os_psh_flag); - os_psh_flag = __FALSE; - } else { - OS_X_UNLOCK(os_tick_irqn); - os_lock = __FALSE; - OS_X_PEND (pend_flags, os_psh_flag); - os_psh_flag = __FALSE; - } -} - - -/*--------------------------- rt_psh_req ------------------------------------*/ - -void rt_psh_req (void) { - /* Initiate a post service handling request if required. */ - if (os_lock == __FALSE) { - OS_PEND_IRQ (); - } - else { - os_psh_flag = __TRUE; - } -} - - -/*--------------------------- rt_pop_req ------------------------------------*/ - -void rt_pop_req (void) { - /* Process an ISR post service requests. */ - struct OS_XCB *p_CB; - P_TCB next; - U32 idx; - - os_tsk.run->state = READY; - rt_put_rdy_first (os_tsk.run); - - idx = os_psq->last; - while (os_psq->count) { - p_CB = os_psq->q[idx].id; - if (p_CB->cb_type == TCB) { - /* Is of TCB type */ - rt_evt_psh ((P_TCB)p_CB, (U16)os_psq->q[idx].arg); - } - else if (p_CB->cb_type == MCB) { - /* Is of MCB type */ - rt_mbx_psh ((P_MCB)p_CB, (void *)os_psq->q[idx].arg); - } - else { - /* Must be of SCB type */ - rt_sem_psh ((P_SCB)p_CB); - } - if (++idx == os_psq->size) idx = 0; - rt_dec (&os_psq->count); - } - os_psq->last = idx; - - next = rt_get_first (&os_rdy); - rt_switch_req (next); -} - - -/*--------------------------- os_tick_init ----------------------------------*/ - -__weak int os_tick_init (void) { - /* Initialize SysTick timer as system tick timer. */ - rt_systick_init (); - return (-1); /* Return IRQ number of SysTick timer */ -} - - -/*--------------------------- os_tick_irqack --------------------------------*/ - -__weak void os_tick_irqack (void) { - /* Acknowledge timer interrupt. */ -} - - -/*--------------------------- rt_systick ------------------------------------*/ - -extern void sysTimerTick(void); - -void rt_systick (void) { - /* Check for system clock update, suspend running task. */ - P_TCB next; - - os_tsk.run->state = READY; - rt_put_rdy_first (os_tsk.run); - - /* Check Round Robin timeout. */ - rt_chk_robin (); - - /* Update delays. */ - os_time++; - rt_dec_dly (); - - /* Check the user timers. */ -#ifdef __CMSIS_RTOS - sysTimerTick(); -#else - rt_tmr_tick (); -#endif - - /* Switch back to highest ready task */ - next = rt_get_first (&os_rdy); - rt_switch_req (next); -} - -/*--------------------------- rt_stk_check ----------------------------------*/ -__weak void rt_stk_check (void) { - /* Check for stack overflow. */ - if (os_tsk.run->task_id == 0x01) { - // TODO: For the main thread the check should be done against the main heap pointer - } else { - if ((os_tsk.run->tsk_stack < (U32)os_tsk.run->stack) || - (os_tsk.run->stack[0] != MAGIC_WORD)) { - os_error (OS_ERR_STK_OVF); - } - } -} - -/*---------------------------------------------------------------------------- - * end of file - *---------------------------------------------------------------------------*/ - diff --git a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_System.h b/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_System.h deleted file mode 100644 index 91db648..0000000 --- a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_System.h +++ /dev/null @@ -1,52 +0,0 @@ -/*---------------------------------------------------------------------------- - * RL-ARM - RTX - *---------------------------------------------------------------------------- - * Name: RT_SYSTEM.H - * Purpose: System Task Manager definitions - * Rev.: V4.60 - *---------------------------------------------------------------------------- - * - * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - Neither the name of ARM nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - *---------------------------------------------------------------------------*/ - -/* Variables */ -#define os_psq ((P_PSQ)&os_fifo) -extern int os_tick_irqn; - -/* Functions */ -extern U32 rt_suspend (void); -extern void rt_resume (U32 sleep_time); -extern void rt_tsk_lock (void); -extern void rt_tsk_unlock (void); -extern void rt_psh_req (void); -extern void rt_pop_req (void); -extern void rt_systick (void); -extern void rt_stk_check (void); - -/*---------------------------------------------------------------------------- - * end of file - *---------------------------------------------------------------------------*/ - diff --git a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Task.c b/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Task.c deleted file mode 100644 index 518f78f..0000000 --- a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Task.c +++ /dev/null @@ -1,339 +0,0 @@ -/*---------------------------------------------------------------------------- - * RL-ARM - RTX - *---------------------------------------------------------------------------- - * Name: RT_TASK.C - * Purpose: Task functions and system start up. - * Rev.: V4.60 - *---------------------------------------------------------------------------- - * - * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - Neither the name of ARM nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - *---------------------------------------------------------------------------*/ - -#include "rt_TypeDef.h" -#include "RTX_Conf.h" -#include "rt_System.h" -#include "rt_Task.h" -#include "rt_List.h" -#include "rt_MemBox.h" -#include "rt_Robin.h" -#include "rt_HAL_CM.h" - -/*---------------------------------------------------------------------------- - * Global Variables - *---------------------------------------------------------------------------*/ - -/* Running and next task info. */ -struct OS_TSK os_tsk; - -/* Task Control Blocks of idle demon */ -struct OS_TCB os_idle_TCB; - - -/*---------------------------------------------------------------------------- - * Local Functions - *---------------------------------------------------------------------------*/ - -OS_TID rt_get_TID (void) { - U32 tid; - - for (tid = 1; tid <= os_maxtaskrun; tid++) { - if (os_active_TCB[tid-1] == NULL) { - return ((OS_TID)tid); - } - } - return (0); -} - -#if defined (__CC_ARM) && !defined (__MICROLIB) -/*--------------------------- __user_perthread_libspace ---------------------*/ -extern void *__libspace_start; - -void *__user_perthread_libspace (void) { - /* Provide a separate libspace for each task. */ - if (os_tsk.run == NULL) { - /* RTX not running yet. */ - return (&__libspace_start); - } - return (void *)(os_tsk.run->std_libspace); -} -#endif - -/*--------------------------- rt_init_context -------------------------------*/ - -void rt_init_context (P_TCB p_TCB, U8 priority, FUNCP task_body) { - /* Initialize general part of the Task Control Block. */ - p_TCB->cb_type = TCB; - p_TCB->state = READY; - p_TCB->prio = priority; - p_TCB->p_lnk = NULL; - p_TCB->p_rlnk = NULL; - p_TCB->p_dlnk = NULL; - p_TCB->p_blnk = NULL; - p_TCB->delta_time = 0; - p_TCB->interval_time = 0; - p_TCB->events = 0; - p_TCB->waits = 0; - p_TCB->stack_frame = 0; - - rt_init_stack (p_TCB, task_body); -} - - -/*--------------------------- rt_switch_req ---------------------------------*/ - -void rt_switch_req (P_TCB p_new) { - /* Switch to next task (identified by "p_new"). */ - os_tsk.new_tsk = p_new; - p_new->state = RUNNING; - DBG_TASK_SWITCH(p_new->task_id); -} - - -/*--------------------------- rt_dispatch -----------------------------------*/ - -void rt_dispatch (P_TCB next_TCB) { - /* Dispatch next task if any identified or dispatch highest ready task */ - /* "next_TCB" identifies a task to run or has value NULL (=no next task) */ - if (next_TCB == NULL) { - /* Running task was blocked: continue with highest ready task */ - next_TCB = rt_get_first (&os_rdy); - rt_switch_req (next_TCB); - } - else { - /* Check which task continues */ - if (next_TCB->prio > os_tsk.run->prio) { - /* preempt running task */ - rt_put_rdy_first (os_tsk.run); - os_tsk.run->state = READY; - rt_switch_req (next_TCB); - } - else { - /* put next task into ready list, no task switch takes place */ - next_TCB->state = READY; - rt_put_prio (&os_rdy, next_TCB); - } - } -} - - -/*--------------------------- rt_block --------------------------------------*/ - -void rt_block (U16 timeout, U8 block_state) { - /* Block running task and choose next ready task. */ - /* "timeout" sets a time-out value or is 0xffff (=no time-out). */ - /* "block_state" defines the appropriate task state */ - P_TCB next_TCB; - - if (timeout) { - if (timeout < 0xffff) { - rt_put_dly (os_tsk.run, timeout); - } - os_tsk.run->state = block_state; - next_TCB = rt_get_first (&os_rdy); - rt_switch_req (next_TCB); - } -} - - -/*--------------------------- rt_tsk_pass -----------------------------------*/ - -void rt_tsk_pass (void) { - /* Allow tasks of same priority level to run cooperatively.*/ - P_TCB p_new; - - p_new = rt_get_same_rdy_prio(); - if (p_new != NULL) { - rt_put_prio ((P_XCB)&os_rdy, os_tsk.run); - os_tsk.run->state = READY; - rt_switch_req (p_new); - } -} - - -/*--------------------------- rt_tsk_self -----------------------------------*/ - -OS_TID rt_tsk_self (void) { - /* Return own task identifier value. */ - if (os_tsk.run == NULL) { - return (0); - } - return (os_tsk.run->task_id); -} - - -/*--------------------------- rt_tsk_prio -----------------------------------*/ - -OS_RESULT rt_tsk_prio (OS_TID task_id, U8 new_prio) { - /* Change execution priority of a task to "new_prio". */ - P_TCB p_task; - - if (task_id == 0) { - /* Change execution priority of calling task. */ - os_tsk.run->prio = new_prio; -run:if (rt_rdy_prio() > new_prio) { - rt_put_prio (&os_rdy, os_tsk.run); - os_tsk.run->state = READY; - rt_dispatch (NULL); - } - return (OS_R_OK); - } - - /* Find the task in the "os_active_TCB" array. */ - if (task_id > os_maxtaskrun || os_active_TCB[task_id-1] == NULL) { - /* Task with "task_id" not found or not started. */ - return (OS_R_NOK); - } - p_task = os_active_TCB[task_id-1]; - p_task->prio = new_prio; - if (p_task == os_tsk.run) { - goto run; - } - rt_resort_prio (p_task); - if (p_task->state == READY) { - /* Task enqueued in a ready list. */ - p_task = rt_get_first (&os_rdy); - rt_dispatch (p_task); - } - return (OS_R_OK); -} - -/*--------------------------- rt_tsk_delete ---------------------------------*/ - -OS_RESULT rt_tsk_delete (OS_TID task_id) { - /* Terminate the task identified with "task_id". */ - P_TCB task_context; - - if (task_id == 0 || task_id == os_tsk.run->task_id) { - /* Terminate itself. */ - os_tsk.run->state = INACTIVE; - os_tsk.run->tsk_stack = rt_get_PSP (); - rt_stk_check (); - os_active_TCB[os_tsk.run->task_id-1] = NULL; - - os_tsk.run->stack = NULL; - DBG_TASK_NOTIFY(os_tsk.run, __FALSE); - os_tsk.run = NULL; - rt_dispatch (NULL); - /* The program should never come to this point. */ - } - else { - /* Find the task in the "os_active_TCB" array. */ - if (task_id > os_maxtaskrun || os_active_TCB[task_id-1] == NULL) { - /* Task with "task_id" not found or not started. */ - return (OS_R_NOK); - } - task_context = os_active_TCB[task_id-1]; - rt_rmv_list (task_context); - rt_rmv_dly (task_context); - os_active_TCB[task_id-1] = NULL; - - task_context->stack = NULL; - DBG_TASK_NOTIFY(task_context, __FALSE); - } - return (OS_R_OK); -} - - -/*--------------------------- rt_sys_init -----------------------------------*/ - -#ifdef __CMSIS_RTOS -void rt_sys_init (void) { -#else -void rt_sys_init (FUNCP first_task, U32 prio_stksz, void *stk) { -#endif - /* Initialize system and start up task declared with "first_task". */ - U32 i; - - DBG_INIT(); - - /* Initialize dynamic memory and task TCB pointers to NULL. */ - for (i = 0; i < os_maxtaskrun; i++) { - os_active_TCB[i] = NULL; - } - - /* Set up TCB of idle demon */ - os_idle_TCB.task_id = 255; - os_idle_TCB.priv_stack = idle_task_stack_size; - os_idle_TCB.stack = idle_task_stack; - rt_init_context (&os_idle_TCB, 0, os_idle_demon); - - /* Set up ready list: initially empty */ - os_rdy.cb_type = HCB; - os_rdy.p_lnk = NULL; - /* Set up delay list: initially empty */ - os_dly.cb_type = HCB; - os_dly.p_dlnk = NULL; - os_dly.p_blnk = NULL; - os_dly.delta_time = 0; - - /* Fix SP and systemvariables to assume idle task is running */ - /* Transform main program into idle task by assuming idle TCB */ -#ifndef __CMSIS_RTOS - rt_set_PSP (os_idle_TCB.tsk_stack+32); -#endif - os_tsk.run = &os_idle_TCB; - os_tsk.run->state = RUNNING; - - /* Initialize ps queue */ - os_psq->first = 0; - os_psq->last = 0; - os_psq->size = os_fifo_size; - - rt_init_robin (); - - /* Intitialize SVC and PendSV */ - rt_svc_init (); - -#ifndef __CMSIS_RTOS - /* Intitialize and start system clock timer */ - os_tick_irqn = os_tick_init (); - if (os_tick_irqn >= 0) { - OS_X_INIT(os_tick_irqn); - } - - /* Start up first user task before entering the endless loop */ - rt_tsk_create (first_task, prio_stksz, stk, NULL); -#endif -} - - -/*--------------------------- rt_sys_start ----------------------------------*/ - -#ifdef __CMSIS_RTOS -void rt_sys_start (void) { - /* Start system */ - - /* Intitialize and start system clock timer */ - os_tick_irqn = os_tick_init (); - if (os_tick_irqn >= 0) { - OS_X_INIT(os_tick_irqn); - } -} -#endif - -/*---------------------------------------------------------------------------- - * end of file - *---------------------------------------------------------------------------*/ diff --git a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Task.h b/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Task.h deleted file mode 100644 index 9d3727b..0000000 --- a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Task.h +++ /dev/null @@ -1,73 +0,0 @@ -/*---------------------------------------------------------------------------- - * RL-ARM - RTX - *---------------------------------------------------------------------------- - * Name: RT_TASK.H - * Purpose: Task functions and system start up. - * Rev.: V4.60 - *---------------------------------------------------------------------------- - * - * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - Neither the name of ARM nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - *---------------------------------------------------------------------------*/ - -/* Definitions */ -#define __CMSIS_RTOS 1 - -/* Values for 'state' */ -#define INACTIVE 0 -#define READY 1 -#define RUNNING 2 -#define WAIT_DLY 3 -#define WAIT_ITV 4 -#define WAIT_OR 5 -#define WAIT_AND 6 -#define WAIT_SEM 7 -#define WAIT_MBX 8 -#define WAIT_MUT 9 - -/* Return codes */ -#define OS_R_TMO 0x01 -#define OS_R_EVT 0x02 -#define OS_R_SEM 0x03 -#define OS_R_MBX 0x04 -#define OS_R_MUT 0x05 - -#define OS_R_OK 0x00 -#define OS_R_NOK 0xff - -/* Variables */ -extern struct OS_TSK os_tsk; -extern struct OS_TCB os_idle_TCB; - -/* Functions */ -extern void rt_switch_req (P_TCB p_new); -extern void rt_dispatch (P_TCB next_TCB); -extern void rt_block (U16 timeout, U8 block_state); -extern void rt_tsk_pass (void); -extern OS_TID rt_tsk_self (void); -extern OS_RESULT rt_tsk_prio (OS_TID task_id, U8 new_prio); -extern OS_RESULT rt_tsk_delete (OS_TID task_id); -extern void rt_sys_init (void); -extern void rt_sys_start (void); diff --git a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Time.c b/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Time.c deleted file mode 100644 index b02cceb..0000000 --- a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Time.c +++ /dev/null @@ -1,94 +0,0 @@ -/*---------------------------------------------------------------------------- - * RL-ARM - RTX - *---------------------------------------------------------------------------- - * Name: RT_TIME.C - * Purpose: Delay and interval wait functions - * Rev.: V4.60 - *---------------------------------------------------------------------------- - * - * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - Neither the name of ARM nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - *---------------------------------------------------------------------------*/ - -#include "rt_TypeDef.h" -#include "RTX_Conf.h" -#include "rt_Task.h" -#include "rt_Time.h" - -/*---------------------------------------------------------------------------- - * Global Variables - *---------------------------------------------------------------------------*/ - -/* Free running system tick counter */ -U32 os_time; - - -/*---------------------------------------------------------------------------- - * Functions - *---------------------------------------------------------------------------*/ - - -/*--------------------------- rt_time_get -----------------------------------*/ - -U32 rt_time_get (void) { - /* Get system time tick */ - return (os_time); -} - - -/*--------------------------- rt_dly_wait -----------------------------------*/ - -void rt_dly_wait (U16 delay_time) { - /* Delay task by "delay_time" */ - rt_block (delay_time, WAIT_DLY); -} - - -/*--------------------------- rt_itv_set ------------------------------------*/ - -void rt_itv_set (U16 interval_time) { - /* Set interval length and define start of first interval */ - os_tsk.run->interval_time = interval_time; - os_tsk.run->delta_time = interval_time + (U16)os_time; -} - - -/*--------------------------- rt_itv_wait -----------------------------------*/ - -void rt_itv_wait (void) { - /* Wait for interval end and define start of next one */ - U16 delta; - - delta = os_tsk.run->delta_time - (U16)os_time; - os_tsk.run->delta_time += os_tsk.run->interval_time; - if ((delta & 0x8000) == 0) { - rt_block (delta, WAIT_ITV); - } -} - -/*---------------------------------------------------------------------------- - * end of file - *---------------------------------------------------------------------------*/ - diff --git a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Time.h b/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Time.h deleted file mode 100644 index 2770637..0000000 --- a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_Time.h +++ /dev/null @@ -1,47 +0,0 @@ -/*---------------------------------------------------------------------------- - * RL-ARM - RTX - *---------------------------------------------------------------------------- - * Name: RT_TIME.H - * Purpose: Delay and interval wait functions definitions - * Rev.: V4.60 - *---------------------------------------------------------------------------- - * - * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - Neither the name of ARM nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - *---------------------------------------------------------------------------*/ - -/* Variables */ -extern U32 os_time; - -/* Functions */ -extern U32 rt_time_get (void); -extern void rt_dly_wait (U16 delay_time); -extern void rt_itv_set (U16 interval_time); -extern void rt_itv_wait (void); - -/*---------------------------------------------------------------------------- - * end of file - *---------------------------------------------------------------------------*/ - diff --git a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_TypeDef.h b/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_TypeDef.h deleted file mode 100644 index 27416c5..0000000 --- a/libraries/mbed/rtos/rtx/TARGET_CORTEX_M/rt_TypeDef.h +++ /dev/null @@ -1,128 +0,0 @@ -/*---------------------------------------------------------------------------- - * RL-ARM - RTX - *---------------------------------------------------------------------------- - * Name: RT_TYPEDEF.H - * Purpose: Type Definitions - * Rev.: V4.60 - *---------------------------------------------------------------------------- - * - * Copyright (c) 1999-2009 KEIL, 2009-2012 ARM Germany GmbH - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - Neither the name of ARM nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - *---------------------------------------------------------------------------*/ -#ifndef RT_TYPE_DEF_H -#define RT_TYPE_DEF_H - -#include "os_tcb.h" - -typedef U32 OS_TID; -typedef void *OS_ID; -typedef U32 OS_RESULT; - -#define TCB_STACKF 32 /* 'stack_frame' offset */ -#define TCB_TSTACK 40 /* 'tsk_stack' offset */ - -typedef struct OS_PSFE { /* Post Service Fifo Entry */ - void *id; /* Object Identification */ - U32 arg; /* Object Argument */ -} *P_PSFE; - -typedef struct OS_PSQ { /* Post Service Queue */ - U8 first; /* FIFO Head Index */ - U8 last; /* FIFO Tail Index */ - U8 count; /* Number of stored items in FIFO */ - U8 size; /* FIFO Size */ - struct OS_PSFE q[1]; /* FIFO Content */ -} *P_PSQ; - -typedef struct OS_TSK { - P_TCB run; /* Current running task */ - P_TCB new_tsk; /* Scheduled task to run */ -} *P_TSK; - -typedef struct OS_ROBIN { /* Round Robin Control */ - P_TCB task; /* Round Robin task */ - U16 time; /* Round Robin switch time */ - U16 tout; /* Round Robin timeout */ -} *P_ROBIN; - -typedef struct OS_XCB { - U8 cb_type; /* Control Block Type */ - struct OS_TCB *p_lnk; /* Link pointer for ready/sem. wait list */ - struct OS_TCB *p_rlnk; /* Link pointer for sem./mbx lst backwards */ - struct OS_TCB *p_dlnk; /* Link pointer for delay list */ - struct OS_TCB *p_blnk; /* Link pointer for delay list backwards */ - U16 delta_time; /* Time until time out */ -} *P_XCB; - -typedef struct OS_MCB { - U8 cb_type; /* Control Block Type */ - U8 state; /* State flag variable */ - U8 isr_st; /* State flag variable for isr functions */ - struct OS_TCB *p_lnk; /* Chain of tasks waiting for message */ - U16 first; /* Index of the message list begin */ - U16 last; /* Index of the message list end */ - U16 count; /* Actual number of stored messages */ - U16 size; /* Maximum number of stored messages */ - void *msg[1]; /* FIFO for Message pointers 1st element */ -} *P_MCB; - -typedef struct OS_SCB { - U8 cb_type; /* Control Block Type */ - U8 mask; /* Semaphore token mask */ - U16 tokens; /* Semaphore tokens */ - struct OS_TCB *p_lnk; /* Chain of tasks waiting for tokens */ -} *P_SCB; - -typedef struct OS_MUCB { - U8 cb_type; /* Control Block Type */ - U8 prio; /* Owner task default priority */ - U16 level; /* Call nesting level */ - struct OS_TCB *p_lnk; /* Chain of tasks waiting for mutex */ - struct OS_TCB *owner; /* Mutex owner task */ -} *P_MUCB; - -typedef struct OS_XTMR { - struct OS_TMR *next; - U16 tcnt; -} *P_XTMR; - -typedef struct OS_TMR { - struct OS_TMR *next; /* Link pointer to Next timer */ - U16 tcnt; /* Timer delay count */ - U16 info; /* User defined call info */ -} *P_TMR; - -typedef struct OS_BM { - void *free; /* Pointer to first free memory block */ - void *end; /* Pointer to memory block end */ - U32 blk_size; /* Memory block size */ -} *P_BM; - -/* Definitions */ -#define __TRUE 1 -#define __FALSE 0 -#define NULL ((void *) 0) - -#endif diff --git a/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/TOOLCHAIN_GCC_ARM/STM32F429BI.ld b/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/TOOLCHAIN_GCC_ARM/STM32F429BI.ld index ad7ddaf..29ddfcf 100644 --- a/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/TOOLCHAIN_GCC_ARM/STM32F429BI.ld +++ b/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/TOOLCHAIN_GCC_ARM/STM32F429BI.ld @@ -10,9 +10,11 @@ MEMORY BOOTLOADER (rx) : ORIGIN = 0x08000000, LENGTH = 128K FIRMWARE (rx) : ORIGIN = 0x08000000 + 128K, LENGTH = 2048K - 128K FLASH (rx) : ORIGIN = 0x08000000 + 128K, LENGTH = 2048K - 128K - RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 192K - 4 + CCMRAM (rwx) : ORIGIN = 0x10000000, LENGTH = 64K + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 192K - 4 + SDRAM1 (rwx) : ORIGIN = 0xC0000000, LENGTH = 64M + SDRAM2 (rwx) : ORIGIN = 0xD0000000, LENGTH = 64M } -/* original: FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K */ /* Linker script to place sections and symbol values. Should be used together * with other linker script that defines memory regions FLASH and RAM. @@ -86,7 +88,7 @@ SECTIONS __etext = .; _sidata = .; - .data : AT (__etext) + .data : { __data_start__ = .; _sdata = .; @@ -120,7 +122,49 @@ SECTIONS __data_end__ = .; _edata = .; - } > RAM + } > RAM AT> FLASH + + /* If initialized variables are placed in this section, + * the startup code needs to be modified to copy the init-values. + */ + .ccmram : + { + . = ALIGN(4); + _sccmram = .; + *(.ccmram) + *(.ccmram*) + + . = ALIGN(4); + _eccmram = .; + } >CCMRAM AT> FLASH + + __end_ccmram = ORIGIN(CCMRAM) + LENGTH(CCMRAM); + + .sdram1 : + { + . = ALIGN(4); + _ssdram1 = .; + *(.sdram1) + *(.sdram1*) + + . = ALIGN(4); + _esdram1 = .; + } >SDRAM1 + + __end_sdram1 = ORIGIN(SDRAM1) + LENGTH(SDRAM1); + + .sdram2 : + { + . = ALIGN(4); + _ssdram2 = .; + *(.sdram2) + *(.sdram2*) + + . = ALIGN(4); + _esdram2 = .; + } >SDRAM2 + + __end_sdram2 = ORIGIN(SDRAM2) + LENGTH(SDRAM2); .bss : { diff --git a/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/TOOLCHAIN_GCC_ARM/startup_stm32f429xx.S b/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/TOOLCHAIN_GCC_ARM/startup_stm32f429xx.S index c431df8..7b4f6ff 100644 --- a/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/TOOLCHAIN_GCC_ARM/startup_stm32f429xx.S +++ b/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/TOOLCHAIN_GCC_ARM/startup_stm32f429xx.S @@ -110,14 +110,9 @@ LoopFillZerobss: /* Call the clock system intitialization function.*/ bl SystemInit /* Call static constructors */ - //bl __libc_init_array + bl __libc_init_array /* Call the application's entry point.*/ - //bl main - // Calling the crt0 'cold-start' entry point. There __libc_init_array is called - // and when existing hardware_init_hook() and software_init_hook() before - // starting main(). software_init_hook() is available and has to be called due - // to initializsation when using rtos. - bl _start + bl main bx lr .size Reset_Handler, .-Reset_Handler diff --git a/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_hal_conf.h b/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_hal_conf.h index 8a11b8b..50e70d5 100644 --- a/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_hal_conf.h +++ b/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_hal_conf.h @@ -145,7 +145,7 @@ * @brief This is the HAL system configuration section */ #define VDD_VALUE ((uint32_t)3300) /*!< Value of VDD in mv */ -#define TICK_INT_PRIORITY ((uint32_t)0) /*!< tick interrupt priority */ +#define TICK_INT_PRIORITY ((uint32_t)0x0F) /*!< tick interrupt priority */ #define USE_RTOS 0 #define PREFETCH_ENABLE 1 #define INSTRUCTION_CACHE_ENABLE 1 diff --git a/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_hal_msp.c b/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_hal_msp.c index fbd0adf..f64e6ce 100644 --- a/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_hal_msp.c +++ b/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_hal_msp.c @@ -44,16 +44,6 @@ void HAL_MspInit(void) /* USER CODE END MspInit 0 */ - /* XXX - * Fredrik's HAL_MspInit sets this to NVIC_PRIORITYGROUP_4 (as just - * happened in HAL_Init), but then he resets it to NVIC_PRIORITYGROUP_0 - * in stm_init. */ - HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_0); - - /* System interrupt init*/ - /* SysTick_IRQn interrupt configuration */ - HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0); - /* USER CODE BEGIN MspInit 1 */ /* USER CODE END MspInit 1 */ @@ -97,19 +87,23 @@ void HAL_RNG_MspDeInit(RNG_HandleTypeDef* hrng) void HAL_SRAM_MspInit(SRAM_HandleTypeDef* hsram) { + hsram = hsram; } void HAL_SRAM_MspDeInit(SRAM_HandleTypeDef* hsram) { + hsram = hsram; } void HAL_SDRAM_MspInit(SDRAM_HandleTypeDef* hsdram) { + hsdram = hsdram; } void HAL_SDRAM_MspDeInit(SDRAM_HandleTypeDef* hsdram) { + hsdram = hsdram; } void HAL_UART_MspInit(UART_HandleTypeDef* huart) @@ -182,7 +176,7 @@ void HAL_UART_MspInit(UART_HandleTypeDef* huart) hdma->Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma->Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma->Init.Mode = DMA_CIRCULAR; - hdma->Init.Priority = DMA_PRIORITY_LOW; + hdma->Init.Priority = DMA_PRIORITY_HIGH; hdma->Init.FIFOMode = DMA_FIFOMODE_DISABLE; /* hdma->Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL; @@ -190,6 +184,7 @@ void HAL_UART_MspInit(UART_HandleTypeDef* huart) hdma->Init.PeriphBurst = DMA_PBURST_SINGLE; */ if (HAL_DMA_Init(hdma) != HAL_OK) { + extern void mbed_die(void); mbed_die(); } } diff --git a/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_it.c b/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_it.c index 7c30228..d3bafb2 100644 --- a/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_it.c +++ b/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/TARGET_CRYPTECH_ALPHA/stm32f4xx_it.c @@ -44,20 +44,6 @@ /* Cortex-M4 Processor Exceptions Handlers */ /******************************************************************************/ -/* - * We define these to make debugging easier, because otherwise gdb reports - * HardFault_Handler as WWDG_IRQHandler. - */ - -/** - * @brief This function handles NMI exception. - * @param None - * @retval None - */ -void NMI_Handler(void) -{ -} - /** * @brief This function handles Hard Fault exception. * @param None @@ -65,72 +51,19 @@ void NMI_Handler(void) */ void HardFault_Handler(void) { - /* Go to infinite loop when Hard Fault exception occurs */ - while (1) { ; } -} - -/** - * @brief This function handles Memory Manage exception. - * @param None - * @retval None - */ -void MemManage_Handler(void) -{ - /* Go to infinite loop when Memory Manage exception occurs */ - while (1) { ; } -} - -/** - * @brief This function handles Bus Fault exception. - * @param None - * @retval None +/* + * We define this to make debugging easier, because otherwise gdb reports + * HardFault_Handler as WWDG_IRQHandler. */ -void BusFault_Handler(void) -{ - /* Go to infinite loop when Bus Fault exception occurs */ - while (1) { ; } -} -/** - * @brief This function handles Usage Fault exception. - * @param None - * @retval None - */ -void UsageFault_Handler(void) -{ - /* Go to infinite loop when Usage Fault exception occurs */ +#ifdef HAL_GPIO_MODULE_ENABLED + //HAL_GPIO_WritePin(LED_PORT, LED_RED, GPIO_PIN_SET); + HAL_GPIO_WritePin(GPIOK, GPIO_PIN_7, GPIO_PIN_SET); +#endif + /* Go to infinite loop when Hard Fault exception occurs */ while (1) { ; } } - -#if 0 /* already defined in libraries/mbed/rtos/ */ -/** - * @brief This function handles SVCall exception. - * @param None - * @retval None - */ -void SVC_Handler(void) -{ -} - -/** - * @brief This function handles Debug Monitor exception. - * @param None - * @retval None - */ -void DebugMon_Handler(void) -{ -} - -/** - * @brief This function handles PendSVC exception. - * @param None - * @retval None - */ -void PendSV_Handler(void) -{ -} - /** * @brief This function handles SysTick Handler. * @param None @@ -139,8 +72,8 @@ void PendSV_Handler(void) void SysTick_Handler(void) { HAL_IncTick(); + HAL_SYSTICK_IRQHandler(); } -#endif /******************************************************************************/ /* STM32F4xx Peripherals Interrupt Handlers */ @@ -187,6 +120,12 @@ void USART2_IRQHandler(void) HAL_UART_IRQHandler(&huart_user); } +/** + * @brief Rx Transfer completed callbacks. + * @param huart: pointer to a UART_HandleTypeDef structure that contains + * the configuration information for the specified UART module. + * @retval None + */ void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { extern void HAL_UART1_RxCpltCallback(UART_HandleTypeDef *huart); @@ -199,24 +138,62 @@ void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) HAL_UART2_RxCpltCallback(huart); } +__weak void HAL_UART1_RxCpltCallback(UART_HandleTypeDef *huart) +{ + /* NOTE: This function Should not be modified, when the callback is needed, + the HAL_UART1_RxCpltCallback could be implemented in the user file + */ + huart = huart; +} + +__weak void HAL_UART2_RxCpltCallback(UART_HandleTypeDef *huart) +{ + /* NOTE: This function Should not be modified, when the callback is needed, + the HAL_UART2_RxCpltCallback could be implemented in the user file + */ + huart = huart; +} + /** - * @brief Rx Transfer completed callbacks. + * @brief Rx Half Transfer completed callbacks. * @param huart: pointer to a UART_HandleTypeDef structure that contains * the configuration information for the specified UART module. * @retval None */ -__weak void HAL_UART1_RxCpltCallback(UART_HandleTypeDef *huart) +void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart) +{ + extern void HAL_UART1_RxHalfCpltCallback(UART_HandleTypeDef *huart); + extern void HAL_UART2_RxHalfCpltCallback(UART_HandleTypeDef *huart); + + if (huart->Instance == USART1) + HAL_UART1_RxHalfCpltCallback(huart); + + else if (huart->Instance == USART2) + HAL_UART2_RxHalfCpltCallback(huart); +} + +__weak void HAL_UART1_RxHalfCpltCallback(UART_HandleTypeDef *huart) { /* NOTE: This function Should not be modified, when the callback is needed, - the HAL_UART_RxCpltCallback could be implemented in the user file + the HAL_UART1_RxHalfCpltCallback could be implemented in the user file */ + huart = huart; } -__weak void HAL_UART2_RxCpltCallback(UART_HandleTypeDef *huart) +__weak void HAL_UART2_RxHalfCpltCallback(UART_HandleTypeDef *huart) { /* NOTE: This function Should not be modified, when the callback is needed, - the HAL_UART_TxCpltCallback could be implemented in the user file + the HAL_UART2_RxHalfCpltCallback could be implemented in the user file */ + huart = huart; +} + +void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) +{ + huart = huart; + + /* I dunno, just trap it for now */ + Error_Handler(); } /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/stm32f4xx_ll_fmc.c b/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/stm32f4xx_ll_fmc.c index bdf38fc..8010aef 100644 --- a/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/stm32f4xx_ll_fmc.c +++ b/libraries/mbed/targets/cmsis/TARGET_STM/TARGET_STM32F4/stm32f4xx_ll_fmc.c @@ -1413,25 +1413,35 @@ HAL_StatusTypeDef FMC_SDRAM_Init(FMC_SDRAM_TypeDef *Device, FMC_SDRAM_InitTypeDe } else /* FMC_Bank2_SDRAM */ { -/////////////////////////////// -// BEGIN PIECE OF WEIRD CODE // -/////////////////////////////// -// -// tmpr1 = Device->SDCR[FMC_SDRAM_BANK1]; -// -// /* Clear NC, NR, MWID, NB, CAS, WP, SDCLK, RBURST, and RPIPE bits */ -// tmpr1 &= ((uint32_t)~(FMC_SDCR1_NC | FMC_SDCR1_NR | FMC_SDCR1_MWID | \ -// FMC_SDCR1_NB | FMC_SDCR1_CAS | FMC_SDCR1_WP | \ -// FMC_SDCR1_SDCLK | FMC_SDCR1_RBURST | FMC_SDCR1_RPIPE)); -// -// tmpr1 |= (uint32_t)(Init->SDClockPeriod |\ -// Init->ReadBurst |\ -// Init->ReadPipeDelay); -// -/////////////////////////////// -// END PIECE OF WEIRD CODE // -/////////////////////////////// - +#if 0 /* broken code */ + tmpr1 = Device->SDCR[FMC_SDRAM_BANK1]; + + /* Clear NC, NR, MWID, NB, CAS, WP, SDCLK, RBURST, and RPIPE bits */ + tmpr1 &= ((uint32_t)~(FMC_SDCR1_NC | FMC_SDCR1_NR | FMC_SDCR1_MWID | \ + FMC_SDCR1_NB | FMC_SDCR1_CAS | FMC_SDCR1_WP | \ + FMC_SDCR1_SDCLK | FMC_SDCR1_RBURST | FMC_SDCR1_RPIPE)); + + tmpr1 |= (uint32_t)(Init->SDClockPeriod |\ + Init->ReadBurst |\ + Init->ReadPipeDelay); + + tmpr2 = Device->SDCR[FMC_SDRAM_BANK2]; + + /* Clear NC, NR, MWID, NB, CAS, WP, SDCLK, RBURST, and RPIPE bits */ + tmpr2 &= ((uint32_t)~(FMC_SDCR1_NC | FMC_SDCR1_NR | FMC_SDCR1_MWID | \ + FMC_SDCR1_NB | FMC_SDCR1_CAS | FMC_SDCR1_WP | \ + FMC_SDCR1_SDCLK | FMC_SDCR1_RBURST | FMC_SDCR1_RPIPE)); + + tmpr2 |= (uint32_t)(Init->ColumnBitsNumber |\ + Init->RowBitsNumber |\ + Init->MemoryDataWidth |\ + Init->InternalBankNumber |\ + Init->CASLatency |\ + Init->WriteProtection); + + Device->SDCR[FMC_SDRAM_BANK1] = tmpr1; + Device->SDCR[FMC_SDRAM_BANK2] = tmpr2; +#else tmpr2 = Device->SDCR[FMC_SDRAM_BANK1]; /* Clear NC, NR, MWID, NB, CAS, WP, SDCLK, RBURST, and RPIPE bits */ @@ -1446,10 +1456,8 @@ HAL_StatusTypeDef FMC_SDRAM_Init(FMC_SDRAM_TypeDef *Device, FMC_SDRAM_InitTypeDe Init->CASLatency |\ Init->WriteProtection); -// -// Device->SDCR[FMC_SDRAM_BANK1] = tmpr1; -// Device->SDCR[FMC_SDRAM_BANK2] = tmpr2; +#endif } return HAL_OK; @@ -1500,27 +1508,32 @@ HAL_StatusTypeDef FMC_SDRAM_Timing_Init(FMC_SDRAM_TypeDef *Device, FMC_SDRAM_Tim } else /* FMC_Bank2_SDRAM */ { -/////////////////////////////// -// BEGIN PIECE OF WEIRD CODE // -/////////////////////////////// -// -// tmpr1 = Device->SDTR[FMC_SDRAM_BANK2]; -// -// /* Clear TMRD, TXSR, TRAS, TRC, TWR, TRP and TRCD bits */ -// tmpr1 &= ((uint32_t)~(FMC_SDTR1_TMRD | FMC_SDTR1_TXSR | FMC_SDTR1_TRAS | \ -// FMC_SDTR1_TRC | FMC_SDTR1_TWR | FMC_SDTR1_TRP | \ -// FMC_SDTR1_TRCD)); -// -// tmpr1 |= (uint32_t)(((Timing->LoadToActiveDelay)-1) |\ -// (((Timing->ExitSelfRefreshDelay)-1) << 4) |\ -// (((Timing->SelfRefreshTime)-1) << 8) |\ -// (((Timing->WriteRecoveryTime)-1) <<16) |\ -// (((Timing->RCDDelay)-1) << 24)); -// -/////////////////////////////// -// END PIECE OF WEIRD CODE // -/////////////////////////////// +#if 0 /* broken code */ + tmpr1 = Device->SDTR[FMC_SDRAM_BANK2]; + + /* Clear TMRD, TXSR, TRAS, TRC, TWR, TRP and TRCD bits */ + tmpr1 &= ((uint32_t)~(FMC_SDTR1_TMRD | FMC_SDTR1_TXSR | FMC_SDTR1_TRAS | \ + FMC_SDTR1_TRC | FMC_SDTR1_TWR | FMC_SDTR1_TRP | \ + FMC_SDTR1_TRCD)); + + tmpr1 |= (uint32_t)(((Timing->LoadToActiveDelay)-1) |\ + (((Timing->ExitSelfRefreshDelay)-1) << 4) |\ + (((Timing->SelfRefreshTime)-1) << 8) |\ + (((Timing->WriteRecoveryTime)-1) <<16) |\ + (((Timing->RCDDelay)-1) << 24)); + + tmpr2 = Device->SDTR[FMC_SDRAM_BANK1]; + + /* Clear TMRD, TXSR, TRAS, TRC, TWR, TRP and TRCD bits */ + tmpr2 &= ((uint32_t)~(FMC_SDTR1_TMRD | FMC_SDTR1_TXSR | FMC_SDTR1_TRAS | \ + FMC_SDTR1_TRC | FMC_SDTR1_TWR | FMC_SDTR1_TRP | \ + FMC_SDTR1_TRCD)); + tmpr2 |= (uint32_t)((((Timing->RowCycleDelay)-1) << 12) |\ + (((Timing->RPDelay)-1) << 20)); + Device->SDTR[FMC_SDRAM_BANK2] = tmpr1; + Device->SDTR[FMC_SDRAM_BANK1] = tmpr2; +#else tmpr2 = Device->SDTR[FMC_SDRAM_BANK1]; /* Clear TMRD, TXSR, TRAS, TRC, TWR, TRP and TRCD bits */ @@ -1534,10 +1547,8 @@ HAL_StatusTypeDef FMC_SDRAM_Timing_Init(FMC_SDRAM_TypeDef *Device, FMC_SDRAM_Tim (((Timing->WriteRecoveryTime)-1U) <<16U) |\ (((Timing->RCDDelay)-1U) << 24U)); -// -// Device->SDTR[FMC_SDRAM_BANK2] = tmpr1; -// Device->SDTR[FMC_SDRAM_BANK2] = tmpr2; +#endif } return HAL_OK; diff --git a/libraries/thirdparty/libtfm b/libraries/thirdparty/libtfm deleted file mode 160000 -Subproject e2eab1093a134e5a655d1ccad23a31b2b8252c6 diff --git a/projects/board-test/Makefile b/projects/board-test/Makefile index 9b1812f..45e75fc 100644 --- a/projects/board-test/Makefile +++ b/projects/board-test/Makefile @@ -1,4 +1,7 @@ -TEST = led-test short-test uart-test fmc-test fmc-perf fmc-probe rtc-test +TEST = led-test short-test uart-test fmc-test fmc-perf fmc-probe +ifeq (${BOARD},TARGET_CRYPTECH_ALPHA) +TEST += rtc-test spiflash-perf keystore-perf +endif all: $(TEST:=.elf) diff --git a/projects/board-test/fmc-perf.c b/projects/board-test/fmc-perf.c index 0c753a7..5af0946 100644 --- a/projects/board-test/fmc-perf.c +++ b/projects/board-test/fmc-perf.c @@ -1,7 +1,6 @@ /* * Test read/write performance of the fmc bus */ -#include "stm32f4xx_hal.h" #include "stm-init.h" #include "stm-led.h" #include "stm-fmc.h" @@ -32,14 +31,8 @@ static void sanity(void) uint32_t rnd, data; rnd = random(); - if (fmc_write_32(0, &rnd) != 0) { - uart_send_string("fmc_write_32 failed\r\n"); - Error_Handler(); - } - if (fmc_read_32(0, &data) != 0) { - uart_send_string("fmc_read_32 failed\r\n"); - Error_Handler(); - } + fmc_write_32(0, rnd); + fmc_read_32(0, &data); if (data != rnd) { uart_send_string("Data bus fail: expected "); uart_send_hex(rnd, 8); @@ -57,11 +50,11 @@ static void _time_check(char *label, const uint32_t t0) uint32_t t = HAL_GetTick() - t0; uart_send_string(label); - uart_send_integer(t / 1000, 0); + uart_send_integer(t / 1000, 1); uart_send_char('.'); uart_send_integer(t % 1000, 3); uart_send_string(" seconds, "); - uart_send_integer(((1000 * TEST_NUM_ROUNDS) / t), 0); + uart_send_integer(((1000 * TEST_NUM_ROUNDS) / t), 1); uart_send_string("/sec\r\n"); } @@ -77,10 +70,7 @@ static void test_read(void) uint32_t i, data; for (i = 0; i < TEST_NUM_ROUNDS; ++i) { - if (fmc_read_32(0, &data) != 0) { - uart_send_string("fmc_read_32 failed\r\n"); - Error_Handler(); - } + fmc_read_32(0, &data); } } @@ -89,33 +79,16 @@ static void test_write(void) uint32_t i; for (i = 0; i < TEST_NUM_ROUNDS; ++i) { - if (fmc_write_32(0, &i) != 0) { - uart_send_string("fmc_write_32 failed\r\n"); - Error_Handler(); - } + fmc_write_32(0, i); } } int main(void) { stm_init(); - - uart_send_string("Keep calm for Novena boot...\r\n"); - - // Blink blue LED for six seconds to not upset the Novena at boot. - led_on(LED_BLUE); - for (int i = 0; i < 12; i++) { - HAL_Delay(500); - led_toggle(LED_BLUE); - } - led_off(LED_BLUE); - // initialize rng MX_RNG_Init(); - // prepare fmc interface - fmc_init(); - sanity(); time_check("read ", test_read()); diff --git a/projects/board-test/fmc-probe.c b/projects/board-test/fmc-probe.c index 55d3521..38897ab 100644 --- a/projects/board-test/fmc-probe.c +++ b/projects/board-test/fmc-probe.c @@ -2,7 +2,6 @@ * in other cases, it will be the core name and version strings. */ -#include "stm32f4xx_hal.h" #include "stm-init.h" #include "stm-led.h" #include "stm-fmc.h" @@ -22,37 +21,15 @@ static uint32_t read0(uint32_t addr) { uint32_t data; - if (fmc_read_32(addr, &data) != 0) { - uart_send_string("fmc_read_32 failed\r\n"); - Error_Handler(); - } + fmc_read_32(addr, &data); return data; } int main(void) { - int i; - stm_init(); - - uart_send_string("Keep calm for Novena boot...\r\n"); - - // Blink blue LED for six seconds to not upset the Novena at boot. - led_on(LED_BLUE); - for (i = 0; i < 12; i++) { - HAL_Delay(500); - led_toggle(LED_BLUE); - } - - // prepare fmc interface - fmc_init(); - - // turn on green led, turn off other leds led_on(LED_GREEN); - led_off(LED_YELLOW); - led_off(LED_RED); - led_off(LED_BLUE); for (uint32_t addr = 0; addr < 0x00080000; addr += 4) { uint32_t data = read0(addr); diff --git a/projects/board-test/fmc-test.c b/projects/board-test/fmc-test.c index bc5a768..bd30dd5 100644 --- a/projects/board-test/fmc-test.c +++ b/projects/board-test/fmc-test.c @@ -4,8 +4,7 @@ /* This requires a special bitstream with a special test register. - See core/platform/novena/fmc/rtl/novena_fmc_top.v, sections marked - `ifdef test: + See core/platform/alpha/rtl/alpha_fmc_test.v: //---------------------------------------------------------------- // Dummy Register // @@ -34,11 +33,11 @@ //------------------------------------------------------------------------------ // Headers //------------------------------------------------------------------------------ -#include "stm32f4xx_hal.h" #include "stm-init.h" #include "stm-led.h" #include "stm-fmc.h" #include "stm-uart.h" +#include "stm-fpgacfg.h" //------------------------------------------------------------------------------ // Defines @@ -76,6 +75,7 @@ int test_fpga_address_bus(void); // Defines //------------------------------------------------------------------------------ #define TEST_NUM_ROUNDS 100000 +#define VERBOSE 0 //------------------------------------------------------------------------------ @@ -88,7 +88,7 @@ int main(void) uart_send_string("Keep calm for FPGA bitstream loading...\r\n"); - // Blink blue LED until the FPGA reports it has loaded it's bitstream + // Blink blue LED until the FPGA reports it has loaded its bitstream led_on(LED_BLUE); while (! fpgacfg_check_done()) { for (i = 0; i < 4; i++) { @@ -100,9 +100,6 @@ int main(void) // initialize rng MX_RNG_Init(); - // prepare fmc interface - fmc_init(); - // turn on green led, turn off other leds led_on(LED_GREEN); led_off(LED_YELLOW); @@ -120,11 +117,15 @@ int main(void) // test address bus addr_test_ok = test_fpga_address_bus(); - uart_send_string("Data: "); - uart_send_integer(data_test_ok, 6); - uart_send_string(", addr: "); - uart_send_integer(addr_test_ok, 6); - uart_send_string("\r\n"); + if (VERBOSE || + (data_test_ok != TEST_NUM_ROUNDS || + addr_test_ok != TEST_NUM_ROUNDS)) { + uart_send_string("Data: "); + uart_send_integer(data_test_ok, 6); + uart_send_string(", addr: "); + uart_send_integer(addr_test_ok, 6); + uart_send_string("\r\n"); + } if (data_test_ok == TEST_NUM_ROUNDS && addr_test_ok == TEST_NUM_ROUNDS) { @@ -140,11 +141,12 @@ int main(void) } uart_send_string("Success "); - uart_send_integer(successful_runs, 0); + uart_send_integer(successful_runs, 1); uart_send_string(", fail "); - uart_send_integer(failed_runs, 0); - uart_send_string("\r\n\r\n"); - + uart_send_integer(failed_runs, 1); + uart_send_string("\r\n"); + if (VERBOSE) + uart_send_string("\r\n"); HAL_Delay(sleep); } @@ -156,7 +158,7 @@ int main(void) int test_fpga_data_bus(void) //------------------------------------------------------------------------------ { - int c, ok; + int c; uint32_t rnd, buf; HAL_StatusTypeDef hal_result; @@ -169,12 +171,10 @@ int test_fpga_data_bus(void) if (hal_result != HAL_OK) break; // write value to fpga at address 0 - ok = fmc_write_32(0, &rnd); - if (ok != 0) break; + fmc_write_32(0, rnd); // read value from fpga - ok = fmc_read_32(0, &buf); - if (ok != 0) break; + fmc_read_32(0, &buf); // compare (abort testing in case of error) if (buf != rnd) @@ -197,13 +197,16 @@ int test_fpga_data_bus(void) data_diff = buf; data_diff ^= rnd; - uart_send_string("Sample of data bus test data: expected "); - uart_send_binary(rnd, 32); - uart_send_string(", got "); - uart_send_binary(buf, 32); - uart_send_string(", diff "); - uart_send_binary(data_diff, 32); - uart_send_string("\r\n"); + if (VERBOSE || data_diff) { + uart_send_string("Sample of data bus test data: expected "); + uart_send_binary(rnd, 32); + uart_send_string(", got "); + uart_send_binary(buf, 32); + uart_send_string(", diff "); + uart_send_binary(data_diff, 32); + uart_send_string("\r\n"); + } + // return number of successful tests return c; } @@ -213,7 +216,7 @@ int test_fpga_data_bus(void) int test_fpga_address_bus(void) //------------------------------------------------------------------------------ { - int c, ok; + int c; uint32_t rnd, buf; HAL_StatusTypeDef hal_result; @@ -234,12 +237,10 @@ int test_fpga_address_bus(void) if (rnd == 0) continue; // write dummy value to fpga at some non-zero address - ok = fmc_write_32(rnd, &buf); - if (ok != 0) break; + fmc_write_32(rnd, buf); // read value from fpga - ok = fmc_read_32(0, &buf); - if (ok != 0) break; + fmc_read_32(0, &buf); // fpga receives address of 32-bit word, while we need // byte address here to compare @@ -266,13 +267,15 @@ int test_fpga_address_bus(void) addr_diff = buf; addr_diff ^= rnd; - uart_send_string("Sample of addr bus test data: expected "); - uart_send_binary(rnd, 32); - uart_send_string(", got "); - uart_send_binary(buf, 32); - uart_send_string(", diff "); - uart_send_binary(addr_diff, 32); - uart_send_string("\r\n"); + if (VERBOSE || addr_diff) { + uart_send_string("Sample of addr bus test data: expected "); + uart_send_binary(rnd, 32); + uart_send_string(", got "); + uart_send_binary(buf, 32); + uart_send_string(", diff "); + uart_send_binary(addr_diff, 32); + uart_send_string("\r\n"); + } return c; } diff --git a/projects/board-test/keystore-perf.c b/projects/board-test/keystore-perf.c new file mode 100644 index 0000000..c2aa4fb --- /dev/null +++ b/projects/board-test/keystore-perf.c @@ -0,0 +1,197 @@ +/* + * Test read/write/erase performance of the flash keystore. + */ + +#include "string.h" + +#include "stm-init.h" +#include "stm-led.h" +#include "stm-uart.h" +#include "stm-keystore.h" + +/* + * 1. Read the entire flash by subsectors, ignoring data. + */ +static void test_read_data(void) +{ + uint8_t read_buf[KEYSTORE_SUBSECTOR_SIZE]; + uint32_t i; + HAL_StatusTypeDef err; + + for (i = 0; i < KEYSTORE_NUM_SUBSECTORS; ++i) { + err = keystore_read_data(i * KEYSTORE_SUBSECTOR_SIZE, read_buf, KEYSTORE_SUBSECTOR_SIZE); + if (err != HAL_OK) { + uart_send_string("ERROR: keystore_read_data returned "); + uart_send_integer(err, 1); + uart_send_string("\r\n"); + break; + } + } +} + +/* + * Read the flash data and verify it against a known pattern. + */ +static void _read_verify(uint8_t *vrfy_buf) +{ + uint8_t read_buf[KEYSTORE_SUBSECTOR_SIZE]; + uint32_t i; + HAL_StatusTypeDef err; + + for (i = 0; i < KEYSTORE_NUM_SUBSECTORS; ++i) { + err = keystore_read_data(i * KEYSTORE_SUBSECTOR_SIZE, read_buf, KEYSTORE_SUBSECTOR_SIZE); + if (err != HAL_OK) { + uart_send_string("ERROR: keystore_read_data returned "); + uart_send_integer(err, 1); + uart_send_string("\r\n"); + break; + } + if (memcmp(read_buf, vrfy_buf, KEYSTORE_SUBSECTOR_SIZE) != 0) { + uart_send_string("ERROR: verify failed in subsector "); + uart_send_integer(i, 1); + uart_send_string("\r\n"); + break; + } + } +} + +/* + * 2a. Erase the entire flash by sectors. + */ +static void test_erase_sector(void) +{ + uint32_t i; + HAL_StatusTypeDef err; + + for (i = 0; i < KEYSTORE_NUM_SECTORS; ++i) { + err = keystore_erase_sector(i); + if (err != HAL_OK) { + uart_send_string("ERROR: keystore_erase_sector returned "); + uart_send_integer(err, 1); + uart_send_string("\r\n"); + break; + } + } +} + +/* + * 2b. Erase the entire flash by subsectors. + */ +static void test_erase_subsector(void) +{ + uint32_t i; + HAL_StatusTypeDef err; + + for (i = 0; i < KEYSTORE_NUM_SUBSECTORS; ++i) { + err = keystore_erase_subsector(i); + if (err != HAL_OK) { + uart_send_string("ERROR: keystore_erase_subsector returned "); + uart_send_integer(err, 1); + uart_send_string("\r\n"); + break; + } + } +} + +/* + * 2c. Read the entire flash, verify erasure. + */ +static void test_verify_erase(void) +{ + uint8_t vrfy_buf[KEYSTORE_SUBSECTOR_SIZE]; + uint32_t i; + + for (i = 0; i < sizeof(vrfy_buf); ++i) + vrfy_buf[i] = 0xFF; + + _read_verify(vrfy_buf); +} + +/* + * 3a. Write the entire flash with a pattern. + */ +static void test_write_data(void) +{ + uint8_t write_buf[KEYSTORE_SUBSECTOR_SIZE]; + uint32_t i; + HAL_StatusTypeDef err; + + for (i = 0; i < sizeof(write_buf); ++i) + write_buf[i] = i & 0xFF; + + for (i = 0; i < KEYSTORE_NUM_SUBSECTORS; ++i) { + err = keystore_write_data(i * KEYSTORE_SUBSECTOR_SIZE, write_buf, KEYSTORE_SUBSECTOR_SIZE); + if (err != HAL_OK) { + uart_send_string("ERROR: keystore_write_data returned "); + uart_send_integer(err, 1); + uart_send_string(" for subsector "); + uart_send_integer(i, 1); + uart_send_string("\r\n"); + break; + } + } +} + +/* + * 3b. Read the entire flash, verify data. + */ +static void test_verify_write(void) +{ + uint8_t vrfy_buf[KEYSTORE_SUBSECTOR_SIZE]; + uint32_t i; + + for (i = 0; i < sizeof(vrfy_buf); ++i) + vrfy_buf[i] = i & 0xFF; + + _read_verify(vrfy_buf); +} + +static void _time_check(char *label, const uint32_t t0, uint32_t n_rounds) +{ + uint32_t t = HAL_GetTick() - t0; + + uart_send_string(label); + uart_send_integer(t / 1000, 1); + uart_send_char('.'); + uart_send_integer(t % 1000, 3); + uart_send_string(" sec"); + if (n_rounds > 1) { + uart_send_string(" for "); + uart_send_integer(n_rounds, 1); + uart_send_string(" rounds, "); + uart_send_integer(t / n_rounds, 1); + uart_send_char('.'); + uart_send_integer(((t % n_rounds) * 100) / n_rounds, 2); + uart_send_string(" ms each"); + } + uart_send_string("\r\n"); +} + +#define time_check(_label_, _expr_, _n_) \ + do { \ + uint32_t _t = HAL_GetTick(); \ + (_expr_); \ + _time_check(_label_, _t, _n_); \ + } while (0) + +int main(void) +{ + stm_init(); + + if (keystore_check_id() != HAL_OK) { + uart_send_string("ERROR: keystore_check_id failed\r\n"); + return 0; + } + + uart_send_string("Starting...\r\n"); + + time_check("read data ", test_read_data(), KEYSTORE_NUM_SUBSECTORS); + time_check("erase subsector ", test_erase_subsector(), KEYSTORE_NUM_SUBSECTORS); + time_check("erase sector ", test_erase_sector(), KEYSTORE_NUM_SECTORS); + time_check("verify erase ", test_verify_erase(), KEYSTORE_NUM_SUBSECTORS); + time_check("write data ", test_write_data(), KEYSTORE_NUM_SUBSECTORS); + time_check("verify write ", test_verify_write(), KEYSTORE_NUM_SUBSECTORS); + + uart_send_string("Done.\r\n\r\n"); + return 0; +} diff --git a/projects/board-test/led-test.c b/projects/board-test/led-test.c index 7e72788..2ec7c9d 100644 --- a/projects/board-test/led-test.c +++ b/projects/board-test/led-test.c @@ -1,7 +1,6 @@ /* * Blink the four LEDs on the rev01 board in a pattern. */ -#include "stm32f4xx_hal.h" #include "stm-init.h" #include "stm-led.h" diff --git a/projects/board-test/rtc-test.c b/projects/board-test/rtc-test.c index b8a7511..bbb297a 100644 --- a/projects/board-test/rtc-test.c +++ b/projects/board-test/rtc-test.c @@ -8,7 +8,6 @@ */ #include <string.h> -#include "stm32f4xx_hal.h" #include "stm-init.h" #include "stm-led.h" #include "stm-uart.h" @@ -23,18 +22,18 @@ uint32_t i; uint32_t device_ready(uint16_t i2c_addr) { - uart_send_string2(STM_UART_MGMT, "Checking readiness of 0x"); - uart_send_number2(STM_UART_MGMT, i2c_addr, 4, 16); - uart_send_string2(STM_UART_MGMT, "..."); + uart_send_string("Checking readiness of 0x"); + uart_send_hex(i2c_addr, 4); + uart_send_string("..."); if (rtc_device_ready(i2c_addr) == HAL_OK) { - uart_send_string2(STM_UART_MGMT, "OK\r\n"); + uart_send_string("OK\r\n"); return 1; } - uart_send_string2(STM_UART_MGMT, "Not ready (0x"); - uart_send_number2(STM_UART_MGMT, i, 4, 16); - uart_send_string2(STM_UART_MGMT, ")\r\n"); + uart_send_string("Not ready (0x"); + uart_send_hex(i, 4); + uart_send_string(")\r\n"); return 0; } @@ -44,34 +43,34 @@ void send_byte(const uint16_t i2c_addr, const uint8_t value) { uint8_t ch = value; - uart_send_string2(STM_UART_MGMT, "Sending "); - uart_send_number2(STM_UART_MGMT, ch, 2, 16); - uart_send_string2(STM_UART_MGMT, " to 0x"); - uart_send_number2(STM_UART_MGMT, i2c_addr, 4, 16); - uart_send_string2(STM_UART_MGMT, "..."); + uart_send_string("Sending "); + uart_send_hex(ch, 2); + uart_send_string(" to 0x"); + uart_send_hex(i2c_addr, 4); + uart_send_string("..."); if (rtc_send_byte(i2c_addr, ch, 1000) != HAL_OK) { - uart_send_string2(STM_UART_MGMT, "Timeout\r\n"); + uart_send_string("Timeout\r\n"); Error_Handler(); } - uart_send_string2(STM_UART_MGMT, "OK\r\n"); + uart_send_string("OK\r\n"); } void read_bytes (uint8_t *buf, const uint16_t i2c_addr, const uint8_t len) { - uart_send_string2(STM_UART_MGMT, "Reading "); - uart_send_number2(STM_UART_MGMT, len, 3, 10); - uart_send_string2(STM_UART_MGMT, " bytes from 0x"); - uart_send_number2(STM_UART_MGMT, i2c_addr, 4, 16); - uart_send_string2(STM_UART_MGMT, "..."); + uart_send_string("Reading "); + uart_send_integer(len, 1); + uart_send_string(" bytes from 0x"); + uart_send_hex(i2c_addr, 4); + uart_send_string("..."); if (rtc_read_bytes(i2c_addr, buf, len, 1000) != HAL_OK) { - uart_send_string2(STM_UART_MGMT, "Timeout\r\n"); + uart_send_string("Timeout\r\n"); Error_Handler(); } - uart_send_string2(STM_UART_MGMT, "OK\r\n"); + uart_send_string("OK\r\n"); } void request_data(uint8_t *buf, const uint16_t i2c_addr, const uint8_t offset, const uint8_t bytes) @@ -85,8 +84,8 @@ void print_time() request_data(buf, RTC_RTC_ADDR, RTC_TIME_OFFSET, RTC_TIME_BYTES); for (i = 0; i < RTC_TIME_BYTES; i++) { - uart_send_number2(STM_UART_MGMT, buf[i], 2, 16); - uart_send_string2(STM_UART_MGMT, " "); + uart_send_hex(buf[i], 2); + uart_send_string(" "); } } @@ -94,37 +93,37 @@ void dump_sram() { request_data(buf, RTC_RTC_ADDR, 0x0, RTC_SRAM_TOTAL_BYTES); - uart_send_string2(STM_UART_MGMT, "SRAM contents:\r\n"); - uart_send_hexdump(STM_UART_MGMT, buf, 0, RTC_SRAM_TOTAL_BYTES); + uart_send_string("SRAM contents:\r\n"); + uart_send_hexdump(buf, 0, RTC_SRAM_TOTAL_BYTES); - uart_send_string2(STM_UART_MGMT, "\r\n"); + uart_send_string("\r\n"); } void dump_eeprom() { request_data(buf, RTC_EEPROM_ADDR, 0x0, RTC_EEPROM_TOTAL_BYTES); - uart_send_string2(STM_UART_MGMT, "EEPROM contents:\r\n"); - uart_send_hexdump(STM_UART_MGMT, buf, 0, RTC_EEPROM_TOTAL_BYTES); - uart_send_string2(STM_UART_MGMT, "\r\n"); + uart_send_string("EEPROM contents:\r\n"); + uart_send_hexdump(buf, 0, RTC_EEPROM_TOTAL_BYTES); + uart_send_string("\r\n"); request_data(buf, RTC_EEPROM_ADDR, RTC_EEPROM_EUI48_OFFSET, RTC_EEPROM_EUI48_BYTES); - uart_send_string2(STM_UART_MGMT, "EEPROM EUI-48:\r\n"); - uart_send_hexdump(STM_UART_MGMT, buf, RTC_EEPROM_EUI48_OFFSET, RTC_EEPROM_EUI48_BYTES); + uart_send_string("EEPROM EUI-48:\r\n"); + uart_send_hexdump(buf, RTC_EEPROM_EUI48_OFFSET, RTC_EEPROM_EUI48_BYTES); - uart_send_string2(STM_UART_MGMT, "\r\n"); + uart_send_string("\r\n"); } void enable_oscillator() { - uart_send_string2(STM_UART_MGMT, "Enabling oscillator...\r\n"); + uart_send_string("Enabling oscillator...\r\n"); if (rtc_enable_oscillator() != HAL_OK) { - uart_send_string2(STM_UART_MGMT, "Timeout\r\n"); + uart_send_string("Timeout\r\n"); Error_Handler(); } - uart_send_string2(STM_UART_MGMT, "OK\r\n"); + uart_send_string("OK\r\n"); } @@ -132,7 +131,7 @@ int main() { stm_init(); - uart_send_string2(STM_UART_MGMT, "\r\n\r\n*** Init done\r\n"); + uart_send_string("\r\n\r\n*** Init done\r\n"); dump_sram(); dump_eeprom(); @@ -148,7 +147,7 @@ main() print_time(buf); - uart_send_string2(STM_UART_MGMT, "\r\n\r\n"); + uart_send_string("\r\n\r\n"); HAL_GPIO_TogglePin(LED_PORT, LED_GREEN); DELAY(); diff --git a/projects/board-test/short-test.c b/projects/board-test/short-test.c index 27b8e7a..db0251b 100644 --- a/projects/board-test/short-test.c +++ b/projects/board-test/short-test.c @@ -5,7 +5,6 @@ * Toggles the BLUE LED slowly and the RED LED for every * character sent. */ -#include "stm32f4xx_hal.h" #include "stm-init.h" #include "stm-led.h" #include "stm-uart.h" diff --git a/projects/board-test/spiflash-perf.c b/projects/board-test/spiflash-perf.c new file mode 100644 index 0000000..36c6131 --- /dev/null +++ b/projects/board-test/spiflash-perf.c @@ -0,0 +1,249 @@ +/* + * Test read/write/erase performance of the N25Q128 SPI flash chip. + */ + +#include "string.h" + +#include "stm-init.h" +#include "stm-led.h" +#include "stm-uart.h" +#include "stm-keystore.h" +#include "spiflash_n25q128.h" + +/* + * Use the keystore memory for testing, because it's less involved than + * using the FPGA configuration memory, and less work to restore it to a + * useful configuration. + * + * However, rather than using the stm-keystore abstractions, this version + * goes straight to the low-level API. + */ + +extern struct spiflash_ctx keystore_ctx; +static struct spiflash_ctx *ctx = &keystore_ctx; + +/* + * 1a. Read the entire flash by pages, ignoring data. + */ +static void test_read_page(void) +{ + uint8_t read_buf[N25Q128_PAGE_SIZE]; + uint32_t i; + int err; + + for (i = 0; i < N25Q128_NUM_PAGES; ++i) { + err = n25q128_read_page(ctx, i, read_buf); + if (err != HAL_OK) { + uart_send_string("ERROR: n25q128_read_page returned "); + uart_send_integer(err, 1); + uart_send_string("\r\n"); + break; + } + } +} + +/* + * 1b. Read the entire flash by subsectors, ignoring data. + */ +static void test_read_subsector(void) +{ + uint8_t read_buf[N25Q128_SUBSECTOR_SIZE]; + uint32_t i; + int err; + + for (i = 0; i < N25Q128_NUM_SUBSECTORS; ++i) { + err = n25q128_read_subsector(ctx, i, read_buf); + if (err != HAL_OK) { + uart_send_string("ERROR: n25q128_read_subsector returned "); + uart_send_integer(err, 1); + uart_send_string("\r\n"); + break; + } + } +} + +/* + * Read the flash data and verify it against a known pattern. + * It turns out that verification doesn't slow us down in any measurable + * way, because memcmp on 256 bytes is pretty inconsequential. + */ +static void _read_verify(uint8_t *vrfy_buf) +{ + uint8_t read_buf[N25Q128_PAGE_SIZE]; + uint32_t i; + int err; + + for (i = 0; i < N25Q128_NUM_PAGES; ++i) { + err = n25q128_read_page(ctx, i, read_buf); + if (err != HAL_OK) { + uart_send_string("ERROR: n25q128_read_page returned "); + uart_send_integer(err, 1); + uart_send_string("\r\n"); + break; + } + if (memcmp(read_buf, vrfy_buf, N25Q128_PAGE_SIZE) != 0) { + uart_send_string("ERROR: verify failed in page "); + uart_send_integer(i, 1); + uart_send_string("\r\n"); + break; + } + } +} + +/* + * 2a. Erase the entire flash by sectors. + */ +static void test_erase_sector(void) +{ + uint32_t i; + int err; + + for (i = 0; i < N25Q128_NUM_SECTORS; ++i) { + err = n25q128_erase_sector(ctx, i); + if (err != HAL_OK) { + uart_send_string("ERROR: n25q128_erase_sector returned "); + uart_send_integer(err, 1); + uart_send_string("\r\n"); + break; + } + } +} + +/* + * 2b. Erase the entire flash by subsectors. + */ +static void test_erase_subsector(void) +{ + uint32_t i; + int err; + + for (i = 0; i < N25Q128_NUM_SUBSECTORS; ++i) { + err = n25q128_erase_subsector(ctx, i); + if (err != HAL_OK) { + uart_send_string("ERROR: n25q128_erase_subsector returned "); + uart_send_integer(err, 1); + uart_send_string("\r\n"); + break; + } + } +} + +/* + * 2c. Erase the entire flash in bulk. + */ +static void test_erase_bulk(void) +{ + int err; + + err = n25q128_erase_bulk(ctx); + if (err != HAL_OK) { + uart_send_string("ERROR: n25q128_erase_bulk returned "); + uart_send_integer(err, 1); + uart_send_string("\r\n"); + } +} + +/* + * 2d. Read the entire flash, verify erasure. + */ +static void test_verify_erase(void) +{ + uint8_t vrfy_buf[N25Q128_PAGE_SIZE]; + uint32_t i; + + for (i = 0; i < sizeof(vrfy_buf); ++i) + vrfy_buf[i] = 0xFF; + + _read_verify(vrfy_buf); +} + +/* + * 3a. Write the entire flash with a pattern. + */ +static void test_write_page(void) +{ + uint8_t write_buf[N25Q128_PAGE_SIZE]; + uint32_t i; + int err; + + for (i = 0; i < sizeof(write_buf); ++i) + write_buf[i] = i & 0xFF; + + for (i = 0; i < N25Q128_NUM_PAGES; ++i) { + err = n25q128_write_page(ctx, i, write_buf); + if (err != HAL_OK) { + uart_send_string("ERROR: n25q128_write_page returned "); + uart_send_integer(err, 1); + uart_send_string(" for page "); + uart_send_integer(i, 1); + uart_send_string("\r\n"); + break; + } + } +} + +/* + * 3b. Read the entire flash, verify data. + */ +static void test_verify_write(void) +{ + uint8_t vrfy_buf[N25Q128_PAGE_SIZE]; + uint32_t i; + + for (i = 0; i < sizeof(vrfy_buf); ++i) + vrfy_buf[i] = i & 0xFF; + + _read_verify(vrfy_buf); +} + +static void _time_check(char *label, const uint32_t t0, uint32_t n_rounds) +{ + uint32_t t = HAL_GetTick() - t0; + + uart_send_string(label); + uart_send_integer(t / 1000, 1); + uart_send_char('.'); + uart_send_integer(t % 1000, 3); + uart_send_string(" sec"); + if (n_rounds > 1) { + uart_send_string(" for "); + uart_send_integer(n_rounds, 1); + uart_send_string(" rounds, "); + uart_send_integer(t / n_rounds, 1); + uart_send_char('.'); + uart_send_integer(((t % n_rounds) * 100) / n_rounds, 2); + uart_send_string(" ms each"); + } + uart_send_string("\r\n"); +} + +#define time_check(_label_, _expr_, _n_) \ + do { \ + uint32_t _t = HAL_GetTick(); \ + (_expr_); \ + _time_check(_label_, _t, _n_); \ + } while (0) + +int main(void) +{ + stm_init(); + + if (n25q128_check_id(ctx) != HAL_OK) { + uart_send_string("ERROR: n25q128_check_id failed\r\n"); + return 0; + } + + uart_send_string("Starting...\r\n"); + + time_check("read page ", test_read_page(), N25Q128_NUM_PAGES); + time_check("read subsector ", test_read_subsector(), N25Q128_NUM_SUBSECTORS); + time_check("erase subsector ", test_erase_subsector(), N25Q128_NUM_SUBSECTORS); + time_check("erase sector ", test_erase_sector(), N25Q128_NUM_SECTORS); + time_check("erase bulk ", test_erase_bulk(), 1); + time_check("verify erase ", test_verify_erase(), N25Q128_NUM_PAGES); + time_check("write page ", test_write_page(), N25Q128_NUM_PAGES); + time_check("verify write ", test_verify_write(), N25Q128_NUM_PAGES); + + uart_send_string("Done.\r\n\r\n"); + return 0; +} diff --git a/projects/board-test/uart-test.c b/projects/board-test/uart-test.c index be06863..9a56dee 100644 --- a/projects/board-test/uart-test.c +++ b/projects/board-test/uart-test.c @@ -6,7 +6,6 @@ * Toggles the BLUE LED slowly and the GREEN LED for every * character sent. */ -#include "stm32f4xx_hal.h" #include "stm-init.h" #include "stm-led.h" #include "stm-uart.h" diff --git a/projects/bootloader/Makefile b/projects/bootloader/Makefile index 4eef758..6c1012f 100644 --- a/projects/bootloader/Makefile +++ b/projects/bootloader/Makefile @@ -1,6 +1,22 @@ PROG = bootloader -OBJS = crc32.o dfu.o +OBJS = dfu.o log.o + +BOARD_OBJS = \ + ./stm-init.o \ + $(TOPLEVEL)/stm-fmc.o \ + $(TOPLEVEL)/stm-uart.o \ + $(TOPLEVEL)/spiflash_n25q128.o \ + $(TOPLEVEL)/stm-keystore.o \ + $(TOPLEVEL)/stm-flash.o \ + $(TOPLEVEL)/syscalls.o \ + $(BOARD_DIR)/system_stm32f4xx.o \ + $(BOARD_DIR)/stm32f4xx_hal_msp.o \ + ./startup_stm32f429xx.o \ + $(BOARD_DIR)/stm32f4xx_it.o + +CFLAGS += -I$(LIBHAL_SRC) +LIBS += $(LIBHAL_BLD)/libhal.a $(LIBTFM_BLD)/libtfm.a all: $(PROG:=.elf) diff --git a/projects/bootloader/bootloader.c b/projects/bootloader/bootloader.c index ab3c1d9..6413597 100644 --- a/projects/bootloader/bootloader.c +++ b/projects/bootloader/bootloader.c @@ -5,6 +5,8 @@ * or jump to previously installed firmware. * * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * Copyright: 2020, The Commons Conservancy Cryptech Project + * SPDX-License-Identifier: BSD-3-Clause * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -16,9 +18,9 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * - Neither the name of the NORDUnet nor the names of its contributors may - * be used to endorse or promote products derived from this software - * without specific prior written permission. + * - Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED @@ -32,11 +34,30 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/* Ignore "deprecated" warnings in ARM-supplied CMSIS code: + * + * libraries/mbed/targets/cmsis/core_cm4.h:85:28: warning: listing the stack pointer register 'sp' in a clobber list is deprecated + * libraries/mbed/targets/cmsis/core_cm4.h:85:28: note: the value of the stack pointer after an 'asm' statement must be the same as it was before the statement + * + * This comes from our use of __set_MSP to set the stack pointer when + * switching tasks. If GCC ever decides to actually forbid this, then + * we'll have to figure out something else, possibly a native assembly + * function. + */ +#pragma GCC diagnostic ignored "-Wdeprecated" + #include "stm-init.h" #include "stm-led.h" #include "stm-uart.h" +#include "stm-fmc.h" #include "dfu.h" +/* stub these out to avoid linker error */ +void fpgacfg_init(void) { } +void sdram_init(void) { } +void *hal_allocate_static_memory(const size_t size) { return 0; } + /* Linker symbols are strange in C. Make regular pointers for sanity. */ __IO uint32_t *dfu_control = &CRYPTECH_DFU_CONTROL; __IO uint32_t *dfu_firmware = &CRYPTECH_FIRMWARE_START; @@ -49,16 +70,20 @@ __IO uint32_t *dfu_code_ptr = &CRYPTECH_FIRMWARE_START + 1; typedef void (*pFunction)(void); -/* This is it's own function to make it more convenient to set a breakpoint at it in gdb */ -void do_early_dfu_jump(void) +/* called from Reset_Handler */ +void check_early_dfu_jump(void) { - pFunction loaded_app = (pFunction) *dfu_code_ptr; - /* Set the stack pointer to the correct one for the firmware */ - __set_MSP(*dfu_msp_ptr); - /* Set the Vector Table Offset Register */ - SCB->VTOR = (uint32_t) dfu_firmware; - loaded_app(); - while (1); + /* Check if we've just rebooted in order to jump to the firmware. */ + if (*dfu_control == HARDWARE_EARLY_DFU_JUMP) { + *dfu_control = 0; + pFunction loaded_app = (pFunction) *dfu_code_ptr; + /* Set the stack pointer to the correct one for the firmware */ + __set_MSP(*dfu_msp_ptr); + /* Set the Vector Table Offset Register */ + SCB->VTOR = (uint32_t) dfu_firmware; + loaded_app(); + while (1); + } } int should_dfu() @@ -66,35 +91,31 @@ int should_dfu() int i; uint8_t rx = 0; - /* While blinking the blue LED for one second, see if we receive a CR on the MGMT UART. + /* While blinking the blue LED for 5 seconds, see if we receive a CR on the MGMT UART. * We've discussed also requiring one or both of the FPGA config jumpers installed * before allowing DFU of the STM32 - that check could be done here. */ led_on(LED_BLUE); - for (i = 0; i < 10; i++) { + for (i = 0; i < 50; i++) { HAL_Delay(100); led_toggle(LED_BLUE); - if (uart_recv_char2(STM_UART_MGMT, &rx, 0) == HAL_OK) { + if (uart_recv_char(&rx, 0) == HAL_OK) { if (rx == 13) return 1; } } return 0; } -int -main() +/* Sleep for specified number of seconds -- used after bad PIN. */ +void hal_sleep(const unsigned seconds) { HAL_Delay(seconds * 1000); } + +int main(void) { int status; - /* Check if we've just rebooted in order to jump to the firmware. */ - if (*dfu_control == HARDWARE_EARLY_DFU_JUMP) { - *dfu_control = 0; - do_early_dfu_jump(); - } - stm_init(); - uart_send_string2(STM_UART_MGMT, (char *) "\r\n\r\nThis is the bootloader speaking..."); + uart_send_string("\r\n\r\nThis is the bootloader speaking..."); if (should_dfu()) { led_off(LED_BLUE); @@ -104,9 +125,9 @@ main() */ led_off(LED_BLUE); led_on(LED_RED); - uart_send_string2(STM_UART_MGMT, (char *) "dfu_receive_firmware failed: "); - uart_send_number2(STM_UART_MGMT, status, 3, 16); - uart_send_string2(STM_UART_MGMT, (char *) "\r\n\r\nRebooting in three seconds\r\n"); + uart_send_string("dfu_receive_firmware failed: "); + uart_send_hex(status, 2); + uart_send_string("\r\n\r\nRebooting in three seconds\r\n"); HAL_Delay(3000); HAL_NVIC_SystemReset(); while (1) {}; @@ -118,7 +139,7 @@ main() */ *dfu_control = HARDWARE_EARLY_DFU_JUMP; - uart_send_string2(STM_UART_MGMT, (char *) "loading firmware\r\n\r\n"); + uart_send_string("loading firmware\r\n\r\n"); /* De-initialize hardware by rebooting */ HAL_NVIC_SystemReset(); diff --git a/projects/bootloader/crc32.c b/projects/bootloader/crc32.c deleted file mode 100644 index 4d1a0bc..0000000 --- a/projects/bootloader/crc32.c +++ /dev/null @@ -1,62 +0,0 @@ -/* Reference code from RFC1952. Not meant to be used outside test code. */ - -#include "stm32f4xx_hal.h" - - -/* Table of CRCs of all 8-bit messages. */ -unsigned long crc_table[256]; - -/* Flag: has the table been computed? Initially false. */ -int crc_table_computed = 0; - -/* Make the table for a fast CRC. */ -void make_crc_table(void) -{ - unsigned long c; - - int n, k; - for (n = 0; n < 256; n++) { - c = (unsigned long) n; - for (k = 0; k < 8; k++) { - if (c & 1) { - c = 0xedb88320L ^ (c >> 1); - } else { - c = c >> 1; - } - } - crc_table[n] = c; - } - crc_table_computed = 1; -} - -/* - Update a running crc with the bytes buf[0..len-1] and return - the updated crc. The crc should be initialized to zero. Pre- and - post-conditioning (one's complement) is performed within this - function so it shouldn't be done by the caller. Usage example: - - unsigned long crc = 0L; - - while (read_buffer(buffer, length) != EOF) { - crc = update_crc(crc, buffer, length); - } - if (crc != original_crc) error(); -*/ -uint32_t update_crc(uint32_t crc, uint8_t *buf, int len) -{ - unsigned long c = crc ^ 0xffffffffL; - int n; - - if (!crc_table_computed) - make_crc_table(); - for (n = 0; n < len; n++) { - c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8); - } - return c ^ 0xffffffffL; -} - -/* Return the CRC of the bytes buf[0..len-1]. */ -unsigned long crc(unsigned char *buf, int len) -{ - return update_crc(0L, buf, len); -} diff --git a/projects/bootloader/dfu.c b/projects/bootloader/dfu.c index 231e388..83aef20 100644 --- a/projects/bootloader/dfu.c +++ b/projects/bootloader/dfu.c @@ -31,43 +31,132 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/* Rename both CMSIS HAL_OK and libhal HAL_OK to disambiguate */ +#define HAL_OK CMSIS_HAL_OK #include "dfu.h" #include "stm-led.h" #include "stm-uart.h" #include "stm-flash.h" +#undef HAL_OK + +#define HAL_OK LIBHAL_OK +#include "hal.h" +#include "hal_internal.h" +#undef HAL_OK #include <string.h> -extern uint32_t update_crc(uint32_t crc, uint8_t *buf, int len); +static int getline(char *buf, int len) +{ + int i; + uint8_t c; + + for (i = 0; i < len; ++i) { + if (uart_recv_char(&c, HAL_MAX_DELAY) != CMSIS_HAL_OK) + return -1; + if (c == '\r') { + buf[i] = '\0'; + break; + } + buf[i] = c; + } + return i; +} +static void uart_flush(void) +{ + uint8_t c; + while (uart_recv_char(&c, 0) == CMSIS_HAL_OK) { ; } +} + +static int do_login(void) +{ + char username[8]; + char pin[hal_rpc_max_pin_length]; + hal_client_handle_t client = { -1 }; + hal_user_t user; + int n; + + uart_flush(); + uart_send_string("\r\nUsername: "); + if (getline(username, sizeof(username)) <= 0) + return -1; + if (strcmp(username, "wheel") == 0) + user = HAL_USER_WHEEL; + else if (strcmp(username, "so") == 0) + user = HAL_USER_SO; + else if (strcmp(username, "user") == 0) + user = HAL_USER_NORMAL; + else + user = HAL_USER_NONE; + + uart_flush(); + uart_send_string("\r\nPassword: "); + if ((n = getline(pin, sizeof(pin))) <= 0) + return -1; + + uart_flush(); + + hal_ks_init_read_only_pins_only(); + + if (hal_rpc_login(client, user, pin, n) != LIBHAL_OK) { + uart_send_string("\r\nAccess denied\r\n"); + return -1; + } + return 0; +} int dfu_receive_firmware(void) { - uint32_t filesize = 0, crc = 0, my_crc = 0, counter = 0; uint32_t offset = DFU_FIRMWARE_ADDR, n = DFU_UPLOAD_CHUNK_SIZE; - uint32_t buf[DFU_UPLOAD_CHUNK_SIZE / 4]; + hal_crc32_t crc = 0, my_crc = hal_crc32_init(); + uint32_t filesize = 0, counter = 0; + uint8_t buf[DFU_UPLOAD_CHUNK_SIZE]; + + if (do_login() != 0) + return -1; + + /* Fake the CLI */ + uart_send_string("\r\ncryptech> "); + char cmd[64]; + if (getline(cmd, sizeof(cmd)) <= 0) + return -1; + if (strcmp(cmd, "firmware upload") != 0) { + uart_send_string("\r\nInvalid command \""); + uart_send_string(cmd); + uart_send_string("\"\r\n"); + return -1; + } - uart_send_string2(STM_UART_MGMT, (char *) "\r\nOK, bootloader waiting for new firmware\r\n"); + uart_send_string("OK, write size (4 bytes), data in 4096 byte chunks, CRC-32 (4 bytes)\r\n"); /* Read file size (4 bytes) */ - uart_receive_bytes(STM_UART_MGMT, (void *) &filesize, 4, 1000); + uart_receive_bytes((void *) &filesize, sizeof(filesize), 10000); if (filesize < 512 || filesize > DFU_FIRMWARE_END_ADDR - DFU_FIRMWARE_ADDR) { + uart_send_string("Invalid filesize "); + uart_send_integer(filesize, 1); + uart_send_string("\r\n"); return -1; } HAL_FLASH_Unlock(); + uart_send_string("Send "); + uart_send_integer(filesize, 1); + uart_send_string(" bytes of data\r\n"); + while (filesize) { /* By initializing buf to the same value that erased flash has (0xff), we don't * have to try and be smart when writing the last page of data to the memory. */ - memset(buf, 0xffffffff, sizeof(buf)); + memset(buf, 0xff, sizeof(buf)); if (filesize < n) { n = filesize; } - if (uart_receive_bytes(STM_UART_MGMT, (void *) &buf, n, 1000) != HAL_OK) { + if (uart_receive_bytes((void *) buf, n, 10000) != CMSIS_HAL_OK) { return -2; } filesize -= n; @@ -75,23 +164,34 @@ int dfu_receive_firmware(void) /* After reception of a chunk but before ACKing we have "all" the time in the world to * calculate CRC and write it to flash. */ - my_crc = update_crc(my_crc, (uint8_t *) buf, n); - stm_flash_write32(offset, buf, sizeof(buf) / 4); + my_crc = hal_crc32_update(my_crc, buf, n); + stm_flash_write32(offset, (uint32_t *)buf, sizeof(buf)/4); offset += DFU_UPLOAD_CHUNK_SIZE; /* ACK this chunk by sending the current chunk counter (4 bytes) */ counter++; - uart_send_bytes(STM_UART_MGMT, (void *) &counter, 4); + uart_send_bytes((void *) &counter, 4); led_toggle(LED_BLUE); } + my_crc = hal_crc32_finalize(my_crc); + HAL_FLASH_Lock(); - /* The sending side will now send it's calculated CRC-32 */ - uart_receive_bytes(STM_UART_MGMT, (void *) &crc, 4, 1000); + uart_send_string("Send CRC-32\r\n"); + + /* The sending side will now send its calculated CRC-32 */ + uart_receive_bytes((void *) &crc, sizeof(crc), 10000); + + uart_send_string("CRC-32 0x"); + uart_send_hex(crc, 1); + uart_send_string(", calculated CRC 0x"); + uart_send_hex(my_crc, 1); if (crc == my_crc) { - uart_send_string2(STM_UART_MGMT, (char *) "\r\nSuccess\r\n"); - return 0; + uart_send_string("CRC checksum MATCHED\r\n"); + return 0; + } else { + uart_send_string("CRC checksum did NOT match\r\n"); } led_on(LED_RED); diff --git a/projects/bootloader/log.c b/projects/bootloader/log.c new file mode 100644 index 0000000..fbc0e73 --- /dev/null +++ b/projects/bootloader/log.c @@ -0,0 +1,68 @@ +/* + * log.c + * ----- + * Implement libhal logging API on Alpha. + * + * Copyright (c) 2017, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdarg.h> + +#define HAL_OK CMSIS_HAL_OK +#include "stm-uart.h" +#undef HAL_OK + +#define HAL_OK LIBHAL_OK +#include "hal.h" +#include "hal_internal.h" +#undef HAL_OK + +static hal_log_level_t current_log_level; + +void hal_log_set_level(const hal_log_level_t level) +{ + current_log_level = level; +} + +void hal_log(const hal_log_level_t level, const char *format, ...) +{ + if (level < current_log_level) + return; + + char buffer[2048]; + va_list ap; + + va_start(ap, format); + vsnprintf(buffer, sizeof(buffer), format, ap); + va_end(ap); + + uart_send_string(buffer); + uart_send_string("\r\n"); +} diff --git a/projects/bootloader/startup_stm32f429xx.S b/projects/bootloader/startup_stm32f429xx.S new file mode 100644 index 0000000..fc8bf34 --- /dev/null +++ b/projects/bootloader/startup_stm32f429xx.S @@ -0,0 +1,564 @@ +/** + ****************************************************************************** + * @file startup_stm32f429xx.s + * @author MCD Application Team + * @version V2.4.1 + * @date 09-October-2015 + * @brief STM32F429xx Devices vector table for GCC based toolchains. + * This module performs: + * - Set the initial SP + * - Set the initial PC == Reset_Handler, + * - Set the vector table entries with the exceptions ISR address + * - Branches to main in the C library (which eventually + * calls main()). + * After Reset the Cortex-M4 processor is in Thread mode, + * priority is Privileged, and the Stack is set to Main. + ****************************************************************************** + * @attention + * + * <h2><center>© COPYRIGHT 2015 STMicroelectronics</center></h2> + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + + .syntax unified + .cpu cortex-m4 + .fpu softvfp + .thumb + +.global g_pfnVectors +.global Default_Handler + +/* start address for the initialization values of the .data section. +defined in linker script */ +.word _sidata +/* start address for the .data section. defined in linker script */ +.word _sdata +/* end address for the .data section. defined in linker script */ +.word _edata +/* start address for the .bss section. defined in linker script */ +.word _sbss +/* end address for the .bss section. defined in linker script */ +.word _ebss +/* stack used for SystemInit_ExtMemCtl; always internal RAM used */ + +/** + * @brief This is the code that gets called when the processor first + * starts execution following a reset event. Only the absolutely + * necessary set is performed, after which the application + * supplied main() routine is called. + * @param None + * @retval : None +*/ + + .section .text.Reset_Handler + .weak Reset_Handler + .type Reset_Handler, %function +Reset_Handler: + ldr sp, =_estack /* set stack pointer */ + +/* Copy the data segment initializers from flash to SRAM */ + movs r1, #0 + b LoopCopyDataInit + +CopyDataInit: + ldr r3, =_sidata + ldr r3, [r3, r1] + str r3, [r0, r1] + adds r1, r1, #4 + +LoopCopyDataInit: + ldr r0, =_sdata + ldr r3, =_edata + adds r2, r0, r1 + cmp r2, r3 + bcc CopyDataInit + ldr r2, =_sbss + b LoopFillZerobss +/* Zero fill the bss segment. */ +FillZerobss: + movs r3, #0 + str r3, [r2], #4 + +LoopFillZerobss: + ldr r3, = _ebss + cmp r2, r3 + bcc FillZerobss + + /* Check if we've just rebooted in order to jump to the firmware. */ + bl check_early_dfu_jump + +/* Call the clock system intitialization function.*/ + bl SystemInit +/* Call static constructors */ + bl __libc_init_array +/* Call the application's entry point.*/ + bl main + bx lr +.size Reset_Handler, .-Reset_Handler + +/** + * @brief This is the code that gets called when the processor receives an + * unexpected interrupt. This simply enters an infinite loop, preserving + * the system state for examination by a debugger. + * @param None + * @retval None +*/ + .section .text.Default_Handler,"ax",%progbits +Default_Handler: +Infinite_Loop: + b Infinite_Loop + .size Default_Handler, .-Default_Handler +/****************************************************************************** +* +* The minimal vector table for a Cortex M3. Note that the proper constructs +* must be placed on this to ensure that it ends up at physical address +* 0x0000.0000. +* +*******************************************************************************/ + .section .isr_vector,"a",%progbits + .type g_pfnVectors, %object + .size g_pfnVectors, .-g_pfnVectors + +g_pfnVectors: + .word _estack + .word Reset_Handler + + .word NMI_Handler + .word HardFault_Handler + .word MemManage_Handler + .word BusFault_Handler + .word UsageFault_Handler + .word 0 + .word 0 + .word 0 + .word 0 + .word SVC_Handler + .word DebugMon_Handler + .word 0 + .word PendSV_Handler + .word SysTick_Handler + + /* External Interrupts */ + .word WWDG_IRQHandler /* Window WatchDog */ + .word PVD_IRQHandler /* PVD through EXTI Line detection */ + .word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */ + .word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */ + .word FLASH_IRQHandler /* FLASH */ + .word RCC_IRQHandler /* RCC */ + .word EXTI0_IRQHandler /* EXTI Line0 */ + .word EXTI1_IRQHandler /* EXTI Line1 */ + .word EXTI2_IRQHandler /* EXTI Line2 */ + .word EXTI3_IRQHandler /* EXTI Line3 */ + .word EXTI4_IRQHandler /* EXTI Line4 */ + .word DMA1_Stream0_IRQHandler /* DMA1 Stream 0 */ + .word DMA1_Stream1_IRQHandler /* DMA1 Stream 1 */ + .word DMA1_Stream2_IRQHandler /* DMA1 Stream 2 */ + .word DMA1_Stream3_IRQHandler /* DMA1 Stream 3 */ + .word DMA1_Stream4_IRQHandler /* DMA1 Stream 4 */ + .word DMA1_Stream5_IRQHandler /* DMA1 Stream 5 */ + .word DMA1_Stream6_IRQHandler /* DMA1 Stream 6 */ + .word ADC_IRQHandler /* ADC1, ADC2 and ADC3s */ + .word CAN1_TX_IRQHandler /* CAN1 TX */ + .word CAN1_RX0_IRQHandler /* CAN1 RX0 */ + .word CAN1_RX1_IRQHandler /* CAN1 RX1 */ + .word CAN1_SCE_IRQHandler /* CAN1 SCE */ + .word EXTI9_5_IRQHandler /* External Line[9:5]s */ + .word TIM1_BRK_TIM9_IRQHandler /* TIM1 Break and TIM9 */ + .word TIM1_UP_TIM10_IRQHandler /* TIM1 Update and TIM10 */ + .word TIM1_TRG_COM_TIM11_IRQHandler /* TIM1 Trigger and Commutation and TIM11 */ + .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */ + .word TIM2_IRQHandler /* TIM2 */ + .word TIM3_IRQHandler /* TIM3 */ + .word TIM4_IRQHandler /* TIM4 */ + .word I2C1_EV_IRQHandler /* I2C1 Event */ + .word I2C1_ER_IRQHandler /* I2C1 Error */ + .word I2C2_EV_IRQHandler /* I2C2 Event */ + .word I2C2_ER_IRQHandler /* I2C2 Error */ + .word SPI1_IRQHandler /* SPI1 */ + .word SPI2_IRQHandler /* SPI2 */ + .word USART1_IRQHandler /* USART1 */ + .word USART2_IRQHandler /* USART2 */ + .word USART3_IRQHandler /* USART3 */ + .word EXTI15_10_IRQHandler /* External Line[15:10]s */ + .word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */ + .word OTG_FS_WKUP_IRQHandler /* USB OTG FS Wakeup through EXTI line */ + .word TIM8_BRK_TIM12_IRQHandler /* TIM8 Break and TIM12 */ + .word TIM8_UP_TIM13_IRQHandler /* TIM8 Update and TIM13 */ + .word TIM8_TRG_COM_TIM14_IRQHandler /* TIM8 Trigger and Commutation and TIM14 */ + .word TIM8_CC_IRQHandler /* TIM8 Capture Compare */ + .word DMA1_Stream7_IRQHandler /* DMA1 Stream7 */ + .word FMC_IRQHandler /* FMC */ + .word SDIO_IRQHandler /* SDIO */ + .word TIM5_IRQHandler /* TIM5 */ + .word SPI3_IRQHandler /* SPI3 */ + .word UART4_IRQHandler /* UART4 */ + .word UART5_IRQHandler /* UART5 */ + .word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */ + .word TIM7_IRQHandler /* TIM7 */ + .word DMA2_Stream0_IRQHandler /* DMA2 Stream 0 */ + .word DMA2_Stream1_IRQHandler /* DMA2 Stream 1 */ + .word DMA2_Stream2_IRQHandler /* DMA2 Stream 2 */ + .word DMA2_Stream3_IRQHandler /* DMA2 Stream 3 */ + .word DMA2_Stream4_IRQHandler /* DMA2 Stream 4 */ + .word ETH_IRQHandler /* Ethernet */ + .word ETH_WKUP_IRQHandler /* Ethernet Wakeup through EXTI line */ + .word CAN2_TX_IRQHandler /* CAN2 TX */ + .word CAN2_RX0_IRQHandler /* CAN2 RX0 */ + .word CAN2_RX1_IRQHandler /* CAN2 RX1 */ + .word CAN2_SCE_IRQHandler /* CAN2 SCE */ + .word OTG_FS_IRQHandler /* USB OTG FS */ + .word DMA2_Stream5_IRQHandler /* DMA2 Stream 5 */ + .word DMA2_Stream6_IRQHandler /* DMA2 Stream 6 */ + .word DMA2_Stream7_IRQHandler /* DMA2 Stream 7 */ + .word USART6_IRQHandler /* USART6 */ + .word I2C3_EV_IRQHandler /* I2C3 event */ + .word I2C3_ER_IRQHandler /* I2C3 error */ + .word OTG_HS_EP1_OUT_IRQHandler /* USB OTG HS End Point 1 Out */ + .word OTG_HS_EP1_IN_IRQHandler /* USB OTG HS End Point 1 In */ + .word OTG_HS_WKUP_IRQHandler /* USB OTG HS Wakeup through EXTI */ + .word OTG_HS_IRQHandler /* USB OTG HS */ + .word DCMI_IRQHandler /* DCMI */ + .word 0 /* Reserved */ + .word HASH_RNG_IRQHandler /* Hash and Rng */ + .word FPU_IRQHandler /* FPU */ + .word UART7_IRQHandler /* UART7 */ + .word UART8_IRQHandler /* UART8 */ + .word SPI4_IRQHandler /* SPI4 */ + .word SPI5_IRQHandler /* SPI5 */ + .word SPI6_IRQHandler /* SPI6 */ + .word SAI1_IRQHandler /* SAI1 */ + .word LTDC_IRQHandler /* LTDC_IRQHandler */ + .word LTDC_ER_IRQHandler /* LTDC_ER_IRQHandler */ + .word DMA2D_IRQHandler /* DMA2D */ + +/******************************************************************************* +* +* Provide weak aliases for each Exception handler to the Default_Handler. +* As they are weak aliases, any function with the same name will override +* this definition. +* +*******************************************************************************/ + .weak NMI_Handler + .thumb_set NMI_Handler,Default_Handler + + .weak HardFault_Handler + .thumb_set HardFault_Handler,Default_Handler + + .weak MemManage_Handler + .thumb_set MemManage_Handler,Default_Handler + + .weak BusFault_Handler + .thumb_set BusFault_Handler,Default_Handler + + .weak UsageFault_Handler + .thumb_set UsageFault_Handler,Default_Handler + + .weak SVC_Handler + .thumb_set SVC_Handler,Default_Handler + + .weak DebugMon_Handler + .thumb_set DebugMon_Handler,Default_Handler + + .weak PendSV_Handler + .thumb_set PendSV_Handler,Default_Handler + + .weak SysTick_Handler + .thumb_set SysTick_Handler,Default_Handler + + .weak WWDG_IRQHandler + .thumb_set WWDG_IRQHandler,Default_Handler + + .weak PVD_IRQHandler + .thumb_set PVD_IRQHandler,Default_Handler + + .weak TAMP_STAMP_IRQHandler + .thumb_set TAMP_STAMP_IRQHandler,Default_Handler + + .weak RTC_WKUP_IRQHandler + .thumb_set RTC_WKUP_IRQHandler,Default_Handler + + .weak FLASH_IRQHandler + .thumb_set FLASH_IRQHandler,Default_Handler + + .weak RCC_IRQHandler + .thumb_set RCC_IRQHandler,Default_Handler + + .weak EXTI0_IRQHandler + .thumb_set EXTI0_IRQHandler,Default_Handler + + .weak EXTI1_IRQHandler + .thumb_set EXTI1_IRQHandler,Default_Handler + + .weak EXTI2_IRQHandler + .thumb_set EXTI2_IRQHandler,Default_Handler + + .weak EXTI3_IRQHandler + .thumb_set EXTI3_IRQHandler,Default_Handler + + .weak EXTI4_IRQHandler + .thumb_set EXTI4_IRQHandler,Default_Handler + + .weak DMA1_Stream0_IRQHandler + .thumb_set DMA1_Stream0_IRQHandler,Default_Handler + + .weak DMA1_Stream1_IRQHandler + .thumb_set DMA1_Stream1_IRQHandler,Default_Handler + + .weak DMA1_Stream2_IRQHandler + .thumb_set DMA1_Stream2_IRQHandler,Default_Handler + + .weak DMA1_Stream3_IRQHandler + .thumb_set DMA1_Stream3_IRQHandler,Default_Handler + + .weak DMA1_Stream4_IRQHandler + .thumb_set DMA1_Stream4_IRQHandler,Default_Handler + + .weak DMA1_Stream5_IRQHandler + .thumb_set DMA1_Stream5_IRQHandler,Default_Handler + + .weak DMA1_Stream6_IRQHandler + .thumb_set DMA1_Stream6_IRQHandler,Default_Handler + + .weak ADC_IRQHandler + .thumb_set ADC_IRQHandler,Default_Handler + + .weak CAN1_TX_IRQHandler + .thumb_set CAN1_TX_IRQHandler,Default_Handler + + .weak CAN1_RX0_IRQHandler + .thumb_set CAN1_RX0_IRQHandler,Default_Handler + + .weak CAN1_RX1_IRQHandler + .thumb_set CAN1_RX1_IRQHandler,Default_Handler + + .weak CAN1_SCE_IRQHandler + .thumb_set CAN1_SCE_IRQHandler,Default_Handler + + .weak EXTI9_5_IRQHandler + .thumb_set EXTI9_5_IRQHandler,Default_Handler + + .weak TIM1_BRK_TIM9_IRQHandler + .thumb_set TIM1_BRK_TIM9_IRQHandler,Default_Handler + + .weak TIM1_UP_TIM10_IRQHandler + .thumb_set TIM1_UP_TIM10_IRQHandler,Default_Handler + + .weak TIM1_TRG_COM_TIM11_IRQHandler + .thumb_set TIM1_TRG_COM_TIM11_IRQHandler,Default_Handler + + .weak TIM1_CC_IRQHandler + .thumb_set TIM1_CC_IRQHandler,Default_Handler + + .weak TIM2_IRQHandler + .thumb_set TIM2_IRQHandler,Default_Handler + + .weak TIM3_IRQHandler + .thumb_set TIM3_IRQHandler,Default_Handler + + .weak TIM4_IRQHandler + .thumb_set TIM4_IRQHandler,Default_Handler + + .weak I2C1_EV_IRQHandler + .thumb_set I2C1_EV_IRQHandler,Default_Handler + + .weak I2C1_ER_IRQHandler + .thumb_set I2C1_ER_IRQHandler,Default_Handler + + .weak I2C2_EV_IRQHandler + .thumb_set I2C2_EV_IRQHandler,Default_Handler + + .weak I2C2_ER_IRQHandler + .thumb_set I2C2_ER_IRQHandler,Default_Handler + + .weak SPI1_IRQHandler + .thumb_set SPI1_IRQHandler,Default_Handler + + .weak SPI2_IRQHandler + .thumb_set SPI2_IRQHandler,Default_Handler + + .weak USART1_IRQHandler + .thumb_set USART1_IRQHandler,Default_Handler + + .weak USART2_IRQHandler + .thumb_set USART2_IRQHandler,Default_Handler + + .weak USART3_IRQHandler + .thumb_set USART3_IRQHandler,Default_Handler + + .weak EXTI15_10_IRQHandler + .thumb_set EXTI15_10_IRQHandler,Default_Handler + + .weak RTC_Alarm_IRQHandler + .thumb_set RTC_Alarm_IRQHandler,Default_Handler + + .weak OTG_FS_WKUP_IRQHandler + .thumb_set OTG_FS_WKUP_IRQHandler,Default_Handler + + .weak TIM8_BRK_TIM12_IRQHandler + .thumb_set TIM8_BRK_TIM12_IRQHandler,Default_Handler + + .weak TIM8_UP_TIM13_IRQHandler + .thumb_set TIM8_UP_TIM13_IRQHandler,Default_Handler + + .weak TIM8_TRG_COM_TIM14_IRQHandler + .thumb_set TIM8_TRG_COM_TIM14_IRQHandler,Default_Handler + + .weak TIM8_CC_IRQHandler + .thumb_set TIM8_CC_IRQHandler,Default_Handler + + .weak DMA1_Stream7_IRQHandler + .thumb_set DMA1_Stream7_IRQHandler,Default_Handler + + .weak FMC_IRQHandler + .thumb_set FMC_IRQHandler,Default_Handler + + .weak SDIO_IRQHandler + .thumb_set SDIO_IRQHandler,Default_Handler + + .weak TIM5_IRQHandler + .thumb_set TIM5_IRQHandler,Default_Handler + + .weak SPI3_IRQHandler + .thumb_set SPI3_IRQHandler,Default_Handler + + .weak UART4_IRQHandler + .thumb_set UART4_IRQHandler,Default_Handler + + .weak UART5_IRQHandler + .thumb_set UART5_IRQHandler,Default_Handler + + .weak TIM6_DAC_IRQHandler + .thumb_set TIM6_DAC_IRQHandler,Default_Handler + + .weak TIM7_IRQHandler + .thumb_set TIM7_IRQHandler,Default_Handler + + .weak DMA2_Stream0_IRQHandler + .thumb_set DMA2_Stream0_IRQHandler,Default_Handler + + .weak DMA2_Stream1_IRQHandler + .thumb_set DMA2_Stream1_IRQHandler,Default_Handler + + .weak DMA2_Stream2_IRQHandler + .thumb_set DMA2_Stream2_IRQHandler,Default_Handler + + .weak DMA2_Stream3_IRQHandler + .thumb_set DMA2_Stream3_IRQHandler,Default_Handler + + .weak DMA2_Stream4_IRQHandler + .thumb_set DMA2_Stream4_IRQHandler,Default_Handler + + .weak ETH_IRQHandler + .thumb_set ETH_IRQHandler,Default_Handler + + .weak ETH_WKUP_IRQHandler + .thumb_set ETH_WKUP_IRQHandler,Default_Handler + + .weak CAN2_TX_IRQHandler + .thumb_set CAN2_TX_IRQHandler,Default_Handler + + .weak CAN2_RX0_IRQHandler + .thumb_set CAN2_RX0_IRQHandler,Default_Handler + + .weak CAN2_RX1_IRQHandler + .thumb_set CAN2_RX1_IRQHandler,Default_Handler + + .weak CAN2_SCE_IRQHandler + .thumb_set CAN2_SCE_IRQHandler,Default_Handler + + .weak OTG_FS_IRQHandler + .thumb_set OTG_FS_IRQHandler,Default_Handler + + .weak DMA2_Stream5_IRQHandler + .thumb_set DMA2_Stream5_IRQHandler,Default_Handler + + .weak DMA2_Stream6_IRQHandler + .thumb_set DMA2_Stream6_IRQHandler,Default_Handler + + .weak DMA2_Stream7_IRQHandler + .thumb_set DMA2_Stream7_IRQHandler,Default_Handler + + .weak USART6_IRQHandler + .thumb_set USART6_IRQHandler,Default_Handler + + .weak I2C3_EV_IRQHandler + .thumb_set I2C3_EV_IRQHandler,Default_Handler + + .weak I2C3_ER_IRQHandler + .thumb_set I2C3_ER_IRQHandler,Default_Handler + + .weak OTG_HS_EP1_OUT_IRQHandler + .thumb_set OTG_HS_EP1_OUT_IRQHandler,Default_Handler + + .weak OTG_HS_EP1_IN_IRQHandler + .thumb_set OTG_HS_EP1_IN_IRQHandler,Default_Handler + + .weak OTG_HS_WKUP_IRQHandler + .thumb_set OTG_HS_WKUP_IRQHandler,Default_Handler + + .weak OTG_HS_IRQHandler + .thumb_set OTG_HS_IRQHandler,Default_Handler + + .weak DCMI_IRQHandler + .thumb_set DCMI_IRQHandler,Default_Handler + + .weak HASH_RNG_IRQHandler + .thumb_set HASH_RNG_IRQHandler,Default_Handler + + .weak FPU_IRQHandler + .thumb_set FPU_IRQHandler,Default_Handler + + .weak UART7_IRQHandler + .thumb_set UART7_IRQHandler,Default_Handler + + .weak UART8_IRQHandler + .thumb_set UART8_IRQHandler,Default_Handler + + .weak SPI4_IRQHandler + .thumb_set SPI4_IRQHandler,Default_Handler + + .weak SPI5_IRQHandler + .thumb_set SPI5_IRQHandler,Default_Handler + + .weak SPI6_IRQHandler + .thumb_set SPI6_IRQHandler,Default_Handler + + .weak SAI1_IRQHandler + .thumb_set SAI1_IRQHandler,Default_Handler + + .weak LTDC_IRQHandler + .thumb_set LTDC_IRQHandler,Default_Handler + + .weak LTDC_ER_IRQHandler + .thumb_set LTDC_ER_IRQHandler,Default_Handler + + .weak DMA2D_IRQHandler + .thumb_set DMA2D_IRQHandler,Default_Handler + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + + + diff --git a/projects/bootloader/stm-init.c b/projects/bootloader/stm-init.c new file mode 100644 index 0000000..b331b8a --- /dev/null +++ b/projects/bootloader/stm-init.c @@ -0,0 +1,7 @@ +/* Disable modules that the bootloader doesn't need. */ + +#include "stm32f4xx_hal.h" + +#undef HAL_I2C_MODULE_ENABLED + +#include "../../stm-init.c" diff --git a/projects/cli-test/Makefile b/projects/cli-test/Makefile index acf2720..5bb3fb1 100644 --- a/projects/cli-test/Makefile +++ b/projects/cli-test/Makefile @@ -1,11 +1,28 @@ -TEST = cli-test +PROJ = cli-test -OBJS = crc32.o test_sdram.o mgmt-cli.o mgmt-dfu.c mgmt-fpga.c mgmt-misc.c mgmt-show.c mgmt-test.c +# objs in addition to $(PROJ).o +OBJS = \ + mgmt-cli.o \ + mgmt-dfu.o \ + mgmt-fpga.o \ + mgmt-keystore.o \ + mgmt-masterkey.o \ + mgmt-misc.o \ + mgmt-show.o -CFLAGS += -I$(LIBCLI_DIR) -LIBS += $(LIBCLI_DIR)/libcli.a +CFLAGS += -I$(LIBCLI_SRC) -I$(LIBHAL_SRC) +CFLAGS += -I$(LIBTFM_BLD) +CFLAGS += -Wno-missing-field-initializers -all: $(TEST:=.elf) +ifdef DO_TIMING +CFLAGS += -DDO_TIMING +OBJS += mgmt-timing.o $(TOPLEVEL)/stm-dwt.o +LDFLAGS += -lm +endif + +LIBS += $(LIBCLI_BLD)/libcli.a $(LIBHAL_BLD)/libhal.a $(LIBTFM_BLD)/libtfm.a + +all: $(PROJ:=.elf) %.elf: %.o $(BOARD_OBJS) $(OBJS) $(LIBS) $(CC) $(CFLAGS) $^ -o $@ -T$(LDSCRIPT) -g -Wl,-Map=$*.map diff --git a/projects/cli-test/cli-test.c b/projects/cli-test/cli-test.c index ed6aac3..c50338b 100644 --- a/projects/cli-test/cli-test.c +++ b/projects/cli-test/cli-test.c @@ -33,6 +33,7 @@ */ #include "stm-init.h" #include "stm-led.h" +#include "stm-uart.h" #include "mgmt-cli.h" #include "mgmt-dfu.h" @@ -40,72 +41,78 @@ #include "mgmt-misc.h" #include "mgmt-show.h" #include "mgmt-test.h" +#include "mgmt-keystore.h" #include <string.h> +#include <strings.h> /* MGMT UART interrupt receive buffer (data will be put in a larger ring buffer) */ volatile uint8_t uart_rx; - -int check_auth(const char *username, const char *password) -{ - if (strcasecmp(username, "ct") != 0) - return CLI_ERROR; - if (strcasecmp(password, "ct") != 0) - return CLI_ERROR; - return CLI_OK; -} - -typedef void (*pFunction)(void); - -/* This is it's own function to make it more convenient to set a breakpoint at it in gdb */ -void do_early_dfu_jump(void) -{ - pFunction loaded_app = (pFunction) *dfu_code_ptr; - /* Set the stack pointer to the correct one for the firmware */ - __set_MSP(*dfu_msp_ptr); - /* Set the Vector Table Offset Register */ - SCB->VTOR = (uint32_t) dfu_firmware; - loaded_app(); - while (1); -} +/* Sleep for specified number of seconds -- used after bad PIN. */ +void hal_sleep(const unsigned seconds) { HAL_Delay(seconds * 1000); } int main() { - static struct cli_def cli; + stm_init(); + led_on(LED_GREEN); - /* Check if we've just rebooted in order to jump to the firmware. */ - if (*dfu_control == HARDWARE_EARLY_DFU_JUMP) { - *dfu_control = 0; - do_early_dfu_jump(); + /* For the hsm, the keystores are initialized in hal_rpc_server_init(), + * which is...less than optimal, but this is not the time or place to fix + * it, especially in light of all the terrible things I'm doing in this + * version of cli-test. + */ + extern void *hal_ks_token, *hal_ks_volatile; + extern int hal_ks_init(void *, int); + if (hal_ks_init(hal_ks_volatile, 1) != 0 || hal_ks_init(hal_ks_token, 1) != 0) + Error_Handler(); + + while (1) { + cli_main(); + /* embedded_cli_loop returns when the user enters 'quit' or 'exit' */ } - stm_init(); + /* NOT REACHED */ + Error_Handler(); +} - led_on(LED_RED); - mgmt_cli_init(&cli); - cli_set_auth_callback(&cli, check_auth); +/* end of variables declared with __attribute__((section(".sdram1"))) */ +extern uint8_t _esdram1 __asm ("_esdram1"); +/* end of SDRAM1 section */ +extern uint8_t __end_sdram1 __asm ("__end_sdram1"); +static uint8_t *sdram_heap = &_esdram1; - configure_cli_show(&cli); - configure_cli_fpga(&cli); - configure_cli_test(&cli); - configure_cli_misc(&cli); - configure_cli_dfu(&cli); +/* Allocate memory from SDRAM1. */ +static uint8_t *sdram_malloc(size_t size) +{ + uint8_t *p = sdram_heap; - led_off(LED_RED); - led_on(LED_GREEN); +#define pad(n) (((n) + 3) & ~3) + size = pad(size); - embedded_cli_loop(&cli); + if (p + size + sizeof(uint32_t) > &__end_sdram1) + return NULL; - /* embedded_cli_loop returns when the user enters 'quit' or 'exit' */ + *(uint32_t *)p = (uint32_t)size; + p += sizeof(uint32_t); - cli_print(&cli, "Rebooting in 3 seconds"); - HAL_Delay(3000); - HAL_NVIC_SystemReset(); + sdram_heap += size + sizeof(uint32_t); + return p; +} - /* NOT REACHED */ - Error_Handler(); +/* Implement static memory allocation for libhal over sdram_malloc(). + * Used in hal_ks_init. + */ +void *hal_allocate_static_memory(const size_t size) +{ + return sdram_malloc(size); +} + +int hal_free_static_memory(const void * const ptr) +{ + return 0; } + diff --git a/projects/cli-test/crc32.c b/projects/cli-test/crc32.c deleted file mode 100644 index 4d1a0bc..0000000 --- a/projects/cli-test/crc32.c +++ /dev/null @@ -1,62 +0,0 @@ -/* Reference code from RFC1952. Not meant to be used outside test code. */ - -#include "stm32f4xx_hal.h" - - -/* Table of CRCs of all 8-bit messages. */ -unsigned long crc_table[256]; - -/* Flag: has the table been computed? Initially false. */ -int crc_table_computed = 0; - -/* Make the table for a fast CRC. */ -void make_crc_table(void) -{ - unsigned long c; - - int n, k; - for (n = 0; n < 256; n++) { - c = (unsigned long) n; - for (k = 0; k < 8; k++) { - if (c & 1) { - c = 0xedb88320L ^ (c >> 1); - } else { - c = c >> 1; - } - } - crc_table[n] = c; - } - crc_table_computed = 1; -} - -/* - Update a running crc with the bytes buf[0..len-1] and return - the updated crc. The crc should be initialized to zero. Pre- and - post-conditioning (one's complement) is performed within this - function so it shouldn't be done by the caller. Usage example: - - unsigned long crc = 0L; - - while (read_buffer(buffer, length) != EOF) { - crc = update_crc(crc, buffer, length); - } - if (crc != original_crc) error(); -*/ -uint32_t update_crc(uint32_t crc, uint8_t *buf, int len) -{ - unsigned long c = crc ^ 0xffffffffL; - int n; - - if (!crc_table_computed) - make_crc_table(); - for (n = 0; n < len; n++) { - c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8); - } - return c ^ 0xffffffffL; -} - -/* Return the CRC of the bytes buf[0..len-1]. */ -unsigned long crc(unsigned char *buf, int len) -{ - return update_crc(0L, buf, len); -} diff --git a/projects/cli-test/filetransfer b/projects/cli-test/filetransfer index f704e31..6e58781 100755 --- a/projects/cli-test/filetransfer +++ b/projects/cli-test/filetransfer @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # # Copyright (c) 2016, NORDUnet A/S All rights reserved. # @@ -37,7 +37,7 @@ import struct import serial import argparse -from binascii import crc32 +from binascii import crc32, hexlify CHUNK_SIZE = 256 DFU_CHUNK_SIZE = 256 @@ -79,19 +79,19 @@ def parse_args(): def _write(dst, data): dst.write(data) if len(data) == 4: - print("Wrote 0x{!s}".format(data.encode('hex'))) + print(("Wrote 0x{!s}".format(hexlify(data).decode("ascii")))) else: - print("Wrote {!r}".format(data)) + print(("Wrote {!r}".format(data))) def _read(dst): - res = '' + res = b'' while True: x = dst.read(1) if not x: break res += x - print ("Read {!r}".format(res)) + print(("Read {!r}".format(res))) return res @@ -142,19 +142,19 @@ def send_file(filename, args, dst): if not data: break dst.write(data) - print("Wrote {!s} bytes (chunk {!s}/{!s})".format(len(data), counter, int(size / chunk_size))) + print(("Wrote {!s} bytes (chunk {!s}/{!s})".format(len(data), counter, int(size / chunk_size)))) # read ACK (a counter of number of 4k chunks received) while True: ack_bytes = dst.read(4) if len(ack_bytes) == 4: break - print('ERROR: Did not receive an ACK, got {!r}'.format(ack_bytes)) + print(('ERROR: Did not receive an ACK, got {!r}'.format(ack_bytes))) dst.write('\r') # eventually get back to the CLI prompt ack = struct.unpack('<I', ack_bytes)[0] if ack != counter + 1: - print('ERROR: Did not receive the expected counter as ACK (got {!r}/{!r}, not {!r})'.format(ack, ack_bytes, counter)) + print(('ERROR: Did not receive the expected counter as ACK (got {!r}/{!r}, not {!r})'.format(ack, ack_bytes, counter))) flush = dst.read(100) - print('FLUSH data: {!r}'.format(flush)) + print(('FLUSH data: {!r}'.format(flush))) return False counter += 1 diff --git a/projects/cli-test/mgmt-cli.c b/projects/cli-test/mgmt-cli.c index 3b4ffe9..960d691 100644 --- a/projects/cli-test/mgmt-cli.c +++ b/projects/cli-test/mgmt-cli.c @@ -3,7 +3,9 @@ * --------- * Management CLI code. * - * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * Copyright (c) 2016-2017, NORDUnet A/S All rights reserved. + * Copyright: 2020, The Commons Conservancy Cryptech Project + * SPDX-License-Identifier: BSD-3-Clause * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -15,9 +17,9 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * - Neither the name of the NORDUnet nor the names of its contributors may - * be used to endorse or promote products derived from this software - * without specific prior written permission. + * - Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED @@ -31,140 +33,166 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +#include <string.h> + +/* Rename both CMSIS HAL_OK and libhal HAL_OK to disambiguate */ +#define HAL_OK CMSIS_HAL_OK #include "stm-init.h" #include "stm-uart.h" #include "stm-led.h" + #include "mgmt-cli.h" +#include "mgmt-fpga.h" +#include "mgmt-misc.h" +#include "mgmt-show.h" +#include "mgmt-test.h" +#include "mgmt-keystore.h" +#include "mgmt-masterkey.h" +#ifdef DO_TIMING +#include "mgmt-timing.h" +#endif + +#undef HAL_OK +#define HAL_OK LIBHAL_OK +#include "hal.h" +#undef HAL_OK + +#ifndef CLI_UART_RECVBUF_SIZE +#define CLI_UART_RECVBUF_SIZE 256 +#endif + +typedef struct { + unsigned ridx; + unsigned widx; + mgmt_cli_dma_state_t rx_state; + uint8_t buf[CLI_UART_RECVBUF_SIZE]; +} ringbuf_t; -#include <string.h> +inline void ringbuf_init(ringbuf_t *rb) +{ + memset(rb, 0, sizeof(*rb)); +} -extern uint8_t uart_rx; +/* return number of characters read */ +inline int ringbuf_read_char(ringbuf_t *rb, uint8_t *c) +{ + if (rb->ridx != rb->widx) { + *c = rb->buf[rb->ridx]; + if (++rb->ridx >= sizeof(rb->buf)) + rb->ridx = 0; + return 1; + } + return 0; +} -struct uart_ringbuf_t { - uint32_t enabled, ridx; - enum mgmt_cli_dma_state rx_state; - uint8_t buf[CLI_UART_RECVBUF_SIZE]; -}; +inline void ringbuf_write_char(ringbuf_t *rb, uint8_t c) +{ + rb->buf[rb->widx] = c; + if (++rb->widx >= sizeof(rb->buf)) + rb->widx = 0; +} + +static ringbuf_t uart_ringbuf; -volatile struct uart_ringbuf_t uart_ringbuf = {1, 0, DMA_RX_STOP, {0}}; +/* current character received from UART */ +static uint8_t uart_rx; -#define RINGBUF_RIDX(rb) (rb.ridx & CLI_UART_RECVBUF_MASK) -#define RINGBUF_WIDX(rb) (sizeof(rb.buf) - __HAL_DMA_GET_COUNTER(huart_mgmt.hdmarx)) -#define RINGBUF_COUNT(rb) ((unsigned)(RINGBUF_WIDX(rb) - RINGBUF_RIDX(rb))) -#define RINGBUF_READ(rb, dst) {dst = rb.buf[RINGBUF_RIDX(rb)]; rb.buf[RINGBUF_RIDX(rb)] = '.'; rb.ridx++;} +/* Callback for HAL_UART_Receive_DMA(). + */ +void HAL_UART1_RxCpltCallback(UART_HandleTypeDef *huart) +{ + huart = huart; -void uart_cli_print(struct cli_def *cli __attribute__ ((unused)), const char *buf) + ringbuf_write_char(&uart_ringbuf, uart_rx); +} + +static void uart_cli_print(struct cli_def *cli __attribute__ ((unused)), const char *buf) { - char crlf[] = "\r\n"; - uart_send_string2(STM_UART_MGMT, buf); - uart_send_string2(STM_UART_MGMT, crlf); + uart_send_string(buf); + uart_send_string("\r\n"); } -int uart_cli_read(struct cli_def *cli __attribute__ ((unused)), void *buf, size_t count) +static ssize_t uart_cli_read(struct cli_def *cli __attribute__ ((unused)), void *buf, size_t count) { - uint32_t timeout = 0xffffff; - while (count && timeout) { - if (RINGBUF_COUNT(uart_ringbuf)) { - RINGBUF_READ(uart_ringbuf, *(uint8_t *) buf); - buf++; - count--; + for (size_t i = 0; i < count; ++i) { + while (ringbuf_read_char(&uart_ringbuf, (uint8_t *)(buf + i)) == 0) { } - timeout--; } - if (! timeout) return 0; - - return 1; + return (ssize_t)count; } -int uart_cli_write(struct cli_def *cli __attribute__ ((unused)), const void *buf, size_t count) +static ssize_t uart_cli_write(struct cli_def *cli __attribute__ ((unused)), const void *buf, size_t count) { - uart_send_bytes(STM_UART_MGMT, (uint8_t *) buf, count); - return (int) count; + uart_send_bytes((uint8_t *) buf, count); + return (ssize_t)count; } -int control_mgmt_uart_dma_rx(enum mgmt_cli_dma_state state) +int control_mgmt_uart_dma_rx(mgmt_cli_dma_state_t state) { if (state == DMA_RX_START) { if (uart_ringbuf.rx_state != DMA_RX_START) { - memset((void *) uart_ringbuf.buf, 0, sizeof(uart_ringbuf.buf)); - - /* Start receiving data from the UART using DMA */ - HAL_UART_Receive_DMA(&huart_mgmt, (uint8_t *) uart_ringbuf.buf, sizeof(uart_ringbuf.buf)); - uart_ringbuf.ridx = 0; + ringbuf_init(&uart_ringbuf); + HAL_UART_Receive_DMA(&huart_mgmt, &uart_rx, 1); uart_ringbuf.rx_state = DMA_RX_START; } return 1; } else if (state == DMA_RX_STOP) { - if (HAL_UART_DMAStop(&huart_mgmt) != HAL_OK) return 0; + if (HAL_UART_DMAStop(&huart_mgmt) != CMSIS_HAL_OK) return 0; uart_ringbuf.rx_state = DMA_RX_STOP; return 1; } return 0; } -int embedded_cli_loop(struct cli_def *cli) +static struct cli_def *mgmt_cli_init(void) { - unsigned char c; - int n = 0; - static struct cli_loop_ctx ctx; - - memset(&ctx, 0, sizeof(ctx)); - ctx.insertmode = 1; + struct cli_def *cli; + cli = cli_init(); + cli_read_callback(cli, uart_cli_read); + cli_write_callback(cli, uart_cli_write); + cli_print_callback(cli, uart_cli_print); + cli_set_banner(cli, "Cryptech Alpha test CLI"); + cli_set_hostname(cli, "cryptech"); + return cli; +} - cli->state = CLI_STATE_LOGIN; +hal_user_t user; - /* start off in unprivileged mode */ - cli_set_privilege(cli, PRIVILEGE_UNPRIVILEGED); - cli_set_configmode(cli, MODE_EXEC, NULL); +static int check_auth(const char *username, const char *password) +{ + if (strcmp(username, "ct") != 0) + return CLI_ERROR; + if (strcmp(password, "ct") != 0) + return CLI_ERROR; + return CLI_OK; +} - cli_error(cli, "%s", cli->banner); +int cli_main(void) +{ + struct cli_def *cli; + cli = mgmt_cli_init(); + cli_set_auth_callback(cli, check_auth); + + configure_cli_show(cli); + configure_cli_fpga(cli); + configure_cli_misc(cli); + configure_cli_keystore(cli); + configure_cli_masterkey(cli); +#ifdef DO_TIMING + configure_cli_timing(cli); +#endif while (1) { - cli_loop_start_new_command(cli, &ctx); - - control_mgmt_uart_dma_rx(DMA_RX_START); - - while (1) { - cli_loop_show_prompt(cli, &ctx); - - n = cli_loop_read_next_char(cli, &ctx, &c); - - /* - cli_print(cli, "Next char: '%c'/%i, ringbuf ridx %i, widx %i", - c, (int) c, - uart_ringbuf.ridx, - RINGBUF_WIDX(uart_ringbuf) - */ - if (n == CLI_LOOP_CTRL_BREAK) - break; - if (n == CLI_LOOP_CTRL_CONTINUE) - continue; - - n = cli_loop_process_char(cli, &ctx, c); - if (n == CLI_LOOP_CTRL_BREAK) - break; - if (n == CLI_LOOP_CTRL_CONTINUE) - continue; - } - - if (ctx.l < 0) break; + control_mgmt_uart_dma_rx(DMA_RX_START); - /* cli_print(cli, "Process command: '%s'", ctx.cmd); */ - n = cli_loop_process_cmd(cli, &ctx); - if (n == CLI_LOOP_CTRL_BREAK) - break; + cli_loop(cli, 0); + /* cli_loop returns when the user enters 'quit' or 'exit' */ + cli_print(cli, "\nLogging out...\n"); + user = HAL_USER_NONE; } - return CLI_OK; + /*NOTREACHED*/ + return -1; } -void mgmt_cli_init(struct cli_def *cli) -{ - cli_init(cli); - cli_read_callback(cli, uart_cli_read); - cli_write_callback(cli, uart_cli_write); - cli_print_callback(cli, uart_cli_print); - cli_set_banner(cli, "Cryptech Alpha"); - cli_set_hostname(cli, "cryptech"); - cli_telnet_protocol(cli, 0); -} diff --git a/projects/cli-test/mgmt-cli.h b/projects/cli-test/mgmt-cli.h index 16c9fbd98..0b9c40c 100644 --- a/projects/cli-test/mgmt-cli.h +++ b/projects/cli-test/mgmt-cli.h @@ -35,52 +35,15 @@ #ifndef __STM32_MGMT_CLI_H #define __STM32_MGMT_CLI_H -#include "stm-init.h" #include <libcli.h> - -/* A bunch of defines to make it easier to add/maintain the CLI commands. - * - */ -#define _cli_cmd_struct(name, fullname, func, help) \ - static struct cli_command cmd_##fullname##_s = \ - {(char *) #name, func, 0, help, \ - PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL, NULL, NULL} - -/* ROOT is a top-level label with no command */ -#define cli_command_root(name) \ - _cli_cmd_struct(name, name, NULL, NULL); \ - cli_register_command2(cli, &cmd_##name##_s, NULL) - -/* BRANCH is a label with a parent, but no command */ -#define cli_command_branch(parent, name) \ - _cli_cmd_struct(name, parent##_##name, NULL, NULL); \ - cli_register_command2(cli, &cmd_##parent##_##name##_s, &cmd_##parent##_s) - -/* NODE is a label with a parent and with a command associated with it */ -#define cli_command_node(parent, name, help) \ - _cli_cmd_struct(name, parent##_##name, cmd_##parent##_##name, (char *) help); \ - cli_register_command2(cli, &cmd_##parent##_##name##_s, &cmd_##parent##_s) - -/* ROOT NODE is a label without a parent, but with a command associated with it */ -#define cli_command_root_node(name, help) \ - _cli_cmd_struct(name, name, cmd_##name, (char *) help); \ - cli_register_command2(cli, &cmd_##name##_s, NULL) - - -#define CLI_UART_RECVBUF_SIZE 256 /* This must be a power of 2 */ -#define CLI_UART_RECVBUF_MASK (CLI_UART_RECVBUF_SIZE - 1) - -enum mgmt_cli_dma_state { +typedef enum { DMA_RX_STOP, DMA_RX_START, -}; +} mgmt_cli_dma_state_t; + +extern int control_mgmt_uart_dma_rx(mgmt_cli_dma_state_t state); -extern void uart_cli_print(struct cli_def *cli __attribute__ ((unused)), const char *buf); -extern int uart_cli_read(struct cli_def *cli __attribute__ ((unused)), void *buf, size_t count); -extern int uart_cli_write(struct cli_def *cli __attribute__ ((unused)), const void *buf, size_t count); -extern int embedded_cli_loop(struct cli_def *cli); -extern void mgmt_cli_init(struct cli_def *cli); -extern int control_mgmt_uart_dma_rx(enum mgmt_cli_dma_state state); +extern int cli_main(void); #endif /* __STM32_MGMT_CLI_H */ diff --git a/projects/cli-test/mgmt-dfu.c b/projects/cli-test/mgmt-dfu.c index 27fd722..c7273f4 100644 --- a/projects/cli-test/mgmt-dfu.c +++ b/projects/cli-test/mgmt-dfu.c @@ -40,7 +40,10 @@ #include <string.h> -extern uint32_t update_crc(uint32_t crc, uint8_t *buf, int len); +#define DFU_FIRMWARE_ADDR ((uint32_t) &CRYPTECH_FIRMWARE_START) +#define DFU_FIRMWARE_END_ADDR ((uint32_t) &CRYPTECH_FIRMWARE_END) +#define DFU_UPLOAD_CHUNK_SIZE 256 +#define HARDWARE_EARLY_DFU_JUMP 0xBADABADA /* Linker symbols are strange in C. Make regular pointers for sanity. */ __IO uint32_t *dfu_control = &CRYPTECH_DFU_CONTROL; @@ -53,25 +56,29 @@ __IO uint32_t *dfu_msp_ptr = &CRYPTECH_FIRMWARE_START; */ __IO uint32_t *dfu_code_ptr = &CRYPTECH_FIRMWARE_START + 1; - - -int cmd_dfu_dump(struct cli_def *cli, const char *command, char *argv[], int argc) +static int cmd_dfu_dump(struct cli_def *cli, const char *command, char *argv[], int argc) { + command = command; + argv = argv; + argc = argc; + cli_print(cli, "First 256 bytes from DFU application address %p:\r\n", dfu_firmware); - uart_send_hexdump(STM_UART_MGMT, (uint8_t *) dfu_firmware, 0, 0xff); - uart_send_string2(STM_UART_MGMT, (char *) "\r\n\r\n"); + uart_send_hexdump((uint8_t *) dfu_firmware, 0, 0xff); + cli_print(cli, "\n"); return CLI_OK; } -int cmd_dfu_erase(struct cli_def *cli, const char *command, char *argv[], int argc) +static int cmd_dfu_erase(struct cli_def *cli, const char *command, char *argv[], int argc) { int status; - cli_print(cli, "Erasing flash sectors %i to %i (address %p to %p) - expect the CLI to crash now", - stm_flash_sector_num((uint32_t) dfu_firmware), - stm_flash_sector_num((uint32_t) dfu_firmware_end), + command = command; + argv = argv; + argc = argc; + + cli_print(cli, "Erasing flash address %p to %p - expect the CLI to crash now", dfu_firmware, dfu_firmware_end); @@ -82,9 +89,14 @@ int cmd_dfu_erase(struct cli_def *cli, const char *command, char *argv[], int ar return CLI_OK; } -int cmd_dfu_jump(struct cli_def *cli, const char *command, char *argv[], int argc) +static int cmd_dfu_jump(struct cli_def *cli, const char *command, char *argv[], int argc) { uint32_t i; + + command = command; + argv = argv; + argc = argc; + /* Load first byte from the DFU_FIRMWARE_PTR to verify it contains an IVT before * jumping there. */ @@ -112,9 +124,11 @@ int cmd_dfu_jump(struct cli_def *cli, const char *command, char *argv[], int arg void configure_cli_dfu(struct cli_def *cli) { - cli_command_root(dfu); + struct cli_command *c; + + c = cli_register_command(cli, NULL, "dfu", NULL, 0, 0, NULL); - cli_command_node(dfu, dump, "Show the first 256 bytes of the loaded firmware"); - cli_command_node(dfu, jump, "Jump to the loaded firmware"); - cli_command_node(dfu, erase, "Erase the firmware memory (will crash the CLI)"); + cli_register_command(cli, c, "dump", cmd_dfu_dump, 0, 0, "Show the first 256 bytes of the loaded firmware"); + cli_register_command(cli, c, "jump", cmd_dfu_jump, 0, 0, "Jump to the loaded firmware"); + cli_register_command(cli, c, "erase", cmd_dfu_erase, 0, 0, "Erase the firmware memory (will crash the CLI)"); } diff --git a/projects/cli-test/mgmt-dfu.h b/projects/cli-test/mgmt-dfu.h index ac6589c..6128b35 100644 --- a/projects/cli-test/mgmt-dfu.h +++ b/projects/cli-test/mgmt-dfu.h @@ -35,7 +35,6 @@ #ifndef __STM32_CLI_MGMT_DFU_H #define __STM32_CLI_MGMT_DFU_H -#include "stm-init.h" #include <libcli.h> /* symbols defined in the linker script (STM32F429BI.ld) */ @@ -43,17 +42,6 @@ extern uint32_t CRYPTECH_FIRMWARE_START; extern uint32_t CRYPTECH_FIRMWARE_END; extern uint32_t CRYPTECH_DFU_CONTROL; -#define DFU_FIRMWARE_ADDR ((uint32_t) &CRYPTECH_FIRMWARE_START) -#define DFU_FIRMWARE_END_ADDR ((uint32_t) &CRYPTECH_FIRMWARE_END) -#define DFU_UPLOAD_CHUNK_SIZE 256 -#define HARDWARE_EARLY_DFU_JUMP 0xBADABADA - -extern __IO uint32_t *dfu_control; -extern __IO uint32_t *dfu_firmware; -extern __IO uint32_t *dfu_msp_ptr; -extern __IO uint32_t *dfu_code_ptr; - - extern void configure_cli_dfu(struct cli_def *cli); #endif /* __STM32_CLI_MGMT_DFU_H */ diff --git a/projects/cli-test/mgmt-fpga.c b/projects/cli-test/mgmt-fpga.c index 8c1b2a8..b913316 100644 --- a/projects/cli-test/mgmt-fpga.c +++ b/projects/cli-test/mgmt-fpga.c @@ -3,7 +3,7 @@ * ----------- * CLI code to manage the FPGA configuration etc. * - * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * Copyright (c) 2016-2017, NORDUnet A/S All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -43,25 +43,43 @@ #include <string.h> -volatile uint32_t dfu_offset = 0; +static volatile uint32_t dfu_offset = 0; -int _flash_write_callback(uint8_t *buf, size_t len) { - int res = fpgacfg_write_data(dfu_offset, buf, BITSTREAM_UPLOAD_CHUNK_SIZE) == 1; + +static HAL_StatusTypeDef _flash_write_callback(uint8_t *buf, size_t len) +{ + HAL_StatusTypeDef res; + + if ((dfu_offset % FPGACFG_SECTOR_SIZE) == 0) + /* first page in sector, need to erase sector */ + if ((res = fpgacfg_erase_sector(dfu_offset / FPGACFG_SECTOR_SIZE)) != HAL_OK) + return res; + + /* fpgacfg_write_data (a thin wrapper around n25q128_write_data) + * requires the offset and length to be page-aligned. The last chunk + * will be short, so we pad it out to the full chunk size. + */ + len = len; + res = fpgacfg_write_data(dfu_offset, buf, BITSTREAM_UPLOAD_CHUNK_SIZE); dfu_offset += BITSTREAM_UPLOAD_CHUNK_SIZE; return res; } -int cmd_fpga_bitstream_upload(struct cli_def *cli, const char *command, char *argv[], int argc) +static int cmd_fpga_bitstream_upload(struct cli_def *cli, const char *command, char *argv[], int argc) { uint8_t buf[BITSTREAM_UPLOAD_CHUNK_SIZE]; + command = command; + argv = argv; + argc = argc; + dfu_offset = 0; fpgacfg_access_control(ALLOW_ARM); cli_print(cli, "Checking if FPGA config memory is accessible"); - if (fpgacfg_check_id() != 1) { + if (fpgacfg_check_id() != HAL_OK) { cli_print(cli, "ERROR: FPGA config memory not accessible. Check that jumpers JP7 and JP8 are installed."); return CLI_ERROR; } @@ -74,12 +92,16 @@ int cmd_fpga_bitstream_upload(struct cli_def *cli, const char *command, char *ar return CLI_OK; } -int cmd_fpga_bitstream_erase(struct cli_def *cli, const char *command, char *argv[], int argc) +static int cmd_fpga_bitstream_erase(struct cli_def *cli, const char *command, char *argv[], int argc) { + command = command; + argv = argv; + argc = argc; + fpgacfg_access_control(ALLOW_ARM); cli_print(cli, "Checking if FPGA config memory is accessible"); - if (fpgacfg_check_id() != 1) { + if (fpgacfg_check_id() != HAL_OK) { cli_print(cli, "ERROR: FPGA config memory not accessible. Check that jumpers JP7 and JP8 are installed."); return CLI_ERROR; } @@ -90,7 +112,7 @@ int cmd_fpga_bitstream_erase(struct cli_def *cli, const char *command, char *arg * * This command could be made to accept an argument indicating the whole memory should be erased. */ - if (! fpgacfg_erase_sectors(1)) { + if (fpgacfg_erase_sector(0) != HAL_OK) { cli_print(cli, "Erasing first sector in FPGA config memory failed"); return CLI_ERROR; } @@ -101,8 +123,12 @@ int cmd_fpga_bitstream_erase(struct cli_def *cli, const char *command, char *arg return CLI_OK; } -int cmd_fpga_reset(struct cli_def *cli, const char *command, char *argv[], int argc) +static int cmd_fpga_reset(struct cli_def *cli, const char *command, char *argv[], int argc) { + command = command; + argv = argv; + argc = argc; + fpgacfg_access_control(ALLOW_FPGA); fpgacfg_reset_fpga(RESET_FULL); cli_print(cli, "FPGA has been reset"); @@ -110,8 +136,12 @@ int cmd_fpga_reset(struct cli_def *cli, const char *command, char *argv[], int a return CLI_OK; } -int cmd_fpga_reset_registers(struct cli_def *cli, const char *command, char *argv[], int argc) +static int cmd_fpga_reset_registers(struct cli_def *cli, const char *command, char *argv[], int argc) { + command = command; + argv = argv; + argc = argc; + fpgacfg_access_control(ALLOW_FPGA); fpgacfg_reset_fpga(RESET_REGISTERS); cli_print(cli, "FPGA registers have been reset"); @@ -121,16 +151,19 @@ int cmd_fpga_reset_registers(struct cli_def *cli, const char *command, char *arg void configure_cli_fpga(struct cli_def *cli) { - /* fpga */ - cli_command_root(fpga); + struct cli_command *c = cli_register_command(cli, NULL, "fpga", NULL, 0, 0, NULL); + /* fpga reset */ - cli_command_node(fpga, reset, "Reset FPGA (config reset)"); + struct cli_command *c_reset = cli_register_command(cli, c, "reset", cmd_fpga_reset, 0, 0, "Reset FPGA (config reset)"); + /* fpga reset registers */ - cli_command_node(fpga_reset, registers, "Reset FPGA registers (soft reset)"); + cli_register_command(cli, c_reset, "registers", cmd_fpga_reset_registers, 0, 0, "Reset FPGA registers (soft reset)"); + + struct cli_command *c_bitstream = cli_register_command(cli, c, "bitstream", NULL, 0, 0, NULL); - cli_command_branch(fpga, bitstream); /* fpga bitstream upload */ - cli_command_node(fpga_bitstream, upload, "Upload new FPGA bitstream"); + cli_register_command(cli, c_bitstream, "upload", cmd_fpga_bitstream_upload, 0, 0, "Upload new FPGA bitstream"); + /* fpga bitstream erase */ - cli_command_node(fpga_bitstream, erase, "Erase FPGA config memory"); + cli_register_command(cli, c_bitstream, "erase", cmd_fpga_bitstream_erase, 0, 0, "Erase FPGA config memory"); } diff --git a/projects/cli-test/mgmt-fpga.h b/projects/cli-test/mgmt-fpga.h index ce185de..9d0aedc 100644 --- a/projects/cli-test/mgmt-fpga.h +++ b/projects/cli-test/mgmt-fpga.h @@ -35,7 +35,6 @@ #ifndef __STM32_CLI_MGMT_FPGA_H #define __STM32_CLI_MGMT_FPGA_H -#include "stm-init.h" #include <libcli.h> diff --git a/projects/cli-test/mgmt-keystore.c b/projects/cli-test/mgmt-keystore.c new file mode 100644 index 0000000..6d0d38d --- /dev/null +++ b/projects/cli-test/mgmt-keystore.c @@ -0,0 +1,412 @@ +/* + * mgmt-keystore.c + * --------------- + * CLI 'keystore' commands. + * + * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Rename both CMSIS HAL_OK and libhal HAL_OK to disambiguate */ + +#define HAL_OK CMSIS_HAL_OK +#include "stm-init.h" +#include "stm-keystore.h" +#include "stm-fpgacfg.h" +#include "stm-uart.h" +#include "mgmt-cli.h" +#include "mgmt-show.h" +#undef HAL_OK + +#define HAL_OK LIBHAL_OK +#include "hal.h" +#warning Really should not be including hal_internal.h here, fix API instead of bypassing it +#include "hal_internal.h" +#undef HAL_OK + +#include <stdlib.h> +#include <string.h> + + +static int cmd_keystore_set_pin(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + hal_user_t user; + hal_error_t status; + hal_client_handle_t client = { -1 }; + + command = command; + + if (argc != 2) { + cli_print(cli, "Wrong number of arguments (%i).", argc); + cli_print(cli, "Syntax: keystore set pin <user|so|wheel> <pin>"); + return CLI_ERROR; + } + + if (!strcmp(argv[0], "user")) + user = HAL_USER_NORMAL; + else if (!strcmp(argv[0], "so")) + user = HAL_USER_SO; + else if (!strcmp(argv[0], "wheel")) + user = HAL_USER_WHEEL; + else { + cli_print(cli, "First argument must be 'user', 'so' or 'wheel' - not '%s'", argv[0]); + return CLI_ERROR; + } + + status = hal_rpc_set_pin(client, user, argv[1], strlen(argv[1])); + if (status != LIBHAL_OK) { + cli_print(cli, "Failed setting PIN: %s", hal_error_string(status)); + return CLI_ERROR; + } + + return CLI_OK; +} + +static int cmd_keystore_clear_pin(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + hal_user_t user; + hal_error_t status; + hal_client_handle_t client = { -1 }; + + command = command; + + if (argc != 1) { + cli_print(cli, "Wrong number of arguments (%i).", argc); + cli_print(cli, "Syntax: keystore clear pin <user|so|wheel>"); + return CLI_ERROR; + } + + if (!strcmp(argv[0], "user")) + user = HAL_USER_NORMAL; + else if (!strcmp(argv[0], "so")) + user = HAL_USER_SO; + else if (!strcmp(argv[0], "wheel")) + user = HAL_USER_WHEEL; + else { + cli_print(cli, "First argument must be 'user', 'so' or 'wheel' - not '%s'", argv[0]); + return CLI_ERROR; + } + + status = hal_rpc_set_pin(client, user, "", 0); + if (status != LIBHAL_OK) { + cli_print(cli, "Failed setting PIN: %s", hal_error_string(status)); + return CLI_ERROR; + } + + return CLI_OK; +} + +static int cmd_keystore_set_pin_iterations(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + hal_error_t status; + hal_client_handle_t client = { -1 }; + + command = command; + + if (argc != 1) { + cli_print(cli, "Wrong number of arguments (%i).", argc); + cli_print(cli, "Syntax: keystore set pin iterations <number>"); + return CLI_ERROR; + } + + status = hal_set_pin_default_iterations(client, strtoul(argv[0], NULL, 0)); + if (status != LIBHAL_OK) { + cli_print(cli, "Failed setting iterations: %s", hal_error_string(status)); + return CLI_ERROR; + } + + return CLI_OK; +} + +/* + * This is badly broken under either old or new keystore API: + * + * + DER is a binary format, it's not safe to read it this way, + * and strlen() will not do what anybody wants; + * + * + As written, this stores an EC public key on no known curve, + * ie, useless nonsense. + * + * The usual text format for DER objects is Base64, often with + * so-called "PEM" header and footer lines. Key type, curve, etcetera + * would be extra command line parameters. + */ +#if 0 +static int cmd_keystore_set_key(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + hal_error_t status; + int hint = 0; + + command = command; + + if (argc != 2) { + cli_print(cli, "Wrong number of arguments (%i).", argc); + cli_print(cli, "Syntax: keystore set key <name> <der>"); + return CLI_ERROR; + } + + if ((status = hal_ks_store(HAL_KEY_TYPE_EC_PUBLIC, + HAL_CURVE_NONE, + 0, + (uint8_t *) argv[0], strlen(argv[0]), + (uint8_t *) argv[1], strlen(argv[1]), + &hint)) != LIBHAL_OK) { + + cli_print(cli, "Failed storing key: %s", hal_error_string(status)); + return CLI_ERROR; + } + + cli_print(cli, "Stored key %i", hint); + + return CLI_OK; +} +#endif /* 0 */ + +static int cmd_keystore_delete_key(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + const hal_client_handle_t client = { HAL_HANDLE_NONE }; + const hal_session_handle_t session = { HAL_HANDLE_NONE }; + hal_pkey_handle_t pkey = { HAL_HANDLE_NONE }; + hal_error_t status; + hal_uuid_t name; + + command = command; + + if (argc != 1) { + cli_print(cli, "Wrong number of arguments (%i).", argc); + cli_print(cli, "Syntax: keystore delete key <name>"); + return CLI_ERROR; + } + + if ((status = hal_uuid_parse(&name, argv[0])) != LIBHAL_OK) { + cli_print(cli, "Couldn't parse key name: %s", hal_error_string(status)); + return CLI_ERROR; + } + + if ((status = hal_rpc_pkey_open(client, session, &pkey, &name)) != LIBHAL_OK || + (status = hal_rpc_pkey_delete(pkey)) != LIBHAL_OK) { + cli_print(cli, "Failed deleting key: %s", hal_error_string(status)); + return CLI_ERROR; + } + + cli_print(cli, "Deleted key %s", argv[0]); + + return CLI_OK; +} + +static int cmd_keystore_show_data(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + uint8_t buf[KEYSTORE_PAGE_SIZE]; + uint32_t i; + + command = command; + argv = argv; + argc = argc; + + if (keystore_check_id() != CMSIS_HAL_OK) { + cli_print(cli, "ERROR: The keystore memory is not accessible."); + } + + memset(buf, 0, sizeof(buf)); + if ((i = keystore_read_data(0, buf, sizeof(buf))) != CMSIS_HAL_OK) { + cli_print(cli, "Failed reading first page from keystore memory: %li", i); + return CLI_ERROR; + } + + cli_print(cli, "First page from keystore memory:\r\n"); + uart_send_hexdump(buf, 0, sizeof(buf) - 1); + cli_print(cli, "\n"); + + return CLI_OK; +} + +static int show_keys(struct cli_def *cli, const char *title) +{ + const hal_client_handle_t client = { -1 }; + const hal_session_handle_t session = { HAL_HANDLE_NONE }; + char key_name[HAL_UUID_TEXT_SIZE]; + hal_uuid_t previous_uuid = {{0}}; + hal_pkey_handle_t pkey; + hal_curve_name_t curve; + hal_key_flags_t flags; + unsigned n, state = 0; + hal_key_type_t type; + hal_error_t status; + hal_uuid_t uuids[50]; + int done = 0; + + cli_print(cli, title); + + while (!done) { + + if ((status = hal_rpc_pkey_match(client, session, HAL_KEY_TYPE_NONE, HAL_CURVE_NONE, + 0, 0, NULL, 0, &state, uuids, &n, + sizeof(uuids)/sizeof(*uuids), + &previous_uuid)) != LIBHAL_OK) { + cli_print(cli, "Could not fetch UUID list: %s", hal_error_string(status)); + return 0; + } + + done = n < sizeof(uuids)/sizeof(*uuids); + + if (!done) + previous_uuid = uuids[sizeof(uuids)/sizeof(*uuids) - 1]; + + for (unsigned i = 0; i < n; i++) { + + if ((status = hal_uuid_format(&uuids[i], key_name, sizeof(key_name))) != LIBHAL_OK) { + cli_print(cli, "Could not convert key name: %s", + hal_error_string(status)); + return 0; + } + + if ((status = hal_rpc_pkey_open(client, session, &pkey, &uuids[i])) != LIBHAL_OK) { + cli_print(cli, "Could not open key %s: %s", + key_name, hal_error_string(status)); + return 0; + } + + if ((status = hal_rpc_pkey_get_key_type(pkey, &type)) != LIBHAL_OK || + (status = hal_rpc_pkey_get_key_curve(pkey, &curve)) != LIBHAL_OK || + (status = hal_rpc_pkey_get_key_flags(pkey, &flags)) != LIBHAL_OK) + cli_print(cli, "Could not fetch metadata for key %s: %s", + key_name, hal_error_string(status)); + + if (status == LIBHAL_OK) + status = hal_rpc_pkey_close(pkey); + else + (void) hal_rpc_pkey_close(pkey); + + if (status != LIBHAL_OK) + return 0; + + const char *type_name = "unknown"; + switch (type) { + case HAL_KEY_TYPE_NONE: type_name = "none"; break; + case HAL_KEY_TYPE_RSA_PRIVATE: type_name = "RSA private"; break; + case HAL_KEY_TYPE_RSA_PUBLIC: type_name = "RSA public"; break; + case HAL_KEY_TYPE_EC_PRIVATE: type_name = "EC private"; break; + case HAL_KEY_TYPE_EC_PUBLIC: type_name = "EC public"; break; + } + + const char *curve_name = "unknown"; + switch (curve) { + case HAL_CURVE_NONE: curve_name = "none"; break; + case HAL_CURVE_P256: curve_name = "P-256"; break; + case HAL_CURVE_P384: curve_name = "P-384"; break; + case HAL_CURVE_P521: curve_name = "P-521"; break; + } + + cli_print(cli, "Key %2i, name %s, type %s, curve %s, flags 0x%lx", + i, key_name, type_name, curve_name, (unsigned long) flags); + } + } + + return 1; +} + +static int cmd_keystore_show_keys(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + command = command; + argv = argv; + argc = argc; + + if (show_keys(cli, "Keystore:")) + return CLI_OK; + else + return CLI_ERROR; +} + +static int cmd_keystore_erase(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + hal_error_t err; + int status; + + command = command; + + if (argc != 1 || strcmp(argv[0], "YesIAmSure") != 0) { + cli_print(cli, "Syntax: keystore erase YesIAmSure"); + return CLI_ERROR; + } + + cli_print(cli, "OK, erasing keystore, this might take a while..."); + if ((status = keystore_erase_bulk()) != CMSIS_HAL_OK) { + cli_print(cli, "Failed erasing token keystore: %i", status); + return CLI_ERROR; + } + + if ((err = hal_ks_init(hal_ks_token, 0)) != LIBHAL_OK) { + cli_print(cli, "Failed to reinitialize token keystore: %s", hal_error_string(err)); + return CLI_ERROR; + } + + if ((err = hal_ks_init(hal_ks_volatile, 0)) != LIBHAL_OK) { + cli_print(cli, "Failed to reinitialize memory keystore: %s", hal_error_string(err)); + return CLI_ERROR; + } + + cli_print(cli, "Keystore erased"); + return CLI_OK; +} + +void configure_cli_keystore(struct cli_def *cli) +{ + struct cli_command *c = cli_register_command(cli, NULL, "keystore", NULL, 0, 0, NULL); + + struct cli_command *c_set = cli_register_command(cli, c, "set", NULL, 0, 0, NULL); + struct cli_command *c_clear = cli_register_command(cli, c, "clear", NULL, 0, 0, NULL); + struct cli_command *c_delete = cli_register_command(cli, c, "delete", NULL, 0, 0, NULL); + struct cli_command *c_show = cli_register_command(cli, c, "show", NULL, 0, 0, NULL); + + /* keystore erase */ + cli_register_command(cli, c, "erase", cmd_keystore_erase, 0, 0, "Erase the whole keystore"); + + /* keystore set pin */ + struct cli_command *c_set_pin = cli_register_command(cli, c_set, "pin", cmd_keystore_set_pin, 0, 0, "Set either 'wheel', 'user' or 'so' PIN"); + + /* keystore set pin iterations */ + cli_register_command(cli, c_set_pin, "iterations", cmd_keystore_set_pin_iterations, 0, 0, "Set PBKDF2 iterations for PINs"); + + /* keystore clear pin */ + cli_register_command(cli, c_clear, "pin", cmd_keystore_clear_pin, 0, 0, "Clear either 'wheel', 'user' or 'so' PIN"); + +#if 0 + /* keystore set key */ + cli_register_command(cli, c_set, "key", cmd_keystore_set_key, 0, 0, "Set a key"); +#endif + + /* keystore delete key */ + cli_register_command(cli, c_delete, "key", cmd_keystore_delete_key, 0, 0, "Delete a key"); + + /* keystore show data */ + cli_register_command(cli, c_show, "data", cmd_keystore_show_data, 0, 0, "Dump the first page from the keystore memory"); + + /* keystore show keys */ + cli_register_command(cli, c_show, "keys", cmd_keystore_show_keys, 0, 0, "Show what keys are in the keystore"); + +} diff --git a/projects/cli-test/mgmt-keystore.h b/projects/cli-test/mgmt-keystore.h new file mode 100644 index 0000000..9e14ac6 --- /dev/null +++ b/projects/cli-test/mgmt-keystore.h @@ -0,0 +1,42 @@ +/* + * mgmt-keystore.h + * ---------- + * Management CLI 'keystore' functions. + * + * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __STM32_CLI_MGMT_KEYSTORE_H +#define __STM32_CLI_MGMT_KEYSTORE_H + +#include <libcli.h> + +extern void configure_cli_keystore(struct cli_def *cli); + +#endif /* __STM32_CLI_MGMT_KEYSTORE_H */ diff --git a/projects/cli-test/mgmt-keywrap.c b/projects/cli-test/mgmt-keywrap.c new file mode 100644 index 0000000..7d3e219 --- /dev/null +++ b/projects/cli-test/mgmt-keywrap.c @@ -0,0 +1,316 @@ +/* + * mgmt-keywrap.h + * ----------- + * Management CLI functions related to AES keywrap + * + * Copyright (c) 2018, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define HAL_OK CMSIS_HAL_OK +#include "stm-init.h" +#include "stm-uart.h" +#include "mgmt-cli.h" +#include "mgmt-keywrap.h" +#undef HAL_OK + +#define HAL_OK LIBHAL_OK +#include "hal.h" +#include "hal_internal.h" +#undef HAL_OK + +#include <string.h> + +/* test vectors and test code are from test-aes-key-wrap.c */ + +/* + * Test cases from RFC 5649 all use a 192-bit key, which our AES + * implementation doesn't support, so had to write our own. + */ + +static const uint8_t Q[] = { /* Plaintext, 81 bytes */ + 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x21, 0x20, 0x20, 0x4d, 0x79, 0x20, 0x6e, + 0x61, 0x6d, 0x65, 0x20, 0x69, 0x73, 0x20, 0x49, 0x6e, 0x69, 0x67, 0x6f, + 0x20, 0x4d, 0x6f, 0x6e, 0x74, 0x6f, 0x79, 0x61, 0x2e, 0x20, 0x20, 0x59, + 0x6f, 0x75, 0x20, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x20, 0x6d, 0x79, 0x20, + 0x41, 0x45, 0x53, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x77, 0x72, 0x61, 0x70, + 0x70, 0x65, 0x72, 0x2e, 0x20, 0x20, 0x50, 0x72, 0x65, 0x70, 0x61, 0x72, + 0x65, 0x20, 0x74, 0x6f, 0x20, 0x64, 0x69, 0x65, 0x2e +}; + +static const uint8_t K_128[] = { /* 128-bit KEK, 16 bytes */ + 0xbc, 0x2a, 0xd8, 0x90, 0xd8, 0x91, 0x10, 0x65, 0xf0, 0x42, 0x10, 0x1b, + 0x4a, 0x6b, 0xaf, 0x99 +}; + +static const uint8_t K_256[] = { /* 256-bit KEK, 32 bytes */ + 0xe3, 0x97, 0x52, 0x81, 0x2b, 0x7e, 0xc2, 0xa4, 0x6a, 0xac, 0x50, 0x18, + 0x0d, 0x10, 0xc6, 0x85, 0x2c, 0xcf, 0x86, 0x0a, 0xa9, 0x4f, 0x69, 0xab, + 0x16, 0xa6, 0x4f, 0x3e, 0x96, 0xa0, 0xbd, 0x9e +}; + +static const uint8_t C_128[] = { /* Plaintext wrapped by 128-bit KEK, 96 bytes */ + 0xb0, 0x10, 0x91, 0x7b, 0xe7, 0x67, 0x9c, 0x10, 0x16, 0x64, 0xe7, 0x73, + 0xd2, 0x68, 0xba, 0xed, 0x8c, 0x50, 0x49, 0x80, 0x16, 0x2f, 0x4e, 0x97, + 0xe8, 0x45, 0x5c, 0x2f, 0x2b, 0x7a, 0x88, 0x0e, 0xd8, 0xef, 0xaa, 0x40, + 0xb0, 0x2e, 0xb4, 0x50, 0xe7, 0x60, 0xf7, 0xbb, 0xed, 0x56, 0x79, 0x16, + 0x65, 0xb7, 0x13, 0x9b, 0x4c, 0x66, 0x86, 0x5f, 0x4d, 0x53, 0x2d, 0xcd, + 0x83, 0x41, 0x01, 0x35, 0x0d, 0x06, 0x39, 0x4e, 0x9e, 0xfe, 0x68, 0xc5, + 0x2f, 0x37, 0x33, 0x99, 0xbb, 0x88, 0xf7, 0x76, 0x1e, 0x82, 0x48, 0xd6, + 0xa2, 0xf3, 0x9b, 0x92, 0x01, 0x65, 0xcb, 0x48, 0x36, 0xf5, 0x42, 0xd3 +}; + +static const uint8_t C_256[] = { /* Plaintext wrapped by 256-bit KEK, 96 bytes */ + 0x08, 0x00, 0xbc, 0x1b, 0x35, 0xe4, 0x2a, 0x69, 0x3f, 0x43, 0x07, 0x54, + 0x31, 0xba, 0xb6, 0x89, 0x7c, 0x64, 0x9f, 0x03, 0x84, 0xc4, 0x4a, 0x71, + 0xdb, 0xcb, 0xae, 0x55, 0x30, 0xdf, 0xb0, 0x2b, 0xc3, 0x91, 0x5d, 0x07, + 0xa9, 0x24, 0xdb, 0xe7, 0xbe, 0x4d, 0x0d, 0x62, 0xd4, 0xf8, 0xb1, 0x94, + 0xf1, 0xb9, 0x22, 0xb5, 0x94, 0xab, 0x7e, 0x0b, 0x15, 0x6a, 0xd9, 0x5f, + 0x6c, 0x20, 0xb7, 0x7e, 0x13, 0x19, 0xfa, 0xc4, 0x70, 0xec, 0x0d, 0xbd, + 0xf7, 0x01, 0xc6, 0xb3, 0x9a, 0x19, 0xaf, 0xf2, 0x47, 0x68, 0xea, 0x7e, + 0x97, 0x7e, 0x52, 0x2e, 0xd4, 0x03, 0x31, 0xcb, 0x22, 0xb6, 0xfe, 0xf5 +}; + +static int run_test(struct cli_def *cli, + const uint8_t * const K, const size_t K_len, + const uint8_t * const C, const size_t C_len) +{ +#define TC_BUFSIZE 96 /* sizeof(C) */ + const size_t Q_len = sizeof(Q); + uint8_t q[TC_BUFSIZE], c[TC_BUFSIZE]; + size_t q_len = sizeof(q), c_len = sizeof(c); + hal_error_t err; + int ok1 = 1, ok2 = 1; + + /* + * Wrap and compare results. + */ + + cli_print(cli, "Wrapping with %lu-bit KEK...", (unsigned long) K_len * 8); + if ((err = hal_aes_keywrap(NULL, K, K_len, Q, Q_len, c, &c_len)) != LIBHAL_OK) { + cli_print(cli, "Couldn't wrap with %lu-bit KEK: %s", + (unsigned long) K_len * 8, hal_error_string(err)); + ok1 = 0; + } + else if (C_len != c_len || memcmp(C, c, C_len) != 0) { + cli_print(cli, "Ciphertext mismatch:\n Want: "); + uart_send_hexdump(C, 0, C_len - 1); + cli_print(cli, "\n Got: "); + uart_send_hexdump(c, 0, c_len - 1); + cli_print(cli, ""); + ok1 = 0; + } + else { + cli_print(cli, "OK"); + } + + /* + * Unwrap and compare results. + */ + + cli_print(cli, "Unwrapping with %lu-bit KEK...", (unsigned long) K_len * 8); + if ((err = hal_aes_keyunwrap(NULL, K, K_len, C, C_len, q, &q_len)) != LIBHAL_OK) { + cli_print(cli, "Couldn't unwrap with %lu-bit KEK: %s", + (unsigned long) K_len * 8, hal_error_string(err)); + ok2 = 0; + } + else if (Q_len != q_len || memcmp(Q, q, Q_len) != 0) { + cli_print(cli, "Plaintext mismatch:\n Want: "); + uart_send_hexdump(Q, 0, Q_len - 1); + cli_print(cli, "\n Got: "); + uart_send_hexdump(q, 0, q_len - 1); + cli_print(cli, ""); + ok2 = 0; + } + else { + cli_print(cli, "OK"); + } + + return ok1 && ok2; +} + +static int cmd_keywrap_test(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + command = command; + + if (argc == 0) { + cli_print(cli, "1. Test vectors with software keywrap"); + hal_aes_use_keywrap_core(0); + run_test(cli, K_128, sizeof(K_128), C_128, sizeof(C_128)); + run_test(cli, K_256, sizeof(K_256), C_256, sizeof(C_256)); + + cli_print(cli, "\n2. Test vectors with keywrap core"); + if (hal_aes_use_keywrap_core(1) == 0) { + cli_print(cli, "keywrap core not found, skipping"); + } + else { + hal_aes_use_keywrap_core(1); + run_test(cli, K_128, sizeof(K_128), C_128, sizeof(C_128)); + run_test(cli, K_256, sizeof(K_256), C_256, sizeof(C_256)); + } + + cli_print(cli, "\nFor more tests: keywrap test <keysize> <iterations>"); + return CLI_OK; + } + + hal_error_t err; + + if (argc != 2) { + usage: + cli_print(cli, "Syntax: keywrap test <keysize> <iterations>"); + return CLI_ERROR; + } + + const int keysize = atoi(argv[0]); + const int iterations = atoi(argv[1]); + if (keysize <= 0 || iterations <= 0) + goto usage; + + uint8_t Q[keysize + 8]; size_t Q_len; + uint8_t C[keysize + 8]; size_t C_len; + memset(C, 0, sizeof(C)); + if ((err = hal_get_random(NULL, Q, keysize)) != LIBHAL_OK) { + cli_print(cli, "hal_get_random: %s", hal_error_string(err)); + return CLI_ERROR; + } + + cli_print(cli, "1. sanity test"); + C_len = sizeof(C); + if ((err = hal_aes_keywrap(NULL, K_256, sizeof(K_256), Q, keysize, C, &C_len)) != LIBHAL_OK) { + cli_print(cli, "hal_aes_keywrap: %s", hal_error_string(err)); + return CLI_ERROR; + } + + for (int i = 0; i <= 1; ++i) { + if (!hal_aes_use_keywrap_core(i) && i) { + cli_print(cli, "keywrap core not found, skipping"); + continue; + } + uint8_t q[keysize + 8]; + size_t q_len = sizeof(q); + if ((err = hal_aes_keyunwrap(NULL, K_256, sizeof(K_256), C, C_len, q, &q_len)) != LIBHAL_OK) { + cli_print(cli, "hal_aes_keyunwrap: %s", hal_error_string(err)); + return CLI_ERROR; + } + if (q_len != (size_t)keysize) { + cli_print(cli, "unwrap size mismatch: expected %d, got %d", (int)keysize, (int)q_len); + return CLI_ERROR; + } + if (memcmp(Q, q, q_len) != 0) { + cli_print(cli, "unwrap mismatch:\n Want: "); + uart_send_hexdump(Q, 0, Q_len - 1); + cli_print(cli, "\n Got: "); + uart_send_hexdump(q, 0, q_len - 1); + cli_print(cli, ""); + return CLI_ERROR; + } + cli_print(cli, "with %s: OK", i ? "keywrap core" : "software keywrap"); + } + + cli_print(cli, "\n2. wrap timing with software keywrap"); + + hal_aes_use_keywrap_core(0); + uint32_t start = HAL_GetTick(); + for (int i = 0; i < iterations; ++i) { + C_len = sizeof(C); + if ((err = hal_aes_keywrap(NULL, K_256, sizeof(K_256), Q, keysize, C, &C_len)) != LIBHAL_OK) { + cli_print(cli, "hal_aes_keywrap: %s", hal_error_string(err)); + return CLI_ERROR; + } + } + uint32_t elapsed = HAL_GetTick() - start; + uint32_t per = 1000 * elapsed / iterations; + cli_print(cli, "%ld.%03lds total, %ld.%03ldms per wrap", + elapsed / 1000, elapsed % 1000, per / 1000, per % 1000); + + cli_print(cli, "\n3. wrap timing with keywrap core"); + + if (hal_aes_use_keywrap_core(1) == 0) { + cli_print(cli, "keywrap core not found, skipping"); + } + else { + start = HAL_GetTick(); + for (int i = 0; i < iterations; ++i) { + C_len = sizeof(C); + if ((err = hal_aes_keywrap(NULL, K_256, sizeof(K_256), Q, keysize, C, &C_len)) != LIBHAL_OK) { + cli_print(cli, "hal_aes_keywrap: %s", hal_error_string(err)); + return CLI_ERROR; + } + } + elapsed = HAL_GetTick() - start; + per = 1000 * elapsed / iterations; + cli_print(cli, "%ld.%03lds total, %ld.%03ldms per wrap", + elapsed / 1000, elapsed % 1000, per / 1000, per % 1000); + } + + cli_print(cli, "\n4. unwrap timing with software keywrap"); + + hal_aes_use_keywrap_core(0); + start = HAL_GetTick(); + for (int i = 0; i < iterations; ++i) { + Q_len = sizeof(Q); + if ((err = hal_aes_keyunwrap(NULL, K_256, sizeof(K_256), C, C_len, Q, &Q_len)) != LIBHAL_OK) { + cli_print(cli, "hal_aes_keyunwrap: %s", hal_error_string(err)); + return CLI_ERROR; + } + } + elapsed = HAL_GetTick() - start; + per = 1000 * elapsed / iterations; + cli_print(cli, "%ld.%03lds total, %ld.%03ldms per wrap", + elapsed / 1000, elapsed % 1000, per / 1000, per % 1000); + + cli_print(cli, "\n5. unwrap timing with keywrap core"); + + if (hal_aes_use_keywrap_core(1) == 0) { + cli_print(cli, "keywrap core not found, skipping"); + } + else { + start = HAL_GetTick(); + for (int i = 0; i < iterations; ++i) { + Q_len = sizeof(Q); + if ((err = hal_aes_keyunwrap(NULL, K_256, sizeof(K_256), C, C_len, Q, &Q_len)) != LIBHAL_OK) { + cli_print(cli, "hal_aes_keywrap: %s", hal_error_string(err)); + return CLI_ERROR; + } + } + elapsed = HAL_GetTick() - start; + per = 1000 * elapsed / iterations; + cli_print(cli, "%ld.%03lds total, %ld.%03ldms per wrap", + elapsed / 1000, elapsed % 1000, per / 1000, per % 1000); + } + + return CLI_OK; +} + +void configure_cli_keywrap(struct cli_def *cli) +{ + struct cli_command *c_keywrap = cli_register_command(cli, NULL, "keywrap", NULL, 0, 0, NULL); + + /* keywrap test */ + cli_register_command(cli, c_keywrap, "test", cmd_keywrap_test, 0, 0, "Test the keywrap core"); +} diff --git a/projects/cli-test/mgmt-keywrap.h b/projects/cli-test/mgmt-keywrap.h new file mode 100644 index 0000000..a18aded --- /dev/null +++ b/projects/cli-test/mgmt-keywrap.h @@ -0,0 +1,42 @@ +/* + * mgmt-keywrap.h + * ----------- + * Management CLI functions related to AES keywrap + * + * Copyright (c) 2018, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __STM32_CLI_MGMT_KEYWRAP_H +#define __STM32_CLI_MGMT_KEYWRAP_H + +#include <libcli.h> + +extern void configure_cli_keywrap(struct cli_def *cli); + +#endif /* __STM32_CLI_MGMT_KEYWRAP_H */ diff --git a/projects/cli-test/mgmt-masterkey.c b/projects/cli-test/mgmt-masterkey.c new file mode 100644 index 0000000..811e15b --- /dev/null +++ b/projects/cli-test/mgmt-masterkey.c @@ -0,0 +1,225 @@ +/* + * mgmt-masterkey.c + * ---------------- + * Masterkey CLI functions. + * + * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Rename both CMSIS HAL_OK and libhal HAL_OK to disambiguate */ +#define HAL_OK CMSIS_HAL_OK +#include "stm-init.h" +#include "stm-uart.h" +#include "mgmt-cli.h" +#include "mgmt-masterkey.h" + +#undef HAL_OK +#define LIBHAL_OK HAL_OK +#include <hal.h> +#warning Refactor so we do not need to include hal_internal here +#include <hal_internal.h> +#undef HAL_OK + +#include <stdlib.h> + +static char * _status2str(const hal_error_t status) +{ + switch (status) { + case LIBHAL_OK: + return (char *) "Set"; + case HAL_ERROR_MASTERKEY_NOT_SET: + return (char *) "Not set"; + default: + return (char *) "Unknown"; + } +} + +static int _parse_hex_groups(uint8_t *buf, size_t len, char *argv[], int argc) +{ + int i; + uint32_t *dst = (uint32_t *) buf; + uint32_t *end = (uint32_t *) buf + len - 1; + char *err_ptr = NULL; + + if (! argc) return 0; + + for (i = 0; i < argc; i++) { + if (dst >= end) return -1; + *dst++ = strtoul(argv[i], &err_ptr, 16); + if (*err_ptr) return -2; + } + + return 1; +} + +static int cmd_masterkey_status(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + hal_error_t status; + uint8_t buf[KEK_LENGTH] = {0}; + + command = command; + argv = argv; + argc = argc; + + cli_print(cli, "Status of master key:\n"); + + status = hal_mkm_volatile_read(NULL, 0); + cli_print(cli, " volatile: %s / %s", _status2str(status), hal_error_string(status)); + + status = hal_mkm_flash_read(NULL, 0); + cli_print(cli, " flash: %s / %s", _status2str(status), hal_error_string(status)); + + /* XXX Temporary gaping security hole while developing the master key functionality. + * REMOVE READ-OUT OF MASTER KEY. + */ + + status = hal_mkm_volatile_read(&buf[0], sizeof(buf)); + if (status == LIBHAL_OK || status == HAL_ERROR_MASTERKEY_NOT_SET) { + cli_print(cli, "\nVolatile read-out:\n"); + uart_send_hexdump(buf, 0, sizeof(buf) - 1); + cli_print(cli, "\n"); + } else { + cli_print(cli, "Failed reading from volatile memory: %s", hal_error_string(status)); + } + + status = hal_mkm_flash_read(&buf[0], sizeof(buf)); + if (status == LIBHAL_OK || status == HAL_ERROR_MASTERKEY_NOT_SET) { + cli_print(cli, "\nFlash read-out:\n"); + uart_send_hexdump(buf, 0, sizeof(buf) - 1); + cli_print(cli, "\n"); + } else { + cli_print(cli, "Failed reading from flash: %s", hal_error_string(status)); + } + + return CLI_OK; +} + +static int cmd_masterkey_set(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + uint8_t buf[KEK_LENGTH] = {0}; + hal_error_t err; + int i; + + command = command; + + if ((i = _parse_hex_groups(&buf[0], sizeof(buf), argv, argc)) != 1) { + cli_print(cli, "Failed parsing master key (%i)", i); + return CLI_OK; + } + + cli_print(cli, "Parsed key:\n"); + uart_send_hexdump(buf, 0, sizeof(buf) - 1); + cli_print(cli, "\n"); + + if ((err = hal_mkm_volatile_write(buf, sizeof(buf))) == LIBHAL_OK) { + cli_print(cli, "Master key set in volatile memory"); + } else { + cli_print(cli, "Failed writing key to volatile memory: %s", hal_error_string(err)); + } + return CLI_OK; +} + +static int cmd_masterkey_erase(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + hal_error_t err; + + command = command; + argv = argv; + argc = argc; + + if ((err = hal_mkm_volatile_erase(KEK_LENGTH)) == LIBHAL_OK) { + cli_print(cli, "Erased master key from volatile memory"); + } else { + cli_print(cli, "Failed erasing master key from volatile memory: %s", hal_error_string(err)); + } + return CLI_OK; +} + +static int cmd_masterkey_unsecure_set(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + uint8_t buf[KEK_LENGTH] = {0}; + hal_error_t err; + int i; + + command = command; + + if ((i = _parse_hex_groups(&buf[0], sizeof(buf), argv, argc)) != 1) { + cli_print(cli, "Failed parsing master key (%i)", i); + return CLI_OK; + } + + cli_print(cli, "Parsed key:\n"); + uart_send_hexdump(buf, 0, sizeof(buf) - 1); + cli_print(cli, "\n"); + + if ((err = hal_mkm_flash_write(buf, sizeof(buf))) == LIBHAL_OK) { + cli_print(cli, "Master key set in unsecure flash memory"); + } else { + cli_print(cli, "Failed writing key to unsecure flash memory: %s", hal_error_string(err)); + } + return CLI_OK; +} + +static int cmd_masterkey_unsecure_erase(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + hal_error_t err; + + command = command; + argv = argv; + argc = argc; + + if ((err = hal_mkm_flash_erase(KEK_LENGTH)) == LIBHAL_OK) { + cli_print(cli, "Erased unsecure master key from flash"); + } else { + cli_print(cli, "Failed erasing unsecure master key from flash: %s", hal_error_string(err)); + } + return CLI_OK; +} + +void configure_cli_masterkey(struct cli_def *cli) +{ + struct cli_command *c = cli_register_command(cli, NULL, "masterkey", NULL, 0, 0, NULL); + + /* masterkey status */ + cli_register_command(cli, c, "status", cmd_masterkey_status, 0, 0, "Show status of master key in RAM/flash"); + + /* masterkey set */ + cli_register_command(cli, c, "set", cmd_masterkey_set, 0, 0, "Set the master key in the volatile Master Key Memory"); + + /* masterkey erase */ + cli_register_command(cli, c, "erase", cmd_masterkey_erase, 0, 0, "Erase the master key from the volatile Master Key Memory"); + + struct cli_command *c_unsecure = cli_register_command(cli, c, "unsecure", NULL, 0, 0, NULL); + + /* masterkey unsecure set */ + cli_register_command(cli, c_unsecure, "set", cmd_masterkey_unsecure_set, 0, 0, "Set master key in unprotected flash memory (if unsure, DON'T)"); + + /* masterkey unsecure erase */ + cli_register_command(cli, c_unsecure, "erase", cmd_masterkey_unsecure_erase, 0, 0, "Erase master key from unprotected flash memory"); +} diff --git a/projects/cli-test/mgmt-masterkey.h b/projects/cli-test/mgmt-masterkey.h new file mode 100644 index 0000000..67835e9 --- /dev/null +++ b/projects/cli-test/mgmt-masterkey.h @@ -0,0 +1,42 @@ +/* + * mgmt-masterkey.h + * ----------- + * Management CLI masterkeyellaneous functions. + * + * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __STM32_CLI_MGMT_MASTERKEY_H +#define __STM32_CLI_MGMT_MASTERKEY_H + +#include <libcli.h> + +extern void configure_cli_masterkey(struct cli_def *cli); + +#endif /* __STM32_CLI_MGMT_MASTERKEY_H */ diff --git a/projects/cli-test/mgmt-misc.c b/projects/cli-test/mgmt-misc.c index aea790a..ca95c63 100644 --- a/projects/cli-test/mgmt-misc.c +++ b/projects/cli-test/mgmt-misc.c @@ -3,7 +3,9 @@ * ----------- * Miscellaneous CLI functions. * - * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * Copyright (c) 2016-2017, NORDUnet A/S All rights reserved. + * Copyright: 2020, The Commons Conservancy Cryptech Project + * SPDX-License-Identifier: BSD-3-Clause * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -15,9 +17,9 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * - Neither the name of the NORDUnet nor the names of its contributors may - * be used to endorse or promote products derived from this software - * without specific prior written permission. + * - Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED @@ -32,41 +34,44 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#define HAL_OK CMSIS_HAL_OK #include "stm-init.h" #include "stm-uart.h" - #include "mgmt-cli.h" #include "mgmt-misc.h" +#undef HAL_OK -#include <string.h> - - -extern uint32_t update_crc(uint32_t crc, uint8_t *buf, int len); +#define HAL_OK LIBHAL_OK +#include "hal.h" +#include "hal_internal.h" +#undef HAL_OK +#include <string.h> -volatile uint32_t demo_crc = 0; +static volatile hal_crc32_t demo_crc; -int _count_bytes_callback(uint8_t *buf, size_t len) { - demo_crc = update_crc(demo_crc, buf, len); - return 1; +static HAL_StatusTypeDef _count_bytes_callback(uint8_t *buf, size_t len) { + demo_crc = hal_crc32_update(demo_crc, buf, len); + return CMSIS_HAL_OK; } int cli_receive_data(struct cli_def *cli, uint8_t *buf, size_t len, cli_data_callback data_callback) { - uint32_t filesize = 0, crc = 0, my_crc = 0, counter = 0; + hal_crc32_t crc = 0, my_crc = hal_crc32_init(); + uint32_t filesize = 0, counter = 0; size_t n = len; if (! control_mgmt_uart_dma_rx(DMA_RX_STOP)) { cli_print(cli, "Failed stopping DMA"); - return CLI_OK; + goto fail; } cli_print(cli, "OK, write size (4 bytes), data in %li byte chunks, CRC-32 (4 bytes)", (uint32_t) n); - if (uart_receive_bytes(STM_UART_MGMT, (void *) &filesize, 4, 1000) != HAL_OK) { + if (uart_receive_bytes((void *) &filesize, sizeof(filesize), 1000) != CMSIS_HAL_OK) { cli_print(cli, "Receive timed out"); - return CLI_ERROR; + goto fail; } cli_print(cli, "Send %li bytes of data", filesize); @@ -79,27 +84,28 @@ int cli_receive_data(struct cli_def *cli, uint8_t *buf, size_t len, cli_data_cal if (filesize < n) n = filesize; - if (uart_receive_bytes(STM_UART_MGMT, (void *) buf, n, 1000) != HAL_OK) { + if (uart_receive_bytes((void *) buf, n, 1000) != CMSIS_HAL_OK) { cli_print(cli, "Receive timed out"); - return CLI_ERROR; + goto fail; } filesize -= n; - my_crc = update_crc(my_crc, buf, n); + my_crc = hal_crc32_update(my_crc, buf, n); /* After reception of a chunk but before ACKing we have "all" the time in the world to * calculate CRC and invoke the data_callback. */ - if (data_callback != NULL && ! data_callback(buf, (size_t) n)) { + if (data_callback != NULL && data_callback(buf, n) != CMSIS_HAL_OK) { cli_print(cli, "Data processing failed"); - return CLI_OK; + goto fail; } counter++; - uart_send_bytes(STM_UART_MGMT, (void *) &counter, 4); + uart_send_bytes((void *) &counter, 4); } + my_crc = hal_crc32_finalize(my_crc); cli_print(cli, "Send CRC-32"); - uart_receive_bytes(STM_UART_MGMT, (void *) &crc, 4, 1000); + uart_receive_bytes((void *) &crc, sizeof(crc), 1000); cli_print(cli, "CRC-32 0x%x, calculated CRC 0x%x", (unsigned int) crc, (unsigned int) my_crc); if (crc == my_crc) { cli_print(cli, "CRC checksum MATCHED"); @@ -107,31 +113,129 @@ int cli_receive_data(struct cli_def *cli, uint8_t *buf, size_t len, cli_data_cal cli_print(cli, "CRC checksum did NOT match"); } + fail: + control_mgmt_uart_dma_rx(DMA_RX_START); return CLI_OK; } -int cmd_filetransfer(struct cli_def *cli, const char *command, char *argv[], int argc) +static int cmd_filetransfer(struct cli_def *cli, const char *command, char *argv[], int argc) { uint8_t buf[FILETRANSFER_UPLOAD_CHUNK_SIZE]; - demo_crc = 0; + command = command; + argv = argv; + argc = argc; + + demo_crc = hal_crc32_init(); cli_receive_data(cli, &buf[0], sizeof(buf), _count_bytes_callback); + demo_crc = hal_crc32_finalize(demo_crc); cli_print(cli, "Demo CRC is: %li/0x%x", demo_crc, (unsigned int) demo_crc); return CLI_OK; } -int cmd_reboot(struct cli_def *cli, const char *command, char *argv[], int argc) +static int cmd_reboot(struct cli_def *cli, const char *command, char *argv[], int argc) { + command = command; + argv = argv; + argc = argc; + cli_print(cli, "\n\n\nRebooting\n\n\n"); HAL_NVIC_SystemReset(); - while (1) {}; + + /*NOTREACHED*/ + return CLI_OK; +} + +static int cmd_rsa_blinding(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + if (argc != 1) { + cli_print(cli, "Wrong number of arguments (%i).", argc); + cli_print(cli, "Syntax: %s <on|off|clear>", command); + return CLI_ERROR; + } + + if (strcmp(argv[0], "on") == 0) + hal_rsa_set_blinding(1); + else if (strcmp(argv[0], "off") == 0) + hal_rsa_set_blinding(0); + else if (strcmp(argv[0], "clear") == 0) + hal_rsa_clear_blinding_cache(); + else { + cli_print(cli, "Argument must be 'on', 'off', or 'clear' - not '%s'", argv[0]); + return CLI_ERROR; + } + + return CLI_OK; +} + +static int cmd_rsa_crt(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + int onoff; + + if (argc != 1) { + cli_print(cli, "Wrong number of arguments (%i).", argc); + cli_print(cli, "Syntax: %s <on|off>", command); + return CLI_ERROR; + } + + if (strcmp(argv[0], "on") == 0) + onoff = 1; + else if (strcmp(argv[0], "off") == 0) + onoff = 0; + else { + cli_print(cli, "Argument must be 'on' or 'off' - not '%s'", argv[0]); + return CLI_ERROR; + } + + hal_rsa_set_crt(onoff); + + return CLI_OK; +} + +static int cmd_rsa_modexpng(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + int onoff; + + if (argc != 1) { + cli_print(cli, "Wrong number of arguments (%i).", argc); + cli_print(cli, "Syntax: %s <on|off>", command); + return CLI_ERROR; + } + + if (strcmp(argv[0], "on") == 0) + onoff = 1; + else if (strcmp(argv[0], "off") == 0) + onoff = 0; + else { + cli_print(cli, "Argument must be 'on' or 'off' - not '%s'", argv[0]); + return CLI_ERROR; + } + + hal_error_t err; + if ((err = hal_modexp_use_modexpng(onoff)) == LIBHAL_OK) + return CLI_OK; + + cli_print(cli, hal_error_string(err)); + return CLI_ERROR; } void configure_cli_misc(struct cli_def *cli) { /* filetransfer */ - cli_command_root_node(filetransfer, "Test file transfering"); + cli_register_command(cli, NULL, "filetransfer", cmd_filetransfer, 0, 0, "Test file transfering"); + + struct cli_command *c_rsa = cli_register_command(cli, NULL, "rsa", NULL, 0, 0, NULL); + + /* rsa blinding */ + cli_register_command(cli, c_rsa, "blinding", cmd_rsa_blinding, 0, 0, "Set use of RSA blinding"); + + /* rsa crt */ + cli_register_command(cli, c_rsa, "crt", cmd_rsa_crt, 0, 0, "Set use of RSA CRT"); + + /* rsa modexpng */ + cli_register_command(cli, c_rsa, "modexpng", cmd_rsa_modexpng, 0, 0, "Set use of ModExpNG"); + /* reboot */ - cli_command_root_node(reboot, "Reboot the STM32"); + cli_register_command(cli, NULL, "reboot", cmd_reboot, 0, 0, "Reboot the STM32"); } diff --git a/projects/cli-test/mgmt-misc.h b/projects/cli-test/mgmt-misc.h index b7eb4f4..c0581c9 100644 --- a/projects/cli-test/mgmt-misc.h +++ b/projects/cli-test/mgmt-misc.h @@ -35,15 +35,14 @@ #ifndef __STM32_CLI_MGMT_MISC_H #define __STM32_CLI_MGMT_MISC_H -#include "stm-init.h" #include <libcli.h> - #define FILETRANSFER_UPLOAD_CHUNK_SIZE 256 -typedef int (*cli_data_callback)(uint8_t *, size_t); +typedef HAL_StatusTypeDef (*cli_data_callback)(uint8_t *, size_t); -extern void configure_cli_misc(struct cli_def *cli); extern int cli_receive_data(struct cli_def *cli, uint8_t *buf, size_t len, cli_data_callback data_callback); +extern void configure_cli_misc(struct cli_def *cli); + #endif /* __STM32_CLI_MGMT_MISC_H */ diff --git a/projects/cli-test/mgmt-show.c b/projects/cli-test/mgmt-show.c index 3ae196e..4338dcd 100644 --- a/projects/cli-test/mgmt-show.c +++ b/projects/cli-test/mgmt-show.c @@ -32,6 +32,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/* Rename both CMSIS HAL_OK and libhal HAL_OK to disambiguate */ +#define HAL_OK CMSIS_HAL_OK #include "stm-init.h" #include "stm-keystore.h" #include "stm-fpgacfg.h" @@ -40,13 +42,24 @@ #include "mgmt-cli.h" #include "mgmt-show.h" -#include <string.h> +#undef HAL_OK +#define LIBHAL_OK HAL_OK +#include "hal.h" + +#define HAL_STATIC_PKEY_STATE_BLOCKS 6 +#include "hal_internal.h" +#undef HAL_OK +#include <string.h> -int cmd_show_cpuspeed(struct cli_def *cli, const char *command, char *argv[], int argc) +static int cmd_show_cpuspeed(struct cli_def *cli, const char *command, char *argv[], int argc) { volatile uint32_t hclk; + command = command; + argv = argv; + argc = argc; + hclk = HAL_RCC_GetHCLKFreq(); cli_print(cli, "HSE_VALUE: %li", HSE_VALUE); cli_print(cli, "HCLK: %li (%i MHz)", hclk, (int) hclk / 1000 / 1000); @@ -54,36 +67,71 @@ int cmd_show_cpuspeed(struct cli_def *cli, const char *command, char *argv[], in return CLI_OK; } -int cmd_show_fpga_status(struct cli_def *cli, const char *command, char *argv[], int argc) +static int cmd_show_fpga_status(struct cli_def *cli, const char *command, char *argv[], int argc) { - cli_print(cli, "FPGA has %sloaded a bitstream", fpgacfg_check_done() ? "":"NOT "); + command = command; + argv = argv; + argc = argc; + + cli_print(cli, "FPGA has %sloaded a bitstream", (fpgacfg_check_done() == CMSIS_HAL_OK) ? "":"NOT "); return CLI_OK; } -int cmd_show_keystore_status(struct cli_def *cli, const char *command, char *argv[], int argc) +static int cmd_show_fpga_cores(struct cli_def *cli, const char *command, char *argv[], int argc) { - cli_print(cli, "Keystore memory is %sonline", (keystore_check_id() != 1) ? "NOT ":""); + hal_core_t *core; + const hal_core_info_t *info; + + command = command; + argv = argv; + argc = argc; + + if (fpgacfg_check_done() != CMSIS_HAL_OK) { + cli_print(cli, "FPGA has not loaded a bitstream"); + return CLI_OK; + } + + for (core = hal_core_iterate(NULL); core != NULL; core = hal_core_iterate(core)) { + info = hal_core_info(core); + cli_print(cli, "%04x: %8.8s %4.4s", + (unsigned int)info->base, info->name, info->version); + } + return CLI_OK; } -int cmd_show_keystore_data(struct cli_def *cli, const char *command, char *argv[], int argc) +static int cmd_show_keystore_status(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + command = command; + argv = argv; + argc = argc; + + cli_print(cli, "Keystore memory is %sonline", (keystore_check_id() == CMSIS_HAL_OK) ? "":"NOT "); + return CLI_OK; +} + +static int cmd_show_keystore_data(struct cli_def *cli, const char *command, char *argv[], int argc) { uint8_t buf[KEYSTORE_PAGE_SIZE]; uint32_t i; - if (keystore_check_id() != 1) { + command = command; + argv = argv; + argc = argc; + + if (keystore_check_id() != CMSIS_HAL_OK) { cli_print(cli, "ERROR: The keystore memory is not accessible."); } memset(buf, 0, sizeof(buf)); - if ((i = keystore_read_data(0, buf, sizeof(buf))) != 1) { + if ((i = keystore_read_data(0, buf, sizeof(buf))) != CMSIS_HAL_OK) { cli_print(cli, "Failed reading first page from keystore memory: %li", i); return CLI_ERROR; } cli_print(cli, "First page from keystore memory:\r\n"); - uart_send_hexdump(STM_UART_MGMT, buf, 0, sizeof(buf) - 1); - uart_send_string2(STM_UART_MGMT, (char *) "\r\n\r\n"); + uart_send_hexdump(buf, 0, sizeof(buf) - 1); + cli_print(cli, "\n"); for (i = 0; i < 8; i++) { if (buf[i] == 0xff) break; /* never written */ @@ -97,14 +145,14 @@ int cmd_show_keystore_data(struct cli_def *cli, const char *command, char *argv[ if (buf[i] == 0xff) { cli_print(cli, "Tombstoning byte %li", i); buf[i] = 0x55; - if ((i = keystore_write_data(0, buf, sizeof(buf))) != 1) { + if ((i = keystore_write_data(0, buf, sizeof(buf))) != CMSIS_HAL_OK) { cli_print(cli, "Failed writing data at offset 0: %li", i); return CLI_ERROR; } } } else { cli_print(cli, "Erasing first sector since all the first 8 bytes are tombstones"); - if ((i = keystore_erase_sectors(1)) != 1) { + if ((i = keystore_erase_sector(0)) != CMSIS_HAL_OK) { cli_print(cli, "Failed erasing the first sector: %li", i); return CLI_ERROR; } @@ -116,18 +164,24 @@ int cmd_show_keystore_data(struct cli_def *cli, const char *command, char *argv[ void configure_cli_show(struct cli_def *cli) { - /* show */ - cli_command_root(show); + struct cli_command *c = cli_register_command(cli, NULL, "show", NULL, 0, 0, NULL); /* show cpuspeed */ - cli_command_node(show, cpuspeed, "Show the speed at which the CPU currently operates"); + cli_register_command(cli, c, "cpuspeed", cmd_show_cpuspeed, 0, 0, "Show the speed at which the CPU currently operates"); + + struct cli_command *c_fpga = cli_register_command(cli, c, "fpga", NULL, 0, 0, NULL); - cli_command_branch(show, fpga); /* show fpga status*/ - cli_command_node(show_fpga, status, "Show status about the FPGA"); + cli_register_command(cli, c_fpga, "status", cmd_show_fpga_status, 0, 0, "Show status about the FPGA"); + + /* show fpga cores*/ + cli_register_command(cli, c_fpga, "cores", cmd_show_fpga_cores, 0, 0, "Show the currently available FPGA cores"); + + struct cli_command *c_keystore = cli_register_command(cli, c, "keystore", NULL, 0, 0, NULL); - cli_command_branch(show, keystore); /* show keystore status*/ - cli_command_node(show_keystore, status, "Show status of the keystore memory"); - cli_command_node(show_keystore, data, "Show the first page of the keystore memory"); + cli_register_command(cli, c_keystore, "status", cmd_show_keystore_status, 0, 0, "Show status of the keystore memory"); + + /* show keystore data */ + cli_register_command(cli, c_keystore, "data", cmd_show_keystore_data, 0, 0, "Show the first page of the keystore memory"); } diff --git a/projects/cli-test/mgmt-show.h b/projects/cli-test/mgmt-show.h index 0d7ba3a..7b80a30 100644 --- a/projects/cli-test/mgmt-show.h +++ b/projects/cli-test/mgmt-show.h @@ -1,5 +1,5 @@ /* - * mgmt-misc.h + * mgmt-show.h * ----------- * Management CLI 'show' functions. * @@ -35,7 +35,6 @@ #ifndef __STM32_CLI_MGMT_SHOW_H #define __STM32_CLI_MGMT_SHOW_H -#include "stm-init.h" #include <libcli.h> extern void configure_cli_show(struct cli_def *cli); diff --git a/projects/cli-test/mgmt-test.c b/projects/cli-test/mgmt-test.c index c1f255e..9b9972d 100644 --- a/projects/cli-test/mgmt-test.c +++ b/projects/cli-test/mgmt-test.c @@ -35,34 +35,31 @@ #include "stm-init.h" #include "stm-led.h" #include "stm-sdram.h" +#include "stm-fmc.h" +#include "stm-fpgacfg.h" #include "mgmt-cli.h" #include "mgmt-test.h" #include "test_sdram.h" +#include "test_mkmif.h" +#include "test-fmc.h" #include <stdlib.h> - -int cmd_test_sdram(struct cli_def *cli, const char *command, char *argv[], int argc) +static int cmd_test_sdram(struct cli_def *cli, const char *command, char *argv[], int argc) { // run external memory initialization sequence - HAL_StatusTypeDef status; int ok, num_cycles = 1, i, test_completed; + command = command; + if (argc == 1) { num_cycles = strtol(argv[0], NULL, 0); if (num_cycles > 100) num_cycles = 100; if (num_cycles < 1) num_cycles = 1; } - cli_print(cli, "Initializing SDRAM"); - status = sdram_init(); - if (status != HAL_OK) { - cli_print(cli, "Failed initializing SDRAM: %i", (int) status); - return CLI_OK; - } - for (i = 1; i <= num_cycles; i++) { cli_print(cli, "Starting SDRAM test (%i/%i)", i, num_cycles); test_completed = 0; @@ -107,11 +104,83 @@ int cmd_test_sdram(struct cli_def *cli, const char *command, char *argv[], int a return CLI_OK; } +static int cmd_test_fmc(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + int i, num_cycles = 1, num_rounds = 100000; + + command = command; + + if (argc >= 1) { + num_cycles = strtol(argv[0], NULL, 0); + if (num_cycles > 100000) num_cycles = 100000; + if (num_cycles < 1) num_cycles = 1; + } + + if (argc == 2) { + num_rounds = strtol(argv[1], NULL, 0); + if (num_rounds > 1000000) num_rounds = 1000000; + if (num_rounds < 1) num_rounds = 1; + } + + cli_print(cli, "Checking if FPGA has loaded it's bitstream"); + // Blink blue LED until the FPGA reports it has loaded it's bitstream + led_on(LED_BLUE); + while (! fpgacfg_check_done()) { + for (i = 0; i < 4; i++) { + HAL_Delay(500); + led_toggle(LED_BLUE); + } + } + + // turn on green led, turn off other leds + led_on(LED_GREEN); + led_off(LED_YELLOW); + led_off(LED_RED); + led_off(LED_BLUE); + + // vars + volatile int data_test_ok = 0, addr_test_ok = 0, successful_runs = 0, failed_runs = 0, sleep = 0; + + for (i = 1; i <= num_cycles; i++) { + cli_print(cli, "Starting FMC test (%i/%i)", i, num_cycles); + + // test data bus + data_test_ok = test_fpga_data_bus(cli, num_rounds); + // test address bus + addr_test_ok = test_fpga_address_bus(cli, num_rounds); + + cli_print(cli, "Data: %i, addr %i", data_test_ok, addr_test_ok); + + if (data_test_ok == num_rounds && + addr_test_ok == num_rounds) { + // toggle yellow led to indicate, that we are alive + led_toggle(LED_YELLOW); + + successful_runs++; + sleep = 0; + } else { + led_on(LED_RED); + failed_runs++; + sleep = 2000; + } + + cli_print(cli, "Success %i, failed %i runs\r\n", successful_runs, failed_runs); + HAL_Delay(sleep); + } + + return CLI_OK; +} + void configure_cli_test(struct cli_def *cli) { - /* test */ - cli_command_root(test); + struct cli_command *c = cli_register_command(cli, NULL, "test", NULL, 0, 0, NULL); /* test sdram */ - cli_command_node(test, sdram, "Run SDRAM tests"); + cli_register_command(cli, c, "sdram", cmd_test_sdram, 0, 0, "Run SDRAM tests"); + + /* test mkmif */ + cli_register_command(cli, c, "mkmif", cmd_test_mkmif, 0, 0, "Run Master Key Memory Interface tests"); + + /* test fmc */ + cli_register_command(cli, c, "fmc", cmd_test_fmc, 0, 0, "Run FMC bus tests"); } diff --git a/projects/cli-test/test-fmc.c b/projects/cli-test/test-fmc.c new file mode 100644 index 0000000..d9b0c9b --- /dev/null +++ b/projects/cli-test/test-fmc.c @@ -0,0 +1,217 @@ +/* + * test-fmc.c + * ----------- + * FPGA communication bus (FMC) tests. + * + * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + This requires a special bitstream with a special test register. + See core/platform/novena/fmc/rtl/novena_fmc_top.v, sections marked + `ifdef test: + //---------------------------------------------------------------- + // Dummy Register + // + // General-purpose register to test FMC interface using STM32 + // demo program instead of core selector logic. + // + // This register is a bit tricky, but it allows testing of both + // data and address buses. Reading from FPGA will always return + // value, which is currently stored in the test register, + // regardless of read transaction address. Writing to FPGA has + // two variants: a) writing to address 0 will store output data + // data value in the test register, b) writing to any non-zero + // address will store _address_ of write transaction in the test + // register. + // + // To test data bus, write some different patterns to address 0, + // then readback from any address and compare. + // + // To test address bus, write anything to some different non-zero + // addresses, then readback from any address and compare returned + // value with previously written address. + // + //---------------------------------------------------------------- + */ + +#include "stm-init.h" +#include "stm-fmc.h" +#include "stm-uart.h" + +#include "test-fmc.h" + +static RNG_HandleTypeDef rng_inst; + +/* These are some interesting-to-look-at-in-the-debugger values that are declared + * volatile so that the compiler wouldn't optimize/obscure them. + */ +volatile uint32_t data_diff = 0; +volatile uint32_t addr_diff = 0; + + +static int _write_then_read(struct cli_def *cli, uint32_t addr, uint32_t write_buf, uint32_t *read_buf) +{ + int ok; + + fmc_write_32(addr, write_buf); + fmc_read_32(0, read_buf); + + return 1; +} + +int test_fpga_data_bus(struct cli_def *cli, uint32_t test_rounds) +{ + int i, c; + uint32_t rnd, buf; + HAL_StatusTypeDef hal_result; + + /* initialize stm32 rng */ + rng_inst.Instance = RNG; + HAL_RNG_Init(&rng_inst); + + /* run some rounds of data bus test */ + for (c = 0; c < (int)test_rounds; c++) { + data_diff = 0; + /* try to generate "random" number */ + hal_result = HAL_RNG_GenerateRandomNumber(&rng_inst, &rnd); + if (hal_result != HAL_OK) { + cli_print(cli, "STM32 RNG failed"); + break; + } + + /* write value to fpga at address 0 and then read it back from the test register */ + if (! _write_then_read(cli, 0, rnd, &buf)) break; + + /* compare (abort testing in case of error) */ + data_diff = buf ^ rnd; + if (data_diff) { + cli_print(cli, "Data bus FAIL: expected %lx got %lx", rnd, buf); + uart_send_string((char *) "Binary diff: "); + uart_send_binary(data_diff, 32); + uart_send_string("\r\n"); + + break; + } + } + + if (! data_diff) { + cli_print(cli, "Sample of data bus test data: expected 0x%lx got 0x%lx", rnd, buf); + } else { + uint32_t data; + cli_print(cli, "\nFMC data bus per-bit analysis:"); + for (i = 0; i < 31; i++) { + data = 1 << i; + + if (! _write_then_read(cli, 0, data, &buf)) break; + + if (data == buf) { + cli_print(cli, "Data 0x%08lx (FMC_D%02i) - OK", data, i + 1); + } else { + cli_print(cli, "Data 0x%08lx (FMC_D%02i) - FAIL (read 0x%08lx)", data, i + 1, buf); + } + } + } + + + /* return number of successful tests */ + return c; +} + +int test_fpga_address_bus(struct cli_def *cli, uint32_t test_rounds) +{ + int i, c; + uint32_t addr, buf, dummy = 1; + HAL_StatusTypeDef hal_result; + + /* initialize stm32 rng */ + rng_inst.Instance = RNG; + HAL_RNG_Init(&rng_inst); + + /* run some rounds of address bus test */ + for (c = 0; c < (int)test_rounds; c++) { + addr_diff = 0; + /* try to generate "random" number */ + hal_result = HAL_RNG_GenerateRandomNumber(&rng_inst, &addr); + if (hal_result != HAL_OK) break; + + /* there are 26 physicaly connected address lines on the alpha, + but "only" 24 usable for now (the top two ones are used by FMC + to choose bank, and we only have one bank set up currently) + */ + addr &= 0x3fffffc; + + /* don't test zero addresses (fpga will store data, not address) */ + if (addr == 0) continue; + + /* write dummy value to fpga at some non-zero address and then read from the + test register to see what address the FPGA thought we wrote to + */ + if (! _write_then_read(cli, addr, dummy, &buf)) break; + + /* fpga receives address of 32-bit word, while we need + byte address here to compare + */ + buf <<= 2; + + /* compare (abort testing in case of error) */ + addr_diff = buf ^ addr; + if (addr_diff) { + cli_print(cli, "Address bus FAIL: expected 0x%lx got 0x%lx", addr, buf); + uart_send_string((char *) "Binary diff: "); + uart_send_binary(addr_diff, 32); + uart_send_string("\r\n"); + + break; + } + } + + if (! addr_diff) { + cli_print(cli, "Sample of address bus test data: expected 0x%lx got 0x%lx", addr, buf); + } else { + cli_print(cli, "\nFMC address bus per-bit analysis:"); + for (i = 0; i < 23; i++) { + uint32_t shifted_addr; + addr = 1 << i; + + shifted_addr = addr << 2; + + if (! _write_then_read(cli, shifted_addr, dummy, &buf)) break; + + if (addr == buf) { + cli_print(cli, "Address 0x%08lx (FMC_A%02i) - OK", addr, i + 1); + } else { + cli_print(cli, "Address 0x%08lx (FMC_A%02i) - FAIL (read 0x%08lx)", addr, i + 1, buf); + } + } + } + + /* return number of successful tests */ + return c; +} diff --git a/projects/cli-test/test-fmc.h b/projects/cli-test/test-fmc.h new file mode 100644 index 0000000..c49da48 --- /dev/null +++ b/projects/cli-test/test-fmc.h @@ -0,0 +1,43 @@ +/* + * test-fmc.h + * ------------ + * Prototypes and defines for testing the FMC bus comms with the FPGA. + * + * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __STM32_CLI_TEST_FMC_H +#define __STM32_CLI_TEST_FMC_H + +#include "mgmt-cli.h" + +extern int test_fpga_data_bus(struct cli_def *cli, uint32_t test_rounds); +extern int test_fpga_address_bus(struct cli_def *cli, uint32_t test_rounds); + + +#endif /* __STM32_CLI_TEST_FMC_H */ diff --git a/projects/cli-test/test-mkmif.c b/projects/cli-test/test-mkmif.c new file mode 100644 index 0000000..cd71040 --- /dev/null +++ b/projects/cli-test/test-mkmif.c @@ -0,0 +1,166 @@ +/* + * Test Joachim's MKMIF core. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <assert.h> + +#include <sys/time.h> + +/* Rename both CMSIS HAL_OK and libhal HAL_OK to disambiguate */ +#define HAL_OK CMSIS_HAL_OK +#include "mgmt-cli.h" + +#undef HAL_OK +#define HAL_OK LIBHAL_OK +#include "hal.h" +#undef HAL_OK + + +#define SCLK_DIV 0x20 + +typedef union { + uint8_t byte[4]; + uint32_t word; +} byteword_t; + +static hal_error_t sclk_test(struct cli_def *cli, hal_core_t *core, const uint32_t divisor) +{ + uint32_t readback; + hal_error_t err; + + cli_print(cli, "Trying to adjust the clockspeed (divisor %x).", (unsigned int) divisor); + + if ((err = hal_mkmif_set_clockspeed(core, divisor)) != LIBHAL_OK) { + cli_print(cli, "hal_mkmif_set_clockspeed: %s", hal_error_string(err)); + return err; + } + if ((err = hal_mkmif_get_clockspeed(core, &readback)) != LIBHAL_OK) { + cli_print(cli, "hal_mkmif_get_clockspeed: %s", hal_error_string(err)); + return err; + } + if (readback != divisor) { + cli_print(cli, "expected %x, got %x", (unsigned int)divisor, (unsigned int)readback); + return HAL_ERROR_IO_UNEXPECTED; + } + return LIBHAL_OK; +} + +static hal_error_t init_test(struct cli_def *cli, hal_core_t *core) +{ + hal_error_t err; + + cli_print(cli, "Trying to init to the memory in continuous mode."); + + if ((err = hal_mkmif_init(core)) != LIBHAL_OK) { + cli_print(cli, "hal_mkmif_init: %s", hal_error_string(err)); + return err; + } + + return LIBHAL_OK; +} + +static hal_error_t write_test(struct cli_def *cli, hal_core_t *core) +{ + uint32_t write_data; + uint32_t write_address; + int i; + hal_error_t err; + + for (write_data = 0x01020304, write_address = 0, i = 0; + i < 0x10; + write_data += 0x01010101, write_address += 4, ++i) { + + cli_print(cli, "Trying to write 0x%08x to memory address 0x%08x.", + (unsigned int)write_data, (unsigned int)write_address); + + if ((err = hal_mkmif_write_word(core, write_address, write_data)) != LIBHAL_OK) { + cli_print(cli, "hal_mkmif_write: %s", hal_error_string(err)); + return err; + } + } + + return LIBHAL_OK; +} + +static hal_error_t read_test(struct cli_def *cli, hal_core_t *core) +{ + uint32_t read_data; + uint32_t read_address; + int i; + hal_error_t err; + + for (read_address = 0, i = 0; + i < 0x10; + read_address += 4, ++i) { + + cli_print(cli, "Trying to read from memory address 0x%08x.", (unsigned int)read_address); + + if ((err = hal_mkmif_read_word(core, read_address, &read_data)) != LIBHAL_OK) { + cli_print(cli, "hal_mkmif_read: %s", hal_error_string(err)); + return err; + } + cli_print(cli, "Data read: 0x%08x", (unsigned int)read_data); + } + + return LIBHAL_OK; +} + +static hal_error_t write_read_test(struct cli_def *cli, hal_core_t *core) +{ + uint32_t data; + uint32_t readback; + hal_error_t err; + + cli_print(cli, "Trying to write 0xdeadbeef to the memory and then read back."); + + data = 0xdeadbeef; + + if ((err = hal_mkmif_write_word(core, 0x00000000, data)) != LIBHAL_OK) { + cli_print(cli, "write error: %s", hal_error_string(err)); + return err; + } + + if ((err = hal_mkmif_read_word(core, 0x00000000, &readback)) != LIBHAL_OK) { + cli_print(cli, "read error: %s", hal_error_string(err)); + return err; + } + + if (readback != data) { + cli_print(cli, "read %08x, expected %08x", (unsigned int)readback, (unsigned int)data); + return HAL_ERROR_IO_UNEXPECTED; + } + + return LIBHAL_OK; +} + +int cmd_test_mkmif(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + hal_core_t *core = hal_core_find(MKMIF_NAME, NULL); + hal_error_t res; + + command = command; + argv = argv; + argc = argc; + + if (core == NULL) { + cli_print(cli, "MKMIF core not present, not testing."); + return HAL_ERROR_CORE_NOT_FOUND; + } + + res = + sclk_test(cli, core, SCLK_DIV) || + init_test(cli, core) || + write_read_test(cli, core) || + write_test(cli, core) || + read_test(cli, core); + + if (res != LIBHAL_OK) { + cli_print(cli, "\nTest FAILED"); + } + + return CLI_OK; +} diff --git a/projects/cli-test/test_mkmif.h b/projects/cli-test/test_mkmif.h new file mode 100644 index 0000000..d5f2f75 --- /dev/null +++ b/projects/cli-test/test_mkmif.h @@ -0,0 +1,40 @@ +/* + * test_mkmif.h + * ------------ + * Prototypes and defines for testing the master key memory interface. + * + * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __STM32_CLI_TEST_MKMIF_H +#define __STM32_CLI_TEST_MKMIF_H + +extern int cmd_test_mkmif(struct cli_def *cli, const char *command, char *argv[], int argc); + + +#endif /* __STM32_CLI_TEST_MKMIF_H */ diff --git a/projects/cli-test/test_sdram.c b/projects/cli-test/test_sdram.c index e720667..4961b94 100644 --- a/projects/cli-test/test_sdram.c +++ b/projects/cli-test/test_sdram.c @@ -31,7 +31,6 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "stm32f4xx_hal.h"
#include "stm-led.h"
#include "stm-sdram.h"
#include "test_sdram.h"
diff --git a/projects/hsm/Makefile b/projects/hsm/Makefile index f5546d8..7fd3ad6 100644 --- a/projects/hsm/Makefile +++ b/projects/hsm/Makefile @@ -1,19 +1,53 @@ PROJ = hsm -SRCS = main.c +# objs in addition to $(PROJ).o +OBJS = mgmt-cli.o \ + mgmt-firmware.o \ + mgmt-bootloader.o \ + mgmt-fpga.o \ + mgmt-keystore.o \ + mgmt-masterkey.o \ + mgmt-misc.o \ + mgmt-task.o \ + log.o \ + $(TOPLEVEL)/task.o -OBJS = $(SRCS:.c=.o) +CFLAGS += -DNUM_RPC_TASK=8 -CFLAGS += -I $(LIBHAL_DIR) +CFLAGS += -I$(LIBHAL_SRC) +CFLAGS += -I$(LIBCLI_SRC) +CFLAGS += -I$(LIBTFM_BLD) +CFLAGS += -Wno-missing-field-initializers -LIBS += $(LIBHAL_DIR)/libhal.a $(LIBTFM_DIR)/libtfm.a +LIBS += $(LIBHAL_BLD)/libhal.a $(LIBTFM_BLD)/libtfm.a +LIBS += $(LIBCLI_BLD)/libcli.a + +LDFLAGS += -mcpu=cortex-m4 -mthumb -mlittle-endian -mthumb-interwork +LDFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16 +LDFLAGS += -Wl,--gc-sections + +ifdef DO_PROFILING +LDFLAGS += --specs=rdimon.specs -lc -lrdimon +endif + +ifdef DO_TASK_METRICS +CFLAGS += -DDO_TASK_METRICS +endif + +ifdef DO_TIMING +CFLAGS += -DDO_TIMING +CFLAGS += -I../cli-test +CFLAGS += -DCLI_STACK_SIZE=65536 +OBJS += ../cli-test/mgmt-timing.o $(TOPLEVEL)/stm-dwt.o +LDFLAGS += -lm +endif all: $(PROJ:=.elf) -$(PROJ).elf: $(OBJS) $(BOARD_OBJS) $(LIBS) - $(CC) $(CFLAGS) $^ -o $@ -T$(LDSCRIPT) -g -Wl,-Map=$(PROJ).map - $(OBJCOPY) -O binary $(PROJ).elf $(PROJ).bin - $(SIZE) $(PROJ).elf +%.elf: %.o $(BOARD_OBJS) $(OBJS) $(LIBS) + $(CC) $^ -o $@ -T$(LDSCRIPT) -g -Wl,-Map=$*.map $(LDFLAGS) + $(OBJCOPY) -O binary $*.elf $*.bin + $(SIZE) $*.elf clean: rm -f *.o diff --git a/projects/hsm/cryptech_miniterm b/projects/hsm/cryptech_miniterm new file mode 100755 index 0000000..b646811 --- /dev/null +++ b/projects/hsm/cryptech_miniterm @@ -0,0 +1,45 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2016, NORDUnet A/S All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# - Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# - Neither the name of the NORDUnet nor the names of its contributors may +# be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +""" +Utility to run PySerial's "miniterm" with default settings suitable +for talking to the Cryptech Alpha's console port. +""" + +import serial.tools.miniterm +import sys +import os + +default_port = os.getenv("CRYPTECH_CTY_CLIENT_SERIAL_DEVICE") +default_baud = os.getenv("CRYPTECH_CTY_CLIENT_SERIAL_SPEED", 921600) + +sys.exit(serial.tools.miniterm.main(default_port = default_port, + default_baudrate = int(default_baud))) + diff --git a/projects/hsm/cryptech_probe b/projects/hsm/cryptech_probe new file mode 100755 index 0000000..356931a --- /dev/null +++ b/projects/hsm/cryptech_probe @@ -0,0 +1,158 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2016, NORDUnet A/S All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# - Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# - Neither the name of the NORDUnet nor the names of its contributors may +# be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +""" +Utility to probe USB serial port(s) trying to figure out which one(s) +we have plugged in today. stdout is environment variable settings, +suitable for use in bash with "eval `cryptech_probe`"; all other output +goes to stderr. +""" + +import sys +import time +import argparse +import serial.tools.list_ports_posix + +if sys.version_info.major == 2: + def colon_hex(raw): + return ":".join("{:02x}".format(ord(b)) for b in raw) +else: + def colon_hex(raw): + return ":".join("{:02x}".format(b) for b in raw) + +class positive_integer(int): + def __init__(self, value): + if self <= 0: + raise ValueError + +parser = argparse.ArgumentParser(formatter_class = argparse.ArgumentDefaultsHelpFormatter) +parser.add_argument("-v", "--verbose", action = "store_true", help = "produce human-readable output") +parser.add_argument("-d", "--debug", action = "store_true", help = "blather about what we're doing") +parser.add_argument("--no-cleanup", action = "store_true", help = "don't send cleanup sequences after probing") +parser.add_argument("--read-buffer-size", type = positive_integer, help = "size of read buffer", default = 1024) +args = parser.parse_args() + +SLIP_END = b"\300" # Indicates end of SLIP packet +SLIP_ESC = b"\333" # Indicates byte stuffing +SLIP_ESC_END = b"\334" # ESC ESC_END means END data byte +SLIP_ESC_ESC = b"\335" # ESC ESC_ESC means ESC data byte + +Control_U = b"\025" # Console: clear line +Control_M = b"\015" # Console: end of line + +RPC_query = b"\0" * 8 # client_handle = 0, function code = RPC_FUNC_GET_VERSION +RPC_reply = b"\0" * 12 # opcode = RPC_FUNC_GET_VERSION, client_handle = 0, valret = HAL_OK + +# This is the query string we send to each USB port we find. It's +# intended to be relatively harmless, at least for either of the HSM +# ports: the final Control-U should prevent the console from trying to +# interpret the RPC command, and the SLIP_END markers should cause +# the RPC server to treat the ASCII control characters as noise. +# +# Yes, this is a total kludge. Useful identifiers for the USB ports +# are are on the wish list for a future revision of the hardware, but +# for the moment, we do what we can with what we have. + +probe_string = SLIP_END + Control_U + SLIP_END + RPC_query + SLIP_END + Control_U + Control_M + +ports = [port for port, desc, hwid in serial.tools.list_ports_posix.comports() + if "VID:PID=0403:6014" in hwid] + +if not ports: + sys.exit("Couldn't find any likely USB ports") + +if args.debug: + sys.stderr.write("Candidate USB ports: {}\n".format(", ".join(ports))) + +env = {} + +for port in ports: + + while True: + try: + tty = serial.Serial(port, 921600, timeout=0.1) + break + except serial.SerialException: + time.sleep(0.2) + + # Not sure we really need to dribble the probe string out this slowly anymore, + # but once upon a time we did this for a reason and it's not like this program + # is a performance bottleneck, so stick with the safe version. + + for i in range(len(probe_string)): + tty.write(probe_string[i:i+1]) + time.sleep(0.1) + + response = tty.read(args.read_buffer_size) + if args.debug: + sys.stderr.write("Received from {}: {!r} ({})\n".format(port, response, colon_hex(response))) + + # Check whether we got a known console prompt. + + is_cty = any(prompt in response for prompt in (b"Username:", b"Password:", b"cryptech>")) + + # Check whether we got something that looks like the response to an RPC version query. + # We skip over the version value itself, as it might change, but we check that it's + # terminated properly. This is fragile, and will need to handle SLIP decoding if + # we ever bump one of the version fields up into the range where the SLIP control + # characters live, but it will do for the moment. + + try: + is_hsm = response[response.index(SLIP_END + RPC_reply) + len(SLIP_END + RPC_reply) + 4] == SLIP_END[0] + except ValueError: + is_hsm = False + except IndexError: + is_hsm = False + + if is_cty and args.verbose: + sys.stderr.write("{} looks like the Cryptech HSM console port\n".format(port)) + + if is_hsm and args.verbose: + sys.stderr.write("{} looks like the Cryptech HSM RPC port\n".format(port)) + + if is_cty: + env.update(CRYPTECH_CTY_CLIENT_SERIAL_DEVICE = port) + + if is_hsm: + env.update(CRYPTECH_RPC_CLIENT_SERIAL_DEVICE = port) + + if (is_cty or is_hsm) and not args.no_cleanup: + if is_cty: + tty.write(Control_U) + if is_hsm: + tty.write(SLIP_END) + while tty.read(args.read_buffer_size): + pass + + tty.close() + +if env: + sys.stdout.write("export {}\n".format( + " ".join("{}='{}'".format(var, env[var]) for var in sorted(env)))) diff --git a/projects/hsm/cryptech_upload b/projects/hsm/cryptech_upload new file mode 100755 index 0000000..b40427d --- /dev/null +++ b/projects/hsm/cryptech_upload @@ -0,0 +1,385 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2016-2017, NORDUnet A/S All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# - Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# - Neither the name of the NORDUnet nor the names of its contributors may +# be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +""" +Utility to upload a new firmware image or FPGA bitstream. +""" + +import os +import sys +import time +import struct +import serial +import socket +import getpass +import os.path +import tarfile +import argparse +import platform + +from binascii import crc32, hexlify + +FIRMWARE_CHUNK_SIZE = 4096 +FPGA_CHUNK_SIZE = 4096 + + +def parse_args(): + """ + Parse the command line arguments + """ + + share_directory = "/usr/share" if platform.system() == "Linux" else "/usr/local/share" + + default_tarball = os.path.join(share_directory, "cryptech-alpha-firmware.tar.gz") + + if not os.path.exists(default_tarball): + default_tarball = None + + parser = argparse.ArgumentParser(description = __doc__, + formatter_class = argparse.ArgumentDefaultsHelpFormatter, + ) + + parser.add_argument("-d", "--device", + default = os.getenv("CRYPTECH_CTY_CLIENT_SERIAL_DEVICE", "/dev/ttyUSB0"), + help = "Name of management port USB serial device", + ) + + parser.add_argument("--socket", + default = os.getenv("CRYPTECH_CTY_CLIENT_SOCKET_NAME", + "/tmp/.cryptech_muxd.cty"), + help = "Name of cryptech_muxd management port socket", + ) + + parser.add_argument("--firmware-tarball", + type = argparse.FileType("rb"), + default = default_tarball, + help = "Location of firmware tarball", + ) + + parser.add_argument("--username", + choices = ("so", "wheel"), + default = "so", + help = "Username to use when logging into the HSM", + ) + + parser.add_argument("--pin", + help = "PIN to use when logging into the HSM", + ) + + parser.add_argument("--separate-pins", + action = "store_true", + help = "Prompt separately for each PIN required during firmware upload") + + actions = parser.add_mutually_exclusive_group(required = True) + actions.add_argument("--fpga", + action = "store_true", + help = "Upload FPGA bitstream", + ) + actions.add_argument("--firmware", "--hsm", + action = "store_true", + help = "Upload HSM firmware image", + ) + actions.add_argument("--bootloader", + action = "store_true", + help = "Upload bootloader image (dangerous!)", + ) + + parser.add_argument("--simon-says-whack-my-bootloader", + action = "store_true", + help = "Confirm that you really want to risk bricking the HSM", + ) + + parser.add_argument("-i", "--explicit-image", + type = argparse.FileType("rb"), + help = "Explicit source image file for upload, overrides firmware tarball") + + parser.add_argument("--debug", + action = "store_true", + help = "Enable debugging of upload protocol", + ) + + parser.add_argument("-q", "--quiet", + action = "store_true", + help = "Only report errors", + ) + + return parser.parse_args() + + +class ManagementPortAbstract(object): + """ + Abstract class encapsulating actions on the HSM management port. + """ + + def __init__(self, args): + self.args = args + + def write(self, data): + numeric = isinstance(data, int) + if numeric: + data = struct.pack("<I", data) + self.send(data) + if self.args.debug: + if numeric: + print("Wrote 0x{}".format(hexlify(data).decode("ascii"))) + else: + print("Wrote {!r}".format(data)) + + def read(self): + res = b"" + x = self.recv() + while not x: + x = self.recv() + while x: + res += x + x = self.recv() + if self.args.debug: + print("Read {!r}".format(res)) + return res + + def execute(self, cmd): + self.write(b"\r") + prompt = self.read() + #if prompt.endswith("This is the bootloader speaking..."): + # prompt = self.read() + if prompt.endswith(b"Username: "): + self.write(self.args.username.encode("ascii") + b"\r") + prompt = self.read() + if prompt.endswith(b"Password: "): + if not self.args.pin or self.args.separate_pins: + self.args.pin = getpass.getpass("{} PIN: ".format(self.args.username)) + self.write(self.args.pin.encode("ascii") + b"\r") + prompt = self.read() + if not prompt.endswith((b"> ", b"# ")): + print("Device does not seem to be ready for a file transfer (got {!r})".format(prompt)) + return prompt + self.write(cmd + b"\r") + response = self.read() + return response + + +class ManagementPortSerial(ManagementPortAbstract): + """ + Implmentation of HSM management port abstraction over a direct + serial connection. + """ + + def __init__(self, args, timeout = 1): + super(ManagementPortSerial, self).__init__(args) + self.serial = serial.Serial(args.device, 921600, timeout = timeout) + + def send(self, data): + self.serial.write(data) + self.serial.flush() + + def recv(self): + return self.serial.read(1) + + def set_timeout(self, timeout): + self.serial.timeout = timeout + + def close(self): + self.serial.close() + +class ManagementPortSocket(ManagementPortAbstract): + """ + Implmentation of HSM management port abstraction over a PF_UNIX + socket connection to the cryptech_muxd management socket. + """ + + def __init__(self, args, timeout = 1): + super(ManagementPortSocket, self).__init__(args) + self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + self.socket.connect(args.socket) + self.socket.settimeout(timeout) + + def send(self, data): + self.socket.sendall(data) + + def recv(self): + try: + return self.socket.recv(1) + except socket.timeout: + return b"" + + def set_timeout(self, timeout): + self.socket.settimeout(timeout) + + def close(self): + self.socket.close() + + +def send_file(src, size, args, dst): + """ + Upload an image from some file-like source to the management port. + Details depend on what kind of image it is. + """ + + if args.fpga: + chunk_size = FPGA_CHUNK_SIZE + response = dst.execute(b"fpga bitstream upload") + elif args.firmware: + chunk_size = FIRMWARE_CHUNK_SIZE + response = dst.execute(b"firmware upload") + if b"Rebooting" in response: + response = dst.execute(b"firmware upload") + elif args.bootloader: + chunk_size = FIRMWARE_CHUNK_SIZE + response = dst.execute(b"bootloader upload") + if b"Access denied" in response: + print("Access denied") + return False + if not b"OK" in response: + print("Device did not accept the upload command (got {!r})".format(response)) + return False + + dst.set_timeout(0.001) + crc = 0 + counter = 0 + # 1. Write size of file (4 bytes) + dst.write(struct.pack("<I", size)) + response = dst.read() + if not response.startswith(b"Send "): + print(response) + return False + + # 2. Write file contents while calculating CRC-32 + chunks = int((size + chunk_size - 1) / chunk_size) + for counter in range(chunks): + data = src.read(chunk_size) + dst.write(data) + if not args.quiet: + print("Wrote {!s} bytes (chunk {!s}/{!s})".format(len(data), counter + 1, chunks)) + # read ACK (a counter of number of 4k chunks received) + ack_bytes = b"" + while len(ack_bytes) < 4: + ack_bytes += dst.read() + ack = struct.unpack("<I", ack_bytes[:4])[0] + if ack != counter + 1: + print("ERROR: Did not receive the expected counter as ACK (got {!r}/{!r}, not {!r})".format(ack, ack_bytes, counter)) + return False + counter += 1 + + crc = crc32(data, crc) & 0xffffffff + + # 3. Write CRC-32 (4 bytes) + dst.write(struct.pack("<I", crc)) + response = dst.read() + if not args.quiet: + print(response) + + src.close() + + if args.fpga: + # tell the fpga to read its new configuration + dst.execute(b"fpga reset") + # log out of the CLI + # (firmware/bootloader upgrades reboot, don't need an exit) + dst.execute(b"exit") + + return True + + +dire_bootloader_warning = ''' + WARNING + +Updating the bootloader risks bricking your HSM! If something goes +badly wrong here, or you upload a bad bootloader image, you will not +be able to recover without an ST-LINK programmer. + +In most cases a normal "--firmware" upgrade should be all that is +necessary to bring your HSM up to date, there is seldom any real need +to update the bootloader. + +Do not proceed with this unless you REALLY know what you are doing. + +If you got here by accident, ^C now, without answering the PIN prompt. +''' + + +def main(): + global args + args = parse_args() + + + if args.bootloader: + if not args.simon_says_whack_my_bootloader: + sys.exit("You didn't say \"Simon says\"") + print(dire_bootloader_warning) + args.pin = None + + if args.explicit_image is None and args.firmware_tarball is None: + sys.exit("No source file specified for upload and firmware tarball not found") + + if args.explicit_image: + src = args.explicit_image # file-like object, thanks to argparse + size = os.fstat(src.fileno()).st_size + if size == 0: # Flashing from stdin won't work, sorry + sys.exit("Can't flash from a pipe or zero-length file") + if not args.quiet: + print("Uploading from explicitly-specified file {}".format(args.explicit_image.name)) + + else: + tar = tarfile.open(fileobj = args.firmware_tarball) + if not args.quiet: + print("Firmware tarball {} content:".format(args.firmware_tarball.name)) + tar.list(True) + if args.fpga: + name = "alpha_fmc.bit" + elif args.firmware: + name = "hsm.bin" + elif args.bootloader: + name = "bootloader.bin" + else: + # Somebody updated other part of this script without updating this part :( + sys.exit("Don't know which component to select from firmware tarball, sorry") + try: + size = tar.getmember(name).size + except KeyError: + sys.exit("Expected component {} missing from firmware tarball {}".format(name, args.firmware_tarball.name)) + src = tar.extractfile(name) + if not args.quiet: + print("Uploading {} from {}".format(name, args.firmware_tarball.name)) + + if not args.quiet: + print("Initializing management port and synchronizing with HSM, this may take a few seconds") + try: + dst = ManagementPortSocket(args, timeout = 1) + except socket.error as e: + dst = ManagementPortSerial(args, timeout = 1) + send_file(src, size, args, dst) + dst.close() + + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + pass diff --git a/projects/hsm/hsm.c b/projects/hsm/hsm.c new file mode 100644 index 0000000..52157c9 --- /dev/null +++ b/projects/hsm/hsm.c @@ -0,0 +1,522 @@ +/* + * hsm.c + * ---------------- + * Main module for the HSM project. + * + * Copyright (c) 2016-2017, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This is the main RPC server module. At the moment, it has a single + * worker thread to handle RPC requests, while the main thread handles CLI + * activity. The design allows for multiple worker threads to handle + * concurrent RPC requests from multiple clients (muxed through a daemon + * on the host). + */ + +#include <string.h> + +/* Rename both CMSIS HAL_OK and libhal HAL_OK to disambiguate */ +#define HAL_OK CMSIS_HAL_OK +#include "stm-init.h" +#include "stm-led.h" +#include "stm-fmc.h" +#include "stm-uart.h" +#include "stm-sdram.h" +#include "task.h" + +#include "mgmt-cli.h" + +#undef HAL_OK +#define HAL_OK LIBHAL_OK +#include "hal.h" +#include "hal_internal.h" +#include "slip_internal.h" +#include "xdr_internal.h" +#undef HAL_OK + +#ifndef NUM_RPC_TASK +#define NUM_RPC_TASK 1 +#elif NUM_RPC_TASK < 1 || NUM_RPC_TASK > 10 +#error invalid NUM_RPC_TASK +#endif + +#ifndef TASK_STACK_SIZE +/* Define an absurdly large task stack, because some pkey operation use a + * lot of stack variables. This has to go in SDRAM, because it exceeds the + * total RAM on the ARM. + */ +#define TASK_STACK_SIZE 200*1024 +#endif + +/* Stack for the busy task. This doesn't need to be very big. + */ +#ifndef BUSY_STACK_SIZE +#define BUSY_STACK_SIZE 1*1024 +#endif +static uint8_t busy_stack[BUSY_STACK_SIZE]; + +/* Stack for the CLI task. This needs to be big enough to accept a + * 4096-byte block of an FPGA or bootloader image upload. + */ +#ifndef CLI_STACK_SIZE +#define CLI_STACK_SIZE 16*1024 +#endif + +/* RPC buffers. For each active request, there will be two - input and output. + */ +typedef struct rpc_buffer_s { + size_t len; + uint8_t buf[HAL_RPC_MAX_PKT_SIZE]; + struct rpc_buffer_s *next; /* for ibuf queue linking */ +} rpc_buffer_t; + +/* RPC input (requst) buffers */ +static rpc_buffer_t *ibufs; + +/* ibuf queue structure */ +typedef struct { + rpc_buffer_t *head, *tail; + size_t len, max; /* for reporting */ +} ibufq_t; + +/* ibuf queues. These correspond roughly to task states - 'waiting' is for + * unallocated ibufs, while 'ready' is for requests that are ready to be + * processed. + */ +static ibufq_t ibuf_waiting, ibuf_ready; + +/* Get an ibuf from a queue. */ +static rpc_buffer_t *ibuf_get(ibufq_t *q) +{ + hal_critical_section_start(); + rpc_buffer_t *ibuf = q->head; + if (ibuf) { + q->head = ibuf->next; + if (q->head == NULL) + q->tail = NULL; + ibuf->next = NULL; + --q->len; + } + hal_critical_section_end(); + return ibuf; +} + +/* Put an ibuf on a queue. */ +static void ibuf_put(ibufq_t *q, rpc_buffer_t *ibuf) +{ + hal_critical_section_start(); + if (q->tail) + q->tail->next = ibuf; + else + q->head = ibuf; + q->tail = ibuf; + ibuf->next = NULL; + if (++q->len > q->max) + q->max = q->len; + hal_critical_section_end(); +} + +/* Get the current length of the 'ready' queue, for reporting in the CLI. */ +size_t request_queue_len(void) +{ + size_t n; + + hal_critical_section_start(); + n = ibuf_ready.len; + hal_critical_section_end(); + + return n; +} + +/* Get the maximum length of the 'ready' queue, for reporting in the CLI. */ +size_t request_queue_max(void) +{ + size_t n; + + hal_critical_section_start(); + n = ibuf_ready.max; + hal_critical_section_end(); + + return n; +} + +static void dispatch_task(void); +static void busy_task(void); +static tcb_t *busy_tcb; + +/* Select an available dispatch task. For simplicity, this doesn't try to + * allocate tasks in a round-robin fashion, so the lowest-numbered task + * will see the most action. OTOH, this lets us gauge the level of system + * activity in the CLI's 'task show' command. + */ +static tcb_t *task_next_waiting(void) +{ + for (tcb_t *t = task_iterate(NULL); t; t = task_iterate(t)) { + if (task_get_func(t) == dispatch_task && + task_get_state(t) == TASK_WAITING) + return t; + } + return NULL; +} + +static uint8_t *sdram_malloc(size_t size); + +/* Callback for HAL_UART_Receive_DMA(). + */ +static void RxCallback(uint8_t c) +{ + int complete; + static rpc_buffer_t *ibuf = NULL; + + /* If we couldn't previously get an ibuf, a task may have freed one up + * in the meantime. Otherwise, allocate one from SDRAM. In normal + * operation, the number of ibufs will expand to the number of remote + * clients (which we don't know and can't predict). It would take an + * active attempt to DOS the system to exhaust SDRAM, and there are + * easier ways to attack the device (don't release hash or pkey handles). + */ + if (ibuf == NULL) { + ibuf = ibuf_get(&ibuf_waiting); + if (ibuf == NULL) { + ibuf = (rpc_buffer_t *)sdram_malloc(sizeof(rpc_buffer_t)); + if (ibuf == NULL) + Error_Handler(); + } + ibuf->len = 0; + } + + /* Process this character into the ibuf. */ + if (hal_slip_process_char(c, ibuf->buf, &ibuf->len, sizeof(ibuf->buf), &complete) != LIBHAL_OK) + Error_Handler(); + + if (complete) { + /* Add the ibuf to the request queue, and try to get another ibuf. + */ + ibuf_put(&ibuf_ready, ibuf); + ibuf = ibuf_get(&ibuf_waiting); + if (ibuf != NULL) + ibuf->len = 0; + /* else all ibufs are busy, try again next time */ + + /* Wake a dispatch task to deal with this request, or wake the + * busy task to re-try scheduling a dispatch task. + */ + tcb_t *t = task_next_waiting(); + if (t) + task_wake(t); + else + task_wake(busy_tcb); + } +} + +/* A ring buffer for the UART DMA receiver. In theory, it should get at most + * 92 characters per 1ms tick, but we're going to up-size it for safety. + */ +#ifndef RPC_UART_RECVBUF_SIZE +#define RPC_UART_RECVBUF_SIZE 1024 /* must be a power of 2 */ +#endif +#define RPC_UART_RECVBUF_MASK (RPC_UART_RECVBUF_SIZE - 1) + +typedef struct { + uint32_t ridx; + uint8_t buf[RPC_UART_RECVBUF_SIZE]; +} uart_ringbuf_t; + +volatile uart_ringbuf_t uart_ringbuf = {0, {0}}; + +#define RINGBUF_RIDX(rb) (rb.ridx & RPC_UART_RECVBUF_MASK) +#define RINGBUF_WIDX(rb) (sizeof(rb.buf) - __HAL_DMA_GET_COUNTER(huart_user.hdmarx)) +#define RINGBUF_COUNT(rb) ((RINGBUF_WIDX(rb) - RINGBUF_RIDX(rb)) & RPC_UART_RECVBUF_MASK) +#define RINGBUF_READ(rb, dst) {dst = rb.buf[RINGBUF_RIDX(rb)]; rb.ridx++;} + +size_t uart_rx_max = 0; + +void HAL_SYSTICK_Callback(void) +{ +#ifdef DO_PROFILING + extern void profil_callback(void); + profil_callback(); +#endif + + size_t count = RINGBUF_COUNT(uart_ringbuf); + if (uart_rx_max < count) uart_rx_max = count; + + while (RINGBUF_COUNT(uart_ringbuf)) { + uint8_t c; + RINGBUF_READ(uart_ringbuf, c); + RxCallback(c); + } +} + +/* Send one character over the UART. This is called from + * hal_slip_send_char(). + */ +hal_error_t hal_serial_send_char(uint8_t c) +{ + return (uart_send_char2(STM_UART_USER, c) == 0) ? LIBHAL_OK : HAL_ERROR_RPC_TRANSPORT; +} + +/* Task entry point for the RPC request handler. + */ +static void dispatch_task(void) +{ + rpc_buffer_t obuf_s, *obuf = &obuf_s; + + while (1) { + /* Wait for a complete RPC request */ + task_sleep(); + + rpc_buffer_t *ibuf = ibuf_get(&ibuf_ready); + if (ibuf == NULL) + /* probably an error, but go back to sleep */ + continue; + + memset(obuf, 0, sizeof(*obuf)); + obuf->len = sizeof(obuf->buf); + + /* Process the request */ + hal_error_t ret = hal_rpc_server_dispatch(ibuf->buf, ibuf->len, obuf->buf, &obuf->len); + ibuf_put(&ibuf_waiting, ibuf); + if (ret == LIBHAL_OK) { + /* Send the response */ + if (hal_rpc_sendto(obuf->buf, obuf->len, NULL) != LIBHAL_OK) + Error_Handler(); + } + /* Else hal_rpc_server_dispatch failed with an XDR error, which + * probably means the request packet was garbage. In any case, we + * have nothing to transmit. + */ + } +} + +/* Task entry point for the task-rescheduling task. + */ +static void busy_task(void) +{ + while (1) { + /* Wake as many tasks as we have requests. + */ + size_t n; + for (n = request_queue_len(); n > 0; --n) { + tcb_t *t; + if ((t = task_next_waiting()) != NULL) + task_wake(t); + else + break; + } + if (n == 0) + /* flushed the queue, our work here is done */ + task_sleep(); + else + /* more work to do, try again after some tasks have run */ + task_yield(); + } +} + +#include "stm-fpgacfg.h" + +static void hashsig_restart_task(void) +{ + /* wait for the fpga to configure itself on cold-boot */ + while (fpgacfg_check_done() != CMSIS_HAL_OK) + task_yield(); + + /* reinitialize the hashsig key structures after a device restart */ + hal_hashsig_ks_init(); + + /* done, convert this task to an RPC handler */ + task_mod((char *)task_get_cookie(NULL), dispatch_task, NULL); +} + +/* end of variables declared with __attribute__((section(".sdram1"))) */ +extern uint8_t _esdram1 __asm ("_esdram1"); +/* end of SDRAM1 section */ +extern uint8_t __end_sdram1 __asm ("__end_sdram1"); +static uint8_t *sdram_heap = &_esdram1; + +/* Allocate memory from SDRAM1. */ +static uint8_t *sdram_malloc(size_t size) +{ + uint8_t *p = sdram_heap; + +#define pad(n) (((n) + 3) & ~3) + size = pad(size); + + if (p + size + sizeof(uint32_t) > &__end_sdram1) + return NULL; + + *(uint32_t *)p = (uint32_t)size; + p += sizeof(uint32_t); + + sdram_heap += size + sizeof(uint32_t); + return p; +} + +/* A very limited form of free(), which only frees memory if it's at the + * top of the heap. + */ +static hal_error_t sdram_free(uint8_t *ptr) +{ + uint8_t *p = ptr - sizeof(uint32_t); + uint32_t size = *(uint32_t *)p; + if (ptr + size == sdram_heap) { + sdram_heap = p; + return LIBHAL_OK; + } + else + return HAL_ERROR_FORBIDDEN; +} + +hal_error_t sdram_stats(size_t *used, size_t *available) +{ + if (used == NULL || available == NULL) + return HAL_ERROR_BAD_ARGUMENTS; + + *used = sdram_heap - &_esdram1; + *available = &__end_sdram1 - sdram_heap; + + return LIBHAL_OK; +} + +/* Implement static memory allocation for libhal over sdram_malloc(). + */ +void *hal_allocate_static_memory(const size_t size) +{ + return sdram_malloc(size); +} + +hal_error_t hal_free_static_memory(const void * const ptr) +{ + return sdram_free((uint8_t *)ptr); +} + +/* Critical section start/end - temporarily disable interrupts. + */ +void hal_critical_section_start(void) +{ + __disable_irq(); +} + +void hal_critical_section_end(void) +{ + __enable_irq(); +} + +/* A genericized public interface to task_yield(), for calling from + * libhal. + */ +void hal_task_yield(void) +{ + task_yield(); +} + +void hal_task_yield_maybe(void) +{ + task_yield_maybe(); +} + +/* A mutex to arbitrate concurrent access to the keystore. + */ +task_mutex_t ks_mutex = { 0 }; +void hal_ks_lock(void) { task_mutex_lock(&ks_mutex); } +void hal_ks_unlock(void) { task_mutex_unlock(&ks_mutex); } + +/* A mutex to arbitrary concurrent access to the RSA blinding factors cache. + */ +task_mutex_t rsa_bf_mutex = { 0 }; +void hal_rsa_bf_lock(void) { task_mutex_lock(&rsa_bf_mutex); } +void hal_rsa_bf_unlock(void) { task_mutex_unlock(&rsa_bf_mutex); } + +/* Sleep for specified number of seconds. + */ +void hal_sleep(const unsigned seconds) { task_delay(seconds * 1000); } + +/* The main task. This does all the setup, and the worker tasks handle + * the rest. + */ +int main(void) +{ + stm_init(); + led_on(LED_GREEN); + + if (hal_rpc_server_init() != LIBHAL_OK) + Error_Handler(); + + /* Initialize the ibuf queues. */ + ibufs = (rpc_buffer_t *)sdram_malloc(NUM_RPC_TASK * sizeof(rpc_buffer_t)); + if (ibufs == NULL) + Error_Handler(); + memset(ibufs, 0, NUM_RPC_TASK * sizeof(rpc_buffer_t)); + memset(&ibuf_waiting, 0, sizeof(ibuf_waiting)); + memset(&ibuf_ready, 0, sizeof(ibuf_ready)); + for (size_t i = 0; i < NUM_RPC_TASK; ++i) + ibuf_put(&ibuf_waiting, &ibufs[i]); + + /* Create the rpc dispatch worker tasks. */ + static char label[NUM_RPC_TASK][sizeof("dispatch0")]; + for (int i = 0; i < NUM_RPC_TASK; ++i) { + sprintf(label[i], "dispatch%d", i); + void *stack = (void *)sdram_malloc(TASK_STACK_SIZE); + if (stack == NULL) + Error_Handler(); + if (i == NUM_RPC_TASK - 1) { + if (task_add("hashsig_restart", hashsig_restart_task, label[i], stack, TASK_STACK_SIZE) == NULL) + Error_Handler(); + } + else { + if (task_add(label[i], dispatch_task, NULL, stack, TASK_STACK_SIZE) == NULL) + Error_Handler(); + } + } + + /* Create the busy task. */ + busy_tcb = task_add("busy", busy_task, NULL, busy_stack, sizeof(busy_stack)); + if (busy_tcb == NULL) + Error_Handler(); + + /* Start the UART receiver. */ + if (HAL_UART_Receive_DMA(&huart_user, (uint8_t *) uart_ringbuf.buf, sizeof(uart_ringbuf.buf)) != CMSIS_HAL_OK) + Error_Handler(); + + /* Launch other tasks (csprng warm-up task?) + * Wait for FPGA_DONE interrupt. + */ + + /* Create the CLI task. */ + void *cli_stack = (void *)sdram_malloc(CLI_STACK_SIZE); + if (task_add("cli", (funcp_t)cli_main, NULL, cli_stack, CLI_STACK_SIZE) == NULL) + Error_Handler(); + + /* Start the tasker */ + task_yield(); + + /*NOTREACHED*/ + return 0; +} diff --git a/projects/hsm/log.c b/projects/hsm/log.c new file mode 100644 index 0000000..fbc0e73 --- /dev/null +++ b/projects/hsm/log.c @@ -0,0 +1,68 @@ +/* + * log.c + * ----- + * Implement libhal logging API on Alpha. + * + * Copyright (c) 2017, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdarg.h> + +#define HAL_OK CMSIS_HAL_OK +#include "stm-uart.h" +#undef HAL_OK + +#define HAL_OK LIBHAL_OK +#include "hal.h" +#include "hal_internal.h" +#undef HAL_OK + +static hal_log_level_t current_log_level; + +void hal_log_set_level(const hal_log_level_t level) +{ + current_log_level = level; +} + +void hal_log(const hal_log_level_t level, const char *format, ...) +{ + if (level < current_log_level) + return; + + char buffer[2048]; + va_list ap; + + va_start(ap, format); + vsnprintf(buffer, sizeof(buffer), format, ap); + va_end(ap); + + uart_send_string(buffer); + uart_send_string("\r\n"); +} diff --git a/projects/hsm/main.c b/projects/hsm/main.c deleted file mode 100644 index 79c567b..0000000 --- a/projects/hsm/main.c +++ /dev/null @@ -1,226 +0,0 @@ -/* - * rpc_server.c - * ------------ - * Remote procedure call server-side private API implementation. - * - * Copyright (c) 2016, NORDUnet A/S All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the NORDUnet nor the names of its contributors may - * be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This is the main RPC server moddule. It creates a new thread to deal - * with each request, to prevent a long-running request (e.g. RSA keygen) - * from blocking independent requests from other clients. This has a - * number of consequences. We can't do a blocking receive in the main - * thread, because that prevents the dispatch thread from transmitting the - * response (because they both want to lock the UART - see - * stm32f4xx_hal_uart.c). So we have to do a non-blocking receive with a - * callback routine. But we can't create a thread from the callback - * routine, because it's in the context of an ISR, so we raise a semaphore - * for the main thread to create the dispatch thread. - */ - -#include <string.h> - -#include "cmsis_os.h" - -#include "stm-init.h" -#include "stm-led.h" -#include "stm-fmc.h" -#include "stm-uart.h" - -/* stm32f4xx_hal_def.h and hal.h both define HAL_OK as an enum value */ -#define HAL_OK HAL_OKAY - -#include "hal.h" -#include "hal_internal.h" -#include "slip_internal.h" -#include "xdr_internal.h" - -/* RPC buffers. For each active RPC, there will be two - input and output. - */ - -#ifndef NUM_RPC_BUFFER -/* An arbitrary number, but we don't expect to have more than 8 concurrent - * RPC requests. - */ -#define NUM_RPC_BUFFER 16 -#endif - -#ifndef MAX_PKT_SIZE -/* Another arbitrary number, more or less driven by the 4096-bit RSA - * keygen test. - */ -#define MAX_PKT_SIZE 4096 -#endif - -/* The thread entry point takes a single void* argument, so we bundle the - * packet buffer and length arguments together. - */ -typedef struct { - size_t len; - uint8_t buf[MAX_PKT_SIZE]; -} rpc_buffer_t; - -osPoolDef(rpc_buffer_pool, NUM_RPC_BUFFER, rpc_buffer_t); -osPoolId rpc_buffer_pool; - -static rpc_buffer_t *rpc_buffer_alloc(void) -{ - return (rpc_buffer_t *)osPoolCAlloc(rpc_buffer_pool); -} - -/* A mutex to arbitrate concurrent UART transmits, from RPC responses. - */ -osMutexId uart_mutex; -osMutexDef(uart_mutex); - -/* Thread entry point for the RPC request handler. - */ -static void dispatch_thread(void const *args) -{ - rpc_buffer_t *ibuf = (rpc_buffer_t *)args; - rpc_buffer_t *obuf = rpc_buffer_alloc(); - if (obuf == NULL) { - uint8_t buf[8]; - uint8_t * bufptr = &buf[4]; - const uint8_t * const limit = buf + sizeof(buf); - memcpy(buf, ibuf->buf, 4); - hal_xdr_encode_int(&bufptr, limit, HAL_ERROR_ALLOCATION_FAILURE); - osMutexWait(uart_mutex, osWaitForever); - hal_rpc_sendto(ibuf->buf, sizeof(buf), NULL); - osMutexRelease(uart_mutex); - osPoolFree(rpc_buffer_pool, ibuf); - Error_Handler(); - } - /* copy client ID from request to response */ - memcpy(obuf->buf, ibuf->buf, 4); - obuf->len = sizeof(obuf->buf) - 4; - hal_rpc_server_dispatch(ibuf->buf + 4, ibuf->len - 4, obuf->buf + 4, &obuf->len); - osPoolFree(rpc_buffer_pool, ibuf); - osMutexWait(uart_mutex, osWaitForever); - hal_error_t ret = hal_rpc_sendto(obuf->buf, obuf->len + 4, NULL); - osMutexRelease(uart_mutex); - osPoolFree(rpc_buffer_pool, obuf); - if (ret != HAL_OK) - Error_Handler(); -} -osThreadDef(dispatch_thread, osPriorityNormal, DEFAULT_STACK_SIZE); - -/* Semaphore to inform the main thread that there's a new RPC request. - */ -osSemaphoreId rpc_sem; -osSemaphoreDef(rpc_sem); - -static uint8_t c; /* current character received from UART */ -static rpc_buffer_t *ibuf; /* current RPC input buffer */ - -/* Callback for HAL_UART_Receive_IT(). - */ -void HAL_UART2_RxCpltCallback(UART_HandleTypeDef *huart) -{ - int complete; - hal_slip_recv_char(ibuf->buf, &ibuf->len, sizeof(ibuf->buf), &complete); - if (complete) - osSemaphoreRelease(rpc_sem); - - HAL_UART_Receive_IT(huart, &c, 1); -} - -hal_error_t hal_serial_send_char(uint8_t c) -{ - return (uart_send_char(c) == 0) ? HAL_OK : HAL_ERROR_RPC_TRANSPORT; -} - -hal_error_t hal_serial_recv_char(uint8_t *cp) -{ - /* return the character from HAL_UART_Receive_IT */ - *cp = c; - return HAL_OK; -} - -/* The main thread. After the system setup, it waits for the RPC-request - * semaphore from HAL_UART_RxCpltCallback, and spawns a dispatch thread. - */ -int main() -{ - stm_init(); - -#ifdef TARGET_CRYPTECH_DEV_BRIDGE - /* Wait six seconds to not upset the Novena at boot. */ - led_on(LED_BLUE); - for (int i = 0; i < 12; i++) { - osDelay(500); - led_toggle(LED_BLUE); - } - led_off(LED_BLUE); -#endif - led_on(LED_GREEN); - /* Prepare FMC interface. */ - fmc_init(); - - /* Haaaack. probe_cores() calls malloc(), which works from the main - * thread, but not from a spawned thread. It would be better to - * rewrite it to use static memory, but for now, just force it to - * probe early. - */ - hal_core_iterate(NULL); - - rpc_buffer_pool = osPoolCreate(osPool(rpc_buffer_pool)); - uart_mutex = osMutexCreate(osMutex(uart_mutex)); - rpc_sem = osSemaphoreCreate(osSemaphore(rpc_sem), 0); - -#ifdef TARGET_CRYPTECH_ALPHA - /* Launch other threads: - * - admin thread on USART1 - * - csprng warm-up thread? - */ -#endif - - if (hal_rpc_server_init() != HAL_OK) - Error_Handler(); - - ibuf = rpc_buffer_alloc(); - if (ibuf == NULL) - /* Something is badly wrong. */ - Error_Handler(); - - /* Start the non-blocking receive */ - HAL_UART_Receive_IT(&huart_user, &c, 1); - - while (1) { - osSemaphoreWait(rpc_sem, osWaitForever); - if (osThreadCreate(osThread(dispatch_thread), (void *)ibuf) == NULL) - Error_Handler(); - while ((ibuf = rpc_buffer_alloc()) == NULL); - /* XXX There's a potential race condition, where another request - * could write into the old ibuf, or into the null pointer if - * we're out of ibufs. - */ - } -} diff --git a/projects/hsm/mgmt-bootloader.c b/projects/hsm/mgmt-bootloader.c new file mode 100644 index 0000000..1d8b8ad --- /dev/null +++ b/projects/hsm/mgmt-bootloader.c @@ -0,0 +1,89 @@ +/* + * mgmt-bootloader.c + * ----------------- + * CLI code for updating the bootloader. + * + * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Rename both CMSIS HAL_OK and libhal HAL_OK to disambiguate */ +#define HAL_OK CMSIS_HAL_OK +#include "stm-init.h" +#include "stm-uart.h" +#include "stm-flash.h" +#include "mgmt-cli.h" +#include "mgmt-misc.h" +#include "mgmt-bootloader.h" + +#undef HAL_OK +#define HAL_OK LIBHAL_OK +#include "hal.h" +#undef HAL_OK + +extern hal_user_t user; + +static uint32_t dfu_offset; + +static HAL_StatusTypeDef _flash_write_callback(uint8_t *buf, size_t len) +{ + HAL_StatusTypeDef status = stm_flash_write32(dfu_offset, (uint32_t *)buf, len/4); + dfu_offset += DFU_UPLOAD_CHUNK_SIZE; + return status; +} + +static int cmd_bootloader_upload(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + command = command; + argv = argv; + argc = argc; + + if (user < HAL_USER_SO) { + cli_print(cli, "Permission denied."); + return CLI_ERROR; + } + + uint8_t buf[DFU_UPLOAD_CHUNK_SIZE]; + dfu_offset = DFU_BOOTLOADER_ADDR; + + int ret = cli_receive_data(cli, buf, sizeof(buf), _flash_write_callback); + if (ret == CLI_OK) { + cli_print(cli, "\nRebooting\n"); + HAL_NVIC_SystemReset(); + } + return ret; +} + +void configure_cli_bootloader(struct cli_def *cli) +{ + struct cli_command *c; + + c = cli_register_command(cli, NULL, "bootloader", NULL, 0, 0, NULL); + + cli_register_command(cli, c, "upload", cmd_bootloader_upload, 0, 0, "Upload new bootloader image"); +} diff --git a/projects/hsm/mgmt-bootloader.h b/projects/hsm/mgmt-bootloader.h new file mode 100644 index 0000000..31dbefc --- /dev/null +++ b/projects/hsm/mgmt-bootloader.h @@ -0,0 +1,51 @@ +/* + * mgmt-bootloader.h + * --------------- + * Management CLI bootloader upgrade code. + * + * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __STM32_CLI_MGMT_BOOTLOADER_H +#define __STM32_CLI_MGMT_BOOTLOADER_H + +#include <libcli.h> + +/* symbols defined in the linker script (STM32F429BI_bootloader.ld) */ +extern uint32_t CRYPTECH_BOOTLOADER_START; +extern uint32_t CRYPTECH_BOOTLOADER_END; +extern uint32_t CRYPTECH_DFU_CONTROL; + +#define DFU_BOOTLOADER_ADDR ((uint32_t) &CRYPTECH_BOOTLOADER_START) +#define DFU_BOOTLOADER_END_ADDR ((uint32_t) &CRYPTECH_BOOTLOADER_END) +#define DFU_UPLOAD_CHUNK_SIZE 4096 + +extern void configure_cli_bootloader(struct cli_def *cli); + +#endif /* __STM32_CLI_MGMT_BOOTLOADER_H */ diff --git a/projects/hsm/mgmt-cli.c b/projects/hsm/mgmt-cli.c new file mode 100644 index 0000000..fd5c90a --- /dev/null +++ b/projects/hsm/mgmt-cli.c @@ -0,0 +1,220 @@ +/* + * mgmt-cli.c + * --------- + * Management CLI code. + * + * Copyright (c) 2016-2017, NORDUnet A/S All rights reserved. + * Copyright: 2020, The Commons Conservancy Cryptech Project + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string.h> + +/* Rename both CMSIS HAL_OK and libhal HAL_OK to disambiguate */ +#define HAL_OK CMSIS_HAL_OK +#include "stm-init.h" +#include "stm-uart.h" +#include "stm-led.h" +#include "task.h" + +#include "mgmt-cli.h" +#include "mgmt-firmware.h" +#include "mgmt-bootloader.h" +#include "mgmt-fpga.h" +#include "mgmt-misc.h" +#include "mgmt-keystore.h" +#include "mgmt-masterkey.h" +#include "mgmt-task.h" +#ifdef DO_TIMING +#include "mgmt-timing.h" +#endif + +#undef HAL_OK +#define HAL_OK LIBHAL_OK +#include "hal.h" +#warning Refactor so we do not need to include hal_internal.h here +#include "hal_internal.h" +#undef HAL_OK + +static tcb_t *cli_task; + +#ifndef CLI_UART_RECVBUF_SIZE +#define CLI_UART_RECVBUF_SIZE 256 +#endif + +typedef struct { + unsigned ridx; + unsigned widx; + mgmt_cli_dma_state_t rx_state; + uint8_t buf[CLI_UART_RECVBUF_SIZE]; +} ringbuf_t; + +inline void ringbuf_init(ringbuf_t *rb) +{ + memset(rb, 0, sizeof(*rb)); +} + +/* return number of characters read */ +inline int ringbuf_read_char(ringbuf_t *rb, uint8_t *c) +{ + if (rb->ridx != rb->widx) { + *c = rb->buf[rb->ridx]; + if (++rb->ridx >= sizeof(rb->buf)) + rb->ridx = 0; + return 1; + } + return 0; +} + +inline void ringbuf_write_char(ringbuf_t *rb, uint8_t c) +{ + rb->buf[rb->widx] = c; + if (++rb->widx >= sizeof(rb->buf)) + rb->widx = 0; +} + +static ringbuf_t uart_ringbuf; + +/* current character received from UART */ +static uint8_t uart_rx; + +/* Callback for HAL_UART_Receive_DMA(). + */ +void HAL_UART1_RxCpltCallback(UART_HandleTypeDef *huart) +{ + huart = huart; + + ringbuf_write_char(&uart_ringbuf, uart_rx); + task_wake(cli_task); +} + +static void uart_cli_print(struct cli_def *cli __attribute__ ((unused)), const char *buf) +{ + char crlf[] = "\r\n"; + uart_send_string(buf); + uart_send_string(crlf); +} + +static ssize_t uart_cli_read(struct cli_def *cli __attribute__ ((unused)), void *buf, size_t count) +{ + for (size_t i = 0; i < count; ++i) { + while (ringbuf_read_char(&uart_ringbuf, (uint8_t *)(buf + i)) == 0) + task_sleep(); + } + return (ssize_t)count; +} + +static ssize_t uart_cli_write(struct cli_def *cli __attribute__ ((unused)), const void *buf, size_t count) +{ + uart_send_bytes((uint8_t *) buf, count); + return (ssize_t)count; +} + +int control_mgmt_uart_dma_rx(mgmt_cli_dma_state_t state) +{ + if (state == DMA_RX_START) { + if (uart_ringbuf.rx_state != DMA_RX_START) { + ringbuf_init(&uart_ringbuf); + HAL_UART_Receive_DMA(&huart_mgmt, &uart_rx, 1); + uart_ringbuf.rx_state = DMA_RX_START; + } + return 1; + } else if (state == DMA_RX_STOP) { + if (HAL_UART_DMAStop(&huart_mgmt) != CMSIS_HAL_OK) return 0; + uart_ringbuf.rx_state = DMA_RX_STOP; + return 1; + } + return 0; +} + +hal_user_t user; + +static int check_auth(const char *username, const char *password) +{ + hal_client_handle_t client = { -1 }; + + /* PIN-based login */ + if (strcmp(username, "wheel") == 0) + user = HAL_USER_WHEEL; + else if (strcmp(username, "so") == 0) + user = HAL_USER_SO; + else if (strcmp(username, "user") == 0) + user = HAL_USER_NORMAL; + else + user = HAL_USER_NONE; + + if (hal_rpc_login(client, user, password, strlen(password)) == LIBHAL_OK) + return CLI_OK; + + user = HAL_USER_NONE; + return CLI_ERROR; +} + +int cli_main(void) +{ + cli_task = task_get_tcb(); + + struct cli_def *cli; + cli = cli_init(); + if (cli == NULL) + Error_Handler(); + + cli_read_callback(cli, uart_cli_read); + cli_write_callback(cli, uart_cli_write); + cli_print_callback(cli, uart_cli_print); + cli_set_banner(cli, "Cryptech Alpha"); + cli_set_hostname(cli, "cryptech"); + cli_set_auth_callback(cli, check_auth); + + /* we don't have any privileged commands at the moment */ + cli_unregister_command(cli, "enable"); + + configure_cli_fpga(cli); + configure_cli_keystore(cli); + configure_cli_masterkey(cli); + configure_cli_firmware(cli); + configure_cli_bootloader(cli); + configure_cli_misc(cli); + configure_cli_task(cli); +#ifdef DO_TIMING + configure_cli_timing(cli); +#endif + + while (1) { + control_mgmt_uart_dma_rx(DMA_RX_START); + + cli_loop(cli, 0); + /* cli_loop returns when the user enters 'quit' or 'exit' */ + cli_print(cli, "\nLogging out...\n"); + user = HAL_USER_NONE; + } + + /*NOTREACHED*/ + return -1; +} diff --git a/projects/hsm/mgmt-cli.h b/projects/hsm/mgmt-cli.h new file mode 100644 index 0000000..0b9c40c --- /dev/null +++ b/projects/hsm/mgmt-cli.h @@ -0,0 +1,49 @@ +/* + * mgmt-cli.h + * --------- + * Management CLI code. + * + * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __STM32_MGMT_CLI_H +#define __STM32_MGMT_CLI_H + +#include <libcli.h> + +typedef enum { + DMA_RX_STOP, + DMA_RX_START, +} mgmt_cli_dma_state_t; + +extern int control_mgmt_uart_dma_rx(mgmt_cli_dma_state_t state); + +extern int cli_main(void); + +#endif /* __STM32_MGMT_CLI_H */ diff --git a/projects/hsm/mgmt-firmware.c b/projects/hsm/mgmt-firmware.c new file mode 100644 index 0000000..b6b3321 --- /dev/null +++ b/projects/hsm/mgmt-firmware.c @@ -0,0 +1,75 @@ +/* + * mgmt-firmware.c + * --------------- + * CLI code for managing the loaded firmware. + * + * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Rename both CMSIS HAL_OK and libhal HAL_OK to disambiguate */ +#define HAL_OK CMSIS_HAL_OK +#include "stm-init.h" +#include "stm-uart.h" + +#include "mgmt-cli.h" + +#undef HAL_OK +#define HAL_OK LIBHAL_OK +#include "hal.h" +#undef HAL_OK + +extern hal_user_t user; + +static int cmd_firmware_upload(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + command = command; + argv = argv; + argc = argc; + + if (user < HAL_USER_SO) { + cli_print(cli, "Permission denied."); + return CLI_ERROR; + } + + /* reboot and let the bootloader handle the upload */ + cli_print(cli, "\n\n\nRebooting\n\n\n"); + HAL_NVIC_SystemReset(); + + /*NOTREACHED*/ + return CLI_OK; +} + +void configure_cli_firmware(struct cli_def *cli) +{ + struct cli_command *c; + + c = cli_register_command(cli, NULL, "firmware", NULL, 0, 0, NULL); + + cli_register_command(cli, c, "upload", cmd_firmware_upload, 0, 0, "Upload new firmware image"); +} diff --git a/projects/hsm/mgmt-firmware.h b/projects/hsm/mgmt-firmware.h new file mode 100644 index 0000000..af7c67c --- /dev/null +++ b/projects/hsm/mgmt-firmware.h @@ -0,0 +1,42 @@ +/* + * mgmt-firmware.h + * --------------- + * Management CLI Device Firmware Upgrade code. + * + * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __STM32_CLI_MGMT_FIRMWARE_H +#define __STM32_CLI_MGMT_FIRMWARE_H + +#include <libcli.h> + +extern void configure_cli_firmware(struct cli_def *cli); + +#endif /* __STM32_CLI_MGMT_FIRMWARE_H */ diff --git a/projects/hsm/mgmt-fpga.c b/projects/hsm/mgmt-fpga.c new file mode 100644 index 0000000..af7ba11 --- /dev/null +++ b/projects/hsm/mgmt-fpga.c @@ -0,0 +1,194 @@ +/* + * mgmt-fpga.c + * ----------- + * CLI code to manage the FPGA configuration etc. + * + * Copyright (c) 2016-2017, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Rename both CMSIS HAL_OK and libhal HAL_OK to disambiguate */ +#define HAL_OK CMSIS_HAL_OK +#include "stm-init.h" +#include "stm-uart.h" +#include "stm-fpgacfg.h" + +#include "mgmt-cli.h" +#include "mgmt-fpga.h" +#include "mgmt-misc.h" + +#undef HAL_OK +#define HAL_OK LIBHAL_OK +#include "hal.h" +#undef HAL_OK + +#include <string.h> + + +extern hal_user_t user; + +static volatile uint32_t dfu_offset = 0; + + +static HAL_StatusTypeDef _flash_write_callback(uint8_t *buf, size_t len) +{ + HAL_StatusTypeDef res; + + if ((dfu_offset % FPGACFG_SECTOR_SIZE) == 0) + /* first page in sector, need to erase sector */ + if ((res = fpgacfg_erase_sector(dfu_offset / FPGACFG_SECTOR_SIZE)) != CMSIS_HAL_OK) + return res; + + /* fpgacfg_write_data (a thin wrapper around n25q128_write_data) + * requires the offset and length to be page-aligned. The last chunk + * will be short, so we pad it out to the full chunk size. + */ + len = len; + res = fpgacfg_write_data(dfu_offset, buf, BITSTREAM_UPLOAD_CHUNK_SIZE); + dfu_offset += BITSTREAM_UPLOAD_CHUNK_SIZE; + return res; +} + +static int cmd_fpga_bitstream_upload(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + command = command; + argv = argv; + argc = argc; + + if (user < HAL_USER_SO) { + cli_print(cli, "Permission denied."); + return CLI_ERROR; + } + + uint8_t buf[BITSTREAM_UPLOAD_CHUNK_SIZE]; + + dfu_offset = 0; + + fpgacfg_access_control(ALLOW_ARM); + + cli_print(cli, "Checking if FPGA config memory is accessible"); + if (fpgacfg_check_id() != CMSIS_HAL_OK) { + cli_print(cli, "ERROR: FPGA config memory not accessible. Check that jumpers JP7 and JP8 are installed."); + return CLI_ERROR; + } + + cli_receive_data(cli, &buf[0], sizeof(buf), _flash_write_callback); + + fpgacfg_access_control(ALLOW_FPGA); + + cli_print(cli, "DFU offset now: %li (%li chunks)", dfu_offset, dfu_offset / BITSTREAM_UPLOAD_CHUNK_SIZE); + return CLI_OK; +} + +static int cmd_fpga_bitstream_erase(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + command = command; + argv = argv; + argc = argc; + + fpgacfg_access_control(ALLOW_ARM); + + cli_print(cli, "Checking if FPGA config memory is accessible"); + if (fpgacfg_check_id() != CMSIS_HAL_OK) { + cli_print(cli, "ERROR: FPGA config memory not accessible. Check that jumpers JP7 and JP8 are installed."); + return CLI_ERROR; + } + + /* Erasing the whole config memory takes a while, we just need to erase the first sector. + * The bitstream has an EOF marker, so even if the next bitstream uploaded is shorter than + * the current one there should be no problem. + * + * This command could be made to accept an argument indicating the whole memory should be erased. + */ + if (fpgacfg_erase_sector(0) != CMSIS_HAL_OK) { + cli_print(cli, "Erasing first sector in FPGA config memory failed"); + return CLI_ERROR; + } + + cli_print(cli, "Erased FPGA config memory"); + fpgacfg_access_control(ALLOW_FPGA); + + return CLI_OK; +} + +static int cmd_fpga_reset(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + command = command; + argv = argv; + argc = argc; + + fpgacfg_access_control(ALLOW_FPGA); + fpgacfg_reset_fpga(RESET_FULL); + hal_core_reset_table(); + cli_print(cli, "FPGA has been reset"); + + return CLI_OK; +} + +static int cmd_fpga_show_cores(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + hal_core_t *core; + const hal_core_info_t *info; + + command = command; + argv = argv; + argc = argc; + + if (fpgacfg_check_done() != CMSIS_HAL_OK) { + cli_print(cli, "FPGA has not loaded a bitstream"); + return CLI_OK; + } + + for (core = hal_core_iterate(NULL); core != NULL; core = hal_core_iterate(core)) { + info = hal_core_info(core); + cli_print(cli, "%04x: %8.8s %4.4s", + (unsigned int)info->base, info->name, info->version); + } + + return CLI_OK; +} + +void configure_cli_fpga(struct cli_def *cli) +{ + struct cli_command *c = cli_register_command(cli, NULL, "fpga", NULL, 0, 0, NULL); + + struct cli_command *c_show = cli_register_command(cli, c, "show", NULL, 0, 0, NULL); + struct cli_command *c_bitstream = cli_register_command(cli, c, "bitstream", NULL, 0, 0, NULL); + + /* fpga show cores */ + cli_register_command(cli, c_show, "cores", cmd_fpga_show_cores, 0, 0, "Show FPGA core names and versions"); + + /* fpga reset */ + cli_register_command(cli, c, "reset", cmd_fpga_reset, 0, 0, "Reset FPGA (config reset)"); + + /* fpga bitstream upload */ + cli_register_command(cli, c_bitstream, "upload", cmd_fpga_bitstream_upload, 0, 0, "Upload new FPGA bitstream"); + + /* fpga bitstream erase */ + cli_register_command(cli, c_bitstream, "erase", cmd_fpga_bitstream_erase, 0, 0, "Erase FPGA config memory"); +} diff --git a/projects/hsm/mgmt-fpga.h b/projects/hsm/mgmt-fpga.h new file mode 100644 index 0000000..9d0aedc --- /dev/null +++ b/projects/hsm/mgmt-fpga.h @@ -0,0 +1,49 @@ +/* + * mgmt-fpga.h + * ----------- + * Management FPGA related code. + * + * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __STM32_CLI_MGMT_FPGA_H +#define __STM32_CLI_MGMT_FPGA_H + +#include <libcli.h> + + +/* The chunk size have to be a multiple of the SPI flash page size (256 bytes), + and it has to match the chunk size in the program sending the bitstream over the UART. +*/ +#define BITSTREAM_UPLOAD_CHUNK_SIZE 4096 + + +extern void configure_cli_fpga(struct cli_def *cli); + +#endif /* __STM32_CLI_MGMT_FPGA_H */ diff --git a/projects/hsm/mgmt-keystore.c b/projects/hsm/mgmt-keystore.c new file mode 100644 index 0000000..9eb42da --- /dev/null +++ b/projects/hsm/mgmt-keystore.c @@ -0,0 +1,408 @@ +/* + * mgmt-keystore.c + * --------------- + * CLI 'keystore' commands. + * + * Copyright (c) 2016-2017, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Rename both CMSIS HAL_OK and libhal HAL_OK to disambiguate */ +#define HAL_OK CMSIS_HAL_OK +#include "stm-init.h" +#include "stm-keystore.h" +#include "stm-fpgacfg.h" +#include "stm-uart.h" + +#include "mgmt-cli.h" + +#undef HAL_OK +#define LIBHAL_OK HAL_OK +#include "hal.h" +#warning Really should not be including hal_internal.h here, fix API instead of bypassing it +#include "hal_internal.h" +#undef HAL_OK + +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <ctype.h> + + +static int cmd_keystore_set_pin(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + hal_user_t user; + hal_error_t status; + hal_client_handle_t client = { -1 }; + + command = command; + + if (argc != 2) { + cli_print(cli, "Wrong number of arguments (%i).", argc); + cli_print(cli, "Syntax: keystore set pin <user|so|wheel> <pin>"); + return CLI_ERROR; + } + + if (strcmp(argv[0], "user") == 0) + user = HAL_USER_NORMAL; + else if (strcmp(argv[0], "so") == 0) + user = HAL_USER_SO; + else if (strcmp(argv[0], "wheel") == 0) + user = HAL_USER_WHEEL; + else { + cli_print(cli, "First argument must be 'user', 'so' or 'wheel' - not '%s'", argv[0]); + return CLI_ERROR; + } + + status = hal_rpc_set_pin(client, user, argv[1], strlen(argv[1])); + if (status != LIBHAL_OK) { + cli_print(cli, "Failed setting PIN: %s", hal_error_string(status)); + return CLI_ERROR; + } + + return CLI_OK; +} + +static int cmd_keystore_clear_pin(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + hal_user_t user; + hal_error_t status; + hal_client_handle_t client = { -1 }; + + command = command; + + if (argc != 1) { + cli_print(cli, "Wrong number of arguments (%i).", argc); + cli_print(cli, "Syntax: keystore clear pin <user|so|wheel>"); + return CLI_ERROR; + } + + user = HAL_USER_NONE; + if (strcmp(argv[0], "user") == 0) + user = HAL_USER_NORMAL; + else if (strcmp(argv[0], "so") == 0) + user = HAL_USER_SO; + else if (strcmp(argv[0], "wheel") == 0) + user = HAL_USER_WHEEL; + else { + cli_print(cli, "First argument must be 'user', 'so' or 'wheel' - not '%s'", argv[0]); + return CLI_ERROR; + } + + if ((status = hal_rpc_set_pin(client, user, "", 0)) != LIBHAL_OK) { + cli_print(cli, "Failed clearing PIN: %s", hal_error_string(status)); + return CLI_ERROR; + } + + return CLI_OK; +} + +static int cmd_keystore_set_pin_iterations(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + hal_error_t status; + hal_client_handle_t client = { -1 }; + + command = command; + + if (argc != 1) { + cli_print(cli, "Wrong number of arguments (%i).", argc); + cli_print(cli, "Syntax: keystore set pin iterations <number>"); + return CLI_ERROR; + } + + status = hal_set_pin_default_iterations(client, strtoul(argv[0], NULL, 0)); + if (status != LIBHAL_OK) { + cli_print(cli, "Failed setting iterations: %s", hal_error_string(status)); + return CLI_ERROR; + } + + return CLI_OK; +} + +static int cmd_keystore_delete_key(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + const hal_client_handle_t client = { -1 }; + const hal_session_handle_t session = { HAL_HANDLE_NONE }; + hal_pkey_handle_t pkey = { HAL_HANDLE_NONE }; + hal_error_t status; + hal_uuid_t name; + + command = command; + + if (argc != 1) { + cli_print(cli, "Wrong number of arguments (%i).", argc); + cli_print(cli, "Syntax: keystore delete key <name>"); + return CLI_ERROR; + } + + if ((status = hal_uuid_parse(&name, argv[0])) != LIBHAL_OK) { + cli_print(cli, "Couldn't parse key name: %s", hal_error_string(status)); + return CLI_ERROR; + } + + if ((status = hal_rpc_pkey_open(client, session, &pkey, &name)) != LIBHAL_OK) { + cli_print(cli, "Couldn't find key: %s", hal_error_string(status)); + return CLI_ERROR; + } + + if ((status = hal_rpc_pkey_delete(pkey)) != LIBHAL_OK) { + cli_print(cli, "Failed deleting key: %s", hal_error_string(status)); + (void) hal_rpc_pkey_close(pkey); + return CLI_ERROR; + } + + cli_print(cli, "Deleted key %s", argv[0]); + + return CLI_OK; +} + +#include "ks.h" + +static int show_keys(struct cli_def *cli, const char *title) +{ + const hal_client_handle_t client = { -1 }; + const hal_session_handle_t session = { HAL_HANDLE_NONE }; + char key_name[HAL_UUID_TEXT_SIZE]; + hal_uuid_t previous_uuid = {{0}}; + hal_pkey_handle_t pkey; + hal_curve_name_t curve; + hal_key_flags_t flags; + unsigned n, state = 0; + hal_uuid_t uuids[50]; + hal_key_type_t type; + hal_error_t status; + int count = 0; + int done = 0; + + cli_print(cli, title); + + size_t avail; + if ((status = hal_ks_available(hal_ks_token, &avail)) == HAL_OK) + cli_print(cli, "Token keystore: %d available", avail); + else + cli_print(cli, "Error reading token keystore: %s", hal_error_string(status)); + if ((status = hal_ks_available(hal_ks_volatile, &avail)) == HAL_OK) + cli_print(cli, "Volatile keystore: %d available", avail); + else + cli_print(cli, "Error reading volatile keystore: %s", hal_error_string(status)); + + while (!done) { + + if ((status = hal_rpc_pkey_match(client, session, HAL_KEY_TYPE_NONE, HAL_CURVE_NONE, + 0, 0, NULL, 0, &state, uuids, &n, + sizeof(uuids)/sizeof(*uuids), + &previous_uuid)) != LIBHAL_OK) { + cli_print(cli, "Could not fetch UUID list: %s", hal_error_string(status)); + return CLI_ERROR; + } + + done = n < sizeof(uuids)/sizeof(*uuids); + + if (!done) + previous_uuid = uuids[sizeof(uuids)/sizeof(*uuids) - 1]; + + for (unsigned i = 0; i < n; i++) { + + if ((status = hal_uuid_format(&uuids[i], key_name, sizeof(key_name))) != LIBHAL_OK) { + cli_print(cli, "Could not convert key name, skipping: %s", + hal_error_string(status)); + continue; + } + + if ((status = hal_rpc_pkey_open(client, session, &pkey, &uuids[i])) != LIBHAL_OK) { + cli_print(cli, "Could not open key %s, skipping: %s", + key_name, hal_error_string(status)); + continue; + } + + if ((status = hal_rpc_pkey_get_key_type(pkey, &type)) != LIBHAL_OK || + (status = hal_rpc_pkey_get_key_curve(pkey, &curve)) != LIBHAL_OK || + (status = hal_rpc_pkey_get_key_flags(pkey, &flags)) != LIBHAL_OK) + cli_print(cli, "Could not fetch metadata for key %s, skipping: %s", + key_name, hal_error_string(status)); + + if (status == LIBHAL_OK) + status = hal_rpc_pkey_close(pkey); + else + (void) hal_rpc_pkey_close(pkey); + + if (status != LIBHAL_OK) + continue; + + const char *type_name = "unknown"; + switch (type) { + case HAL_KEY_TYPE_NONE: type_name = "none"; break; + case HAL_KEY_TYPE_RSA_PRIVATE: type_name = "RSA private"; break; + case HAL_KEY_TYPE_RSA_PUBLIC: type_name = "RSA public"; break; + case HAL_KEY_TYPE_EC_PRIVATE: type_name = "EC private"; break; + case HAL_KEY_TYPE_EC_PUBLIC: type_name = "EC public"; break; + case HAL_KEY_TYPE_HASHSIG_PRIVATE: type_name = "hashsig private"; break; + case HAL_KEY_TYPE_HASHSIG_PUBLIC: type_name = "hashsig public"; break; + case HAL_KEY_TYPE_HASHSIG_LMS: type_name = "hashsig lms"; break; + case HAL_KEY_TYPE_HASHSIG_LMOTS: type_name = "hashsig lmots"; break; + } + + const char *curve_name = "unknown"; + switch (curve) { + case HAL_CURVE_NONE: curve_name = "none"; break; + case HAL_CURVE_P256: curve_name = "P-256"; break; + case HAL_CURVE_P384: curve_name = "P-384"; break; + case HAL_CURVE_P521: curve_name = "P-521"; break; + } + + cli_print(cli, "Key %2i, name %s, type %s, curve %s, flags 0x%lx", + count++, key_name, type_name, curve_name, (unsigned long) flags); + } + } + + return CLI_OK; +} + +static int show_pin(struct cli_def *cli, char *label, hal_user_t user) +{ + const hal_ks_pin_t *p; + + if (hal_get_pin(user, &p) != HAL_OK) + return CLI_ERROR; + + /* + * I'm not sure iterations is the most interesting thing to show, but + * it's what we had before. + */ + + cli_print(cli, "%s iterations: 0x%lx", label, p->iterations); + return CLI_OK; +} + +static int cmd_keystore_show_keys(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + command = command; + argv = argv; + argc = argc; + + int err = 0; + + err |= show_keys(cli, "Keystore:"); + + cli_print(cli, "\nPins:"); + err |= show_pin(cli, "Wheel", HAL_USER_WHEEL); + err |= show_pin(cli, "SO ", HAL_USER_SO); + err |= show_pin(cli, "User ", HAL_USER_NORMAL); + + return err ? CLI_ERROR : CLI_OK; +} + +static int cmd_keystore_erase(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + hal_error_t err; + HAL_StatusTypeDef status; + int preserve_PINs = 0; + + command = command; + + if (argc < 1 || argc > 2 || strcmp(argv[0], "YesIAmSure") != 0) { + usage: + cli_print(cli, "Syntax: keystore erase YesIAmSure [preservePINs]"); + return CLI_ERROR; + } + if (argc == 2) { + if (strcasecmp(argv[1], "preservePINs") != 0) + goto usage; + else + preserve_PINs = 1; + } + + hal_user_t users[3] = { HAL_USER_NORMAL, HAL_USER_SO, HAL_USER_WHEEL }; + hal_ks_pin_t pins[3]; + if (preserve_PINs) { + for (size_t i = 0; i < 3; ++i) { + const hal_ks_pin_t *pin; + if (hal_get_pin(users[i], &pin) != HAL_OK) { + cli_print(cli, "Failed to get the PINs"); + return CLI_ERROR; + } + memcpy(&pins[i], pin, sizeof(*pin)); + } + } + + cli_print(cli, "OK, erasing keystore, this will take about 45 seconds..."); + if ((status = keystore_erase_bulk()) != CMSIS_HAL_OK) { + cli_print(cli, "Failed erasing token keystore: %i", status); + return CLI_ERROR; + } + + if ((err = hal_ks_init(hal_ks_token, 0)) != LIBHAL_OK) { + cli_print(cli, "Failed to reinitialize token keystore: %s", hal_error_string(err)); + return CLI_ERROR; + } + + if ((err = hal_ks_init(hal_ks_volatile, 0)) != LIBHAL_OK) { + cli_print(cli, "Failed to reinitialize memory keystore: %s", hal_error_string(err)); + return CLI_ERROR; + } + + if (preserve_PINs) { + for (size_t i = 0; i < 3; ++i) { + if (hal_set_pin(users[i], &pins[i]) != HAL_OK) { + cli_print(cli, "Failed to restore the PINs"); + return CLI_ERROR; + } + } + } + + cli_print(cli, "Keystore erased"); + return CLI_OK; +} + +void configure_cli_keystore(struct cli_def *cli) +{ + struct cli_command *c = cli_register_command(cli, NULL, "keystore", NULL, 0, 0, NULL); + + struct cli_command *c_show = cli_register_command(cli, c, "show", NULL, 0, 0, NULL); + struct cli_command *c_set = cli_register_command(cli, c, "set", NULL, 0, 0, NULL); + struct cli_command *c_clear = cli_register_command(cli, c, "clear", NULL, 0, 0, NULL); + struct cli_command *c_delete = cli_register_command(cli, c, "delete", NULL, 0, 0, NULL); + + /* keystore show keys */ + cli_register_command(cli, c_show, "keys", cmd_keystore_show_keys, 0, 0, "Show what PINs and keys are in the keystore"); + + /* keystore set pin */ + struct cli_command *c_set_pin = cli_register_command(cli, c_set, "pin", cmd_keystore_set_pin, 0, 0, "Set either 'wheel', 'user' or 'so' PIN"); + + /* keystore set pin iterations */ + cli_register_command(cli, c_set_pin, "iterations", cmd_keystore_set_pin_iterations, 0, 0, "Set PBKDF2 iterations for PINs"); + + /* keystore clear pin */ + cli_register_command(cli, c_clear, "pin", cmd_keystore_clear_pin, 0, 0, "Clear either 'wheel', 'user' or 'so' PIN"); + + /* keystore delete key */ + cli_register_command(cli, c_delete, "key", cmd_keystore_delete_key, 0, 0, "Delete a key"); + + /* keystore erase */ + cli_register_command(cli, c, "erase", cmd_keystore_erase, 0, 0, "Erase the whole keystore"); +} diff --git a/projects/hsm/mgmt-keystore.h b/projects/hsm/mgmt-keystore.h new file mode 100644 index 0000000..9e14ac6 --- /dev/null +++ b/projects/hsm/mgmt-keystore.h @@ -0,0 +1,42 @@ +/* + * mgmt-keystore.h + * ---------- + * Management CLI 'keystore' functions. + * + * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __STM32_CLI_MGMT_KEYSTORE_H +#define __STM32_CLI_MGMT_KEYSTORE_H + +#include <libcli.h> + +extern void configure_cli_keystore(struct cli_def *cli); + +#endif /* __STM32_CLI_MGMT_KEYSTORE_H */ diff --git a/projects/hsm/mgmt-masterkey.c b/projects/hsm/mgmt-masterkey.c new file mode 100644 index 0000000..97e62a0 --- /dev/null +++ b/projects/hsm/mgmt-masterkey.c @@ -0,0 +1,244 @@ +/* + * mgmt-masterkey.c + * ---------------- + * Masterkey CLI functions. + * + * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Rename both CMSIS HAL_OK and libhal HAL_OK to disambiguate */ +#define HAL_OK CMSIS_HAL_OK +#include "stm-init.h" +#include "stm-uart.h" +#include "mgmt-cli.h" +#include "mgmt-masterkey.h" + +#undef HAL_OK +#define LIBHAL_OK HAL_OK +#include <hal.h> +#warning Refactor so we do not need to include hal_internal.h here +#include <hal_internal.h> +#undef HAL_OK + +#include <stdlib.h> + +static char * _status2str(const hal_error_t status) +{ + switch (status) { + case LIBHAL_OK: + return (char *) "Set"; + case HAL_ERROR_MASTERKEY_NOT_SET: + return (char *) "Not set"; + default: + return (char *) "Unknown"; + } +} + +static int cmd_masterkey_status(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + hal_error_t status; + + command = command; + argv = argv; + argc = argc; + + cli_print(cli, "Status of master key:\n"); + + status = hal_keywrap_mkm_status(NULL); + cli_print(cli, " volatile: %s / %s", _status2str(status), hal_error_string(status)); + + status = hal_mkm_flash_read(NULL, 0); + cli_print(cli, " flash: %s / %s", _status2str(status), hal_error_string(status)); + + return CLI_OK; +} + +static int str_to_hex_digit(char c) +{ + if (c >= '0' && c <= '9') + c -= '0'; + else if (c >= 'a' && c <= 'f') + c = c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + c = c - 'A' + 10; + else + return -1; + + return c; +} + +static inline char hex_to_str_digit(const uint8_t c) +{ + return (c < 10) ? ((char)c + '0') : ((char)c + 'A' - 10); +} + +static char *hexdump_kek(const uint8_t * const kek) +{ + /* This is only for dumping masterkey values, so has no length checks. + * Do not use it for anything else. + * + * For convenience of possibly hand-copying and hand-retyping, the key + * is divided into 8 4-byte (8-character) groups. + */ + + static char buf[2 * KEK_LENGTH + 8]; + char *dst = buf; + + for (size_t i = 0; i < KEK_LENGTH; ++i) { + uint8_t b = kek[i]; + *dst++ = hex_to_str_digit(b >> 4); + *dst++ = hex_to_str_digit(b & 0xf); + if ((i & 3) == 3) + *dst++ = ' '; + } + buf[sizeof(buf) - 1] = '\0'; + + return buf; +} + +static int _masterkey_set(struct cli_def *cli, char *argv[], int argc, + char *label, hal_error_t (*writer)(const uint8_t * const, const size_t)) +{ + uint8_t buf[KEK_LENGTH] = {0}; + hal_error_t err; + + if (argc == 0) { + /* fill master key with yummy randomness */ + if ((err = hal_get_random(NULL, buf, sizeof(buf))) != LIBHAL_OK) { + cli_print(cli, "Error getting random key: %s", hal_error_string(err)); + return CLI_ERROR; + } + cli_print(cli, "Random key:\n%s", hexdump_kek(buf)); + } + + else { + /* input is 32 hex bytes, arranged however the user wants */ + size_t len = 0; + for (int i = 0; i < argc; ++i) { + for (char *cp = argv[i]; *cp != '\0'; ) { + int c; + if ((c = str_to_hex_digit(*cp++)) < 0) + goto errout; + buf[len] = c << 4; + if ((c = str_to_hex_digit(*cp++)) < 0) + goto errout; + buf[len] |= c & 0xf; + if (++len > KEK_LENGTH) + goto errout; + } + } + if (len < KEK_LENGTH) { + errout: + cli_print(cli, "Failed parsing master key, expected exactly %d hex bytes", KEK_LENGTH); + return CLI_ERROR; + } + + cli_print(cli, "Parsed key:\n%s", hexdump_kek(buf)); + } + + if ((err = writer(buf, sizeof(buf))) == LIBHAL_OK) { + cli_print(cli, "Master key set in %s memory", label); + } else { + cli_print(cli, "Failed writing key to %s memory: %s", label, hal_error_string(err)); + } + return CLI_OK; +} + +static hal_error_t _mkm_volatile_write(const uint8_t *kek, const size_t kek_len) +{ + return hal_keywrap_mkm_write(NULL, kek, kek_len); +} + +static int cmd_masterkey_set(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + command = command; + + return _masterkey_set(cli, argv, argc, "volatile", _mkm_volatile_write); +} + +static int cmd_masterkey_erase(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + hal_error_t err; + + command = command; + argv = argv; + argc = argc; + + if ((err = hal_keywrap_mkm_erase(NULL, KEK_LENGTH)) == LIBHAL_OK) { + cli_print(cli, "Erased master key from volatile memory"); + } else { + cli_print(cli, "Failed erasing master key from volatile memory: %s", hal_error_string(err)); + } + return CLI_OK; +} + +static int cmd_masterkey_unsecure_set(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + command = command; + + return _masterkey_set(cli, argv, argc, "flash", hal_mkm_flash_write); +} + +static int cmd_masterkey_unsecure_erase(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + hal_error_t err; + + command = command; + argv = argv; + argc = argc; + + if ((err = hal_mkm_flash_erase(KEK_LENGTH)) == LIBHAL_OK) { + cli_print(cli, "Erased unsecure master key from flash"); + } else { + cli_print(cli, "Failed erasing unsecure master key from flash: %s", hal_error_string(err)); + } + return CLI_OK; +} + +void configure_cli_masterkey(struct cli_def *cli) +{ + struct cli_command *c = cli_register_command(cli, NULL, "masterkey", NULL, 0, 0, NULL); + + /* masterkey status */ + cli_register_command(cli, c, "status", cmd_masterkey_status, 0, 0, "Show status of master key in RAM/flash"); + + /* masterkey set */ + cli_register_command(cli, c, "set", cmd_masterkey_set, 0, 0, "Set the master key in the volatile Master Key Memory"); + + /* masterkey erase */ + cli_register_command(cli, c, "erase", cmd_masterkey_erase, 0, 0, "Erase the master key from the volatile Master Key Memory"); + + struct cli_command *c_unsecure = cli_register_command(cli, c, "unsecure", NULL, 0, 0, NULL); + + /* masterkey unsecure set */ + cli_register_command(cli, c_unsecure, "set", cmd_masterkey_unsecure_set, 0, 0, "Set master key in unprotected flash memory (if unsure, DON'T)"); + + /* masterkey unsecure erase */ + cli_register_command(cli, c_unsecure, "erase", cmd_masterkey_unsecure_erase, 0, 0, "Erase master key from unprotected flash memory"); +} diff --git a/projects/hsm/mgmt-masterkey.h b/projects/hsm/mgmt-masterkey.h new file mode 100644 index 0000000..67835e9 --- /dev/null +++ b/projects/hsm/mgmt-masterkey.h @@ -0,0 +1,42 @@ +/* + * mgmt-masterkey.h + * ----------- + * Management CLI masterkeyellaneous functions. + * + * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __STM32_CLI_MGMT_MASTERKEY_H +#define __STM32_CLI_MGMT_MASTERKEY_H + +#include <libcli.h> + +extern void configure_cli_masterkey(struct cli_def *cli); + +#endif /* __STM32_CLI_MGMT_MASTERKEY_H */ diff --git a/projects/hsm/mgmt-misc.c b/projects/hsm/mgmt-misc.c new file mode 100644 index 0000000..377af73 --- /dev/null +++ b/projects/hsm/mgmt-misc.c @@ -0,0 +1,259 @@ +/* + * mgmt-misc.c + * ----------- + * Miscellaneous CLI functions. + * + * Copyright (c) 2016-2018, NORDUnet A/S All rights reserved. + * Copyright: 2020, The Commons Conservancy Cryptech Project + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define HAL_OK CMSIS_HAL_OK +#include "stm-init.h" +#include "stm-uart.h" +#include "mgmt-cli.h" +#include "mgmt-misc.h" +#undef HAL_OK + +#define HAL_OK LIBHAL_OK +#include "hal.h" +#include "hal_internal.h" +#undef HAL_OK + +#include <string.h> + + +int cli_receive_data(struct cli_def *cli, uint8_t *buf, size_t len, cli_data_callback data_callback) +{ + hal_crc32_t crc = 0, my_crc = hal_crc32_init(); + uint32_t filesize = 0, counter = 0; + size_t n = len; + + if (! control_mgmt_uart_dma_rx(DMA_RX_STOP)) { + cli_print(cli, "Failed stopping DMA"); + goto okay; + } + + cli_print(cli, "OK, write size (4 bytes), data in %li byte chunks, CRC-32 (4 bytes)", (uint32_t) n); + + if (uart_receive_bytes((void *) &filesize, sizeof(filesize), 2000) != CMSIS_HAL_OK) { + cli_print(cli, "Receive timed out"); + goto fail; + } + + cli_print(cli, "Send %li bytes of data", filesize); + + while (filesize) { + /* By initializing buf to the same value that erased flash has (0xff), we don't + * have to try and be smart when writing the last page of data to a flash memory. + */ + memset(buf, 0xff, len); + + if (filesize < n) n = filesize; + + if (uart_receive_bytes((void *) buf, n, 2000) != CMSIS_HAL_OK) { + cli_print(cli, "Receive timed out"); + goto fail; + } + filesize -= n; + my_crc = hal_crc32_update(my_crc, buf, n); + + /* After reception of a chunk but before ACKing we have "all" the time in the world to + * calculate CRC and invoke the data_callback. + */ + if (data_callback != NULL && data_callback(buf, n) != CMSIS_HAL_OK) { + cli_print(cli, "Data processing failed"); + goto okay; + } + + counter++; + uart_send_bytes((void *) &counter, 4); + } + + my_crc = hal_crc32_finalize(my_crc); + cli_print(cli, "Send CRC-32"); + uart_receive_bytes((void *) &crc, sizeof(crc), 2000); + cli_print(cli, "CRC-32 0x%x, calculated CRC 0x%x", (unsigned int) crc, (unsigned int) my_crc); + if (crc == my_crc) { + cli_print(cli, "CRC checksum MATCHED"); + } else { + cli_print(cli, "CRC checksum did NOT match"); + } + + okay: + control_mgmt_uart_dma_rx(DMA_RX_START); + return CLI_OK; + + fail: + control_mgmt_uart_dma_rx(DMA_RX_START); + return CLI_ERROR; +} + +#ifdef DO_PROFILING +static int cmd_profile_start(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + cli = cli; + command = command; + argv = argv; + argc = argc; + + extern uint32_t CRYPTECH_FIRMWARE_START; + extern char __etext; /* end of text/code symbol, defined by linker */ + extern void monstartup (size_t lowpc, size_t highpc); + monstartup((size_t)&CRYPTECH_FIRMWARE_START, (size_t)&__etext); + return CLI_OK; +} + +static int cmd_profile_stop(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + cli = cli; + command = command; + argv = argv; + argc = argc; + + extern void _mcleanup(void); + _mcleanup(); + return CLI_OK; +} + +#endif + +static int cmd_reboot(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + command = command; + argv = argv; + argc = argc; + + cli_print(cli, "\n\n\nRebooting\n\n\n"); + HAL_NVIC_SystemReset(); + + /*NOTREACHED*/ + return CLI_OK; +} + +static int cmd_rsa_blinding(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + if (argc != 1) { + cli_print(cli, "Wrong number of arguments (%i).", argc); + cli_print(cli, "Syntax: %s <on|off|clear>", command); + return CLI_ERROR; + } + + if (strcmp(argv[0], "on") == 0) + hal_rsa_set_blinding(1); + else if (strcmp(argv[0], "off") == 0) + hal_rsa_set_blinding(0); + else if (strcmp(argv[0], "clear") == 0) + hal_rsa_clear_blinding_cache(); + else { + cli_print(cli, "Argument must be 'on', 'off', or 'clear' - not '%s'", argv[0]); + return CLI_ERROR; + } + + return CLI_OK; +} + +static int cmd_rsa_crt(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + int onoff; + + if (argc != 1) { + cli_print(cli, "Wrong number of arguments (%i).", argc); + cli_print(cli, "Syntax: %s <on|off>", command); + return CLI_ERROR; + } + + if (strcmp(argv[0], "on") == 0) + onoff = 1; + else if (strcmp(argv[0], "off") == 0) + onoff = 0; + else { + cli_print(cli, "Argument must be 'on' or 'off' - not '%s'", argv[0]); + return CLI_ERROR; + } + + hal_rsa_set_crt(onoff); + + return CLI_OK; +} + +static int cmd_rsa_modexpng(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + int onoff; + + if (argc != 1) { + cli_print(cli, "Wrong number of arguments (%i).", argc); + cli_print(cli, "Syntax: %s <on|off>", command); + return CLI_ERROR; + } + + if (strcmp(argv[0], "on") == 0) + onoff = 1; + else if (strcmp(argv[0], "off") == 0) + onoff = 0; + else { + cli_print(cli, "Argument must be 'on' or 'off' - not '%s'", argv[0]); + return CLI_ERROR; + } + + hal_error_t err; + if ((err = hal_modexp_use_modexpng(onoff)) == LIBHAL_OK) + return CLI_OK; + + cli_print(cli, hal_error_string(err)); + return CLI_ERROR; +} + +void configure_cli_misc(struct cli_def *cli) +{ +#ifdef DO_PROFILING + struct cli_command *c_profile = cli_register_command(cli, NULL, "profile", NULL, 0, 0, NULL); + + /* profile start */ + cli_register_command(cli, c_profile, "start", cmd_profile_start, 0, 0, "Start collecting profiling data"); + + /* profile stop */ + cli_register_command(cli, c_profile, "stop", cmd_profile_stop, 0, 0, "Stop collecting profiling data"); +#endif + + struct cli_command *c_rsa = cli_register_command(cli, NULL, "rsa", NULL, 0, 0, NULL); + + /* rsa blinding */ + cli_register_command(cli, c_rsa, "blinding", cmd_rsa_blinding, 0, 0, "Set use of RSA blinding"); + + /* rsa crt */ + cli_register_command(cli, c_rsa, "crt", cmd_rsa_crt, 0, 0, "Set use of RSA CRT"); + + /* rsa modexpng */ + cli_register_command(cli, c_rsa, "modexpng", cmd_rsa_modexpng, 0, 0, "Set use of ModExpNG"); + + /* reboot */ + cli_register_command(cli, NULL, "reboot", cmd_reboot, 0, 0, "Reboot the STM32"); +} + diff --git a/projects/hsm/mgmt-misc.h b/projects/hsm/mgmt-misc.h new file mode 100644 index 0000000..ef63a9e --- /dev/null +++ b/projects/hsm/mgmt-misc.h @@ -0,0 +1,47 @@ +/* + * mgmt-misc.h + * ----------- + * Management CLI miscellaneous functions. + * + * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __STM32_CLI_MGMT_MISC_H +#define __STM32_CLI_MGMT_MISC_H + +#include <libcli.h> + +/* Write a chunk of received data to flash. */ +typedef HAL_StatusTypeDef (*cli_data_callback)(uint8_t *, size_t); + +extern int cli_receive_data(struct cli_def *cli, uint8_t *buf, size_t len, cli_data_callback data_callback); + +extern void configure_cli_misc(struct cli_def *cli); + +#endif /* __STM32_CLI_MGMT_MISC_H */ diff --git a/projects/hsm/mgmt-task.c b/projects/hsm/mgmt-task.c new file mode 100644 index 0000000..180c6d9 --- /dev/null +++ b/projects/hsm/mgmt-task.c @@ -0,0 +1,136 @@ +/* + * mgmt-task.c + * ----------- + * CLI 'task' functions. + * + * Copyright (c) 2016-2017, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Show the active tasks. This is mostly for debugging, and looks deeply + * into OS-level structures, but sometimes you just need to know... + */ + +#include "mgmt-cli.h" +#include "mgmt-task.h" +#include "task.h" + +static char *task_state[] = { + "INIT", + "WAITING", + "READY" +}; + +extern size_t request_queue_len(void); +extern size_t request_queue_max(void); + +static int cmd_task_show(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + command = command; + argv = argv; + argc = argc; + + cli_print(cli, "name state stack high water"); + cli_print(cli, "-------- -------- ----------------"); + + for (tcb_t *t = task_iterate(NULL); t != NULL; t = task_iterate(t)) { + cli_print(cli, "%-15s %-15s %d", + task_get_name(t), + task_state[task_get_state(t)], + task_get_stack_highwater(t)); + } + + cli_print(cli, " "); + cli_print(cli, "RPC request queue current length: %u", request_queue_len()); + cli_print(cli, "RPC request queue maximum length: %u", request_queue_max()); + + extern size_t uart_rx_max; + cli_print(cli, " "); + cli_print(cli, "UART receive queue maximum length: %u", uart_rx_max); + + size_t used, available; + extern void sdram_stats(size_t *used, size_t *available); + sdram_stats(&used, &available); + cli_print(cli, " "); + cli_print(cli, "SDRAM used: %u, available: %u", used, available); + + return CLI_OK; +} + +#ifdef DO_TASK_METRICS +static int cmd_task_show_metrics(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + command = command; + argv = argv; + argc = argc; + + struct task_metrics tm; + + task_get_metrics(&tm); + + cli_print(cli, "avg time between yields: %ld.%06ld sec", tm.avg.tv_sec, tm.avg.tv_usec); + cli_print(cli, "max time between yields: %ld.%06ld sec", tm.max.tv_sec, tm.max.tv_usec); + + return CLI_OK; +} + +static int cmd_task_reset_metrics(struct cli_def *cli, const char *command, char *argv[], int argc) +{ + cli = cli; + command = command; + argv = argv; + argc = argc; + + task_reset_metrics(); + + return CLI_OK; +} +#endif + +void configure_cli_task(struct cli_def *cli) +{ + struct cli_command *c = cli_register_command(cli, NULL, "task", NULL, 0, 0, NULL); + + /* task show */ +#ifdef DO_TASK_METRICS + struct cli_command *c_show = +#endif + cli_register_command(cli, c, "show", cmd_task_show, 0, 0, "Show the active tasks"); + +#ifdef DO_TASK_METRICS + /* task show metrics */ + cli_register_command(cli, c_show, "metrics", cmd_task_show_metrics, 0, 0, "Show task metrics"); + + /* task reset */ + struct cli_command *c_reset = cli_register_command(cli, c, "reset", NULL, 0, 0, NULL); + + /* task reset metrics */ + cli_register_command(cli, c_reset, "metrics", cmd_task_reset_metrics, 0, 0, "Reset task metrics"); +#endif +} diff --git a/projects/hsm/mgmt-task.h b/projects/hsm/mgmt-task.h new file mode 100644 index 0000000..f903962 --- /dev/null +++ b/projects/hsm/mgmt-task.h @@ -0,0 +1,42 @@ +/* + * mgmt-task.h + * ----------- + * Management CLI 'task' functions. + * + * Copyright (c) 2016-2017, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __STM32_CLI_MGMT_TASK_H +#define __STM32_CLI_MGMT_TASK_H + +#include <libcli.h> + +extern void configure_cli_task(struct cli_def *cli); + +#endif /* __STM32_CLI_MGMT_TASK_H */ diff --git a/projects/libhal-test/Makefile b/projects/libhal-test/Makefile index f58f480..c5dbc84 100644 --- a/projects/libhal-test/Makefile +++ b/projects/libhal-test/Makefile @@ -1,12 +1,12 @@ -TEST = cores test-bus test-trng test-hash test-aes-key-wrap test-pbkdf2 test-ecdsa test-rsa test-mkmif +TEST = cores test-bus test-trng test-hash test-aes-key-wrap test-pbkdf2 test-ecdsa test-rsa -CFLAGS += -I $(LIBHAL_DIR) +CFLAGS += -I $(LIBHAL_SRC) LIBC_OBJS = printf.o gettimeofday.o -LIBS += $(LIBHAL_DIR)/libhal.a $(LIBTFM_DIR)/libtfm.a +LIBS += $(LIBHAL_BLD)/libhal.a $(LIBTFM_BLD)/libtfm.a all: $(TEST:=.elf) -vpath %.c $(LIBHAL_DIR)/tests $(LIBHAL_DIR)/utils +vpath %.c $(LIBHAL_SRC)/tests $(LIBHAL_SRC)/utils # .mo extension for files with main() that need to be wrapped as __main() %.mo: %.c @@ -17,9 +17,6 @@ vpath %.c $(LIBHAL_DIR)/tests $(LIBHAL_DIR)/utils $(OBJCOPY) -O binary $*.elf $*.bin $(SIZE) $*.elf -# don't automatically delete objects, to avoid a lot of unnecessary rebuilding -.SECONDARY: $(BOARD_OBJS) $(LIBC_OBJS) - clean: rm -f *.o *.mo rm -f *.elf diff --git a/projects/libhal-test/gettimeofday.c b/projects/libhal-test/gettimeofday.c index b13485d..f7a87f1 100644 --- a/projects/libhal-test/gettimeofday.c +++ b/projects/libhal-test/gettimeofday.c @@ -56,6 +56,8 @@ int gettimeofday(struct timeval *tv, struct timezone *tz) { uint32_t tick = HAL_GetTick(); /* uptime in ms */ + tz = tz; + tv->tv_sec = tick / 1000; tv->tv_usec = (tick % 1000) * 1000; diff --git a/projects/libhal-test/main.c b/projects/libhal-test/main.c index a40871b..c0d9330 100644 --- a/projects/libhal-test/main.c +++ b/projects/libhal-test/main.c @@ -43,18 +43,8 @@ extern void __main(void); int main(void) { stm_init(); - -#ifdef TARGET_CRYPTECH_DEV_BRIDGE - // Blink blue LED for six seconds to not upset the Novena at boot. - led_on(LED_BLUE); - for (int i = 0; i < 12; i++) { - HAL_Delay(500); - led_toggle(LED_BLUE); - } - led_off(LED_BLUE); -#endif + HAL_Delay(500); led_on(LED_GREEN); - fmc_init(); __main(); diff --git a/projects/libhal-test/printf.c b/projects/libhal-test/printf.c index 5a15d12..85af09b 100644 --- a/projects/libhal-test/printf.c +++ b/projects/libhal-test/printf.c @@ -244,7 +244,7 @@ OK, I found my mistake. The math here is _always_ unsigned */ if (precision != 0)
{
width = max(width, precision);
- if (precision > strlen(where))
+ if (precision > strlen((const char *)where))
flags |= PR_LZ;
precision = 0;
}
@@ -295,7 +295,7 @@ EMIT2: if((flags & PR_LJ) == 0) count++;
}
/* emit string/char/converted number */
- for(int i = (flags & PR_WS) ? 1 : 0;
+ for(unsigned i = (flags & PR_WS) ? 1 : 0;
i < length; ++i)
{
fn(*where++, &ptr);
@@ -362,6 +362,8 @@ You must write your own putchar() *****************************************************************************/
int vprintf_help(unsigned c, void **ptr)
{
+ ptr = ptr;
+
putchar(c);
return 0 ;
}
diff --git a/projects/rtos-test/Makefile b/projects/rtos-test/Makefile deleted file mode 100644 index dd2cab5..0000000 --- a/projects/rtos-test/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -TEST = thread-test semaphore-test mutex-test - -all: $(TEST:=.elf) - -%.elf: %.o $(BOARD_OBJS) $(LIBS) - $(CC) $(CFLAGS) $^ -o $@ -T$(LDSCRIPT) -g -Wl,-Map=$*.map - $(OBJCOPY) -O ihex $*.elf $*.hex - $(OBJCOPY) -O binary $*.elf $*.bin - $(OBJDUMP) -St $*.elf >$*.lst - $(SIZE) $*.elf - -clean: - rm -f *.o - rm -f *.elf - rm -f *.hex - rm -f *.bin - rm -f *.map - rm -f *.lst diff --git a/projects/rtos-test/mutex-test.c b/projects/rtos-test/mutex-test.c deleted file mode 100644 index 402f9ba..0000000 --- a/projects/rtos-test/mutex-test.c +++ /dev/null @@ -1,40 +0,0 @@ -#include "cmsis_os.h" - -#include "stm-init.h" -#include "stm-uart.h" - -osMutexId stdio_mutex; -osMutexDef(stdio_mutex); - -void notify(const char* name, int state) { - osMutexWait(stdio_mutex, osWaitForever); - //printf("%s: %d\n\r", name, state); - uart_send_string(name); - uart_send_string(": "); - uart_send_integer(state, 1); - uart_send_string("\r\n"); - osMutexRelease(stdio_mutex); -} - -void test_thread(void const *args) { - while (1) { - notify((const char*)args, 0); osDelay(1000); - notify((const char*)args, 1); osDelay(1000); - } -} - -void t2(void const *argument) {test_thread("Th 2");} -osThreadDef(t2, osPriorityNormal, DEFAULT_STACK_SIZE); - -void t3(void const *argument) {test_thread("Th 3");} -osThreadDef(t3, osPriorityNormal, DEFAULT_STACK_SIZE); - -int main() { - stm_init(); - stdio_mutex = osMutexCreate(osMutex(stdio_mutex)); - - osThreadCreate(osThread(t2), NULL); - osThreadCreate(osThread(t3), NULL); - - test_thread((void *)"Th 1"); -} diff --git a/projects/rtos-test/semaphore-test.c b/projects/rtos-test/semaphore-test.c deleted file mode 100644 index 3a3b5de..0000000 --- a/projects/rtos-test/semaphore-test.c +++ /dev/null @@ -1,34 +0,0 @@ -#include "cmsis_os.h" - -#include "stm-init.h" -#include "stm-uart.h" - -osSemaphoreId two_slots; -osSemaphoreDef(two_slots); - -void test_thread(void const *name) { - while (1) { - osSemaphoreWait(two_slots, osWaitForever); - //printf("%s\n\r", (const char*)name); - uart_send_string((const char*)name); - uart_send_string("\r\n"); - osDelay(1000); - osSemaphoreRelease(two_slots); - } -} - -void t2(void const *argument) {test_thread("Th 2");} -osThreadDef(t2, osPriorityNormal, DEFAULT_STACK_SIZE); - -void t3(void const *argument) {test_thread("Th 3");} -osThreadDef(t3, osPriorityNormal, DEFAULT_STACK_SIZE); - -int main (void) { - stm_init(); - two_slots = osSemaphoreCreate(osSemaphore(two_slots), 2); - - osThreadCreate(osThread(t2), NULL); - osThreadCreate(osThread(t3), NULL); - - test_thread((void *)"Th 1"); -} diff --git a/projects/rtos-test/thread-test.c b/projects/rtos-test/thread-test.c deleted file mode 100644 index 8b31a26..0000000 --- a/projects/rtos-test/thread-test.c +++ /dev/null @@ -1,24 +0,0 @@ -#include "cmsis_os.h" - -#include "stm-init.h" -#include "stm-led.h" - -void led2_thread(void const *args) -{ - while (1) { - led_toggle(LED_BLUE); - osDelay(1000); - } -} -osThreadDef(led2_thread, osPriorityNormal, DEFAULT_STACK_SIZE); - -int main() -{ - stm_init(); - osThreadCreate(osThread(led2_thread), NULL); - - while (1) { - led_toggle(LED_GREEN); - osDelay(500); - } -} diff --git a/spiflash_n25q128.c b/spiflash_n25q128.c index 6e35a41..df53f19 100644 --- a/spiflash_n25q128.c +++ b/spiflash_n25q128.c @@ -6,7 +6,7 @@ * The Alpha board has two of these SPI flash memorys, the FPGA config memory * and the keystore memory. * - * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * Copyright (c) 2016-2017, NORDUnet A/S All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -35,320 +35,310 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "stm32f4xx_hal.h" -#include "stm-fpgacfg.h" -#include "stm-init.h" +#include "spiflash_n25q128.h" -#define _n25q128_select(ctx) HAL_GPIO_WritePin(ctx->cs_n_port, ctx->cs_n_pin, GPIO_PIN_RESET); -#define _n25q128_deselect(ctx) HAL_GPIO_WritePin(ctx->cs_n_port, ctx->cs_n_pin, GPIO_PIN_SET); +#define N25Q128_NUM_BYTES (N25Q128_PAGE_SIZE * N25Q128_NUM_PAGES) +#if N25Q128_SECTOR_SIZE * N25Q128_NUM_SECTORS != N25Q128_NUM_BYTES || \ + N25Q128_SUBSECTOR_SIZE * N25Q128_NUM_SUBSECTORS != N25Q128_NUM_BYTES +#error Inconsistent definitions for pages / sectors / subsectors +#endif -int _n25q128_get_wel_flag(struct spiflash_ctx *ctx); +static inline void _n25q128_select(struct spiflash_ctx *ctx) +{ + HAL_GPIO_WritePin(ctx->cs_n_port, ctx->cs_n_pin, GPIO_PIN_RESET); +} + +static inline void _n25q128_deselect(struct spiflash_ctx *ctx) +{ + HAL_GPIO_WritePin(ctx->cs_n_port, ctx->cs_n_pin, GPIO_PIN_SET); +} -int n25q128_check_id(struct spiflash_ctx *ctx) +/* Read a bit from the status register. */ +static inline int _n25q128_get_status_bit(struct spiflash_ctx *ctx, unsigned bitnum) { // tx, rx buffers - uint8_t spi_tx[4]; - uint8_t spi_rx[4]; + uint8_t spi_tx[2]; + uint8_t spi_rx[2]; - // result - HAL_StatusTypeDef ok; + //assert(bitnum < sizeof(uint8_t)); - // send READ ID command - spi_tx[0] = N25Q128_COMMAND_READ_ID; + // send READ STATUS command + spi_tx[0] = N25Q128_COMMAND_READ_STATUS; - // select, send command & read response, deselect + // send command, read response, deselect _n25q128_select(ctx); - ok = HAL_SPI_TransmitReceive(ctx->hspi, spi_tx, spi_rx, 4, N25Q128_SPI_TIMEOUT); - HAL_Delay(1); + int ok = + HAL_SPI_TransmitReceive(ctx->hspi, spi_tx, spi_rx, 2, N25Q128_SPI_TIMEOUT) == HAL_OK; _n25q128_deselect(ctx); // check - if (ok != HAL_OK) return 0; - - // parse response (note, that the very first byte was received during the - // transfer of the command byte, so it contains garbage and should - // be ignored here) - if (spi_rx[1] != N25Q128_ID_MANUFACTURER) return 0; - if (spi_rx[2] != N25Q128_ID_DEVICE_TYPE) return 0; - if (spi_rx[3] != N25Q128_ID_DEVICE_CAPACITY) return 0; + if (!ok) return -1; // done - return 1; + return ((spi_rx[1] >> bitnum) & 1); } - -int n25q128_read_page(struct spiflash_ctx *ctx, uint32_t page_offset, uint8_t *page_buffer) +/* Read the Write Enable Latch bit in the status register. */ +static inline int _n25q128_get_wel_flag(struct spiflash_ctx *ctx) { - // tx buffer - uint8_t spi_tx[4]; - - // result - HAL_StatusTypeDef ok; - - // check offset - if (page_offset >= N25Q128_NUM_PAGES) return 0; - - // calculate byte address - page_offset *= N25Q128_PAGE_SIZE; - - // prepare READ command - spi_tx[0] = N25Q128_COMMAND_READ_PAGE; - spi_tx[1] = (uint8_t)(page_offset >> 16); - spi_tx[2] = (uint8_t)(page_offset >> 8); - spi_tx[3] = (uint8_t)(page_offset >> 0); - - // activate, send command - _n25q128_select(ctx); - ok = HAL_SPI_Transmit(ctx->hspi, spi_tx, 4, N25Q128_SPI_TIMEOUT); - HAL_Delay(1); - - // check - if (ok != HAL_OK) { - _n25q128_deselect(ctx); - return 0; - } - - // read response, deselect - ok = HAL_SPI_Receive(ctx->hspi, page_buffer, N25Q128_PAGE_SIZE, N25Q128_SPI_TIMEOUT); - HAL_Delay(1); - _n25q128_deselect(ctx); - - // check - if (ok != HAL_OK) return 0; + return _n25q128_get_status_bit(ctx, 1); +} - // done - return 1; +/* Read the Write In Progress bit in the status register. */ +static inline int _n25q128_get_wip_flag(struct spiflash_ctx *ctx) +{ + return _n25q128_get_status_bit(ctx, 0); } +/* Wait until the flash memory is done writing */ +static HAL_StatusTypeDef _n25q128_wait_while_wip(struct spiflash_ctx *ctx, uint32_t timeout) +{ + uint32_t tick_end = HAL_GetTick() + timeout; + + do { + switch (_n25q128_get_wip_flag(ctx)) { + case 0: + return HAL_OK; + case -1: + return HAL_ERROR; + default: + /* try again */ + continue; + } + } while (HAL_GetTick() < tick_end); + + return HAL_TIMEOUT; +} -int n25q128_write_page(struct spiflash_ctx *ctx, uint32_t page_offset, const uint8_t *page_buffer) +/* Send the Write Enable command */ +static HAL_StatusTypeDef _n25q128_write_enable(struct spiflash_ctx *ctx) { // tx buffer - uint8_t spi_tx[4]; - - // result - HAL_StatusTypeDef ok; - - // check offset - if (page_offset >= N25Q128_NUM_PAGES) return 0; + uint8_t spi_tx[1]; // enable writing spi_tx[0] = N25Q128_COMMAND_WRITE_ENABLE; // activate, send command, deselect _n25q128_select(ctx); - ok = HAL_SPI_Transmit(ctx->hspi, spi_tx, 1, N25Q128_SPI_TIMEOUT); - HAL_Delay(1); + int ok = + HAL_SPI_Transmit(ctx->hspi, spi_tx, 1, N25Q128_SPI_TIMEOUT) == HAL_OK; _n25q128_deselect(ctx); // check - if (ok != HAL_OK) return 0; + if (!ok) return HAL_ERROR; // make sure, that write enable did the job - int wel = _n25q128_get_wel_flag(ctx); - if (wel != 1) return 0; + return _n25q128_get_wel_flag(ctx) ? HAL_OK : HAL_ERROR; +} - // calculate byte address - page_offset *= N25Q128_PAGE_SIZE; +HAL_StatusTypeDef n25q128_check_id(struct spiflash_ctx *ctx) +{ + // tx, rx buffers + uint8_t spi_tx[4]; + uint8_t spi_rx[4]; - // prepare PROGRAM PAGE command - spi_tx[0] = N25Q128_COMMAND_PAGE_PROGRAM; - spi_tx[1] = (uint8_t)(page_offset >> 16); - spi_tx[2] = (uint8_t)(page_offset >> 8); - spi_tx[3] = (uint8_t)(page_offset >> 0); + // send READ ID command + spi_tx[0] = N25Q128_COMMAND_READ_ID; - // activate, send command + // select, send command & read response, deselect _n25q128_select(ctx); - ok = HAL_SPI_Transmit(ctx->hspi, spi_tx, 4, N25Q128_SPI_TIMEOUT); - HAL_Delay(1); - - // check - if (ok != HAL_OK) { - _n25q128_deselect(ctx); - return 0; - } - - // send data, deselect - ok = HAL_SPI_Transmit(ctx->hspi, (uint8_t *) page_buffer, N25Q128_PAGE_SIZE, N25Q128_SPI_TIMEOUT); - HAL_Delay(1); + int ok = + HAL_SPI_TransmitReceive(ctx->hspi, spi_tx, spi_rx, 4, N25Q128_SPI_TIMEOUT) == HAL_OK; _n25q128_deselect(ctx); // check - if (ok != HAL_OK) return 0; + if (!ok) return HAL_ERROR; - // done - return 1; + // parse response (note, that the very first byte was received during the + // transfer of the command byte, so it contains garbage and should + // be ignored here) + return + (spi_rx[1] == N25Q128_ID_MANUFACTURER && + spi_rx[2] == N25Q128_ID_DEVICE_TYPE && + spi_rx[3] == N25Q128_ID_DEVICE_CAPACITY) ? HAL_OK : HAL_ERROR; } -int n25q128_get_wip_flag(struct spiflash_ctx *ctx) +HAL_StatusTypeDef n25q128_write_page(struct spiflash_ctx *ctx, uint32_t page_offset, const uint8_t *page_buffer) { - // tx, rx buffers - uint8_t spi_tx[2]; - uint8_t spi_rx[2]; + // tx buffer + uint8_t spi_tx[4]; - // result - HAL_StatusTypeDef ok; + // check offset + if (page_offset >= N25Q128_NUM_PAGES) return HAL_ERROR; - // send READ STATUS command - spi_tx[0] = N25Q128_COMMAND_READ_STATUS; + // enable writing + if (_n25q128_write_enable(ctx) != 0) return HAL_ERROR; - // send command, read response, deselect + // calculate byte address + uint32_t byte_offset = page_offset * N25Q128_PAGE_SIZE; + + // prepare PROGRAM PAGE command + spi_tx[0] = N25Q128_COMMAND_PAGE_PROGRAM; + spi_tx[1] = (uint8_t)(byte_offset >> 16); + spi_tx[2] = (uint8_t)(byte_offset >> 8); + spi_tx[3] = (uint8_t)(byte_offset >> 0); + + // activate, send command, send data, deselect _n25q128_select(ctx); - ok = HAL_SPI_TransmitReceive(ctx->hspi, spi_tx, spi_rx, 2, N25Q128_SPI_TIMEOUT); - HAL_Delay(1); + int ok = + HAL_SPI_Transmit(ctx->hspi, spi_tx, 4, N25Q128_SPI_TIMEOUT) == HAL_OK && + HAL_SPI_Transmit(ctx->hspi, (uint8_t *) page_buffer, N25Q128_PAGE_SIZE, N25Q128_SPI_TIMEOUT) == HAL_OK; _n25q128_deselect(ctx); // check - if (ok != HAL_OK) return -1; + if (!ok) return HAL_ERROR; - // done - return (spi_rx[1] & 1); + // wait until write finishes + return _n25q128_wait_while_wip(ctx, 1000); } -int n25q128_erase_sector(struct spiflash_ctx *ctx, uint32_t sector_offset) +static HAL_StatusTypeDef n25q128_erase_something(struct spiflash_ctx *ctx, uint8_t command, uint32_t byte_offset) { + // check offset + if (byte_offset >= N25Q128_NUM_BYTES) return HAL_ERROR; + // tx buffer uint8_t spi_tx[4]; - // result - HAL_StatusTypeDef ok; - - // check offset - if (sector_offset >= N25Q128_NUM_SECTORS) return 0; - // enable writing - spi_tx[0] = N25Q128_COMMAND_WRITE_ENABLE; + if (_n25q128_write_enable(ctx) != 0) return HAL_ERROR; - // select, send command, deselect + // send command (ERASE SECTOR or ERASE SUBSECTOR) + spi_tx[0] = command; + spi_tx[1] = (uint8_t)(byte_offset >> 16); + spi_tx[2] = (uint8_t)(byte_offset >> 8); + spi_tx[3] = (uint8_t)(byte_offset >> 0); + + // activate, send command, deselect _n25q128_select(ctx); - ok = HAL_SPI_Transmit(ctx->hspi, spi_tx, 1, N25Q128_SPI_TIMEOUT); - HAL_Delay(1); + int ok = + HAL_SPI_Transmit(ctx->hspi, spi_tx, 4, N25Q128_SPI_TIMEOUT) == HAL_OK; _n25q128_deselect(ctx); // check - if (ok != HAL_OK) return 0; + if (!ok) return HAL_ERROR; - // make sure, that write enable did the job - int wel = _n25q128_get_wel_flag(ctx); - if (wel != 1) return 0; - - // calculate byte address - sector_offset *= N25Q128_SECTOR_SIZE; + // wait for erase to finish + return _n25q128_wait_while_wip(ctx, 1000); +} - // send ERASE SUBSECTOR command - spi_tx[0] = N25Q128_COMMAND_ERASE_SECTOR; - spi_tx[1] = (uint8_t)(sector_offset >> 16); - spi_tx[2] = (uint8_t)(sector_offset >> 8); - spi_tx[3] = (uint8_t)(sector_offset >> 0); - // activate, send command, deselect - _n25q128_select(ctx); - ok = HAL_SPI_Transmit(ctx->hspi, spi_tx, 4, N25Q128_SPI_TIMEOUT); - HAL_Delay(1); - _n25q128_deselect(ctx); +HAL_StatusTypeDef n25q128_erase_sector(struct spiflash_ctx *ctx, uint32_t sector_offset) +{ + return n25q128_erase_something(ctx, N25Q128_COMMAND_ERASE_SECTOR, + sector_offset * N25Q128_SECTOR_SIZE); +} - // check - if (ok != HAL_OK) return 0; - // done - return 1; +HAL_StatusTypeDef n25q128_erase_subsector(struct spiflash_ctx *ctx, uint32_t subsector_offset) +{ + return n25q128_erase_something(ctx, N25Q128_COMMAND_ERASE_SUBSECTOR, + subsector_offset * N25Q128_SUBSECTOR_SIZE); } -int _n25q128_get_wel_flag(struct spiflash_ctx *ctx) +HAL_StatusTypeDef n25q128_erase_bulk(struct spiflash_ctx *ctx) { - // tx, rx buffers - uint8_t spi_tx[2]; - uint8_t spi_rx[2]; + // tx buffer + uint8_t spi_tx[1]; - // result - HAL_StatusTypeDef ok; + // enable writing + if (_n25q128_write_enable(ctx) != 0) return HAL_ERROR; - // send READ STATUS command - spi_tx[0] = N25Q128_COMMAND_READ_STATUS; + // send command + spi_tx[0] = N25Q128_COMMAND_ERASE_BULK; - // send command, read response, deselect + // activate, send command, deselect _n25q128_select(ctx); - ok = HAL_SPI_TransmitReceive(ctx->hspi, spi_tx, spi_rx, 2, N25Q128_SPI_TIMEOUT); - HAL_Delay(1); + int ok = + HAL_SPI_Transmit(ctx->hspi, spi_tx, 1, N25Q128_SPI_TIMEOUT) == HAL_OK; _n25q128_deselect(ctx); // check - if (ok != HAL_OK) return -1; + if (!ok) return HAL_ERROR; - // done - return ((spi_rx[1] >> 1) & 1); + // wait for erase to finish + return _n25q128_wait_while_wip(ctx, 60000); } -/* Wait until the flash memory is done writing (wip = Write In Progress) */ -inline int _wait_while_wip(struct spiflash_ctx *ctx, uint32_t timeout) -{ - int i; - while (timeout--) { - i = n25q128_get_wip_flag(ctx); - if (i < 0) return 0; - if (! i) break; - HAL_Delay(10); - } - return 1; -} -/* This function performs erasure if needed, and then writing of a number of pages to the flash memory */ -int n25q128_write_data(struct spiflash_ctx *ctx, uint32_t offset, const uint8_t *buf, const uint32_t len) +/* This function writes of a number of pages to the flash memory. + * The caller is responsible for ensuring that the pages have been erased. + */ +HAL_StatusTypeDef n25q128_write_data(struct spiflash_ctx *ctx, uint32_t offset, const uint8_t *buf, const uint32_t len) { uint32_t page; - /* Ensure alignment */ - if ((offset % N25Q128_PAGE_SIZE) != 0) return -1; - if ((len % N25Q128_PAGE_SIZE) != 0) return -2; - - if ((offset % N25Q128_SECTOR_SIZE) == 0) { - /* first page in sector, need to erase sector */ - - if (! _wait_while_wip(ctx, 1000)) return -3; - - if (! n25q128_erase_sector(ctx, offset / N25Q128_SECTOR_SIZE)) { - return -4; - } - } + /* + * The data sheet says: + * If the bits of the least significant address, which is the starting + * address, are not all zero, all data transmitted beyond the end of the + * current page is programmed from the starting address of the same page. + * If the number of bytes sent to the device exceed the maximum page size, + * previously latched data is discarded and only the last maximum + * page-size number of data bytes are guaranteed to be programmed + * correctly within the same page. If the number of bytes sent to the + * device is less than the maximum page size, they are correctly + * programmed at the specified addresses without any effect on the other + * bytes of the same page. + * + * This is sufficiently confusing that it makes sense to constrain the API + * to page alignment in address and length, because that's how we're using + * it anyway. + */ + + if (offset % N25Q128_PAGE_SIZE != 0 || len % N25Q128_PAGE_SIZE != 0) return HAL_ERROR; for (page = 0; page < len / N25Q128_PAGE_SIZE; page++) { - if (! _wait_while_wip(ctx, 1000)) return -5; - - if (! n25q128_write_page(ctx, offset / N25Q128_PAGE_SIZE, buf)) { - return -6; + if (n25q128_write_page(ctx, offset / N25Q128_PAGE_SIZE, buf) != 0) { + return HAL_ERROR; } buf += N25Q128_PAGE_SIZE; offset += N25Q128_PAGE_SIZE; - - /* XXX read back data and verify it, or maybe just verify ability to write - * to memory by verifying the contents of one page after erase? - */ } - return 1; + return HAL_OK; } /* This function reads zero or more pages from the SPI flash. */ -int n25q128_read_data(struct spiflash_ctx *ctx, uint32_t offset, uint8_t *buf, const uint32_t len) +HAL_StatusTypeDef n25q128_read_data(struct spiflash_ctx *ctx, uint32_t offset, uint8_t *buf, const uint32_t len) { - uint32_t page; + // tx buffer + uint8_t spi_tx[4]; - /* Ensure alignment */ - if ((offset % N25Q128_PAGE_SIZE) != 0) return -1; - if ((len % N25Q128_PAGE_SIZE) != 0) return -2; + /* + * The data sheet says: + * The addressed byte can be at any location, and the address + * automatically increments to the next address after each byte of data is + * shifted out; therefore, the entire memory can be read with a single + * command. The operation is terminated by driving S# [chip select] HIGH + * at any time during data output. + * + * We're only going to call this with page-aligned address and length, but + * we're not going to enforce it here. + */ + + // avoid overflow + if (offset + len > N25Q128_NUM_BYTES) return HAL_ERROR; - for (page = 0; page < len / N25Q128_PAGE_SIZE; page++) { - if (! n25q128_read_page(ctx, offset / N25Q128_PAGE_SIZE, buf)) { - return -3; - } - buf += N25Q128_PAGE_SIZE; - offset += N25Q128_PAGE_SIZE; - } + // prepare READ command + spi_tx[0] = N25Q128_COMMAND_READ; + spi_tx[1] = (uint8_t)(offset >> 16); + spi_tx[2] = (uint8_t)(offset >> 8); + spi_tx[3] = (uint8_t)(offset >> 0); - return 1; + // activate, send command, read response, deselect + _n25q128_select(ctx); + int ok = + HAL_SPI_Transmit(ctx->hspi, spi_tx, 4, N25Q128_SPI_TIMEOUT) == HAL_OK && + HAL_SPI_Receive(ctx->hspi, buf, len, N25Q128_SPI_TIMEOUT) == HAL_OK; + _n25q128_deselect(ctx); + + // check + return ok ? HAL_OK : HAL_ERROR; } diff --git a/spiflash_n25q128.h b/spiflash_n25q128.h index fefcb0d..926be56 100644 --- a/spiflash_n25q128.h +++ b/spiflash_n25q128.h @@ -6,7 +6,7 @@ * The Alpha board has two of these SPI flash memorys, the FPGA config memory * and the keystore memory. * - * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * Copyright (c) 2016-2017, NORDUnet A/S All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -40,11 +40,13 @@ #include "stm32f4xx_hal.h" -#define N25Q128_COMMAND_READ_ID 0x9E -#define N25Q128_COMMAND_READ_PAGE 0x03 +#define N25Q128_COMMAND_READ 0x03 #define N25Q128_COMMAND_READ_STATUS 0x05 +#define N25Q128_COMMAND_READ_ID 0x9E #define N25Q128_COMMAND_WRITE_ENABLE 0x06 #define N25Q128_COMMAND_ERASE_SECTOR 0xD8 +#define N25Q128_COMMAND_ERASE_SUBSECTOR 0x20 +#define N25Q128_COMMAND_ERASE_BULK 0xC7 #define N25Q128_COMMAND_PAGE_PROGRAM 0x02 #define N25Q128_PAGE_SIZE 0x100 // 256 @@ -53,6 +55,9 @@ #define N25Q128_SECTOR_SIZE 0x10000 // 65536 #define N25Q128_NUM_SECTORS 0x100 // 256 +#define N25Q128_SUBSECTOR_SIZE 0x1000 // 4096 +#define N25Q128_NUM_SUBSECTORS 0x1000 // 4096 + #define N25Q128_SPI_TIMEOUT 1000 #define N25Q128_ID_MANUFACTURER 0x20 @@ -65,12 +70,17 @@ struct spiflash_ctx { uint16_t cs_n_pin; }; -extern int n25q128_check_id(struct spiflash_ctx *ctx); -extern int n25q128_get_wip_flag(struct spiflash_ctx *ctx); -extern int n25q128_read_page(struct spiflash_ctx *ctx, uint32_t page_offset, uint8_t *page_buffer); -extern int n25q128_write_page(struct spiflash_ctx *ctx, uint32_t page_offset, const uint8_t *page_buffer); -extern int n25q128_erase_sector(struct spiflash_ctx *ctx, uint32_t sector_offset); +extern HAL_StatusTypeDef n25q128_check_id(struct spiflash_ctx *ctx); +extern HAL_StatusTypeDef n25q128_read_data(struct spiflash_ctx *ctx, uint32_t offset, uint8_t *buf, const uint32_t len); +extern HAL_StatusTypeDef n25q128_write_page(struct spiflash_ctx *ctx, uint32_t page_offset, const uint8_t *page_buffer); +extern HAL_StatusTypeDef n25q128_write_data(struct spiflash_ctx *ctx, uint32_t offset, const uint8_t *buf, const uint32_t len); +extern HAL_StatusTypeDef n25q128_erase_subsector(struct spiflash_ctx *ctx, uint32_t subsector_offset); +extern HAL_StatusTypeDef n25q128_erase_sector(struct spiflash_ctx *ctx, uint32_t sector_offset); +extern HAL_StatusTypeDef n25q128_erase_bulk(struct spiflash_ctx *ctx); + +#define n25q128_read_page(ctx, page_offset, page_buffer) \ + n25q128_read_data(ctx, page_offset * N25Q128_PAGE_SIZE, page_buffer, N25Q128_PAGE_SIZE) +#define n25q128_read_subsector(ctx, subsector_offset, subsector_buffer) \ + n25q128_read_data(ctx, subsector_offset * N25Q128_SUBSECTOR_SIZE, subsector_buffer, N25Q128_SUBSECTOR_SIZE) -extern int n25q128_write_data(struct spiflash_ctx *ctx, uint32_t offset, const uint8_t *buf, const uint32_t len); -extern int n25q128_read_data(struct spiflash_ctx *ctx, uint32_t offset, uint8_t *buf, const uint32_t len); #endif /* __STM32_SPIFLASH_N25Q128_H */ diff --git a/stm-flash.c b/stm-flash.c index 991379b..952543f 100644 --- a/stm-flash.c +++ b/stm-flash.c @@ -33,9 +33,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "stm32f4xx_hal.h" -#include "stm-flash.h" #include "stm-init.h" +#include "stm-flash.h" /* Flash sector offsets from RM0090, Table 6. Flash module - 2 Mbyte dual bank organization */ @@ -70,28 +69,30 @@ uint32_t flash_sector_offsets[FLASH_NUM_SECTORS + 1] = { 0x08200000 /* first address *after* flash */ }; -int stm_flash_sector_num(const uint32_t offset) +static uint32_t stm_flash_sector_num(const uint32_t offset) { - int i = FLASH_NUM_SECTORS; + uint32_t i; + + if (offset < flash_sector_offsets[0]) + return 0xFFFFFFFF; - while (i-- >= 0) { - if (offset >= flash_sector_offsets[i] && - offset < flash_sector_offsets[i + 1]) { + for (i = 0; i < FLASH_NUM_SECTORS; ++i) + if (offset < flash_sector_offsets[i + 1]) return i; - } - } - return -1; + + return 0xFFFFFFFF; } -int stm_flash_erase_sectors(const uint32_t start_offset, const uint32_t end_offset) +HAL_StatusTypeDef stm_flash_erase_sectors(const uint32_t start_offset, const uint32_t end_offset) { uint32_t start_sector = stm_flash_sector_num(start_offset); uint32_t end_sector = stm_flash_sector_num(end_offset); FLASH_EraseInitTypeDef FLASH_EraseInitStruct; uint32_t SectorError = 0; + HAL_StatusTypeDef err; - if (start_sector > end_sector) return -1; - if (start_sector < 0 || end_sector > FLASH_NUM_SECTORS) return -2; + if (start_sector > end_sector || end_sector > FLASH_NUM_SECTORS) + return HAL_ERROR; FLASH_EraseInitStruct.Sector = start_sector; FLASH_EraseInitStruct.NbSectors = (end_sector - start_sector) + 1; @@ -99,40 +100,38 @@ int stm_flash_erase_sectors(const uint32_t start_offset, const uint32_t end_offs FLASH_EraseInitStruct.VoltageRange = VOLTAGE_RANGE_3; HAL_FLASH_Unlock(); - - if (HAL_FLASHEx_Erase(&FLASH_EraseInitStruct, &SectorError) != HAL_OK) { - return -3; - } - + err = HAL_FLASHEx_Erase(&FLASH_EraseInitStruct, &SectorError); HAL_FLASH_Lock(); - if (SectorError == 0xFFFFFFFF) return 0; + if (err != HAL_OK || SectorError != 0xFFFFFFFF) + return HAL_ERROR; - return -3; + return HAL_OK; } -int stm_flash_write32(uint32_t offset, const uint32_t *buf, const uint32_t elements) +HAL_StatusTypeDef stm_flash_write32(uint32_t offset, const uint32_t *buf, const size_t elements) { uint32_t sector = stm_flash_sector_num(offset); - uint32_t i, j; + size_t i; + HAL_StatusTypeDef err = HAL_OK; if (offset == flash_sector_offsets[sector]) { /* Request to write to beginning of a flash sector, erase it first. */ if (stm_flash_erase_sectors(offset, offset) != 0) { - return -1; + return HAL_ERROR; } } HAL_FLASH_Unlock(); for (i = 0; i < elements; i++) { - if ((j = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, offset, buf[i])) != HAL_OK) { - return -2; + if ((err = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, offset, buf[i])) != HAL_OK) { + break; } offset += 4; } HAL_FLASH_Lock(); - return 1; + return err; } diff --git a/stm-flash.h b/stm-flash.h index a9cf7db..db7d327 100644 --- a/stm-flash.h +++ b/stm-flash.h @@ -1,7 +1,8 @@ /* * stm-flash.h * ----------- - * Functions and defines for accessing the flash memory. + * Functions for writing/erasing the STM32 internal flash memory. + * The flash is memory mapped, so no code is needed here to read it. * * Copyright (c) 2016, NORDUnet A/S All rights reserved. * @@ -35,8 +36,7 @@ #ifndef __STM32_FLASH_H #define __STM32_FLASH_H -extern int stm_flash_sector_num(const uint32_t offset); -extern int stm_flash_erase_sectors(const uint32_t start_offset, const uint32_t end_offset); -extern int stm_flash_write32(const uint32_t offset, const uint32_t *buf, const uint32_t elements); +extern HAL_StatusTypeDef stm_flash_erase_sectors(const uint32_t start_offset, const uint32_t end_offset); +extern HAL_StatusTypeDef stm_flash_write32(const uint32_t offset, const uint32_t *buf, const size_t elements); #endif /* __STM32_FLASH_H */ @@ -3,7 +3,9 @@ * --------- * Functions to set up and use the FMC bus. * - * Copyright (c) 2015, NORDUnet A/S All rights reserved. + * Copyright 2015-2019 NORDUnet A/S + * Copyright 2021 The Commons Conservancy Cryptech Project + * SPDX-License-Identifier: BSD-3-Clause * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -15,9 +17,9 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * - Neither the name of the NORDUnet nor the names of its contributors may - * be used to endorse or promote products derived from this software - * without specific prior written permission. + * - Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED @@ -31,113 +33,20 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "stm32f4xx_hal.h" #include "stm-init.h" #include "stm-fmc.h" static SRAM_HandleTypeDef _fmc_fpga_inst; -static HAL_StatusTypeDef _fmc_init_params(void); -static int _fmc_nwait_idle(void); - - -HAL_StatusTypeDef fmc_init(void) +void fmc_init(void) { static int initialized = 0; - - if (initialized) { - return HAL_OK; - } + if (initialized) return; initialized = 1; // configure fmc pins - fmc_init_gpio(); - - // configure fmc registers - return _fmc_init_params(); -} - - -int fmc_write_32(uint32_t addr, uint32_t *data) -{ - // calculate target fpga address - uint32_t ptr = FMC_FPGA_BASE_ADDR + (addr & FMC_FPGA_ADDR_MASK); - - // write data to fpga - HAL_StatusTypeDef ok = HAL_SRAM_Write_32b(&_fmc_fpga_inst, (uint32_t *)ptr, data, 1); - - // check for error - if (ok != HAL_OK) return -1; - - // wait for transaction to complete - int wait = _fmc_nwait_idle(); - - // check for timeout - if (wait != 0) return -1; - - // everything went ok - return 0; -} - - -int fmc_read_32(uint32_t addr, uint32_t *data) -{ - // calculate target fpga address - uint32_t ptr = FMC_FPGA_BASE_ADDR + (addr & FMC_FPGA_ADDR_MASK); - - // perform dummy read transaction - HAL_StatusTypeDef ok = HAL_SRAM_Read_32b(&_fmc_fpga_inst, (uint32_t *)ptr, data, 1); - - // check for error - if (ok != HAL_OK) return -1; - - // wait for dummy transaction to complete - int wait = _fmc_nwait_idle(); - - // check for timeout - if (wait != 0) return -1; - - // read data from fpga - ok = HAL_SRAM_Read_32b(&_fmc_fpga_inst, (uint32_t *)ptr, data, 1); - // check for error - if (ok != HAL_OK) return -1; - - // wait for read transaction to complete - wait = _fmc_nwait_idle(); - - // check for timeout - if (wait != 0) return -1; - - // everything went ok - return 0; -} - - -static int _fmc_nwait_idle() -{ - int cnt; // counter - - // poll NWAIT (number of iterations is limited) - for (cnt=0; cnt<FMC_FPGA_NWAIT_MAX_POLL_TICKS; cnt++) - { - // read pin state - GPIO_PinState nwait = HAL_GPIO_ReadPin(FMC_GPIO_PORT_NWAIT, FMC_GPIO_PIN_NWAIT); - - // stop waiting if fpga is ready - if (nwait == FMC_NWAIT_IDLE) break; - } - - // check for timeout - if (cnt >= FMC_FPGA_NWAIT_MAX_POLL_TICKS) return -1; - - // ok - return 0; -} - -void fmc_init_gpio(void) -{ GPIO_InitTypeDef GPIO_InitStruct; // enable fmc clock @@ -155,7 +64,7 @@ void fmc_init_gpio(void) */ GPIO_InitStruct.Pin = GPIO_PIN_6; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; - GPIO_InitStruct.Pull = GPIO_PULLUP; + GPIO_InitStruct.Pull = GPIO_PULLDOWN; HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); fmc_af_gpio(GPIOE, GPIO_PIN_2 @@ -171,11 +80,9 @@ void fmc_init_gpio(void) | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15); fmc_af_gpio(GPIOI, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_9 | GPIO_PIN_10); -} + // configure fmc registers -static HAL_StatusTypeDef _fmc_init_params(void) -{ /* * fill internal fields */ @@ -210,7 +117,7 @@ static HAL_StatusTypeDef _fmc_init_params(void) _fmc_fpga_inst.Init.WrapMode = FMC_WRAP_MODE_DISABLE; // don't care in fixed latency mode - _fmc_fpga_inst.Init.WaitSignalActive = FMC_WAIT_TIMING_DURING_WS; + _fmc_fpga_inst.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS; // allow write access to fpga _fmc_fpga_inst.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE; @@ -244,18 +151,40 @@ static HAL_StatusTypeDef _fmc_init_params(void) // don't care in sync mode fmc_timing.DataSetupTime = 255; - // not needed, since nwait will be polled manually + // not needed fmc_timing.BusTurnAroundDuration = 0; - // use smallest allowed divisor for best performance - fmc_timing.CLKDivision = 2; + // use 45 MHz to match what FMC arbiter in the FPGA expects + fmc_timing.CLKDivision = 4; // 180/4 - // stm is too slow to work with min allowed 2-cycle latency - fmc_timing.DataLatency = 3; + // use 6 to match what FMC arbiter in the FPGA expects + fmc_timing.DataLatency = 6; // don't care in sync mode fmc_timing.AccessMode = FMC_ACCESS_MODE_A; // initialize fmc - return HAL_SRAM_Init(&_fmc_fpga_inst, &fmc_timing, NULL); + HAL_SRAM_Init(&_fmc_fpga_inst, &fmc_timing, NULL); + + // STM32 only enables FMC clock right before the very first read/write + // access. FPGA takes certain time (<= 100 us) to lock its PLL to this frequency, + // so a certain number of initial FMC transactions may be missed. One read transaction + // takes ~0.22 us (10 ticks @ 45 MHz), so doing ~500 dummy reads will make sure, that FPGA + // has already locked its PLL and is ready. Another way around is to repeatedly read + // some register that is guaranteed to have known value until reading starts returning + // correct data. + + // to prevent compiler from optimizing this away, we pretent we're calculating sum + int cyc; + uint32_t sum = 0; + volatile uint32_t part; + + for (cyc=0; cyc<500; cyc++) + { + part = *(__IO uint32_t *)FMC_FPGA_BASE_ADDR; + sum += part; + } + + // dummy write to read-only address to not let the compiler remove the above loop + *(__IO uint32_t *)FMC_FPGA_BASE_ADDR = sum; } @@ -4,6 +4,8 @@ * Functions to set up and use the FMC bus. * * Copyright (c) 2015, NORDUnet A/S All rights reserved. + * Copyright: 2020, The Commons Conservancy Cryptech Project + * SPDX-License-Identifier: BSD-3-Clause * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -15,9 +17,9 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * - Neither the name of the NORDUnet nor the names of its contributors may - * be used to endorse or promote products derived from this software - * without specific prior written permission. + * - Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED @@ -39,12 +41,6 @@ #define FMC_FPGA_BASE_ADDR 0x60000000 #define FMC_FPGA_ADDR_MASK 0x03FFFFFC // there are 26 physical lines, but "only" 24 usable for now -#define FMC_FPGA_NWAIT_MAX_POLL_TICKS 10 - -#define FMC_GPIO_PORT_NWAIT GPIOD -#define FMC_GPIO_PIN_NWAIT GPIO_PIN_6 - -#define FMC_NWAIT_IDLE GPIO_PIN_SET #define fmc_af_gpio(port, pins) \ GPIO_InitStruct.Pin = pins; \ @@ -56,10 +52,21 @@ HAL_GPIO_Init(port, &GPIO_InitStruct) -extern HAL_StatusTypeDef fmc_init(void); -extern void fmc_init_gpio(void); +extern void fmc_init(void); + +static inline void *fmc_fpga_addr(off_t addr) +{ + return (void *)(FMC_FPGA_BASE_ADDR + (addr & FMC_FPGA_ADDR_MASK)); +} + +static inline void fmc_write_32(uint32_t addr, uint32_t data) +{ + *(uint32_t *)fmc_fpga_addr(addr) = data; +} -extern int fmc_write_32(uint32_t addr, uint32_t *data); -extern int fmc_read_32(uint32_t addr, uint32_t *data); +static inline void fmc_read_32(uint32_t addr, uint32_t *data) +{ + *data = *(uint32_t *)fmc_fpga_addr(addr); +} #endif /* __STM_FMC_H */ diff --git a/stm-fpgacfg.c b/stm-fpgacfg.c index 6f6114d..54342bf 100644 --- a/stm-fpgacfg.c +++ b/stm-fpgacfg.c @@ -4,7 +4,7 @@ * Functions for accessing the FPGA config memory and controlling * the low-level status of the FPGA (reset registers/reboot etc.). * - * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * Copyright (c) 2016-2017, NORDUnet A/S All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -33,20 +33,47 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "stm32f4xx_hal.h" #include "stm-fpgacfg.h" #include "stm-init.h" -SPI_HandleTypeDef hspi_fpgacfg; +static SPI_HandleTypeDef hspi_fpgacfg; -struct spiflash_ctx fpgacfg_ctx = {&hspi_fpgacfg, PROM_CS_N_GPIO_Port, PROM_CS_N_Pin}; +static struct spiflash_ctx fpgacfg_ctx = {&hspi_fpgacfg, PROM_CS_N_GPIO_Port, PROM_CS_N_Pin}; -int fpgacfg_check_id() +void fpgacfg_init(void) +{ + /* Give the FPGA access to it's bitstream ASAP (maybe this should actually + * be done in the application, before calling stm_init()). + */ + fpgacfg_access_control(ALLOW_FPGA); + + /* Set up GPIOs to manage access to the FPGA config memory. + * FPGACFG_GPIO_INIT is defined in stm-fpgacfg.h. + */ + FPGACFG_GPIO_INIT(); + + /* SPI2 (FPGA config memory) init function */ + hspi_fpgacfg.Instance = SPI2; + hspi_fpgacfg.Init.Mode = SPI_MODE_MASTER; + hspi_fpgacfg.Init.Direction = SPI_DIRECTION_2LINES; + hspi_fpgacfg.Init.DataSize = SPI_DATASIZE_8BIT; + hspi_fpgacfg.Init.CLKPolarity = SPI_POLARITY_LOW; + hspi_fpgacfg.Init.CLKPhase = SPI_PHASE_1EDGE; + hspi_fpgacfg.Init.NSS = SPI_NSS_SOFT; + hspi_fpgacfg.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; + hspi_fpgacfg.Init.FirstBit = SPI_FIRSTBIT_MSB; + hspi_fpgacfg.Init.TIMode = SPI_TIMODE_DISABLE; + hspi_fpgacfg.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; + hspi_fpgacfg.Init.CRCPolynomial = 10; + HAL_SPI_Init(&hspi_fpgacfg); +} + +HAL_StatusTypeDef fpgacfg_check_id(void) { return n25q128_check_id(&fpgacfg_ctx); } -int fpgacfg_write_data(uint32_t offset, const uint8_t *buf, const uint32_t len) +HAL_StatusTypeDef fpgacfg_write_data(uint32_t offset, const uint8_t *buf, const uint32_t len) { return n25q128_write_data(&fpgacfg_ctx, offset, buf, len); } @@ -86,29 +113,12 @@ void fpgacfg_reset_fpga(enum fpgacfg_reset reset) } } -int fpgacfg_check_done(void) +HAL_StatusTypeDef fpgacfg_check_done(void) { - GPIO_PinState status = HAL_GPIO_ReadPin(FPGA_DONE_Port, FPGA_DONE_Pin); - return (status == GPIO_PIN_SET); + return (HAL_GPIO_ReadPin(FPGA_DONE_Port, FPGA_DONE_Pin) == GPIO_PIN_SET) ? HAL_OK : HAL_ERROR; } -int fpgacfg_erase_sectors(int num) +HAL_StatusTypeDef fpgacfg_erase_sector(uint32_t sector_offset) { - if (num > N25Q128_NUM_SECTORS || num < 0) num = N25Q128_NUM_SECTORS; - while (num) { - int timeout = 200; /* times 10ms = 2 seconds timeout */ - while (timeout--) { - int i = n25q128_get_wip_flag(&fpgacfg_ctx); - if (i < 0) return 0; - if (! i) break; - HAL_Delay(10); - } - if (! timeout) return 0; - - if (! n25q128_erase_sector(&fpgacfg_ctx, num - 1)) { - return -1; - } - num--; - } - return 1; + return n25q128_erase_sector(&fpgacfg_ctx, sector_offset); } diff --git a/stm-fpgacfg.h b/stm-fpgacfg.h index 0d5eeb9..74cc683 100644 --- a/stm-fpgacfg.h +++ b/stm-fpgacfg.h @@ -4,7 +4,7 @@ * Functions and defines for accessing the FPGA config memory and controlling * the low-level status of the FPGA (reset registers/reboot etc.). * - * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * Copyright (c) 2016-2017, NORDUnet A/S All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -39,6 +39,8 @@ #include "stm32f4xx_hal.h" #include "spiflash_n25q128.h" +#define FPGACFG_SECTOR_SIZE N25Q128_SECTOR_SIZE + /* Pins connected to the FPGA config memory (SPI flash) */ #define PROM_FPGA_DIS_Pin GPIO_PIN_14 #define PROM_FPGA_DIS_GPIO_Port GPIOI @@ -83,15 +85,14 @@ enum fpgacfg_reset { RESET_REGISTERS, }; -extern SPI_HandleTypeDef hspi_fpgacfg; - -extern int fpgacfg_check_id(void); -extern int fpgacfg_write_data(uint32_t offset, const uint8_t *buf, const uint32_t len); -extern int fpgacfg_erase_sectors(int num); +extern void fpgacfg_init(void); +extern HAL_StatusTypeDef fpgacfg_check_id(void); +extern HAL_StatusTypeDef fpgacfg_write_data(uint32_t offset, const uint8_t *buf, const uint32_t len); +extern HAL_StatusTypeDef fpgacfg_erase_sector(uint32_t sector_offset); extern void fpgacfg_access_control(enum fpgacfg_access_ctrl access); /* Reset the FPGA */ extern void fpgacfg_reset_fpga(enum fpgacfg_reset reset); /* Check status of FPGA bitstream loading */ -extern int fpgacfg_check_done(void); +extern HAL_StatusTypeDef fpgacfg_check_done(void); #endif /* __STM32_FPGACFG_H */ @@ -33,7 +33,6 @@ */ /* Includes ------------------------------------------------------------------*/ -#include "stm32f4xx_hal.h" #include "stm-init.h" #ifdef HAL_GPIO_MODULE_ENABLED #include "stm-led.h" @@ -48,6 +47,12 @@ #include "stm-fpgacfg.h" #include "stm-keystore.h" #endif +#ifdef HAL_SRAM_MODULE_ENABLED +#include "stm-fmc.h" +#endif +#ifdef HAL_SDRAM_MODULE_ENABLED +#include "stm-sdram.h" +#endif /* Private variables ---------------------------------------------------------*/ @@ -55,20 +60,6 @@ #ifdef HAL_GPIO_MODULE_ENABLED static void MX_GPIO_Init(void); #endif -#ifdef HAL_UART_MODULE_ENABLED -static void MX_USART1_UART_Init(void); -static void MX_USART2_UART_Init(void); -#endif -#ifdef HAL_DMA_MODULE_ENABLED -static void MX_DMA_Init(void); -#endif -#ifdef HAL_I2C_MODULE_ENABLED -static void MX_I2C2_Init(void); -#endif -#ifdef HAL_SPI_MODULE_ENABLED -static void MX_SPI1_Init(void); -static void MX_SPI2_Init(void); -#endif void stm_init(void) { @@ -78,187 +69,52 @@ void stm_init(void) /* System interrupt init*/ /* Sets the priority grouping field */ HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_0); - HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0); /* Initialize all configured peripherals */ #ifdef HAL_GPIO_MODULE_ENABLED MX_GPIO_Init(); - #ifdef HAL_SPI_MODULE_ENABLED - /* Give the FPGA access to it's bitstream ASAP (maybe this should actually - * be done in the application, before calling stm_init()). - */ - fpgacfg_access_control(ALLOW_FPGA); - #endif -#endif -#ifdef HAL_DMA_MODULE_ENABLED - MX_DMA_Init(); #endif #ifdef HAL_UART_MODULE_ENABLED - MX_USART1_UART_Init(); - MX_USART2_UART_Init(); + uart_init(); #endif #ifdef HAL_I2C_MODULE_ENABLED - MX_I2C2_Init(); + rtc_init(); #endif #ifdef HAL_SPI_MODULE_ENABLED - MX_SPI1_Init(); - MX_SPI2_Init(); + fpgacfg_init(); + keystore_init(); +#endif +#ifdef TARGET_CRYPTECH_DEV_BRIDGE + // Blink blue LED for six seconds to not upset the Novena at boot. + led_on(LED_BLUE); + for (int i = 0; i < 12; i++) { + HAL_Delay(500); + led_toggle(LED_BLUE); + } + led_off(LED_BLUE); #endif -} - - -#ifdef HAL_UART_MODULE_ENABLED -/* USART1 init function */ -static void MX_USART1_UART_Init(void) -{ - huart_mgmt.Instance = USART1; - huart_mgmt.Init.BaudRate = USART_MGMT_BAUD_RATE; - huart_mgmt.Init.WordLength = UART_WORDLENGTH_8B; - huart_mgmt.Init.StopBits = UART_STOPBITS_1; - huart_mgmt.Init.Parity = UART_PARITY_NONE; - huart_mgmt.Init.Mode = UART_MODE_TX_RX; - huart_mgmt.Init.HwFlowCtl = UART_HWCONTROL_RTS_CTS; - huart_mgmt.Init.OverSampling = UART_OVERSAMPLING_16; - -#ifdef HAL_DMA_MODULE_ENABLED - __HAL_LINKDMA(&huart_mgmt, hdmarx, hdma_usart_mgmt_rx); +#ifdef HAL_SRAM_MODULE_ENABLED + fmc_init(); #endif - - if (HAL_UART_Init(&huart_mgmt) != HAL_OK) { - /* Initialization Error */ - Error_Handler(); - } -} -/* USART2 init function */ -static void MX_USART2_UART_Init(void) -{ - huart_user.Instance = USART2; - huart_user.Init.BaudRate = USART_USER_BAUD_RATE; - huart_user.Init.WordLength = UART_WORDLENGTH_8B; - huart_user.Init.StopBits = UART_STOPBITS_1; - huart_user.Init.Parity = UART_PARITY_NONE; - huart_user.Init.Mode = UART_MODE_TX_RX; - huart_user.Init.HwFlowCtl = UART_HWCONTROL_RTS_CTS; - huart_user.Init.OverSampling = UART_OVERSAMPLING_16; - -#ifdef HAL_DMA_MODULE_ENABLED - __HAL_LINKDMA(&huart_user, hdmarx, hdma_usart_user_rx); +#ifdef HAL_SDRAM_MODULE_ENABLED + sdram_init(); #endif - - if (HAL_UART_Init(&huart_user) != HAL_OK) { - /* Initialization Error */ - Error_Handler(); - } } -#endif + #ifdef HAL_GPIO_MODULE_ENABLED /* Configure General Purpose Input/Output pins */ static void MX_GPIO_Init(void) { - GPIO_InitTypeDef GPIO_InitStruct; - /* GPIO Ports Clock Enable */ LED_CLK_ENABLE(); /* Configure LED GPIO pins */ gpio_output(LED_PORT, LED_RED | LED_YELLOW | LED_GREEN | LED_BLUE, GPIO_PIN_RESET); - -#ifdef HAL_SPI_MODULE_ENABLED - /* Set up GPIOs to manage access to the FPGA config memory. - * FPGACFG_GPIO_INIT is defined in stm-fpgacfg.h. - */ - FPGACFG_GPIO_INIT(); - /* Set up GPIOs for the keystore memory. - * KEYSTORE_GPIO_INIT is defined in stm-keystore.h. - */ - KEYSTORE_GPIO_INIT(); -#endif /* HAL_SPI_MODULE_ENABLED */ } -#undef gpio_output #endif - -#ifdef HAL_DMA_MODULE_ENABLED -/** - * Enable DMA controller clock - */ -static void MX_DMA_Init(void) -{ - /* DMA controller clock enable */ - __HAL_RCC_DMA2_CLK_ENABLE(); - __HAL_RCC_DMA1_CLK_ENABLE(); - - /* DMA interrupt init */ - - /* USER UART RX */ - HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 0, 0); - HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn); - /* MGMT UART RX */ - HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 0, 0); - HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn); -} -#endif /* HAL_DMA_MODULE_ENABLED */ - - -#ifdef HAL_I2C_MODULE_ENABLED -/* I2C2 init function (external RTC chip) */ -void MX_I2C2_Init(void) -{ - hi2c_rtc.Instance = I2C2; - hi2c_rtc.Init.ClockSpeed = 10000; - hi2c_rtc.Init.DutyCycle = I2C_DUTYCYCLE_2; - hi2c_rtc.Init.OwnAddress1 = 0; /* Will operate as Master */ - hi2c_rtc.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; - hi2c_rtc.Init.DualAddressMode = I2C_DUALADDRESS_DISABLED; - hi2c_rtc.Init.OwnAddress2 = 0; - hi2c_rtc.Init.GeneralCallMode = I2C_GENERALCALL_DISABLED; - hi2c_rtc.Init.NoStretchMode = I2C_NOSTRETCH_DISABLED; - - if (HAL_I2C_Init(&hi2c_rtc) != HAL_OK) { - Error_Handler(); - } -} -#endif - -#ifdef HAL_SPI_MODULE_ENABLED -/* SPI1 (keystore memory) init function */ -void MX_SPI1_Init(void) -{ - hspi_keystore.Instance = SPI1; - hspi_keystore.Init.Mode = SPI_MODE_MASTER; - hspi_keystore.Init.Direction = SPI_DIRECTION_2LINES; - hspi_keystore.Init.DataSize = SPI_DATASIZE_8BIT; - hspi_keystore.Init.CLKPolarity = SPI_POLARITY_LOW; - hspi_keystore.Init.CLKPhase = SPI_PHASE_1EDGE; - hspi_keystore.Init.NSS = SPI_NSS_SOFT; - hspi_keystore.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; - hspi_keystore.Init.FirstBit = SPI_FIRSTBIT_MSB; - hspi_keystore.Init.TIMode = SPI_TIMODE_DISABLE; - hspi_keystore.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; - hspi_keystore.Init.CRCPolynomial = 10; - HAL_SPI_Init(&hspi_keystore); -} -/* SPI2 (FPGA config memory) init function */ -void MX_SPI2_Init(void) -{ - hspi_fpgacfg.Instance = SPI2; - hspi_fpgacfg.Init.Mode = SPI_MODE_MASTER; - hspi_fpgacfg.Init.Direction = SPI_DIRECTION_2LINES; - hspi_fpgacfg.Init.DataSize = SPI_DATASIZE_8BIT; - hspi_fpgacfg.Init.CLKPolarity = SPI_POLARITY_LOW; - hspi_fpgacfg.Init.CLKPhase = SPI_PHASE_1EDGE; - hspi_fpgacfg.Init.NSS = SPI_NSS_SOFT; - hspi_fpgacfg.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; - hspi_fpgacfg.Init.FirstBit = SPI_FIRSTBIT_MSB; - hspi_fpgacfg.Init.TIMode = SPI_TIMODE_DISABLE; - hspi_fpgacfg.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; - hspi_fpgacfg.Init.CRCPolynomial = 10; - HAL_SPI_Init(&hspi_fpgacfg); -} -#endif /* HAL_SPI_MODULE_ENABLED */ - /** * @brief This function is executed in case of error occurrence. * @param None @@ -269,29 +125,10 @@ void Error_Handler(void) #ifdef HAL_GPIO_MODULE_ENABLED HAL_GPIO_WritePin(LED_PORT, LED_RED, GPIO_PIN_SET); #endif - while (1) { ; } -} - -#ifdef USE_FULL_ASSERT - -/** - * @brief Reports the name of the source file and the source line number - * where the assert_param error has occurred. - * @param file: pointer to the source file name - * @param line: assert_param error line source number - * @retval None - */ -void assert_failed(uint8_t* file, uint32_t line) -{ - /* USER CODE BEGIN 6 */ - /* User can add his own implementation to report the file name and line number, - ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ - /* USER CODE END 6 */ + while (1) { ; } } -#endif - /** * @} */ @@ -35,31 +35,37 @@ #ifndef __STM_INIT_H #define __STM_INIT_H -#include "cmsis_os.h" #include "stm32f4xx_hal.h" -/* Macros used to make GPIO pin setup (in stm-init.c) easier */ -#define gpio_output(output_port, output_pins, output_level) \ - /* Configure GPIO pin Output Level */ \ - HAL_GPIO_WritePin(output_port, output_pins, output_level); \ - /* Configure pin as output */ \ - GPIO_InitStruct.Pin = output_pins; \ - GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; \ - GPIO_InitStruct.Pull = GPIO_NOPULL; \ - GPIO_InitStruct.Speed = GPIO_SPEED_LOW; \ - HAL_GPIO_Init(output_port, &GPIO_InitStruct) +/* Functions used to make GPIO pin setup (in stm-init.c) easier */ -#define gpio_input(input_port, input_pin, input_pull) \ - GPIO_InitStruct.Pin = input_pin; \ - GPIO_InitStruct.Mode = GPIO_MODE_INPUT; \ - GPIO_InitStruct.Pull = input_pull; \ - GPIO_InitStruct.Speed = GPIO_SPEED_LOW; \ - HAL_GPIO_Init(input_port, &GPIO_InitStruct) +static inline void gpio_output(GPIO_TypeDef* output_port, uint16_t output_pins, GPIO_PinState output_level) +{ + GPIO_InitTypeDef GPIO_InitStruct; + /* Configure GPIO pin Output Level */ + HAL_GPIO_WritePin(output_port, output_pins, output_level); + + /* Configure pin as output */ + GPIO_InitStruct.Pin = output_pins; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_LOW; + HAL_GPIO_Init(output_port, &GPIO_InitStruct); +} + +static inline void gpio_input(GPIO_TypeDef* input_port, uint16_t input_pin, GPIO_PinState input_pull) +{ + GPIO_InitTypeDef GPIO_InitStruct; + + GPIO_InitStruct.Pin = input_pin; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = input_pull; + GPIO_InitStruct.Speed = GPIO_SPEED_LOW; + HAL_GPIO_Init(input_port, &GPIO_InitStruct); +} extern void stm_init(void); extern void Error_Handler(void); -#define HAL_Delay osDelay - #endif /* __STM_INIT_H */ diff --git a/stm-keystore.c b/stm-keystore.c index 74826d0..7683f40 100644 --- a/stm-keystore.c +++ b/stm-keystore.c @@ -3,7 +3,7 @@ * ---------- * Functions for accessing the keystore memory. * - * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * Copyright (c) 2016-2017, NORDUnet A/S All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -32,46 +32,62 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "stm32f4xx_hal.h" -#include "stm-keystore.h" #include "stm-init.h" +#include "stm-keystore.h" -SPI_HandleTypeDef hspi_keystore; +static SPI_HandleTypeDef hspi_keystore; struct spiflash_ctx keystore_ctx = {&hspi_keystore, KSM_PROM_CS_N_GPIO_Port, KSM_PROM_CS_N_Pin}; -int keystore_check_id() +/* SPI1 (keystore memory) init function */ +void keystore_init(void) +{ + /* Set up GPIOs for the keystore memory. + * KEYSTORE_GPIO_INIT is defined in stm-keystore.h. + */ + KEYSTORE_GPIO_INIT(); + + hspi_keystore.Instance = SPI1; + hspi_keystore.Init.Mode = SPI_MODE_MASTER; + hspi_keystore.Init.Direction = SPI_DIRECTION_2LINES; + hspi_keystore.Init.DataSize = SPI_DATASIZE_8BIT; + hspi_keystore.Init.CLKPolarity = SPI_POLARITY_LOW; + hspi_keystore.Init.CLKPhase = SPI_PHASE_1EDGE; + hspi_keystore.Init.NSS = SPI_NSS_SOFT; + hspi_keystore.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2; + hspi_keystore.Init.FirstBit = SPI_FIRSTBIT_MSB; + hspi_keystore.Init.TIMode = SPI_TIMODE_DISABLE; + hspi_keystore.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; + hspi_keystore.Init.CRCPolynomial = 10; + HAL_SPI_Init(&hspi_keystore); +} + +HAL_StatusTypeDef keystore_check_id(void) { return n25q128_check_id(&keystore_ctx); } -int keystore_read_data(uint32_t offset, uint8_t *buf, const uint32_t len) +HAL_StatusTypeDef keystore_read_data(uint32_t offset, uint8_t *buf, const uint32_t len) { return n25q128_read_data(&keystore_ctx, offset, buf, len); } -int keystore_write_data(uint32_t offset, const uint8_t *buf, const uint32_t len) +HAL_StatusTypeDef keystore_write_data(uint32_t offset, const uint8_t *buf, const uint32_t len) { return n25q128_write_data(&keystore_ctx, offset, buf, len); } -int keystore_erase_sectors(int num) +HAL_StatusTypeDef keystore_erase_subsector(uint32_t subsector_offset) { - if (num > N25Q128_NUM_SECTORS || num < 0) num = N25Q128_NUM_SECTORS; - while (num) { - int timeout = 200; /* times 10ms = 2 seconds timeout */ - while (timeout--) { - int i = n25q128_get_wip_flag(&keystore_ctx); - if (i < 0) return 0; - if (! i) break; - HAL_Delay(10); - } - if (! timeout) return 0; + return n25q128_erase_subsector(&keystore_ctx, subsector_offset); +} - if (! n25q128_erase_sector(&keystore_ctx, num - 1)) { - return -1; - } - num--; - } - return 1; +HAL_StatusTypeDef keystore_erase_sector(uint32_t sector_offset) +{ + return n25q128_erase_sector(&keystore_ctx, sector_offset); +} + +HAL_StatusTypeDef keystore_erase_bulk(void) +{ + return n25q128_erase_bulk(&keystore_ctx); } diff --git a/stm-keystore.h b/stm-keystore.h index 2c493d2..9aa740c 100644 --- a/stm-keystore.h +++ b/stm-keystore.h @@ -3,7 +3,7 @@ * --------- * Functions and defines for accessing the keystore memory. * - * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * Copyright (c) 2016-2017, NORDUnet A/S All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -39,7 +39,11 @@ #include "spiflash_n25q128.h" #define KEYSTORE_PAGE_SIZE N25Q128_PAGE_SIZE +#define KEYSTORE_NUM_PAGES N25Q128_NUM_PAGES #define KEYSTORE_SECTOR_SIZE N25Q128_SECTOR_SIZE +#define KEYSTORE_NUM_SECTORS N25Q128_NUM_SECTORS +#define KEYSTORE_SUBSECTOR_SIZE N25Q128_SUBSECTOR_SIZE +#define KEYSTORE_NUM_SUBSECTORS N25Q128_NUM_SUBSECTORS /* Pins connected to the FPGA config memory (SPI flash) */ #define KSM_PROM_CS_N_Pin GPIO_PIN_0 @@ -51,11 +55,12 @@ gpio_output(KSM_PROM_CS_N_GPIO_Port, KSM_PROM_CS_N_Pin, GPIO_PIN_SET) -extern SPI_HandleTypeDef hspi_keystore; - -extern int keystore_check_id(void); -extern int keystore_read_data(uint32_t offset, uint8_t *buf, const uint32_t len); -extern int keystore_write_data(uint32_t offset, const uint8_t *buf, const uint32_t len); -extern int keystore_erase_sectors(int num); +extern void keystore_init(void); +extern HAL_StatusTypeDef keystore_check_id(void); +extern HAL_StatusTypeDef keystore_read_data(uint32_t offset, uint8_t *buf, const uint32_t len); +extern HAL_StatusTypeDef keystore_write_data(uint32_t offset, const uint8_t *buf, const uint32_t len); +extern HAL_StatusTypeDef keystore_erase_subsector(uint32_t subsector_offset); +extern HAL_StatusTypeDef keystore_erase_sector(uint32_t sector_offset); +extern HAL_StatusTypeDef keystore_erase_bulk(void); #endif /* __STM32_KEYSTORE_H */ @@ -32,17 +32,35 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "stm32f4xx_hal.h" +#include "stm-init.h" #include "stm-rtc.h" I2C_HandleTypeDef hi2c_rtc; +/* I2C2 init function (external RTC chip) */ +void rtc_init(void) +{ + hi2c_rtc.Instance = I2C2; + hi2c_rtc.Init.ClockSpeed = 10000; + hi2c_rtc.Init.DutyCycle = I2C_DUTYCYCLE_2; + hi2c_rtc.Init.OwnAddress1 = 0; /* Will operate as Master */ + hi2c_rtc.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; + hi2c_rtc.Init.DualAddressMode = I2C_DUALADDRESS_DISABLED; + hi2c_rtc.Init.OwnAddress2 = 0; + hi2c_rtc.Init.GeneralCallMode = I2C_GENERALCALL_DISABLED; + hi2c_rtc.Init.NoStretchMode = I2C_NOSTRETCH_DISABLED; + + if (HAL_I2C_Init(&hi2c_rtc) != HAL_OK) { + Error_Handler(); + } +} + HAL_StatusTypeDef rtc_device_ready(uint16_t i2c_addr) { return HAL_I2C_IsDeviceReady (&hi2c_rtc, i2c_addr, 10, 1000); } -HAL_StatusTypeDef rtc_enable_oscillator() +HAL_StatusTypeDef rtc_enable_oscillator(void) { uint8_t buf[2]; HAL_StatusTypeDef res; @@ -78,7 +96,7 @@ HAL_StatusTypeDef rtc_read_bytes (const uint16_t i2c_addr, uint8_t *buf, const u { HAL_StatusTypeDef res; - while (HAL_I2C_Master_Receive (&hi2c_rtc, i2c_addr, buf, len, 1000) != HAL_OK) { + while (HAL_I2C_Master_Receive (&hi2c_rtc, i2c_addr, buf, len, timeout) != HAL_OK) { res = HAL_I2C_GetError (&hi2c_rtc); if (res != HAL_I2C_ERROR_AF) { return res; @@ -37,8 +37,7 @@ #include "stm32f4xx_hal.h" -extern I2C_HandleTypeDef hi2c_rtc; - +extern void rtc_init(void); extern HAL_StatusTypeDef rtc_device_ready(uint16_t i2c_addr); extern HAL_StatusTypeDef rtc_enable_oscillator(); extern HAL_StatusTypeDef rtc_send_byte(const uint16_t i2c_addr, const uint8_t value, const uint16_t timeout); diff --git a/stm-sdram.c b/stm-sdram.c index 0ec8065..3ad17f0 100644 --- a/stm-sdram.c +++ b/stm-sdram.c @@ -1,267 +1,216 @@ -/*
- * stm-sdram.c
- * -----------
- * Functions concerning the 2x512 Mbit SDRAM working memory.
- *
- * Copyright (c) 2016, NORDUnet A/S All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * - Neither the name of the NORDUnet nor the names of its contributors may
- * be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#include "stm32f4xx_hal.h"
-#include "stm-init.h"
-#include "stm-sdram.h"
-#include "stm-fmc.h"
-#include "stm-led.h"
-
-SDRAM_HandleTypeDef hsdram1;
-SDRAM_HandleTypeDef hsdram2;
-
-void _sdram_init_gpio(void);
-HAL_StatusTypeDef _sdram_init_fmc(void);
-HAL_StatusTypeDef _sdram_init_params(SDRAM_HandleTypeDef *sdram1, SDRAM_HandleTypeDef *sdram2);
-
-
-HAL_StatusTypeDef sdram_init(void)
-{
- HAL_StatusTypeDef status;
- static int initialized = 0;
-
- if (initialized) {
- return;
- }
- initialized = 1;
-
- /* We rely on several things being set up by fmc_init() instead of duplicating all
- * that code here for independent FPGA/SDRAM FMC setup. This means the FPGA<->STM32
- * FMC bus can be used without the SDRAMs initialized, but the SDRAMs can't be
- * initialized withouth the FPGA<->STM32 FMC bus being set up too.
- */
- fmc_init();
-
- // configure FMC
- _sdram_init_gpio();
- status = _sdram_init_fmc();
- if (status != HAL_OK) return status;
-
- // configure SDRAM registers
- status = _sdram_init_params(&hsdram1, &hsdram2);
- if (status != HAL_OK) return status;
-
- return HAL_OK;
-}
-
-void _sdram_init_gpio(void)
-{
- GPIO_InitTypeDef GPIO_InitStruct;
-
- /* The bulk of the FMC GPIO pins are set up in fmc_init_gpio().
- * This function just needs to enable the additional ones used
- * with the SDRAMs.
- */
- fmc_af_gpio(GPIOB, GPIO_PIN_5 | GPIO_PIN_6);
- fmc_af_gpio(GPIOC, GPIO_PIN_0 | GPIO_PIN_2 | GPIO_PIN_3);
- fmc_af_gpio(GPIOE, GPIO_PIN_0 | GPIO_PIN_1);
- fmc_af_gpio(GPIOF, GPIO_PIN_11);
- fmc_af_gpio(GPIOG, GPIO_PIN_8 | GPIO_PIN_15);
- fmc_af_gpio(GPIOI, GPIO_PIN_4 | GPIO_PIN_5);
-}
-
-HAL_StatusTypeDef _sdram_init_fmc()
-{
- HAL_StatusTypeDef status;
- FMC_SDRAM_TimingTypeDef SdramTiming;
-
- /*
- * following settings are for -75E speed grade memory chip
- * clocked at only 90 MHz instead of the rated 133 MHz
- *
- * ExitSelfRefreshDelay: 67 ns @ 90 MHz is 6.03 cycles, so in theory
- * 6 can be used here, but let's be on the safe side
- *
- * WriteRecoveryTime: must be >= tRAS - tRCD (5 - 2 = 3 cycles),
- * and >= tRC - tRCD - tRP (8 - 2 - 2 = 4 cycles)
- */
- SdramTiming.LoadToActiveDelay = 2; // tMRD
- SdramTiming.ExitSelfRefreshDelay = 7; // (see above)
- SdramTiming.SelfRefreshTime = 5; // should be >= tRAS (5 cycles)
- SdramTiming.RowCycleDelay = 8; // tRC
- SdramTiming.WriteRecoveryTime = 4; // (see above)
- SdramTiming.RPDelay = 2; // tRP
- SdramTiming.RCDDelay = 2; // tRCD
-
- /*
- * configure the first bank
- */
-
- // memory type
- hsdram1.Instance = FMC_SDRAM_DEVICE;
-
- // bank
- hsdram1.Init.SDBank = FMC_SDRAM_BANK1;
-
- // settings for IS42S32160F
- hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_9;
- hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_13;
- hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_32;
- hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
- hsdram1.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_2;
-
- // write protection not needed
- hsdram1.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
-
- // memory clock is 90 MHz (HCLK / 2)
- hsdram1.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2;
-
- // read burst not needed
- hsdram1.Init.ReadBurst = FMC_SDRAM_RBURST_DISABLE;
-
- // additional pipeline stages not neeed
- hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0;
-
- // call HAL layer
- status = HAL_SDRAM_Init(&hsdram1, &SdramTiming);
- if (status != HAL_OK) return status;
-
- /*
- * configure the second bank
- */
-
- // memory type
- hsdram2.Instance = FMC_SDRAM_DEVICE;
-
- // bank number
- hsdram2.Init.SDBank = FMC_SDRAM_BANK2;
-
- // settings for IS42S32160F
- hsdram2.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_9;
- hsdram2.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_13;
- hsdram2.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_32;
- hsdram2.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
- hsdram2.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_2;
-
- // write protection not needed
- hsdram2.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
-
- // memory clock is 90 MHz (HCLK / 2)
- hsdram2.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2;
-
- // read burst not needed
- hsdram2.Init.ReadBurst = FMC_SDRAM_RBURST_DISABLE;
-
- // additional pipeline stages not neeed
- hsdram2.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0;
-
- // call HAL layer
- return HAL_SDRAM_Init(&hsdram2, &SdramTiming);
-}
-
-HAL_StatusTypeDef _sdram_init_params(SDRAM_HandleTypeDef *sdram1, SDRAM_HandleTypeDef *sdram2)
-{
- HAL_StatusTypeDef ok; // status
- FMC_SDRAM_CommandTypeDef cmd; // command
-
- /*
- * enable clocking
- */
- cmd.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
- cmd.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1_2;
- cmd.AutoRefreshNumber = 1;
- cmd.ModeRegisterDefinition = 0;
-
- HAL_Delay(1);
- ok = HAL_SDRAM_SendCommand(sdram1, &cmd, 1);
- if (ok != HAL_OK) return ok;
-
- /*
- * precharge all banks
- */
- cmd.CommandMode = FMC_SDRAM_CMD_PALL;
- cmd.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1_2;
- cmd.AutoRefreshNumber = 1;
- cmd.ModeRegisterDefinition = 0;
-
- HAL_Delay(1);
- ok = HAL_SDRAM_SendCommand(sdram1, &cmd, 1);
- if (ok != HAL_OK) return ok;
-
-
- /*
- * send two auto-refresh commands in a row
- */
- cmd.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
- cmd.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1_2;
- cmd.AutoRefreshNumber = 1;
- cmd.ModeRegisterDefinition = 0;
-
- ok = HAL_SDRAM_SendCommand(sdram1, &cmd, 1);
- if (ok != HAL_OK) return ok;
-
- ok = HAL_SDRAM_SendCommand(sdram1, &cmd, 1);
- if (ok != HAL_OK) return ok;
-
-
- /*
- * load mode register
- */
- cmd.CommandMode = FMC_SDRAM_CMD_LOAD_MODE;
- cmd.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1_2;
- cmd.AutoRefreshNumber = 1;
- cmd.ModeRegisterDefinition =
- SDRAM_MODEREG_BURST_LENGTH_1 |
- SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL |
- SDRAM_MODEREG_CAS_LATENCY_2 |
- SDRAM_MODEREG_OPERATING_MODE_STANDARD |
- SDRAM_MODEREG_WRITEBURST_MODE_SINGLE ;
-
- ok = HAL_SDRAM_SendCommand(sdram1, &cmd, 1);
- if (ok != HAL_OK) return ok;
-
-
- /*
- * set number of consequtive auto-refresh commands
- * and program refresh rate
- *
- * RefreshRate = 64 ms / 8192 cyc = 7.8125 us/cyc
- *
- * RefreshCycles = 7.8125 us * 90 MHz = 703
- *
- * According to the formula on p.1665 of the reference manual,
- * we also need to subtract 20 from the value, so the target
- * refresh rate is 703 - 20 = 683.
- */
-
- ok = HAL_SDRAM_SetAutoRefreshNumber(sdram1, 8);
- if (ok != HAL_OK) return ok;
-
- HAL_SDRAM_ProgramRefreshRate(sdram1, 683);
- if (ok != HAL_OK) return ok;
-
- /*
- * done
- */
- return HAL_OK;
-}
+/* + * stm-sdram.c + * ----------- + * Functions concerning the 2x512 Mbit SDRAM working memory. + * + * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "stm-init.h" +#include "stm-sdram.h" +#include "stm-fmc.h" +#include "stm-led.h" + +/* Mode Register Bits */ +#define SDRAM_MODEREG_BURST_LENGTH_1 ((uint16_t)0x0000) +#define SDRAM_MODEREG_BURST_LENGTH_2 ((uint16_t)0x0001) +#define SDRAM_MODEREG_BURST_LENGTH_4 ((uint16_t)0x0002) +#define SDRAM_MODEREG_BURST_LENGTH_8 ((uint16_t)0x0004) + +#define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL ((uint16_t)0x0000) +#define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED ((uint16_t)0x0008) + +#define SDRAM_MODEREG_CAS_LATENCY_2 ((uint16_t)0x0020) +#define SDRAM_MODEREG_CAS_LATENCY_3 ((uint16_t)0x0030) + +#define SDRAM_MODEREG_OPERATING_MODE_STANDARD ((uint16_t)0x0000) + +#define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000) +#define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE ((uint16_t)0x0200) + +static SDRAM_HandleTypeDef hsdram1; +static SDRAM_HandleTypeDef hsdram2; + +static void _sdram_init_gpio(void); +static void _sdram_init_fmc(void); +static void _sdram_init_params(void); + +void sdram_init(void) +{ + static int initialized = 0; + if (initialized) return; + initialized = 1; + + /* We rely on several things being set up by fmc_init() instead of duplicating all + * that code here for independent FPGA/SDRAM FMC setup. This means the FPGA<->STM32 + * FMC bus can be used without the SDRAMs initialized, but the SDRAMs can't be + * initialized withouth the FPGA<->STM32 FMC bus being set up too. + */ + fmc_init(); + + /* configure FMC */ + _sdram_init_gpio(); + _sdram_init_fmc(); + + /* configure SDRAM registers */ + _sdram_init_params(); +} + +static void _sdram_init_gpio(void) +{ + GPIO_InitTypeDef GPIO_InitStruct; + + /* The bulk of the FMC GPIO pins are set up in fmc_init_gpio(). + * This function just needs to enable the additional ones used + * with the SDRAMs. + */ + fmc_af_gpio(GPIOB, GPIO_PIN_5 | GPIO_PIN_6); + fmc_af_gpio(GPIOC, GPIO_PIN_0 | GPIO_PIN_2 | GPIO_PIN_3); + fmc_af_gpio(GPIOE, GPIO_PIN_0 | GPIO_PIN_1); + fmc_af_gpio(GPIOF, GPIO_PIN_11); + fmc_af_gpio(GPIOG, GPIO_PIN_8 | GPIO_PIN_15); + fmc_af_gpio(GPIOI, GPIO_PIN_4 | GPIO_PIN_5); +} + +static void _sdram_config_bank(SDRAM_HandleTypeDef *hsdram, uint32_t SDBank, FMC_SDRAM_TimingTypeDef *SdramTiming) +{ + /* memory type */ + hsdram->Instance = FMC_SDRAM_DEVICE; + + /* bank */ + hsdram->Init.SDBank = SDBank; + + /* settings for IS42S32160F */ + hsdram->Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_9; + hsdram->Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_13; + hsdram->Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_32; + hsdram->Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4; + hsdram->Init.CASLatency = FMC_SDRAM_CAS_LATENCY_2; + + /* write protection not needed */ + hsdram->Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE; + + /* memory clock is 90 MHz (HCLK / 2) */ + hsdram->Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2; + + /* read burst not needed */ + hsdram->Init.ReadBurst = FMC_SDRAM_RBURST_DISABLE; + + /* additional pipeline stages not neeed */ + hsdram->Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0; + + /* call HAL layer */ + HAL_SDRAM_Init(hsdram, SdramTiming); +} + +static void _sdram_init_fmc(void) +{ + FMC_SDRAM_TimingTypeDef SdramTiming; + + /* + * following settings are for -75E speed grade memory chip + * clocked at only 90 MHz instead of the rated 133 MHz + * + * ExitSelfRefreshDelay: 67 ns @ 90 MHz is 6.03 cycles, so in theory + * 6 can be used here, but let's be on the safe side + * + * WriteRecoveryTime: must be >= tRAS - tRCD (5 - 2 = 3 cycles), + * and >= tRC - tRCD - tRP (8 - 2 - 2 = 4 cycles) + */ + SdramTiming.LoadToActiveDelay = 2; // tMRD + SdramTiming.ExitSelfRefreshDelay = 7; // (see above) + SdramTiming.SelfRefreshTime = 5; // should be >= tRAS (5 cycles) + SdramTiming.RowCycleDelay = 8; // tRC + SdramTiming.WriteRecoveryTime = 4; // (see above) + SdramTiming.RPDelay = 2; // tRP + SdramTiming.RCDDelay = 2; // tRCD + + /* configure the first bank */ + _sdram_config_bank(&hsdram1, FMC_SDRAM_BANK1, &SdramTiming); + + /* configure the second bank */ + _sdram_config_bank(&hsdram2, FMC_SDRAM_BANK2, &SdramTiming); +} + +static void _sdram_init_params(void) +{ + FMC_SDRAM_CommandTypeDef cmd; + + /* enable clocking */ + cmd.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE; + cmd.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1_2; + cmd.AutoRefreshNumber = 1; + cmd.ModeRegisterDefinition = 0; + HAL_Delay(1); + HAL_SDRAM_SendCommand(&hsdram1, &cmd, 1); + + /* precharge all banks */ + cmd.CommandMode = FMC_SDRAM_CMD_PALL; + cmd.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1_2; + cmd.AutoRefreshNumber = 1; + cmd.ModeRegisterDefinition = 0; + HAL_Delay(1); + HAL_SDRAM_SendCommand(&hsdram1, &cmd, 1); + + /* send two auto-refresh commands in a row */ + cmd.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE; + cmd.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1_2; + cmd.AutoRefreshNumber = 1; + cmd.ModeRegisterDefinition = 0; + HAL_SDRAM_SendCommand(&hsdram1, &cmd, 1); + HAL_SDRAM_SendCommand(&hsdram1, &cmd, 1); + + /* load mode register */ + cmd.CommandMode = FMC_SDRAM_CMD_LOAD_MODE; + cmd.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1_2; + cmd.AutoRefreshNumber = 1; + cmd.ModeRegisterDefinition = + SDRAM_MODEREG_BURST_LENGTH_1 | + SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL | + SDRAM_MODEREG_CAS_LATENCY_2 | + SDRAM_MODEREG_OPERATING_MODE_STANDARD | + SDRAM_MODEREG_WRITEBURST_MODE_SINGLE ; + HAL_SDRAM_SendCommand(&hsdram1, &cmd, 1); + + /* + * set number of consequtive auto-refresh commands + * and program refresh rate + * + * RefreshRate = 64 ms / 8192 cyc = 7.8125 us/cyc + * + * RefreshCycles = 7.8125 us * 90 MHz = 703 + * + * According to the formula on p.1665 of the reference manual, + * we also need to subtract 20 from the value, so the target + * refresh rate is 703 - 20 = 683. + */ + + HAL_SDRAM_SetAutoRefreshNumber(&hsdram1, 8); + + HAL_SDRAM_ProgramRefreshRate(&hsdram1, 683); +} diff --git a/stm-sdram.h b/stm-sdram.h index 8f58b34..88a7086 100644 --- a/stm-sdram.h +++ b/stm-sdram.h @@ -1,66 +1,46 @@ -/*
- * stm-sdram.h
- * -----------
- * Functions and defines concerning the 2x512 Mbit SDRAM working memory.
- *
- * Copyright (c) 2016, NORDUnet A/S All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * - Neither the name of the NORDUnet nor the names of its contributors may
- * be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
- * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#ifndef __STM32_SDRAM_H
-#define __STM32_SDRAM_H
-
-/* Base Addresses */
-#define SDRAM_BASEADDR_CHIP1 ((uint32_t *)0xC0000000)
-#define SDRAM_BASEADDR_CHIP2 ((uint32_t *)0xD0000000)
-
-/* Memory Size, 64 MBytes (512 Mbits) */
-#define SDRAM_SIZE 0x4000000
-
-/* Mode Register Bits */
-#define SDRAM_MODEREG_BURST_LENGTH_1 ((uint16_t)0x0000)
-#define SDRAM_MODEREG_BURST_LENGTH_2 ((uint16_t)0x0001)
-#define SDRAM_MODEREG_BURST_LENGTH_4 ((uint16_t)0x0002)
-#define SDRAM_MODEREG_BURST_LENGTH_8 ((uint16_t)0x0004)
-
-#define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL ((uint16_t)0x0000)
-#define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED ((uint16_t)0x0008)
-
-#define SDRAM_MODEREG_CAS_LATENCY_2 ((uint16_t)0x0020)
-#define SDRAM_MODEREG_CAS_LATENCY_3 ((uint16_t)0x0030)
-
-#define SDRAM_MODEREG_OPERATING_MODE_STANDARD ((uint16_t)0x0000)
-
-#define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000)
-#define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE ((uint16_t)0x0200)
-
-extern SDRAM_HandleTypeDef hsdram1;
-extern SDRAM_HandleTypeDef hsdram2;
-
-extern HAL_StatusTypeDef sdram_init(void);
-
-#endif
+/* + * stm-sdram.h + * ----------- + * Functions and defines concerning the 2x512 Mbit SDRAM working memory. + * + * Copyright (c) 2016, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __STM32_SDRAM_H +#define __STM32_SDRAM_H + +/* Base Addresses */ +#define SDRAM_BASEADDR_CHIP1 ((uint32_t *)0xC0000000) +#define SDRAM_BASEADDR_CHIP2 ((uint32_t *)0xD0000000) + +/* Memory Size, 64 MBytes (512 Mbits) */ +#define SDRAM_SIZE 0x4000000 + +extern void sdram_init(void); + +#endif @@ -4,6 +4,8 @@ * Functions for sending strings and numbers over the uart. * * Copyright (c) 2015, NORDUnet A/S All rights reserved. + * Copyright: 2020, The Commons Conservancy Cryptech Project + * SPDX-License-Identifier: BSD-3-Clause * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -15,9 +17,9 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * - Neither the name of the NORDUnet nor the names of its contributors may - * be used to endorse or promote products derived from this software - * without specific prior written permission. + * - Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED @@ -32,7 +34,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "stm32f4xx_hal.h" +#include "stm-init.h" #include "stm-uart.h" #include <string.h> @@ -43,96 +45,127 @@ UART_HandleTypeDef huart_user; /* USART2 */ DMA_HandleTypeDef hdma_usart_mgmt_rx; DMA_HandleTypeDef hdma_usart_user_rx; -#define DEFAULT_UART STM_UART_USER +UART_HandleTypeDef* default_uart = STM_UART_MGMT; - -inline UART_HandleTypeDef *_which_uart(stm_uart_port_t port) +#ifdef HAL_DMA_MODULE_ENABLED +/** + * Enable DMA controller clock + */ +static void MX_DMA_Init(void) { - if (port == STM_UART_USER) { - return &huart_user; - } else if (port == STM_UART_MGMT) { - return &huart_mgmt; - } - - return NULL; + /* DMA controller clock enable */ + __HAL_RCC_DMA2_CLK_ENABLE(); + __HAL_RCC_DMA1_CLK_ENABLE(); + + /* DMA interrupt init */ + + /* USER UART RX */ + HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn); + /* MGMT UART RX */ + HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn); } +#endif /* HAL_DMA_MODULE_ENABLED */ -/* send a single character */ -HAL_StatusTypeDef uart_send_char(uint8_t ch) +/* USART1 init function */ +static void MX_USART1_UART_Init(void) { - return uart_send_char2(DEFAULT_UART, ch); + huart_mgmt.Instance = USART1; + huart_mgmt.Init.BaudRate = USART_MGMT_BAUD_RATE; + huart_mgmt.Init.WordLength = UART_WORDLENGTH_8B; + huart_mgmt.Init.StopBits = UART_STOPBITS_1; + huart_mgmt.Init.Parity = UART_PARITY_NONE; + huart_mgmt.Init.Mode = UART_MODE_TX_RX; + huart_mgmt.Init.HwFlowCtl = UART_HWCONTROL_RTS_CTS; + huart_mgmt.Init.OverSampling = UART_OVERSAMPLING_16; + +#ifdef HAL_DMA_MODULE_ENABLED + __HAL_LINKDMA(&huart_mgmt, hdmarx, hdma_usart_mgmt_rx); +#endif + + if (HAL_UART_Init(&huart_mgmt) != HAL_OK) { + /* Initialization Error */ + Error_Handler(); + } } - -HAL_StatusTypeDef uart_send_char2(stm_uart_port_t port, uint8_t ch) +/* USART2 init function */ +static void MX_USART2_UART_Init(void) { - return uart_send_bytes(port, &ch, 1); + huart_user.Instance = USART2; + huart_user.Init.BaudRate = USART_USER_BAUD_RATE; + huart_user.Init.WordLength = UART_WORDLENGTH_8B; + huart_user.Init.StopBits = UART_STOPBITS_1; + huart_user.Init.Parity = UART_PARITY_NONE; + huart_user.Init.Mode = UART_MODE_TX_RX; + huart_user.Init.HwFlowCtl = UART_HWCONTROL_RTS_CTS; + huart_user.Init.OverSampling = UART_OVERSAMPLING_16; + +#ifdef HAL_DMA_MODULE_ENABLED + __HAL_LINKDMA(&huart_user, hdmarx, hdma_usart_user_rx); +#endif + + if (HAL_UART_Init(&huart_user) != HAL_OK) { + /* Initialization Error */ + Error_Handler(); + } } -/* receive a single character */ -HAL_StatusTypeDef uart_recv_char(uint8_t *cp) +void uart_init(void) { - return uart_recv_char2(DEFAULT_UART, cp, HAL_MAX_DELAY); +#ifdef HAL_DMA_MODULE_ENABLED + MX_DMA_Init(); +#endif + MX_USART1_UART_Init(); + MX_USART2_UART_Init(); } -/* receive a single character */ -HAL_StatusTypeDef uart_recv_char2(stm_uart_port_t port, uint8_t *cp, uint32_t timeout) +void uart_set_default(UART_HandleTypeDef *uart) { - UART_HandleTypeDef *uart = _which_uart(port); - - if (uart) - return HAL_UART_Receive(uart, cp, 1, timeout); + default_uart = uart; +} - return HAL_ERROR; +/* send a single character */ +HAL_StatusTypeDef uart_send_char2(UART_HandleTypeDef *uart, uint8_t ch) +{ + return uart_send_bytes2(uart, &ch, 1); } -/* send a string */ -HAL_StatusTypeDef uart_send_string(char *s) +/* receive a single character */ +HAL_StatusTypeDef uart_recv_char2(UART_HandleTypeDef *uart, uint8_t *cp, uint32_t timeout) { - return uart_send_string2(DEFAULT_UART, s); + return HAL_UART_Receive(uart, cp, 1, timeout); } /* send a string */ -HAL_StatusTypeDef uart_send_string2(stm_uart_port_t port, const char *s) +HAL_StatusTypeDef uart_send_string2(UART_HandleTypeDef *uart, const char *s) { - return uart_send_bytes(port, (uint8_t *) s, strlen(s)); + return uart_send_bytes2(uart, (uint8_t *) s, strlen(s)); } /* send raw bytes */ -HAL_StatusTypeDef uart_send_bytes(stm_uart_port_t port, uint8_t *buf, size_t len) +HAL_StatusTypeDef uart_send_bytes2(UART_HandleTypeDef *uart, uint8_t *buf, size_t len) { - uint32_t timeout = 100; - UART_HandleTypeDef *uart = _which_uart(port); - - if (uart) { - while (HAL_UART_GetState(uart) != HAL_UART_STATE_READY && timeout--) { ; } - if (! timeout) return HAL_ERROR; - - return HAL_UART_Transmit(uart, (uint8_t *) buf, (uint32_t) len, 0x1); + for (int timeout = 0; timeout < 100; ++timeout) { + HAL_UART_StateTypeDef status = HAL_UART_GetState(uart); + if (status == HAL_UART_STATE_READY || + status == HAL_UART_STATE_BUSY_RX) + return HAL_UART_Transmit(uart, (uint8_t *) buf, (uint32_t) len, 0x1); } - return HAL_ERROR; + return HAL_TIMEOUT; } /* receive raw bytes */ -HAL_StatusTypeDef uart_receive_bytes(stm_uart_port_t port, uint8_t *buf, size_t len, uint32_t timeout) +HAL_StatusTypeDef uart_receive_bytes2(UART_HandleTypeDef *uart, uint8_t *buf, size_t len, uint32_t timeout) { - UART_HandleTypeDef *uart = _which_uart(port); - - if (uart) - return HAL_UART_Receive(uart, (uint8_t *) buf, (uint32_t) len, timeout); - - return HAL_ERROR; + return HAL_UART_Receive(uart, (uint8_t *) buf, (uint32_t) len, timeout); } /* Generalized routine to send binary, decimal, and hex integers. * This code is adapted from Chris Giese's printf.c */ -HAL_StatusTypeDef uart_send_number(uint32_t num, uint8_t digits, uint8_t radix) -{ - return uart_send_number2(DEFAULT_UART, num, digits, radix); -} - -HAL_StatusTypeDef uart_send_number2(stm_uart_port_t port, uint32_t num, uint8_t digits, uint8_t radix) +HAL_StatusTypeDef uart_send_number2(UART_HandleTypeDef *uart, uint32_t num, uint8_t digits, uint8_t radix) { #define BUFSIZE 32 char buf[BUFSIZE]; @@ -160,29 +193,30 @@ HAL_StatusTypeDef uart_send_number2(stm_uart_port_t port, uint32_t num, uint8_t /* number is larger than the specified number of digits */ digits = buf + BUFSIZE - where; - return uart_send_bytes(port, (uint8_t *) where, digits); + return uart_send_bytes2(uart, (uint8_t *) where, digits); } -HAL_StatusTypeDef uart_send_hexdump(stm_uart_port_t port, const uint8_t *buf, - const uint8_t start_offset, const uint8_t end_offset) +HAL_StatusTypeDef uart_send_hexdump2(UART_HandleTypeDef *uart, const uint8_t *buf, + const uint8_t start_offset, const uint8_t end_offset) { uint32_t i; - uart_send_string2(port, "00 -- "); + uart_send_number2(uart, start_offset, 2, 16); + uart_send_string2(uart, " -- "); - for (i = 0; i <= end_offset; i++) { + for (i = start_offset; i <= end_offset; i++) { if (i && (! (i % 16))) { - uart_send_string2(port, "\r\n"); + uart_send_string2(uart, "\r\n"); if (i != end_offset) { /* Output new offset unless the last byte is reached */ - uart_send_number2(port, i, 2, 16); - uart_send_string2(port, " -- "); + uart_send_number2(uart, i, 2, 16); + uart_send_string2(uart, " -- "); } } - uart_send_number2(port, *(buf + i), 2, 16); - uart_send_string2(port, " "); + uart_send_number2(uart, *(buf + i), 2, 16); + uart_send_string2(uart, " "); } return HAL_OK; @@ -37,37 +37,48 @@ #include "stm32f4xx_hal.h" -#define USART_MGMT_BAUD_RATE 921600 -#define USART_USER_BAUD_RATE 921600 - -typedef enum { - STM_UART_USER, - STM_UART_MGMT -} stm_uart_port_t; +#define USART_MGMT_BAUD_RATE 921600 +#define USART_USER_BAUD_RATE 921600 extern UART_HandleTypeDef huart_mgmt; extern UART_HandleTypeDef huart_user; +#define STM_UART_USER &huart_user +#define STM_UART_MGMT &huart_mgmt + +/* These are only exposed because they're used in the DMA IRQ handler code. + * Pretend you never saw them. + */ extern DMA_HandleTypeDef hdma_usart_mgmt_rx; extern DMA_HandleTypeDef hdma_usart_user_rx; -extern HAL_StatusTypeDef uart_send_char(uint8_t ch); -extern HAL_StatusTypeDef uart_recv_char(uint8_t *cp); - -extern HAL_StatusTypeDef uart_send_string(char *s); -extern HAL_StatusTypeDef uart_send_number(uint32_t num, uint8_t digits, uint8_t radix); +extern void uart_init(void); -extern HAL_StatusTypeDef uart_send_char2(stm_uart_port_t port, uint8_t ch); -extern HAL_StatusTypeDef uart_recv_char2(stm_uart_port_t port, uint8_t *cp, uint32_t timeout); - -extern HAL_StatusTypeDef uart_send_string2(stm_uart_port_t port, const char *s); -extern HAL_StatusTypeDef uart_send_number2(stm_uart_port_t port, uint32_t num, uint8_t digits, uint8_t radix); +/* Default UART is MGMT; don't change it unless you need to. + */ +extern UART_HandleTypeDef* default_uart; +extern void uart_set_default(UART_HandleTypeDef *uart); -extern HAL_StatusTypeDef uart_send_bytes(stm_uart_port_t port, uint8_t *buf, size_t len); -extern HAL_StatusTypeDef uart_receive_bytes(stm_uart_port_t port, uint8_t *buf, size_t len, uint32_t timeout); +/* Send and receive to/from an explicit UART. For the most part, you + * shouldn't need to call these directly, but can use the default_uart + * macros below. + */ +extern HAL_StatusTypeDef uart_send_char2(UART_HandleTypeDef *uart, uint8_t ch); +extern HAL_StatusTypeDef uart_recv_char2(UART_HandleTypeDef *uart, uint8_t *cp, uint32_t timeout); +extern HAL_StatusTypeDef uart_send_string2(UART_HandleTypeDef *uart, const char *s); +extern HAL_StatusTypeDef uart_send_number2(UART_HandleTypeDef *uart, uint32_t num, uint8_t digits, uint8_t radix); +extern HAL_StatusTypeDef uart_send_bytes2(UART_HandleTypeDef *uart, uint8_t *buf, size_t len); +extern HAL_StatusTypeDef uart_receive_bytes2(UART_HandleTypeDef *uart, uint8_t *buf, size_t len, uint32_t timeout); +extern HAL_StatusTypeDef uart_send_hexdump2(UART_HandleTypeDef *uart, const uint8_t *buf, + const uint8_t start_offset, const uint8_t end_offset); -extern HAL_StatusTypeDef uart_send_hexdump(stm_uart_port_t port, const uint8_t *buf, - const uint8_t start_offset, const uint8_t end_offset); +#define uart_send_char(c) uart_send_char2(default_uart, c) +#define uart_recv_char(cp, t) uart_recv_char2(default_uart, cp, t) +#define uart_send_string(s) uart_send_string2(default_uart, s) +#define uart_send_bytes(b, l) uart_send_bytes2(default_uart, b, l) +#define uart_receive_bytes(b, l, t) uart_receive_bytes2(default_uart, b, l, t) +#define uart_send_number(n, d, r) uart_send_number2(default_uart, n, d, r) +#define uart_send_hexdump(b, s, e) uart_send_hexdump2(default_uart, b, s, e) #define uart_send_binary(num, bits) uart_send_number(num, bits, 2) #define uart_send_integer(num, digits) uart_send_number(num, digits, 10) @@ -48,6 +48,7 @@ /***************************************************************************/ +#ifndef DO_PROFILING int _read_r (struct _reent *r, int file, char * ptr, int len) { r = r; @@ -101,8 +102,12 @@ int _write_r (struct _reent *r, int file, char * ptr, int len) int _close_r (struct _reent *r, int file) { + r = r; + file = file; + return 0; } +#endif /***************************************************************************/ @@ -115,6 +120,8 @@ caddr_t _sbrk_r (struct _reent *r, int incr) static char * heap_end; char * prev_heap_end; + r = r; + if (heap_end == NULL) heap_end = & end; @@ -143,6 +150,7 @@ caddr_t _sbrk_r (struct _reent *r, int incr) /***************************************************************************/ +#ifndef DO_PROFILING int _fstat_r (struct _reent *r, int file, struct stat * st) { r = r; @@ -181,6 +189,7 @@ int _kill (int a, int b) return 0; } +#endif /***************************************************************************/ @@ -193,6 +202,7 @@ int _getpid(int a) /***************************************************************************/ +#ifndef DO_PROFILING int _open(int a, int b) { a = a; @@ -200,5 +210,6 @@ int _open(int a, int b) return 0; } +#endif /*** EOF ***/ @@ -0,0 +1,450 @@ +/* + * task.c + * ---------------- + * Simple cooperative tasking system. + * + * Copyright (c) 2017, NORDUnet A/S All rights reserved. + * Copyright: 2020, The Commons Conservancy Cryptech Project + * SPDX-License-Identifier: BSD-3-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Dead-simple fully-cooperative tasker. There are no priorities; tasks + * are run in a strictly round-robin fashion. There is no preemption; + * tasks explicitly yield control. Tasks are created at system init time, + * and are expected to run an infinite loop; tasks do not return, nor are + * tasks deleted. + */ + +/* Ignore "deprecated" warnings in ARM-supplied CMSIS code: + * + * libraries/mbed/targets/cmsis/core_cm4.h:85:28: warning: listing the stack pointer register 'sp' in a clobber list is deprecated + * libraries/mbed/targets/cmsis/core_cm4.h:85:28: note: the value of the stack pointer after an 'asm' statement must be the same as it was before the statement + * + * This comes from our use of __set_MSP to set the stack pointer when + * switching tasks. If GCC ever decides to actually forbid this, then + * we'll have to figure out something else, possibly a native assembly + * function. + */ +#pragma GCC diagnostic ignored "-Wdeprecated" + +#include "stm-init.h" +#include "task.h" + +/* Task Control Block. The structure is private, in case we want to change + * it later without having to change the API. In any case, external code + * shouldn't poke its fingers in the internal details. + */ +struct task_cb { + struct task_cb *next; + task_state_t state; + + char *name; + funcp_t func; + void *cookie; + + void *stack_base; + size_t stack_len; + void *stack_ptr; +}; + +/* Number of tasks. Default is number of RPC dispatch tasks, plus CLI task. */ +#ifndef MAX_TASK +#ifdef NUM_RPC_TASK +#define MAX_TASK (NUM_RPC_TASK + 2) +#else +#define MAX_TASK 6 +#endif +#endif + +static tcb_t tcbs[MAX_TASK]; +static size_t num_task = 0; + +/* We have a circular list of tasks. New tasks are added at the tail, and + * tail->next is the head. + */ +static tcb_t *tail = NULL; + +/* Currently running task */ +static tcb_t *cur_task = NULL; + +#define STACK_GUARD_WORD 0x55AA5A5A + +#ifdef DO_TASK_METRICS +static uint32_t tick_start = 0; +static uint32_t tick_idle = 0; +static uint32_t tick_max = 0; +static uint32_t nyield = 0; +#endif + +static uint32_t tick_prev = 0; +#ifndef TASK_YIELD_THRESHOLD +#define TASK_YIELD_THRESHOLD 100 +#endif + +/* Add a task. + */ +tcb_t *task_add(char *name, funcp_t func, void *cookie, void *stack, size_t stack_len) +{ + if (num_task >= MAX_TASK) + return NULL; + + if (name == NULL || func == NULL || stack == NULL) + return NULL; + + tcb_t *t = &tcbs[num_task++]; + t->state = TASK_INIT; + + t->name = name; + t->func = func; + t->cookie = cookie; + + t->stack_base = stack; + t->stack_len = stack_len; + t->stack_ptr = stack + stack_len; + + for (uint32_t *p = (uint32_t *)t->stack_base; p < (uint32_t *)t->stack_ptr; ++p) + *p = STACK_GUARD_WORD; + + if (tail == NULL) { + /* Empty list; initialize it to this task. */ + t->next = t; + } + else { + /* Otherwise insert at the end of the list. */ + t->next = tail->next; + tail->next = t; + } + tail = t; + + return t; +} + +/* Reinitalize the current task. + * NOTE: This will destroy any state in the running task. + * DO NOT CALL THIS UNLESS YOU ARE REALLY SURE THAT'S WHAT YOU WANT TO DO. + */ +void task_mod(char *name, funcp_t func, void *cookie) +{ + tcb_t *t = cur_task; + t->name = name; + t->func = func; + t->cookie = cookie; + t->state = TASK_INIT; + t->stack_ptr = t->stack_base + t->stack_len; + for (uint32_t *p = (uint32_t *)t->stack_base; p < (uint32_t *)t->stack_ptr; ++p) + *p = STACK_GUARD_WORD; + __set_MSP((uint32_t)cur_task->stack_ptr); + task_yield(); +} + +/* Set the idle hook function pointer. + * + * This function is called repeatedly when the system is idle (there are + * no runnable tasks). + * + * The idle function should NOT call task_delay or HAL_Delay, because that + * will cause fatal recursion. We could add a recursion guard to + * task_yield, but we're not currently using the idle hook, and I'm + * thinking about removing it entirely. + */ +static void default_idle_hook(void) { } +static funcp_t idle_hook = default_idle_hook; +void task_set_idle_hook(funcp_t func) +{ + idle_hook = (func == NULL) ? default_idle_hook : func; +} + +/* Find the next runnable task. + */ +static tcb_t *next_task(void) +{ + tcb_t *t; + + /* If the tasker isn't running yet, return the first task. */ + if (cur_task == NULL) + return (tail == NULL) ? NULL : tail->next; + + // XXX critical section? + + /* find the next runnable task */ + for (t = cur_task->next; t != cur_task; t = t->next) { + if (t->state != TASK_WAITING) + return t; + } + + /* searched all the way back to cur_task - is it runnable? */ + return (cur_task->state == TASK_WAITING) ? NULL : cur_task; +} + +/* Check for stack overruns. + */ +static void check_stack(tcb_t *t) +{ + if (t->stack_ptr < t->stack_base || + t->stack_ptr >= t->stack_base + t->stack_len || + *(uint32_t *)t->stack_base != STACK_GUARD_WORD) + Error_Handler(); +} + +/* Yield control to the next runnable task. + */ +void task_yield(void) +{ + tcb_t *next; + + /* If there are no defined tasks, exit immediately so we don't get + * caught in the idle loop. + */ + if (tail == NULL) + return; + +#ifdef DO_TASK_METRICS + uint32_t tick0 = HAL_GetTick(); +#endif + + /* Find the next runnable task. Loop if every task is waiting. */ + while (1) { + next = next_task(); + if (next == NULL) + idle_hook(); + else + break; + } + + /* If we decide we don't need the idle hook, the preceding loop could + * devolve to something like this: + * + * do { + * next = next_task(); + * } while (next == NULL); + */ + +#ifdef DO_TASK_METRICS + uint32_t tick = HAL_GetTick(); + tick_idle += (tick - tick0); + if (tick_start == 0) + tick_start = tick; + if (tick_prev != 0) { + uint32_t duration = tick0 - tick_prev; + if (duration > tick_max) + tick_max = duration; + } + tick_prev = tick; + ++nyield; +#else + tick_prev = HAL_GetTick(); +#endif + + /* If there are no other runnable tasks (and cur_task is runnable), + * we don't need to context-switch. + */ + if (next == cur_task && cur_task->state != TASK_INIT) + return; + + /* Save current context, if there is one. */ + if (cur_task != NULL && cur_task->state != TASK_INIT) { + __asm("push {r0-r12, lr}"); + cur_task->stack_ptr = (void *)__get_MSP(); + + /* Check for stack overruns. */ + check_stack(cur_task); + } + + cur_task = next; + + /* If task is in init state, call its entry point. */ + if (cur_task->state == TASK_INIT) { + __set_MSP((uint32_t)cur_task->stack_ptr); + cur_task->state = TASK_READY; + cur_task->func(); + /*NOTREACHED*/ + } + + /* Otherwise, restore the task's context. */ + else { + __set_MSP((uint32_t)cur_task->stack_ptr); + __asm("pop {r0-r12, lr}"); + return; + } +} + +/* Yield if it's been "too long" since the last yield. + */ +void task_yield_maybe(void) +{ + if (HAL_GetTick() - tick_prev >= TASK_YIELD_THRESHOLD) + task_yield(); +} + +/* Put the current task to sleep (make it non-runnable). + */ +void task_sleep(void) +{ + if (cur_task != NULL) + cur_task->state = TASK_WAITING; + + task_yield(); +} + +/* Wake a task (make it runnable). + */ +void task_wake(tcb_t *t) +{ + if (t != NULL) + t->state = TASK_READY; +} + +/* Accessor functions */ + +tcb_t *task_get_tcb(void) +{ + return cur_task; +} + +char *task_get_name(tcb_t *t) +{ + if (t == NULL) + t = cur_task; + + return t->name; +} + +funcp_t task_get_func(tcb_t *t) +{ + if (t == NULL) + t = cur_task; + + return t->func; +} + +void *task_get_cookie(tcb_t *t) +{ + if (t == NULL) + t = cur_task; + + return t->cookie; +} + +task_state_t task_get_state(tcb_t *t) +{ + if (t == NULL) + t = cur_task; + + return t->state; +} + +void *task_get_stack(tcb_t *t) +{ + if (t == NULL) + t = cur_task; + + return t->stack_ptr; +} + +/* stupid linear search for first non guard word */ +size_t task_get_stack_highwater(tcb_t *t) +{ + if (t == NULL) + t = cur_task; + + const uint32_t * const b = (uint32_t *)t->stack_base; + + for (size_t i = 0; i < t->stack_len/4; ++i) { + if (b[i] != STACK_GUARD_WORD) { + return (t->stack_len - (i * 4)); + } + } + + return 0; +} + +/* Iterate through tasks. + * + * Returns the next task control block, or NULL at the end of the list. + */ +tcb_t *task_iterate(tcb_t *t) +{ + if (t == NULL) + return (tail == NULL) ? NULL : tail->next; + + if (t == tail) + return NULL; + + return t->next; +} + +/* Delay a number of 1ms ticks. + */ +void task_delay(uint32_t delay) +{ + uint32_t tickstart = HAL_GetTick(); + + while ((HAL_GetTick() - tickstart) < delay) + task_yield(); +} +void HAL_Delay(uint32_t delay) __attribute__((alias("task_delay"))); + +/* Simple mutex-like locks. A real mutex would require the unlocker to be + * the current owner, but then we have to define and return errors, when + * all we want at the moment is simple mutual exclusion. + */ +void task_mutex_lock(task_mutex_t *mutex) +{ + while (mutex->locked) + task_yield(); + mutex->locked = 1; +} + +void task_mutex_unlock(task_mutex_t *mutex) +{ + if (mutex != NULL) + mutex->locked = 0; +} + +#ifdef DO_TASK_METRICS +void task_get_metrics(struct task_metrics *tm) +{ + if (tm != NULL) { + tm->avg.tv_sec = 0; + tm->avg.tv_usec = (HAL_GetTick() - tick_start - tick_idle) * 1000 / nyield; + if (tm->avg.tv_usec > 1000000) { + tm->avg.tv_sec = tm->avg.tv_usec / 1000000; + tm->avg.tv_usec = tm->avg.tv_usec % 1000000; + } + tm->max.tv_sec = tick_max / 1000; + tm->max.tv_usec = (tick_max % 1000) * 1000; + } +} + +void task_reset_metrics(void) +{ + tick_start = HAL_GetTick(); + tick_prev = tick_idle = tick_max = nyield = 0; +} +#endif @@ -0,0 +1,89 @@ +/* + * task.c + * ---------------- + * Simple cooperative tasking system. + * + * Copyright (c) 2017, NORDUnet A/S All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of the NORDUnet nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _TASK_H_ +#define _TASK_H_ + +#include <sys/types.h> +#include <stdint.h> + +typedef enum task_state { + TASK_INIT, + TASK_WAITING, + TASK_READY +} task_state_t; + +typedef struct task_cb tcb_t; + +typedef struct { unsigned locked; } task_mutex_t; + +typedef void (*funcp_t)(void); + +extern tcb_t *task_add(char *name, funcp_t func, void *cookie, void *stack, size_t stack_len); +extern void task_mod(char *name, funcp_t func, void *cookie); + +extern void task_set_idle_hook(funcp_t func); + +extern void task_yield(void); +extern void task_yield_maybe(void); +extern void task_sleep(void); +extern void task_wake(tcb_t *t); + +extern tcb_t *task_get_tcb(void); +extern char *task_get_name(tcb_t *t); +extern funcp_t task_get_func(tcb_t *t); +extern void *task_get_cookie(tcb_t *t); +extern task_state_t task_get_state(tcb_t *t); +extern void *task_get_stack(tcb_t *t); +extern size_t task_get_stack_highwater(tcb_t *t); + +extern tcb_t *task_iterate(tcb_t *t); + +extern void task_delay(uint32_t delay); + +extern void task_mutex_lock(task_mutex_t *mutex); +extern void task_mutex_unlock(task_mutex_t *mutex); + +#ifdef DO_TASK_METRICS +#include <sys/time.h> + +struct task_metrics { + struct timeval avg, max; +}; + +void task_get_metrics(struct task_metrics *tm); +void task_reset_metrics(void); +#endif + +#endif /* _TASK_H_ */ |