├── LICENSE ├── Makefile ├── README.md ├── build ├── .gitignore ├── boards │ ├── B-L072Z-LRWAN1 │ │ └── Makefile │ ├── NUCLEO-L053R8 │ │ └── Makefile │ ├── NUCLEO-L073RZ │ │ └── Makefile │ ├── main.mk │ └── simul-unicorn │ │ └── Makefile └── makefiles │ ├── arm.mk │ ├── stm32lx.mk │ ├── toolchain.mk │ └── unicorn.mk ├── doc ├── img │ ├── fw-done.svg │ ├── fw-init.svg │ ├── fw-lz4-1.svg │ ├── fw-lz4-2.svg │ ├── fw-lz4-3.svg │ ├── fw-lz4-dict-1.svg │ ├── fw-lz4-dict-2.svg │ ├── fw-lz4-dict-3.svg │ ├── fw-lz4-dict-4.svg │ ├── fw-lz4-dict-5.svg │ ├── fw-lz4-dict-inplace-1.svg │ ├── fw-lz4-dict-inplace-2.svg │ ├── fw-lz4-dict-inplace-3.svg │ ├── fw-plain-1.svg │ ├── fw-plain-2.svg │ ├── fw-plain-3.svg │ └── illustrations.odg └── uptypes.md ├── example ├── .gitignore └── stm32l0 │ ├── .gitignore │ ├── Makefile │ ├── fw.ld │ └── hello.c ├── src ├── arm │ ├── CMSIS │ │ ├── Device │ │ │ └── ST │ │ │ │ ├── STM32L0xx │ │ │ │ └── Include │ │ │ │ │ ├── stm32l051xx.h │ │ │ │ │ ├── stm32l052xx.h │ │ │ │ │ ├── stm32l053xx.h │ │ │ │ │ ├── stm32l061xx.h │ │ │ │ │ ├── stm32l062xx.h │ │ │ │ │ ├── stm32l063xx.h │ │ │ │ │ ├── stm32l071xx.h │ │ │ │ │ ├── stm32l072xx.h │ │ │ │ │ ├── stm32l073xx.h │ │ │ │ │ ├── stm32l081xx.h │ │ │ │ │ ├── stm32l082xx.h │ │ │ │ │ ├── stm32l083xx.h │ │ │ │ │ ├── stm32l0xx.h │ │ │ │ │ └── system_stm32l0xx.h │ │ │ │ └── STM32L1xx │ │ │ │ └── Include │ │ │ │ ├── stm32l1xx.h │ │ │ │ └── system_stm32l1xx.h │ │ └── Include │ │ │ ├── arm_common_tables.h │ │ │ ├── arm_const_structs.h │ │ │ ├── arm_math.h │ │ │ ├── core_cm0.h │ │ │ ├── core_cm0plus.h │ │ │ ├── core_cm3.h │ │ │ ├── core_cm4.h │ │ │ ├── core_cm7.h │ │ │ ├── core_cmFunc.h │ │ │ ├── core_cmInstr.h │ │ │ ├── core_cmSimd.h │ │ │ ├── core_sc000.h │ │ │ └── core_sc300.h │ ├── stm32lx │ │ ├── bootloader.c │ │ ├── bootloader_hw.h │ │ ├── bootloader_impl.h │ │ ├── boottab.h │ │ ├── ld │ │ │ ├── STM32L0.ld │ │ │ ├── STM32L0xx8.ld │ │ │ ├── STM32L0xxB.ld │ │ │ └── STM32L0xxZ.ld │ │ ├── startup.S │ │ └── util.S │ └── unicorn │ │ ├── bootloader.c │ │ ├── bootloader_impl.h │ │ ├── boottab.h │ │ └── ld │ │ ├── bootloader.ld │ │ └── mem.ld └── common │ ├── .gitignore │ ├── Makefile │ ├── bootloader.h │ ├── lz4.c │ ├── lz4.h │ ├── sha2.c │ ├── sha2.h │ ├── update.c │ └── update.h └── tools ├── fwtool ├── .gitignore ├── signtool.py └── zfwtool.py └── shavs ├── shabytetestvectors.zip └── shavs.py /LICENSE: -------------------------------------------------------------------------------- 1 | --- Revised 3-Clause BSD License --- 2 | Copyright (C) 2016-2019, SEMTECH (International) AG. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | * Neither the name of the copyright holder nor the names of its contributors 14 | may be used to endorse or promote products derived from this software 15 | without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL SEMTECH BE LIABLE FOR ANY DIRECT, INDIRECT, 21 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 25 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | BOARDDIRS=$(dir $(wildcard build/boards/*/Makefile)) 2 | 3 | default: 4 | 5 | %: 6 | for BOARDDIR in $(BOARDDIRS); do $(MAKE) -C $${BOARDDIR} $@; done 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Basic Loader 2 | 3 | Basic Loader is an update-capable bootloader that supports the unpacking and 4 | installing of new firmware on an end-device. 5 | 6 | Basic MAC uses this component to load its firmware, and to support firmware 7 | updates over-the-air (FUOTA). 8 | 9 | ## Building Basic Loader 10 | 11 | The reference hardware platform for Basic Loader is the B-L072Z-LRWAN1 STM32 12 | LoRa™ Discovery kit. 13 | 14 | ### Prerequisites 15 | It is recommended to use a recent Ubuntu distribution as build host with the 16 | `gcc-arm-embedded` package installed. 17 | 18 | To build the bootloaders for all supported platforms, simply run `make` in 19 | the toplevel directory. 20 | 21 | Alternatively, change into a specific target board's build directory and run 22 | `make` there: 23 | 24 | ``` 25 | cd build/boards/B-L072Z-LRWAN1 26 | make 27 | ``` 28 | 29 | The output of the build process is a file named `bootloader.hex` that can be 30 | loaded onto the B-L072Z-LRWAN1 development board. If there is no valid firmware 31 | installed, the LED LD2 will be flashing the corresponding error sequence 32 | (SYNC-2-2-1). 33 | 34 | ## Release Notes 35 | 36 | ### Release 4 37 | 16-Jan-2020 38 | 39 | - Support for LZ4 in-place delta updates 40 | - Bugfix: Flash writing routines 41 | - Improved readability of LED blink sequence 42 | - Option to blink LED during update process 43 | - Improved out-of-tree build support 44 | - Improved ZFW (firmware patching) tool 45 | 46 | ### Release 3 47 | 01-May-2019 48 | 49 | - Bootloader for STM32 makes SHA-256 function available to firmware 50 | - New ZFW-tool creates firmware archives with metadata 51 | - Changed linker scripts to work around a recent [regression in GNU 52 | ld](https://sourceware.org/bugzilla/show_bug.cgi?id=24289) 53 | - Bugfixes 54 | 55 | ### Pre-release 2 56 | 15-Jan-2019 57 | 58 | - Bootloader for STM32 makes Flash-write function available to firmware 59 | 60 | ### Pre-release 1 61 | 07-Jan-2019 62 | 63 | - Verifies and loads firmware 64 | - Tool for patching firmware image header 65 | - Support for plain updates 66 | -------------------------------------------------------------------------------- /build/.gitignore: -------------------------------------------------------------------------------- 1 | Makefile.local 2 | bootloader 3 | *.o 4 | *.d 5 | *.hex 6 | *.map 7 | -------------------------------------------------------------------------------- /build/boards/B-L072Z-LRWAN1/Makefile: -------------------------------------------------------------------------------- 1 | FLAVOR := stm32lx 2 | MCU := STM32L072Z 3 | 4 | include ../main.mk 5 | 6 | CDEFS += BOOT_LED_GPIO="GPIO('A',5,0)" 7 | CDEFS += UPDATE_LED_GPIO="GPIO('A',5,0)" 8 | -------------------------------------------------------------------------------- /build/boards/NUCLEO-L053R8/Makefile: -------------------------------------------------------------------------------- 1 | FLAVOR := stm32lx 2 | MCU := STM32L053R8 3 | 4 | include ../main.mk 5 | 6 | CDEFS += BOOT_LED_GPIO="GPIO('A',5,0)" 7 | -------------------------------------------------------------------------------- /build/boards/NUCLEO-L073RZ/Makefile: -------------------------------------------------------------------------------- 1 | FLAVOR := stm32lx 2 | MCU := STM32L073Z 3 | 4 | include ../main.mk 5 | 6 | CDEFS += BOOT_LED_GPIO="GPIO('A',5,0)" 7 | -------------------------------------------------------------------------------- /build/boards/main.mk: -------------------------------------------------------------------------------- 1 | TOPDIR ?= ../../.. 2 | MKDIR := $(TOPDIR)/build/makefiles 3 | SRCDIR := $(TOPDIR)/src 4 | 5 | -include Makefile.local 6 | -include $(MKDIR)/Makefile.local 7 | 8 | FLAVOR ?= $(error FLAVOR not set) 9 | 10 | default: 11 | 12 | include $(MKDIR)/$(FLAVOR).mk 13 | -------------------------------------------------------------------------------- /build/boards/simul-unicorn/Makefile: -------------------------------------------------------------------------------- 1 | FLAVOR := unicorn 2 | 3 | include ../main.mk 4 | -------------------------------------------------------------------------------- /build/makefiles/arm.mk: -------------------------------------------------------------------------------- 1 | TOOLCHAIN := gcc 2 | CROSS_COMPILE += arm-none-eabi- 3 | 4 | include $(MKDIR)/toolchain.mk 5 | 6 | CMSIS := $(SRCDIR)/arm/CMSIS 7 | 8 | CFLAGS += -fno-common -fno-builtin -fno-exceptions -ffunction-sections -fdata-sections -fomit-frame-pointer 9 | CFLAGS += -I$(CMSIS)/Include 10 | 11 | LDFLAGS += -nostartfiles 12 | -------------------------------------------------------------------------------- /build/makefiles/stm32lx.mk: -------------------------------------------------------------------------------- 1 | include $(MKDIR)/arm.mk 2 | 3 | VPATH += $(SRCDIR)/arm/stm32lx 4 | VPATH += $(SRCDIR)/common 5 | VPATH += $(SRCDIR)/common/micro-ecc 6 | 7 | SRCS += bootloader.c 8 | SRCS += util.S 9 | SRCS += startup.S 10 | 11 | SRCS += update.c 12 | SRCS += sha2.c 13 | SRCS += lz4.c 14 | 15 | 16 | STM32 := $(shell echo $(MCU) | sed 's/^STM32\(L[01]\)\([0-9][0-9]\)R\?\([8BZ]\)$$/ok t\/\1 v\/\2 s\/\3/') 17 | ifneq (ok,$(firstword $(STM32))) 18 | $(error Could not parse MCU: $(MCU)) 19 | endif 20 | STM32_T := $(notdir $(filter t/%,$(STM32))) 21 | STM32_V := $(notdir $(filter v/%,$(STM32))) 22 | STM32_S := $(notdir $(filter s/%,$(STM32))) 23 | 24 | 25 | DEFS += STM32$(STM32_T) 26 | DEFS += STM32$(STM32_T)$(STM32_V)xx 27 | 28 | DEFS += LZ4_PAGEBUFFER_SZ=128 29 | DEFS += UP_PAGEBUFFER_SZ=128 30 | 31 | FLAGS += -mcpu=cortex-m0plus 32 | FLAGS += -I$(SRCDIR)/common 33 | 34 | CFLAGS += -Wall 35 | CFLAGS += -Os 36 | CFLAGS += -I$(SRCDIR)/arm/CMSIS/Device/ST/STM32$(STM32_T)xx/Include 37 | 38 | LDFLAGS += -mcpu=cortex-m0plus 39 | LDFLAGS += -T$(SRCDIR)/arm/stm32lx/ld/STM32$(STM32_T)xx$(STM32_S).ld 40 | LDFLAGS += -T$(SRCDIR)/arm/stm32lx/ld/STM32$(STM32_T).ld 41 | 42 | OBJS = $(addsuffix .o,$(basename $(SRCS))) 43 | 44 | bootloader: $(OBJS) 45 | 46 | bootloader.hex: bootloader 47 | $(HEX) $< $@ 48 | 49 | default: bootloader.hex 50 | 51 | 52 | clean: 53 | rm -f *.o *.d *.map bootloader bootloader.hex bootloader.bin 54 | 55 | .PHONY: clean default 56 | 57 | 58 | MAKE_DEPS := $(MAKEFILE_LIST) # before we include all the *.d files 59 | 60 | -include $(OBJS:.o=.d) 61 | 62 | $(OBJS): $(MAKE_DEPS) 63 | -------------------------------------------------------------------------------- /build/makefiles/toolchain.mk: -------------------------------------------------------------------------------- 1 | ifeq ($(TOOLCHAIN),gcc) 2 | FLAGS += -MMD -MP 3 | FLAGS += -g 4 | CFLAGS += -std=gnu11 5 | LDFLAGS += -Wl,--gc-sections -Wl,-Map,$(basename $@).map 6 | CC := $(CROSS_COMPILE)gcc 7 | AS := $(CROSS_COMPILE)as 8 | LD := $(CROSS_COMPILE)gcc 9 | HEX := $(CROSS_COMPILE)objcopy -O ihex 10 | BIN := $(CROSS_COMPILE)objcopy -O binary 11 | endif 12 | 13 | CDEFS += $(DEFS) 14 | ASDEFS += $(DEFS) ASSEMBLY 15 | CFLAGS += $(addprefix -D,$(CDEFS)) 16 | ASFLAGS += $(addprefix -D,$(ASDEFS)) 17 | 18 | CFLAGS += $(FLAGS) 19 | ASFLAGS += $(FLAGS) 20 | -------------------------------------------------------------------------------- /build/makefiles/unicorn.mk: -------------------------------------------------------------------------------- 1 | include $(MKDIR)/arm.mk 2 | 3 | VPATH += $(SRCDIR)/arm/unicorn 4 | VPATH += $(SRCDIR)/common 5 | VPATH += $(SRCDIR)/common/micro-ecc 6 | 7 | SRCS += bootloader.c 8 | 9 | SRCS += update.c 10 | SRCS += sha2.c 11 | SRCS += lz4.c 12 | 13 | DEFS += UP_PAGEBUFFER_SZ=128 14 | 15 | FLAGS += -mcpu=cortex-m0plus 16 | FLAGS += -I$(SRCDIR)/common 17 | 18 | CFLAGS += -Wall 19 | CFLAGS += -Os 20 | 21 | LDFLAGS += -mcpu=cortex-m0plus 22 | LDFLAGS += -T$(SRCDIR)/arm/unicorn/ld/mem.ld 23 | LDFLAGS += -T$(SRCDIR)/arm/unicorn/ld/bootloader.ld 24 | 25 | OBJS = $(addsuffix .o,$(basename $(SRCS))) 26 | 27 | bootloader: $(OBJS) 28 | 29 | bootloader.hex: bootloader 30 | $(HEX) $< $@ 31 | 32 | default: bootloader.hex 33 | 34 | 35 | clean: 36 | rm -f *.o *.d *.map bootloader bootloader.hex bootloader.bin 37 | 38 | .PHONY: clean default 39 | 40 | 41 | MAKE_DEPS := $(MAKEFILE_LIST) # before we include all the *.d files 42 | 43 | -include $(OBJS:.o=.d) 44 | 45 | $(OBJS): $(MAKE_DEPS) 46 | -------------------------------------------------------------------------------- /doc/img/fw-done.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | BL 92 | 93 | 94 | 95 | BL 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | New firmware 120 | 121 | 122 | 123 | New firmware 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | -------------------------------------------------------------------------------- /doc/img/fw-init.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | BL 95 | 96 | 97 | 98 | BL 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | Current firmware 123 | 124 | 125 | 126 | Current firmware 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | -------------------------------------------------------------------------------- /doc/img/fw-lz4-1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | BL 103 | 104 | 105 | 106 | BL 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | Current firmware 131 | 132 | 133 | 134 | Current firmware 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | Update (lz4) 185 | 186 | 187 | 188 | Update (lz4) 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | -------------------------------------------------------------------------------- /doc/img/fw-lz4-3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | BL 101 | 102 | 103 | 104 | BL 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | New firmware 129 | 130 | 131 | 132 | New firmware 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | Update (lz4) 183 | 184 | 185 | 186 | Update (lz4) 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | -------------------------------------------------------------------------------- /doc/img/fw-lz4-dict-1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | BL 105 | 106 | 107 | 108 | BL 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | Current firmware 133 | 134 | 135 | 136 | Current firmware 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | Update (lz4-dict) 187 | 188 | 189 | 190 | Update (lz4-dict) 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | -------------------------------------------------------------------------------- /doc/img/fw-plain-1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | BL 101 | 102 | 103 | 104 | BL 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | Current firmware 129 | 130 | 131 | 132 | Current firmware 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | Update (plain) 183 | 184 | 185 | 186 | Update (plain) 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | -------------------------------------------------------------------------------- /doc/img/fw-plain-3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | BL 100 | 101 | 102 | 103 | BL 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | New firmware 128 | 129 | 130 | 131 | New firmware 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | Update (plain) 182 | 183 | 184 | 185 | Update (plain) 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | -------------------------------------------------------------------------------- /doc/img/illustrations.odg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lorabasics/basicloader/a1e6086dd9b106d9a563427bea9da14f614edb7e/doc/img/illustrations.odg -------------------------------------------------------------------------------- /doc/uptypes.md: -------------------------------------------------------------------------------- 1 | # Firmware Update Types 2 | 3 | ## Update Process 4 | 5 | Initially, only the bootloader and the original firmware reside in 6 | the device Flash memory. Generally, the bootloader is located at the 7 | very beginning, followed by the current firmware. The bootloader 8 | component is static and does not change, nor is it updatable itself. 9 | 10 | 11 | 12 | It is the application's responsility to place an available update 13 | somewhere in Flash memory, preferrably at the very end to maximize 14 | the available space for updating. Updating overwrites the current 15 | firmware, leaving only the new firmware in Flash memory. 16 | 17 | 18 | 19 | As the update process is destructive, extreme care is taken to make 20 | this step robust. It is implemented in such a way that in case of 21 | interruption, the update can be restarted or resumed. This ensures 22 | that even in the case of power-loss or other transient failure, the 23 | bootloader can continue updating on the next pass, leaving the device 24 | with a functioning firmware. 25 | 26 | The bootloader supports a number of different update types: 27 | 28 | - Plain Updates 29 | - LZ4 Compressed Updates 30 | - LZ4 Delta Updates 31 | - LZ4 In-Place Delta Updates 32 | 33 | ### Plain Updates (`plain`) 34 | 35 | Plain updates are the most simple way to perform an update. The full 36 | new firmware image is contained as-is in the update blob. 37 | 38 | 39 | 40 | The bootloader then simply copies the firmware from the update blob 41 | to its intended location. 42 | 43 | 44 | 45 | After the process is complete, the new firmware is in place and the 46 | update can be invalidated. 47 | 48 | 49 | 50 | ### LZ4 Compressed Updates (`lz4`) 51 | 52 | LZ4 compressed updates differ from plain updates only by using [LZ4 53 | compression](https://en.wikipedia.org/wiki/LZ4_(compression_algorithm)) 54 | to reduce the size of the update. LZ4 was chosen because of the 55 | simplicity and robustness of the decompressor. 56 | 57 | 58 | 59 | The bootloader then decompresses the firmware from the update blob 60 | to its intended location. 61 | 62 | 63 | 64 | After the process is complete, the new firmware is in place and the 65 | update can be invalidated. 66 | 67 | 68 | 69 | ### LZ4 Delta Updates (`lz4-dict`) 70 | 71 | :wastebasket: *Deprecated* 72 | 73 | LZ4 delta updates make use of _dictionary mode_, whereby data can be 74 | preloaded into the backreferences space. For delta updates, the 75 | previous firmware image is used as the dictionary. This can dramatically 76 | reduce the size of an update, but since decompression requires access 77 | to the dictionary, the update is now specific to the source firmware 78 | it was created for. Further, the entire dictionary must stay available 79 | during the decompression process, which means the original firmware 80 | cannot be decompressed directly to the intended location. 81 | 82 | 83 | 84 | LZ4 delta updates are therefore encoded as plain udpates before the 85 | compression step. The bootloader then decompresses this plain update 86 | blob into free Flash memory between the compressed update and the 87 | current firmware, while using the current firmware as dictionary. 88 | 89 | 90 | 91 | Once the decompression is complete, the plain update is available 92 | in Flash and the compressed update can be invalidated. 93 | 94 | 95 | 96 | The process then continues by using the plain update as above. 97 | 98 | 99 | 100 | After the process is complete, the new firmware is in place and the 101 | update can be invalidated. 102 | 103 | 104 | 105 | As can be seen, while LZ4 delta updates are quite small and can thus 106 | be transmitted very efficiently over-the-air, the two-step decompression 107 | method uses much more Flash memory than any of the other methods. 108 | 109 | ### LZ4 In-Place Delta Updates (`lz4-dict-inplace`) 110 | 111 | By carefully coding the update and making use of a temporary scratch 112 | buffer, the delta update can be extracted directly to its final location 113 | in Flash memory. This dramatically reduces the amount of free space 114 | necessary on the device. The scratch buffer's size can be variable, 115 | thereby allowing the trading of compression efficiency against Flash 116 | memory requirements. 117 | 118 | 119 | 120 | The new firmware is uncompressed one block at a time into a temporary 121 | scratch buffer, before it is copied to its final location. The update 122 | blob contains itegrity protection data for each block to allow transactional 123 | execution of this update method. 124 | 125 | 126 | 127 | While not the entire previous firmware is available as a dictionary 128 | for every block with this method, it still yields compression efficiency 129 | comparable to regular delta updates in practice. 130 | 131 | After the process is complete, the new firmware is in place and the 132 | update can be invalidated. 133 | 134 | 135 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.d 3 | *.hex 4 | *.map 5 | *.zfw 6 | -------------------------------------------------------------------------------- /example/stm32l0/.gitignore: -------------------------------------------------------------------------------- 1 | hello 2 | -------------------------------------------------------------------------------- /example/stm32l0/Makefile: -------------------------------------------------------------------------------- 1 | CC := arm-none-eabi-gcc 2 | 3 | CFLAGS += -std=gnu11 4 | CFLAGS += -Wall 5 | CFLAGS += -g 6 | 7 | CFLAGS += -mcpu=cortex-m0plus -fno-common -fno-builtin -fno-exceptions -ffunction-sections -fdata-sections -fomit-frame-pointer 8 | 9 | CFLAGS += -I../../src/common 10 | CFLAGS += -I../../src/arm/stm32lx 11 | CFLAGS += -I../../src/arm/CMSIS/Include 12 | CFLAGS += -I../../src/arm/CMSIS/Device/ST/STM32L0xx/Include 13 | 14 | LDFLAGS += -Wl,--gc-sections -Wl,-Map,$(basename $@).map 15 | LDFLAGS += -nostdlib 16 | LDFLAGS += -T../../src/arm/stm32lx/ld/STM32L0xxB.ld 17 | LDFLAGS += -Tfw.ld 18 | 19 | ZFWTOOL := ../../tools/fwtool/zfwtool.py 20 | 21 | hello.hex: hello.zfw 22 | $(ZFWTOOL) export $< $@ 23 | 24 | hello.zfw: hello.unpatched.hex 25 | $(ZFWTOOL) create --patch $< $@ 26 | 27 | hello.unpatched.hex: hello 28 | arm-none-eabi-objcopy -O ihex $< $@ 29 | 30 | hello: hello.o 31 | 32 | clean: 33 | rm -f *.o *.map hello hello.hex 34 | 35 | .PHONY: clean 36 | 37 | .DELETE_ON_ERROR: 38 | -------------------------------------------------------------------------------- /example/stm32l0/fw.ld: -------------------------------------------------------------------------------- 1 | SECTIONS { 2 | .text : { 3 | . = ALIGN(4); 4 | KEEP(*(.fwhdr)) 5 | . = ALIGN(4); 6 | *(.text) 7 | *(.text*) 8 | . = ALIGN(4); 9 | } >FWFLASH 10 | 11 | .data : { 12 | . = ALIGN(4); 13 | _sdata = .; 14 | KEEP(*(.isr)) 15 | *(.data) 16 | *(.data*) 17 | . = ALIGN(4); 18 | _edata = .; 19 | } >RAM AT>FWFLASH 20 | 21 | _sidata = LOADADDR(.data); 22 | 23 | .bss : { 24 | . = ALIGN(4); 25 | _sbss = .; 26 | *(.bss) 27 | *(.bss*) 28 | *(COMMON) 29 | . = ALIGN(4); 30 | _ebss = .; 31 | } >RAM 32 | 33 | .rodata : { 34 | . = ALIGN(4); 35 | *(.rodata) 36 | *(.rodata*) 37 | . = ALIGN(4); 38 | 39 | /* make sure flash image is a multiple of page size */ 40 | FILL(0xffffffff) 41 | . = ALIGN(128); 42 | __fw_end__ = .; 43 | } >FWFLASH 44 | } 45 | -------------------------------------------------------------------------------- /example/stm32l0/hello.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016-2019 Semtech (International) AG. All rights reserved. 2 | // 3 | // This file is subject to the terms and conditions defined in file 'LICENSE', 4 | // which is part of this source code package. 5 | 6 | #include "stm32l072xx.h" 7 | #include "bootloader.h" 8 | #include "boottab.h" 9 | 10 | void _start (boot_boottab* boottab); // forward declaration 11 | 12 | // Firmware header 13 | __attribute__((section(".fwhdr"))) 14 | const volatile boot_fwhdr fwhdr = { 15 | // CRC and size will be patched by external tool 16 | .crc = 0, 17 | .size = BOOT_MAGIC_SIZE, 18 | .entrypoint = (uint32_t) _start, 19 | }; 20 | 21 | static void clock_init (void) { 22 | // System is clocked by MSI @2.1MHz at startup 23 | // We want to go to PLL(HSI16) @32MHz 24 | 25 | // 1a. HSI: Enable 26 | RCC->CR |= RCC_CR_HSION; 27 | // 1b. HSI: Wait for it 28 | while ((RCC->CR & RCC_CR_HSIRDY) == 0); 29 | 30 | // 2a. Flash: Enable prefetch buffer 31 | FLASH->ACR |= FLASH_ACR_PRFTEN; 32 | // 2b. Flash: Use 1 Wait state 33 | FLASH->ACR |= FLASH_ACR_LATENCY; 34 | while ((FLASH->ACR & FLASH_ACR_LATENCY) == 0); 35 | 36 | // 3a. Power: Enable clock 37 | RCC->APB1ENR |= RCC_APB1ENR_PWREN; 38 | // 3b. Power: Select Vrange 1 (min. 1.71V!) 39 | PWR->CR = PWR_CR_VOS_0; 40 | // 3c. Power: Wait for regulator 41 | while ((PWR->CSR & PWR_CSR_VOSF) != 0); 42 | 43 | // 4a. PLL: Set source (HSI16), multiplier (4), divider (2) 44 | RCC->CFGR |= (RCC_CFGR_PLLSRC_HSI | RCC_CFGR_PLLMUL4 | RCC_CFGR_PLLDIV2); 45 | // 4b. PLL: Enable 46 | RCC->CR |= RCC_CR_PLLON; 47 | // 4c. PLL: Wait for it 48 | while ((RCC->CR & RCC_CR_PLLRDY) == 0); 49 | 50 | // 5a. System clock: Set source (PLL) 51 | RCC->CFGR |= RCC_CFGR_SW_PLL; 52 | // 5b. System clock: Wait for it 53 | while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); 54 | 55 | // 6. Turn off MSI 56 | RCC->CR &= ~RCC_CR_MSION; 57 | } 58 | 59 | static void uart_init (void) { 60 | // Configure USART (115200/8N1, TX) 61 | RCC->APB1ENR |= RCC_APB1ENR_USART2EN; 62 | USART2->BRR = 278; // 115200 (APB1 clock @32MHz) 63 | USART2->CR1 = USART_CR1_UE | USART_CR1_TE; 64 | 65 | // Configure GPIO (PA2 / USART2_TX / AF4) 66 | RCC->IOPENR |= RCC_IOPENR_GPIOAEN; 67 | GPIOA->AFR[0] = (GPIOA->AFR[0] & ~(7 << (4 * (2)))) | (4 << (4 * (2))); /* af 4 */ 68 | GPIOA->MODER = (GPIOA->MODER & ~(3 << (2 * (2)))) | (2 << (2 * (2))); /* alternate func */ 69 | GPIOA->PUPDR = (GPIOA->PUPDR & ~(3 << (2 * (2)))) | (0 << (2 * (2))); /* no pull-up/down */ 70 | GPIOA->OTYPER = (GPIOA->OTYPER & ~(1 << (1 * (2)))) | (0 << (1 * (2))); /* push-pull */ 71 | GPIOA->OSPEEDR = (GPIOA->OSPEEDR & ~(3 << (2 * (2)))) | (1 << (2 * (2))); /* medium speed */ 72 | } 73 | 74 | static void uart_print (char* s) { 75 | while (*s) { 76 | while ((USART2->ISR & USART_ISR_TXE) == 0); 77 | USART2->TDR = *s++; 78 | } 79 | } 80 | 81 | static void i2h (char* dst, uint32_t v) { 82 | dst[8] = '\0'; 83 | for (int i = 0; i < 8; i++) { 84 | dst[7 - i] = "0123456789abcdef"[v & 0xf]; 85 | v >>= 4; 86 | } 87 | } 88 | 89 | void _start (boot_boottab* boottab) { 90 | // We only use stack in this example. A real firmware 91 | // would need to do initialization at this point, e.g. 92 | // data / bss segments, ISR vector re-map, etc. 93 | 94 | char crcbuf[8+1]; 95 | 96 | clock_init(); 97 | uart_init(); 98 | 99 | uart_print("----------------------\r\n"); 100 | uart_print("Hello World!\r\n"); 101 | 102 | uart_print("Build: " __DATE__ " " __TIME__ "\r\n"); 103 | 104 | i2h(crcbuf, boottab->version); 105 | uart_print("Bootloader: 0x"); 106 | uart_print(crcbuf); 107 | uart_print("\r\n"); 108 | 109 | i2h(crcbuf, fwhdr.crc); 110 | uart_print("Firmware: 0x"); 111 | uart_print(crcbuf); 112 | uart_print("\r\n"); 113 | 114 | while (1) __WFI(); // good night 115 | } 116 | -------------------------------------------------------------------------------- /src/arm/CMSIS/Device/ST/STM32L0xx/Include/stm32l0xx.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file stm32l0xx.h 4 | * @author MCD Application Team 5 | * @version V1.2.0 6 | * @date 06-February-2015 7 | * @brief CMSIS Cortex-M0+ Device Peripheral Access Layer Header File. 8 | * This file contains all the peripheral register's definitions, bits 9 | * definitions and memory mapping for STM32L0xx devices. 10 | * 11 | * The file is the unique include file that the application programmer 12 | * is using in the C source code, usually in main.c. This file contains: 13 | * - Configuration section that allows to select: 14 | * - The device used in the target application 15 | * - To use or not the peripheral’s drivers in application code(i.e. 16 | * code will be based on direct access to peripheral’s registers 17 | * rather than drivers API), this option is controlled by 18 | * "#define USE_HAL_DRIVER" 19 | * 20 | ****************************************************************************** 21 | * @attention 22 | * 23 | *

© COPYRIGHT(c) 2015 STMicroelectronics

24 | * 25 | * Redistribution and use in source and binary forms, with or without modification, 26 | * are permitted provided that the following conditions are met: 27 | * 1. Redistributions of source code must retain the above copyright notice, 28 | * this list of conditions and the following disclaimer. 29 | * 2. Redistributions in binary form must reproduce the above copyright notice, 30 | * this list of conditions and the following disclaimer in the documentation 31 | * and/or other materials provided with the distribution. 32 | * 3. Neither the name of STMicroelectronics nor the names of its contributors 33 | * may be used to endorse or promote products derived from this software 34 | * without specific prior written permission. 35 | * 36 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 37 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 38 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 39 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 40 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 41 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 42 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 43 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 44 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 45 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 46 | * 47 | ****************************************************************************** 48 | */ 49 | 50 | /** @addtogroup CMSIS 51 | * @{ 52 | */ 53 | 54 | /** @addtogroup stm32l0xx 55 | * @{ 56 | */ 57 | 58 | #ifndef __STM32L0xx_H 59 | #define __STM32L0xx_H 60 | 61 | #ifdef __cplusplus 62 | extern "C" { 63 | #endif /* __cplusplus */ 64 | 65 | /** @addtogroup Library_configuration_section 66 | * @{ 67 | */ 68 | 69 | /** 70 | * @brief STM32 Family 71 | */ 72 | #if !defined (STM32L0) 73 | #define STM32L0 74 | #endif /* STM32L0 */ 75 | 76 | /* Uncomment the line below according to the target STM32 device used in your 77 | application 78 | */ 79 | 80 | #if !defined (STM32L051xx) && !defined (STM32L052xx) && !defined (STM32L053xx) && !defined (STM32L061xx) && !defined (STM32L062xx) && !defined (STM32L063xx) \ 81 | && !defined (STM32L071xx) && !defined (STM32L072xx) && !defined (STM32L073xx) && !defined (STM32L081xx) && !defined (STM32L082xx) && !defined (STM32L083xx) 82 | /* #define STM32L051xx */ /*!< STM32L051K8, STM32L051C6, STM32L051C8, STM32L051R6, STM32L051R8 Devices */ 83 | /* #define STM32L052xx */ /*!< STM32L052K6, STM32L052K8, STM32L052C6, STM32L052C8, STM32L052R6, STM32L052R8 Devices */ 84 | /* #define STM32L053xx */ /*!< STM32L053C6, STM32L053C8, STM32L053R6, STM32L053R8 Devices */ 85 | /* #define STM32L061xx */ /*!< */ 86 | /* #define STM32L062xx */ /*!< STM32L062K8 */ 87 | /* #define STM32L063xx */ /*!< STM32L063C8, STM32L063R8 */ 88 | /* #define STM32L071xx */ /*!< */ 89 | /* #define STM32L072xx */ /*!< */ 90 | /* #define STM32L073xx */ /*!< STM32L073V8, STM32L073VB, STM32L073RB, STM32L073VZ, STM32L073RZ Devices */ 91 | /* #define STM32L081xx */ /*!< */ 92 | /* #define STM32L082xx */ /*!< */ 93 | /* #define STM32L083xx */ /*!< */ 94 | #endif 95 | 96 | /* Tip: To avoid modifying this file each time you need to switch between these 97 | devices, you can define the device in your toolchain compiler preprocessor. 98 | */ 99 | #if !defined (USE_HAL_DRIVER) 100 | /** 101 | * @brief Comment the line below if you will not use the peripherals drivers. 102 | In this case, these drivers will not be included and the application code will 103 | be based on direct access to peripherals registers 104 | */ 105 | /*#define USE_HAL_DRIVER */ 106 | #endif /* USE_HAL_DRIVER */ 107 | 108 | /** 109 | * @brief CMSIS Device version number V1.2.0RC1 110 | */ 111 | #define __STM32L0xx_CMSIS_DEVICE_VERSION_MAIN (0x01) /*!< [31:24] main version */ 112 | #define __STM32L0xx_CMSIS_DEVICE_VERSION_SUB1 (0x02) /*!< [23:16] sub1 version */ 113 | #define __STM32L0xx_CMSIS_DEVICE_VERSION_SUB2 (0x00) /*!< [15:8] sub2 version */ 114 | #define __STM32L0xx_CMSIS_DEVICE_VERSION_RC (0x00) /*!< [7:0] release candidate */ 115 | #define __STM32L0xx_CMSIS_DEVICE_VERSION ((__CMSIS_DEVICE_VERSION_MAIN << 24)\ 116 | |(__CMSIS_DEVICE_HAL_VERSION_SUB1 << 16)\ 117 | |(__CMSIS_DEVICE_HAL_VERSION_SUB2 << 8 )\ 118 | |(__CMSIS_DEVICE_HAL_VERSION_RC)) 119 | 120 | /** 121 | * @} 122 | */ 123 | 124 | /** @addtogroup Device_Included 125 | * @{ 126 | */ 127 | 128 | #if defined(STM32L031xx) 129 | #include "stm32l031xx.h" 130 | #elif defined(STM32L041xx) 131 | #include "stm32l041xx.h" 132 | #elif defined(STM32L051xx) 133 | #include "stm32l051xx.h" 134 | #elif defined(STM32L052xx) 135 | #include "stm32l052xx.h" 136 | #elif defined(STM32L053xx) 137 | #include "stm32l053xx.h" 138 | #elif defined(STM32L062xx) 139 | #include "stm32l062xx.h" 140 | #elif defined(STM32L063xx) 141 | #include "stm32l063xx.h" 142 | #elif defined(STM32L061xx) 143 | #include "stm32l061xx.h" 144 | #elif defined(STM32L071xx) 145 | #include "stm32l071xx.h" 146 | #elif defined(STM32L072xx) 147 | #include "stm32l072xx.h" 148 | #elif defined(STM32L073xx) 149 | #include "stm32l073xx.h" 150 | #elif defined(STM32L082xx) 151 | #include "stm32l082xx.h" 152 | #elif defined(STM32L083xx) 153 | #include "stm32l083xx.h" 154 | #elif defined(STM32L081xx) 155 | #include "stm32l081xx.h" 156 | #else 157 | #error "Please select first the target STM32L0xx device used in your application (in stm32l0xx.h file)" 158 | #endif 159 | 160 | /** 161 | * @} 162 | */ 163 | 164 | /** @addtogroup Exported_types 165 | * @{ 166 | */ 167 | typedef enum 168 | { 169 | RESET = 0, 170 | SET = !RESET 171 | } FlagStatus, ITStatus; 172 | 173 | typedef enum 174 | { 175 | DISABLE = 0, 176 | ENABLE = !DISABLE 177 | } FunctionalState; 178 | #define IS_FUNCTIONAL_STATE(STATE) (((STATE) == DISABLE) || ((STATE) == ENABLE)) 179 | 180 | typedef enum 181 | { 182 | ERROR = 0, 183 | SUCCESS = !ERROR 184 | } ErrorStatus; 185 | 186 | /** 187 | * @} 188 | */ 189 | 190 | 191 | /** @addtogroup Exported_macro 192 | * @{ 193 | */ 194 | #define SET_BIT(REG, BIT) ((REG) |= (BIT)) 195 | 196 | #define CLEAR_BIT(REG, BIT) ((REG) &= ~(BIT)) 197 | 198 | #define READ_BIT(REG, BIT) ((REG) & (BIT)) 199 | 200 | #define CLEAR_REG(REG) ((REG) = (0x0)) 201 | 202 | #define WRITE_REG(REG, VAL) ((REG) = (VAL)) 203 | 204 | #define READ_REG(REG) ((REG)) 205 | 206 | #define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK))) 207 | 208 | 209 | /** 210 | * @} 211 | */ 212 | 213 | #if defined (USE_HAL_DRIVER) 214 | #include "stm32l0xx_hal.h" 215 | #endif /* USE_HAL_DRIVER */ 216 | 217 | #ifdef __cplusplus 218 | } 219 | #endif /* __cplusplus */ 220 | 221 | #endif /* __STM32L0xx_H */ 222 | /** 223 | * @} 224 | */ 225 | 226 | /** 227 | * @} 228 | */ 229 | 230 | 231 | 232 | 233 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 234 | -------------------------------------------------------------------------------- /src/arm/CMSIS/Device/ST/STM32L0xx/Include/system_stm32l0xx.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file system_stm32l0xx.h 4 | * @author MCD Application Team 5 | * @version V1.2.0 6 | * @date 06-February-2015 7 | * @brief CMSIS Cortex-M0+ Device Peripheral Access Layer System Header File. 8 | ****************************************************************************** 9 | * @attention 10 | * 11 | *

© COPYRIGHT(c) 2015 STMicroelectronics

12 | * 13 | * Redistribution and use in source and binary forms, with or without modification, 14 | * are permitted provided that the following conditions are met: 15 | * 1. Redistributions of source code must retain the above copyright notice, 16 | * this list of conditions and the following disclaimer. 17 | * 2. Redistributions in binary form must reproduce the above copyright notice, 18 | * this list of conditions and the following disclaimer in the documentation 19 | * and/or other materials provided with the distribution. 20 | * 3. Neither the name of STMicroelectronics nor the names of its contributors 21 | * may be used to endorse or promote products derived from this software 22 | * without specific prior written permission. 23 | * 24 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 25 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 27 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 30 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 32 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 33 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | * 35 | ****************************************************************************** 36 | */ 37 | 38 | /** @addtogroup CMSIS 39 | * @{ 40 | */ 41 | 42 | /** @addtogroup stm32l0xx_system 43 | * @{ 44 | */ 45 | 46 | /** 47 | * @brief Define to prevent recursive inclusion 48 | */ 49 | #ifndef __SYSTEM_STM32L0XX_H 50 | #define __SYSTEM_STM32L0XX_H 51 | 52 | #ifdef __cplusplus 53 | extern "C" { 54 | #endif 55 | 56 | /** @addtogroup STM32L0xx_System_Includes 57 | * @{ 58 | */ 59 | 60 | /** 61 | * @} 62 | */ 63 | 64 | 65 | /** @addtogroup STM32L0xx_System_Exported_types 66 | * @{ 67 | */ 68 | /* This variable is updated in three ways: 69 | 1) by calling CMSIS function SystemCoreClockUpdate() 70 | 2) by calling HAL API function HAL_RCC_GetSysClockFreq() 71 | 3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency 72 | Note: If you use this function to configure the system clock; then there 73 | is no need to call the 2 first functions listed above, since SystemCoreClock 74 | variable is updated automatically. 75 | */ 76 | extern uint32_t SystemCoreClock; /*!< System Clock Frequency (Core Clock) */ 77 | 78 | /** 79 | * @} 80 | */ 81 | 82 | /** @addtogroup STM32L0xx_System_Exported_Constants 83 | * @{ 84 | */ 85 | 86 | /** 87 | * @} 88 | */ 89 | 90 | /** @addtogroup STM32L0xx_System_Exported_Macros 91 | * @{ 92 | */ 93 | 94 | /** 95 | * @} 96 | */ 97 | 98 | /** @addtogroup STM32L0xx_System_Exported_Functions 99 | * @{ 100 | */ 101 | 102 | extern void SystemInit(void); 103 | extern void SystemCoreClockUpdate(void); 104 | /** 105 | * @} 106 | */ 107 | 108 | #ifdef __cplusplus 109 | } 110 | #endif 111 | 112 | #endif /*__SYSTEM_STM32L0XX_H */ 113 | 114 | /** 115 | * @} 116 | */ 117 | 118 | /** 119 | * @} 120 | */ 121 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 122 | -------------------------------------------------------------------------------- /src/arm/CMSIS/Device/ST/STM32L1xx/Include/stm32l1xx.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lorabasics/basicloader/a1e6086dd9b106d9a563427bea9da14f614edb7e/src/arm/CMSIS/Device/ST/STM32L1xx/Include/stm32l1xx.h -------------------------------------------------------------------------------- /src/arm/CMSIS/Device/ST/STM32L1xx/Include/system_stm32l1xx.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file system_stm32l1xx.h 4 | * @author MCD Application Team 5 | * @version V1.3.3 6 | * @date 20-April-2015 7 | * @brief CMSIS Cortex-M3 Device Peripheral Access Layer System Header File. 8 | ****************************************************************************** 9 | * @attention 10 | * 11 | *

© COPYRIGHT 2015 STMicroelectronics

12 | * 13 | * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); 14 | * You may not use this file except in compliance with the License. 15 | * You may obtain a copy of the License at: 16 | * 17 | * http://www.st.com/software_license_agreement_liberty_v2 18 | * 19 | * Unless required by applicable law or agreed to in writing, software 20 | * distributed under the License is distributed on an "AS IS" BASIS, 21 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 22 | * See the License for the specific language governing permissions and 23 | * limitations under the License. 24 | * 25 | ****************************************************************************** 26 | */ 27 | 28 | /** @addtogroup CMSIS 29 | * @{ 30 | */ 31 | 32 | /** @addtogroup stm32l1xx_system 33 | * @{ 34 | */ 35 | 36 | /** 37 | * @brief Define to prevent recursive inclusion 38 | */ 39 | #ifndef __SYSTEM_STM32L1XX_H 40 | #define __SYSTEM_STM32L1XX_H 41 | 42 | #ifdef __cplusplus 43 | extern "C" { 44 | #endif 45 | 46 | /** @addtogroup STM32L1xx_System_Includes 47 | * @{ 48 | */ 49 | 50 | /** 51 | * @} 52 | */ 53 | 54 | 55 | /** @addtogroup STM32L1xx_System_Exported_types 56 | * @{ 57 | */ 58 | 59 | extern uint32_t SystemCoreClock; /*!< System Clock Frequency (Core Clock) */ 60 | 61 | /** 62 | * @} 63 | */ 64 | 65 | /** @addtogroup STM32L1xx_System_Exported_Constants 66 | * @{ 67 | */ 68 | 69 | /** 70 | * @} 71 | */ 72 | 73 | /** @addtogroup STM32L1xx_System_Exported_Macros 74 | * @{ 75 | */ 76 | 77 | /** 78 | * @} 79 | */ 80 | 81 | /** @addtogroup STM32L1xx_System_Exported_Functions 82 | * @{ 83 | */ 84 | 85 | extern void SystemInit(void); 86 | extern void SystemCoreClockUpdate(void); 87 | /** 88 | * @} 89 | */ 90 | 91 | #ifdef __cplusplus 92 | } 93 | #endif 94 | 95 | #endif /*__SYSTEM_STM32L1XX_H */ 96 | 97 | /** 98 | * @} 99 | */ 100 | 101 | /** 102 | * @} 103 | */ 104 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 105 | -------------------------------------------------------------------------------- /src/arm/CMSIS/Include/arm_common_tables.h: -------------------------------------------------------------------------------- 1 | /* ---------------------------------------------------------------------- 2 | * Copyright (C) 2010-2014 ARM Limited. All rights reserved. 3 | * 4 | * $Date: 31. July 2014 5 | * $Revision: V1.4.4 6 | * 7 | * Project: CMSIS DSP Library 8 | * Title: arm_common_tables.h 9 | * 10 | * Description: This file has extern declaration for common tables like Bitreverse, reciprocal etc which are used across different functions 11 | * 12 | * Target Processor: Cortex-M4/Cortex-M3 13 | * 14 | * Redistribution and use in source and binary forms, with or without 15 | * modification, are permitted provided that the following conditions 16 | * are met: 17 | * - Redistributions of source code must retain the above copyright 18 | * notice, this list of conditions and the following disclaimer. 19 | * - Redistributions in binary form must reproduce the above copyright 20 | * notice, this list of conditions and the following disclaimer in 21 | * the documentation and/or other materials provided with the 22 | * distribution. 23 | * - Neither the name of ARM LIMITED nor the names of its contributors 24 | * may be used to endorse or promote products derived from this 25 | * software without specific prior written permission. 26 | * 27 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 28 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 29 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 30 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 31 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 32 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 33 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 34 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 35 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 37 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 38 | * POSSIBILITY OF SUCH DAMAGE. 39 | * -------------------------------------------------------------------- */ 40 | 41 | #ifndef _ARM_COMMON_TABLES_H 42 | #define _ARM_COMMON_TABLES_H 43 | 44 | #include "arm_math.h" 45 | 46 | extern const uint16_t armBitRevTable[1024]; 47 | extern const q15_t armRecipTableQ15[64]; 48 | extern const q31_t armRecipTableQ31[64]; 49 | //extern const q31_t realCoefAQ31[1024]; 50 | //extern const q31_t realCoefBQ31[1024]; 51 | extern const float32_t twiddleCoef_16[32]; 52 | extern const float32_t twiddleCoef_32[64]; 53 | extern const float32_t twiddleCoef_64[128]; 54 | extern const float32_t twiddleCoef_128[256]; 55 | extern const float32_t twiddleCoef_256[512]; 56 | extern const float32_t twiddleCoef_512[1024]; 57 | extern const float32_t twiddleCoef_1024[2048]; 58 | extern const float32_t twiddleCoef_2048[4096]; 59 | extern const float32_t twiddleCoef_4096[8192]; 60 | #define twiddleCoef twiddleCoef_4096 61 | extern const q31_t twiddleCoef_16_q31[24]; 62 | extern const q31_t twiddleCoef_32_q31[48]; 63 | extern const q31_t twiddleCoef_64_q31[96]; 64 | extern const q31_t twiddleCoef_128_q31[192]; 65 | extern const q31_t twiddleCoef_256_q31[384]; 66 | extern const q31_t twiddleCoef_512_q31[768]; 67 | extern const q31_t twiddleCoef_1024_q31[1536]; 68 | extern const q31_t twiddleCoef_2048_q31[3072]; 69 | extern const q31_t twiddleCoef_4096_q31[6144]; 70 | extern const q15_t twiddleCoef_16_q15[24]; 71 | extern const q15_t twiddleCoef_32_q15[48]; 72 | extern const q15_t twiddleCoef_64_q15[96]; 73 | extern const q15_t twiddleCoef_128_q15[192]; 74 | extern const q15_t twiddleCoef_256_q15[384]; 75 | extern const q15_t twiddleCoef_512_q15[768]; 76 | extern const q15_t twiddleCoef_1024_q15[1536]; 77 | extern const q15_t twiddleCoef_2048_q15[3072]; 78 | extern const q15_t twiddleCoef_4096_q15[6144]; 79 | extern const float32_t twiddleCoef_rfft_32[32]; 80 | extern const float32_t twiddleCoef_rfft_64[64]; 81 | extern const float32_t twiddleCoef_rfft_128[128]; 82 | extern const float32_t twiddleCoef_rfft_256[256]; 83 | extern const float32_t twiddleCoef_rfft_512[512]; 84 | extern const float32_t twiddleCoef_rfft_1024[1024]; 85 | extern const float32_t twiddleCoef_rfft_2048[2048]; 86 | extern const float32_t twiddleCoef_rfft_4096[4096]; 87 | 88 | 89 | /* floating-point bit reversal tables */ 90 | #define ARMBITREVINDEXTABLE__16_TABLE_LENGTH ((uint16_t)20 ) 91 | #define ARMBITREVINDEXTABLE__32_TABLE_LENGTH ((uint16_t)48 ) 92 | #define ARMBITREVINDEXTABLE__64_TABLE_LENGTH ((uint16_t)56 ) 93 | #define ARMBITREVINDEXTABLE_128_TABLE_LENGTH ((uint16_t)208 ) 94 | #define ARMBITREVINDEXTABLE_256_TABLE_LENGTH ((uint16_t)440 ) 95 | #define ARMBITREVINDEXTABLE_512_TABLE_LENGTH ((uint16_t)448 ) 96 | #define ARMBITREVINDEXTABLE1024_TABLE_LENGTH ((uint16_t)1800) 97 | #define ARMBITREVINDEXTABLE2048_TABLE_LENGTH ((uint16_t)3808) 98 | #define ARMBITREVINDEXTABLE4096_TABLE_LENGTH ((uint16_t)4032) 99 | 100 | extern const uint16_t armBitRevIndexTable16[ARMBITREVINDEXTABLE__16_TABLE_LENGTH]; 101 | extern const uint16_t armBitRevIndexTable32[ARMBITREVINDEXTABLE__32_TABLE_LENGTH]; 102 | extern const uint16_t armBitRevIndexTable64[ARMBITREVINDEXTABLE__64_TABLE_LENGTH]; 103 | extern const uint16_t armBitRevIndexTable128[ARMBITREVINDEXTABLE_128_TABLE_LENGTH]; 104 | extern const uint16_t armBitRevIndexTable256[ARMBITREVINDEXTABLE_256_TABLE_LENGTH]; 105 | extern const uint16_t armBitRevIndexTable512[ARMBITREVINDEXTABLE_512_TABLE_LENGTH]; 106 | extern const uint16_t armBitRevIndexTable1024[ARMBITREVINDEXTABLE1024_TABLE_LENGTH]; 107 | extern const uint16_t armBitRevIndexTable2048[ARMBITREVINDEXTABLE2048_TABLE_LENGTH]; 108 | extern const uint16_t armBitRevIndexTable4096[ARMBITREVINDEXTABLE4096_TABLE_LENGTH]; 109 | 110 | /* fixed-point bit reversal tables */ 111 | #define ARMBITREVINDEXTABLE_FIXED___16_TABLE_LENGTH ((uint16_t)12 ) 112 | #define ARMBITREVINDEXTABLE_FIXED___32_TABLE_LENGTH ((uint16_t)24 ) 113 | #define ARMBITREVINDEXTABLE_FIXED___64_TABLE_LENGTH ((uint16_t)56 ) 114 | #define ARMBITREVINDEXTABLE_FIXED__128_TABLE_LENGTH ((uint16_t)112 ) 115 | #define ARMBITREVINDEXTABLE_FIXED__256_TABLE_LENGTH ((uint16_t)240 ) 116 | #define ARMBITREVINDEXTABLE_FIXED__512_TABLE_LENGTH ((uint16_t)480 ) 117 | #define ARMBITREVINDEXTABLE_FIXED_1024_TABLE_LENGTH ((uint16_t)992 ) 118 | #define ARMBITREVINDEXTABLE_FIXED_2048_TABLE_LENGTH ((uint16_t)1984) 119 | #define ARMBITREVINDEXTABLE_FIXED_4096_TABLE_LENGTH ((uint16_t)4032) 120 | 121 | extern const uint16_t armBitRevIndexTable_fixed_16[ARMBITREVINDEXTABLE_FIXED___16_TABLE_LENGTH]; 122 | extern const uint16_t armBitRevIndexTable_fixed_32[ARMBITREVINDEXTABLE_FIXED___32_TABLE_LENGTH]; 123 | extern const uint16_t armBitRevIndexTable_fixed_64[ARMBITREVINDEXTABLE_FIXED___64_TABLE_LENGTH]; 124 | extern const uint16_t armBitRevIndexTable_fixed_128[ARMBITREVINDEXTABLE_FIXED__128_TABLE_LENGTH]; 125 | extern const uint16_t armBitRevIndexTable_fixed_256[ARMBITREVINDEXTABLE_FIXED__256_TABLE_LENGTH]; 126 | extern const uint16_t armBitRevIndexTable_fixed_512[ARMBITREVINDEXTABLE_FIXED__512_TABLE_LENGTH]; 127 | extern const uint16_t armBitRevIndexTable_fixed_1024[ARMBITREVINDEXTABLE_FIXED_1024_TABLE_LENGTH]; 128 | extern const uint16_t armBitRevIndexTable_fixed_2048[ARMBITREVINDEXTABLE_FIXED_2048_TABLE_LENGTH]; 129 | extern const uint16_t armBitRevIndexTable_fixed_4096[ARMBITREVINDEXTABLE_FIXED_4096_TABLE_LENGTH]; 130 | 131 | /* Tables for Fast Math Sine and Cosine */ 132 | extern const float32_t sinTable_f32[FAST_MATH_TABLE_SIZE + 1]; 133 | extern const q31_t sinTable_q31[FAST_MATH_TABLE_SIZE + 1]; 134 | extern const q15_t sinTable_q15[FAST_MATH_TABLE_SIZE + 1]; 135 | 136 | #endif /* ARM_COMMON_TABLES_H */ 137 | -------------------------------------------------------------------------------- /src/arm/CMSIS/Include/arm_const_structs.h: -------------------------------------------------------------------------------- 1 | /* ---------------------------------------------------------------------- 2 | * Copyright (C) 2010-2014 ARM Limited. All rights reserved. 3 | * 4 | * $Date: 31. July 2014 5 | * $Revision: V1.4.4 6 | * 7 | * Project: CMSIS DSP Library 8 | * Title: arm_const_structs.h 9 | * 10 | * Description: This file has constant structs that are initialized for 11 | * user convenience. For example, some can be given as 12 | * arguments to the arm_cfft_f32() function. 13 | * 14 | * Target Processor: Cortex-M4/Cortex-M3 15 | * 16 | * Redistribution and use in source and binary forms, with or without 17 | * modification, are permitted provided that the following conditions 18 | * are met: 19 | * - Redistributions of source code must retain the above copyright 20 | * notice, this list of conditions and the following disclaimer. 21 | * - Redistributions in binary form must reproduce the above copyright 22 | * notice, this list of conditions and the following disclaimer in 23 | * the documentation and/or other materials provided with the 24 | * distribution. 25 | * - Neither the name of ARM LIMITED nor the names of its contributors 26 | * may be used to endorse or promote products derived from this 27 | * software without specific prior written permission. 28 | * 29 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 30 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 31 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 32 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 33 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 34 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 35 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 36 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 37 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 38 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 39 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 40 | * POSSIBILITY OF SUCH DAMAGE. 41 | * -------------------------------------------------------------------- */ 42 | 43 | #ifndef _ARM_CONST_STRUCTS_H 44 | #define _ARM_CONST_STRUCTS_H 45 | 46 | #include "arm_math.h" 47 | #include "arm_common_tables.h" 48 | 49 | extern const arm_cfft_instance_f32 arm_cfft_sR_f32_len16; 50 | extern const arm_cfft_instance_f32 arm_cfft_sR_f32_len32; 51 | extern const arm_cfft_instance_f32 arm_cfft_sR_f32_len64; 52 | extern const arm_cfft_instance_f32 arm_cfft_sR_f32_len128; 53 | extern const arm_cfft_instance_f32 arm_cfft_sR_f32_len256; 54 | extern const arm_cfft_instance_f32 arm_cfft_sR_f32_len512; 55 | extern const arm_cfft_instance_f32 arm_cfft_sR_f32_len1024; 56 | extern const arm_cfft_instance_f32 arm_cfft_sR_f32_len2048; 57 | extern const arm_cfft_instance_f32 arm_cfft_sR_f32_len4096; 58 | 59 | extern const arm_cfft_instance_q31 arm_cfft_sR_q31_len16; 60 | extern const arm_cfft_instance_q31 arm_cfft_sR_q31_len32; 61 | extern const arm_cfft_instance_q31 arm_cfft_sR_q31_len64; 62 | extern const arm_cfft_instance_q31 arm_cfft_sR_q31_len128; 63 | extern const arm_cfft_instance_q31 arm_cfft_sR_q31_len256; 64 | extern const arm_cfft_instance_q31 arm_cfft_sR_q31_len512; 65 | extern const arm_cfft_instance_q31 arm_cfft_sR_q31_len1024; 66 | extern const arm_cfft_instance_q31 arm_cfft_sR_q31_len2048; 67 | extern const arm_cfft_instance_q31 arm_cfft_sR_q31_len4096; 68 | 69 | extern const arm_cfft_instance_q15 arm_cfft_sR_q15_len16; 70 | extern const arm_cfft_instance_q15 arm_cfft_sR_q15_len32; 71 | extern const arm_cfft_instance_q15 arm_cfft_sR_q15_len64; 72 | extern const arm_cfft_instance_q15 arm_cfft_sR_q15_len128; 73 | extern const arm_cfft_instance_q15 arm_cfft_sR_q15_len256; 74 | extern const arm_cfft_instance_q15 arm_cfft_sR_q15_len512; 75 | extern const arm_cfft_instance_q15 arm_cfft_sR_q15_len1024; 76 | extern const arm_cfft_instance_q15 arm_cfft_sR_q15_len2048; 77 | extern const arm_cfft_instance_q15 arm_cfft_sR_q15_len4096; 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /src/arm/stm32lx/bootloader.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016-2019 Semtech (International) AG. All rights reserved. 2 | // 3 | // This file is subject to the terms and conditions defined in file 'LICENSE', 4 | // which is part of this source code package. 5 | 6 | #include "bootloader_impl.h" 7 | #include "update.h" 8 | #include "bootloader_hw.h" 9 | #include "sha2.h" 10 | 11 | 12 | // ------------------------------------------------ 13 | // CRC-32 14 | 15 | static uint32_t boot_crc32 (void* buf, uint32_t nwords) { 16 | uint32_t* src = buf; 17 | uint32_t v; 18 | 19 | // enable crc peripheral 20 | RCC->AHBENR |= RCC_AHBENR_CRCEN; 21 | // reset crc peripheral, reverse bits on input and output (L0 only) 22 | CRC->CR = 0 23 | #if defined(STM32L0) 24 | | CRC_CR_REV_IN | CRC_CR_REV_OUT 25 | #endif 26 | | CRC_CR_RESET; 27 | 28 | while (nwords-- > 0) { 29 | v = *src++; 30 | #if defined(STM32L1) 31 | v = __rbit(v); 32 | #endif 33 | CRC->DR = v; 34 | } 35 | v = CRC->DR; 36 | 37 | // disable crc peripheral 38 | RCC->AHBENR &= ~RCC_AHBENR_CRCEN; 39 | 40 | #if defined(STM32L1) 41 | v = __rbit(v); 42 | #endif 43 | 44 | return ~v; 45 | } 46 | 47 | 48 | // ------------------------------------------------ 49 | // LED macros 50 | 51 | #define _LED_INIT(p,n,on) do { \ 52 | (p)->MODER = ((p)->MODER & ~(3 << (2 * (n)))) | (!!(on) << (2 * (n))); /* output */ \ 53 | (p)->PUPDR = ((p)->PUPDR & ~(3 << (2 * (n)))) | (0 << (2 * (n))); /* no pull-up/down */ \ 54 | (p)->OTYPER = ((p)->OTYPER & ~(1 << (1 * (n)))) | (0 << (1 * (n))); /* push-pull */ \ 55 | (p)->OSPEEDR = ((p)->OSPEEDR & ~(3 << (2 * (n)))) | (0 << (2 * (n))); /* low speed */ \ 56 | } while( 0 ) 57 | #define LED_INIT(gpio) do { \ 58 | GPIO_ENABLE(PORTN(gpio)); \ 59 | _LED_INIT(PORT(gpio), PIN(gpio), 1); \ 60 | } while( 0 ) 61 | #define LED_DEINIT(gpio) do { \ 62 | _LED_INIT(PORT(gpio), PIN(gpio), 0); \ 63 | GPIO_DISABLE(PORTN(gpio)); \ 64 | } while( 0 ) 65 | #define LED_ON(gpio) do { SET_PIN(BOOT_LED_GPIO, (BOOT_LED_GPIO & GPIO_F_ACTLOW) ? 0 : 1); } while( 0 ) 66 | #define LED_OFF(gpio) do { SET_PIN(BOOT_LED_GPIO, (BOOT_LED_GPIO & GPIO_F_ACTLOW) ? 1 : 0); } while( 0 ) 67 | 68 | 69 | // ------------------------------------------------ 70 | // Panic handler 71 | 72 | #if defined(BOOT_LED_GPIO) 73 | 74 | extern void delay (int); // provided by util.S 75 | 76 | // delay and refresh watchdog 77 | static void pause (int v) { 78 | // refresh watchdog 79 | IWDG->KR = 0xaaaa; 80 | // pause 81 | delay(v); 82 | } 83 | 84 | static void blink_value (uint32_t v) { 85 | // blink nibble-by-nibble 86 | // least-significant-nibble first, 0x0 -> 1 blink, 0xf -> 16 blinks 87 | do { 88 | uint32_t n = v & 0xf; 89 | do { 90 | LED_ON(BOOT_LED_GPIO); 91 | pause(6); 92 | LED_OFF(BOOT_LED_GPIO); 93 | pause(6); 94 | } while (n--); 95 | v >>= 4; 96 | pause(12); 97 | } while (v); 98 | } 99 | #endif 100 | 101 | // force inlining of reset call 102 | __attribute__((always_inline)) static void NVIC_SystemReset (void); 103 | 104 | __attribute__((noreturn)) 105 | void boot_panic (uint32_t type, uint32_t reason, uint32_t addr) { 106 | // disable all interrupts 107 | __disable_irq(); 108 | // startup MSI @2.1MHz 109 | RCC->ICSCR = (RCC->ICSCR & ~RCC_ICSCR_MSIRANGE) | RCC_ICSCR_MSIRANGE_5; 110 | RCC->CR |= RCC_CR_MSION; 111 | while ((RCC->CR & RCC_CR_MSIRDY) == 0); 112 | // switch clock source to MSI 113 | RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_SW) | RCC_CFGR_SW_MSI; 114 | while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_MSI); 115 | // no flash wait states 116 | FLASH->ACR &= ~FLASH_ACR_LATENCY; 117 | 118 | #if defined(BOOT_LED_GPIO) 119 | LED_INIT(BOOT_LED_GPIO); 120 | 121 | int repeat = 3; 122 | while (repeat-- > 0) { 123 | // blink long 124 | LED_ON(BOOT_LED_GPIO); 125 | pause(30); 126 | LED_OFF(BOOT_LED_GPIO); 127 | pause(30); 128 | // blink type 129 | blink_value(type); 130 | pause(30); 131 | // blink reason 132 | blink_value(reason); 133 | pause(30); 134 | // blink address 135 | blink_value(addr); 136 | pause(30); 137 | } 138 | #endif 139 | NVIC_SystemReset(); 140 | // not reached 141 | while (1); 142 | } 143 | 144 | __attribute__((noreturn, naked)) 145 | static void fw_panic (uint32_t reason, uint32_t addr) { 146 | boot_panic(BOOT_PANIC_TYPE_FIRMWARE, reason, addr); 147 | } 148 | 149 | 150 | // ------------------------------------------------ 151 | // Flash functions 152 | 153 | typedef void (*wr_fl_hp) (uint32_t*, const uint32_t*); 154 | 155 | typedef struct { 156 | boot_uphdr* fwup; 157 | wr_fl_hp wf_func; 158 | } up_ctx; 159 | 160 | static void unlock_flash (void) { 161 | // unlock flash registers 162 | FLASH->PEKEYR = 0x89ABCDEF; // FLASH_PEKEY1 163 | FLASH->PEKEYR = 0x02030405; // FLASH_PEKEY2 164 | // enable flash programming 165 | FLASH->PRGKEYR = 0x8C9DAEBF; // FLASH_PRGKEY1; 166 | FLASH->PRGKEYR = 0x13141516; // FLASH_PRGKEY2; 167 | // enable flash erase and half-page programming 168 | FLASH->PECR |= FLASH_PECR_PROG; 169 | } 170 | 171 | static void relock_flash (void) { 172 | FLASH->PECR |= FLASH_PECR_PELOCK; 173 | } 174 | 175 | static void check_eop (uint32_t panic_addr) { 176 | if (FLASH->SR & FLASH_SR_EOP) { 177 | FLASH->SR = FLASH_SR_EOP; 178 | } else { 179 | boot_panic(BOOT_PANIC_TYPE_BOOTLOADER, 180 | BOOT_PANIC_REASON_FLASH, panic_addr); 181 | } 182 | } 183 | 184 | extern uint32_t wr_fl_hp_begin; // provided by util.S 185 | extern uint32_t wr_fl_hp_end; // provided by util.S 186 | 187 | #define WR_FL_HP_WORDS (&wr_fl_hp_end - &wr_fl_hp_begin) 188 | 189 | static wr_fl_hp prep_wr_fl_hp (uint32_t* funcbuf) { 190 | for (int i = 0; i < WR_FL_HP_WORDS; i++) { 191 | funcbuf[i] = (&wr_fl_hp_begin)[i]; 192 | } 193 | return THUMB_FUNC(funcbuf); 194 | } 195 | 196 | static void fl_write (wr_fl_hp wf_func, uint32_t* dst, const uint32_t* src, uint32_t nwords, bool erase) { 197 | while( nwords > 0 ) { 198 | if( erase && (((uintptr_t) dst) & 127) == 0 ) { 199 | // erase page 200 | FLASH->PECR |= FLASH_PECR_ERASE; 201 | *dst = 0; 202 | while( FLASH->SR & FLASH_SR_BSY ); 203 | check_eop(2); 204 | FLASH->PECR &= ~FLASH_PECR_ERASE; 205 | } 206 | if( src ) { 207 | if( (((uintptr_t) dst) & 63) == 0 && nwords >= 16 ) { 208 | // write half page 209 | FLASH->PECR |= FLASH_PECR_FPRG; 210 | wf_func(dst, src); 211 | check_eop(3); 212 | FLASH->PECR &= ~FLASH_PECR_FPRG; 213 | src += 16; 214 | dst += 16; 215 | nwords -= 16; 216 | } else { 217 | // write word 218 | *dst++ = *src++; 219 | while( FLASH->SR & FLASH_SR_BSY ); 220 | check_eop(4); 221 | nwords -= 1; 222 | } 223 | } else { 224 | if( nwords > 32 ) { 225 | dst += 32; 226 | nwords -= 32; 227 | } else { 228 | nwords = 0; 229 | } 230 | } 231 | } 232 | } 233 | 234 | static void write_flash (uint32_t* dst, const uint32_t* src, uint32_t nwords, bool erase) { 235 | uint32_t funcbuf[WR_FL_HP_WORDS]; 236 | wr_fl_hp wf_func = prep_wr_fl_hp(funcbuf); 237 | 238 | unlock_flash(); 239 | fl_write(wf_func, dst, src, nwords, erase); 240 | relock_flash(); 241 | } 242 | 243 | static void ee_write (uint32_t* dst, uint32_t val) { 244 | *dst = val; 245 | while (FLASH->SR & FLASH_SR_BSY); 246 | } 247 | 248 | 249 | // ------------------------------------------------ 250 | // Update glue functions 251 | 252 | uint32_t up_install_init (void* ctx, uint32_t fwsize, void** pfwdst, uint32_t tmpsize, void** ptmpdst, boot_fwhdr** pcurrentfw) { 253 | up_ctx* uc = ctx; 254 | if (!ISMULT_PAGE_SZ(fwsize) || fwsize > ((uintptr_t) uc->fwup - BOOT_FW_BASE)) { 255 | // new firmware is not multiple of page size or would overwrite update 256 | return BOOT_E_SIZE; 257 | } 258 | 259 | // assume dependency on current firmware when temp storage is requested 260 | if (tmpsize) { 261 | boot_fwhdr* fwhdr = (boot_fwhdr*) BOOT_FW_BASE; 262 | uint32_t fwmax = (fwsize > fwhdr->size) ? fwsize : fwhdr->size; 263 | if (!ISMULT_PAGE_SZ(tmpsize) || fwmax + tmpsize > ((uintptr_t) uc->fwup - BOOT_FW_BASE)) { 264 | return BOOT_E_SIZE; 265 | } 266 | } 267 | 268 | // set installation address for new firmware 269 | *pfwdst = (void*) BOOT_FW_BASE; 270 | 271 | // set address for temporary storage 272 | if (tmpsize && ptmpdst) { 273 | *ptmpdst = (unsigned char*) uc->fwup - tmpsize; 274 | } 275 | 276 | // set pointer to current firmware header 277 | if (pcurrentfw) { 278 | *pcurrentfw = (boot_fwhdr*) BOOT_FW_BASE; 279 | } 280 | 281 | return BOOT_OK; 282 | } 283 | 284 | void up_flash_wr_page (void* ctx, void* dst, void* src) { 285 | up_ctx* uc = ctx; 286 | #if defined(UPDATE_LED_GPIO) 287 | LED_ON(UPDATE_LED_GPIO); 288 | #endif 289 | fl_write(uc->wf_func, dst, src, FLASH_PAGE_SZ >> 2, true); 290 | #if defined(UPDATE_LED_GPIO) 291 | LED_OFF(UPDATE_LED_GPIO); 292 | #endif 293 | } 294 | 295 | void up_flash_unlock (void* ctx) { 296 | #if defined(UPDATE_LED_GPIO) 297 | LED_INIT(UPDATE_LED_GPIO); 298 | #endif 299 | unlock_flash(); 300 | } 301 | 302 | void up_flash_lock (void* ctx) { 303 | relock_flash(); 304 | #if defined(UPDATE_LED_GPIO) 305 | LED_DEINIT(UPDATE_LED_GPIO); 306 | #endif 307 | } 308 | 309 | 310 | // ------------------------------------------------ 311 | // Update functions 312 | 313 | static void do_install (boot_uphdr* fwup) { 314 | uint32_t funcbuf[WR_FL_HP_WORDS]; 315 | up_ctx uc = { 316 | .wf_func = prep_wr_fl_hp(funcbuf), 317 | .fwup = fwup, 318 | }; 319 | if (update(&uc, fwup, true) != BOOT_OK) { 320 | boot_panic(BOOT_PANIC_TYPE_BOOTLOADER, BOOT_PANIC_REASON_UPDATE, 0); 321 | } 322 | } 323 | 324 | static bool check_update (boot_uphdr* fwup) { 325 | uint32_t flash_sz = FLASH_SZ(); 326 | 327 | return ( ((intptr_t) fwup & 3) == 0 328 | && (intptr_t) fwup >= FLASH_BASE 329 | && sizeof(boot_uphdr) <= flash_sz - ((intptr_t) fwup - FLASH_BASE) 330 | && fwup->size >= sizeof(boot_uphdr) 331 | && (fwup->size & 3) == 0 332 | && fwup->size <= flash_sz - ((intptr_t) fwup - FLASH_BASE) 333 | && boot_crc32(((unsigned char*) fwup) + 8, (fwup->size - 8) >> 2) == fwup->crc 334 | && true /* TODO hardware id match */ ); 335 | } 336 | 337 | static uint32_t set_update (void* ptr, hash32* hash) { 338 | uint32_t rv; 339 | if (ptr == NULL) { 340 | rv = BOOT_OK; 341 | } else { 342 | up_ctx uc = { 343 | .fwup = ptr, 344 | }; 345 | rv = check_update((boot_uphdr*) ptr) ? update(&uc, ptr, false) : BOOT_E_SIZE; 346 | } 347 | if (rv == BOOT_OK) { 348 | boot_config* cfg = (boot_config*) BOOT_CONFIG_BASE; 349 | // unlock EEPROM 350 | FLASH->PEKEYR = 0x89ABCDEF; // FLASH_PEKEY1 351 | FLASH->PEKEYR = 0x02030405; // FLASH_PEKEY2 352 | // copy hash 353 | if (hash) { 354 | for (int i = 0; i < 8; i++) { 355 | ee_write(&cfg->hash.w[i], hash->w[i]); 356 | } 357 | } 358 | // set update pointer 359 | ee_write(&cfg->fwupdate1, (uint32_t) ptr); 360 | ee_write(&cfg->fwupdate2, (uint32_t) ptr); 361 | // relock EEPROM 362 | FLASH->PECR |= FLASH_PECR_PELOCK; 363 | } 364 | return rv; 365 | } 366 | 367 | 368 | // ------------------------------------------------ 369 | // Bootloader main entry point 370 | 371 | void* bootloader (void) { 372 | boot_fwhdr* fwh = (boot_fwhdr*) BOOT_FW_BASE; 373 | boot_config* cfg = (boot_config*) BOOT_CONFIG_BASE; 374 | 375 | // check presence and integrity of firmware update 376 | if (cfg->fwupdate1 == cfg->fwupdate2) { 377 | boot_uphdr* fwup = (boot_uphdr*) cfg->fwupdate1; 378 | if (fwup != NULL && check_update(fwup)) { 379 | do_install(fwup); 380 | } 381 | } 382 | 383 | // verify integrity of current firmware 384 | if (fwh->size < sizeof(boot_fwhdr) 385 | || fwh->size > (FLASH_SZ() - (BOOT_FW_BASE - FLASH_BASE)) 386 | || boot_crc32(((unsigned char*) fwh) + 8, (fwh->size - 8) >> 2) != fwh->crc) { 387 | boot_panic(BOOT_PANIC_TYPE_BOOTLOADER, BOOT_PANIC_REASON_CRC, 0); 388 | } 389 | 390 | // clear fwup pointer in EEPROM if set 391 | if (cfg->fwupdate1 != 0 || cfg->fwupdate2 != 0) { 392 | set_update(NULL, NULL); 393 | } 394 | 395 | // return entry point 396 | return (void*) fwh->entrypoint; 397 | } 398 | 399 | 400 | // ------------------------------------------------ 401 | // Bootloader information table 402 | // 403 | // Version history: 404 | // 405 | // 0x100 - initial version 406 | // 0x101 - added wr_flash 407 | // 0x102 - added sha_256 408 | // 0x103 - support for self-contained LZ4 updates 409 | // 0x104 - support for LZ4 block-delta updates 410 | // 0x105 - wr_flash: allow flash erase-only operation by setting src=NULL 411 | 412 | __attribute__((section(".boot.boottab"))) const boot_boottab boottab = { 413 | .version = 0x108, 414 | .update = set_update, 415 | .panic = fw_panic, 416 | .crc32 = boot_crc32, 417 | .wr_flash = write_flash, 418 | .sha256 = sha256, 419 | }; 420 | -------------------------------------------------------------------------------- /src/arm/stm32lx/bootloader_hw.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016-2019 Semtech (International) AG. All rights reserved. 2 | // 3 | // This file is subject to the terms and conditions defined in file 'LICENSE', 4 | // which is part of this source code package. 5 | 6 | #ifndef _bootloader_hw_h_ 7 | #define _bootloader_hw_h_ 8 | 9 | // ------------------------------------------------ 10 | #if defined(STM32L0) 11 | 12 | #include "stm32l0xx.h" 13 | 14 | #define FLASH_SZ() (*((uint16_t*) 0x1FF8007C) << 10) // flash size register (L0x1 RM0377 28.1.1; L0x2 RM0376 33.1.1) 15 | #define FLASH_PAGE_SZ 128 16 | #define ROUND_PAGE_SZ(sz) (((sz) + (FLASH_PAGE_SZ - 1)) & ~(FLASH_PAGE_SZ - 1)) 17 | #define ISMULT_PAGE_SZ(sz) (((sz) & (FLASH_PAGE_SZ - 1)) == 0) 18 | 19 | #define GPIO_RCC_ENR RCC->IOPENR 20 | #define GPIO_RCC_ENB(p) (((p) == 0) ? RCC_IOPENR_GPIOAEN \ 21 | : ((p) == 1) ? RCC_IOPENR_GPIOBEN \ 22 | : ((p) == 2) ? RCC_IOPENR_GPIOCEN \ 23 | : 0) 24 | 25 | 26 | // ------------------------------------------------ 27 | #elif defined(STM32L1) 28 | 29 | #include "stm32l1xx.h" 30 | 31 | #define GPIO_RCC_ENR RCC->AHBENR 32 | #define GPIO_RCC_ENB(p) (((p) == 0) ? RCC_AHBENR_GPIOAEN \ 33 | : ((p) == 1) ? RCC_AHBENR_GPIOBEN \ 34 | : ((p) == 2) ? RCC_AHBENR_GPIOCEN \ 35 | : 0) 36 | 37 | 38 | // ------------------------------------------------ 39 | #else 40 | #error "Unsupported MCU" 41 | #endif 42 | 43 | 44 | // ------------------------------------------------ 45 | // GPIO definition 46 | #define GPIO(p,n,flags) ((((p)-'A') << 8) | (n) | (flags)) 47 | 48 | #define GPIO_F_ACTLOW (1 << 16) 49 | 50 | // GPIO access 51 | #define GPIOx(pn) ((GPIO_TypeDef*) (GPIOA_BASE + (pn) * (GPIOB_BASE - GPIOA_BASE))) 52 | #define PORTN(gpio) ((gpio) >> 8 & 0xff) 53 | #define PORT(gpio) GPIOx(PORTN(gpio)) 54 | #define PIN(gpio) ((gpio) & 0xff) 55 | 56 | #define SET_PIN(gpio, state) do { \ 57 | PORT(gpio)->BSRR |= (1 << (PIN(gpio) + ((state) ? 0 : 16))); \ 58 | } while (0) 59 | 60 | #define GPIO_ENABLE(p) do { GPIO_RCC_ENR |= GPIO_RCC_ENB(p); } while (0) 61 | #define GPIO_DISABLE(p) do { GPIO_RCC_ENR &= ~GPIO_RCC_ENB(p); } while (0) 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /src/arm/stm32lx/bootloader_impl.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016-2019 Semtech (International) AG. All rights reserved. 2 | // 3 | // This file is subject to the terms and conditions defined in file 'LICENSE', 4 | // which is part of this source code package. 5 | 6 | #ifndef _bootloader_impl_h_ 7 | #define _bootloader_impl_h_ 8 | 9 | #include "bootloader.h" 10 | #include "boottab.h" 11 | 12 | // Convert pointer to Thumb function (set least-significant bit) 13 | #define THUMB_FUNC(p) ((void*) (((intptr_t) (p)) | 1)) 14 | 15 | extern uint32_t _ebl; 16 | #define BOOT_FW_BASE ((uint32_t) (&_ebl)) 17 | 18 | #define BOOT_CONFIG_BASE DATA_EEPROM_BASE // XXX 19 | #define BOOT_CONFIG_SZ 64 // XXX 20 | 21 | 22 | // ------------------------------------------------ 23 | // Bootloader configuration 24 | 25 | typedef struct { 26 | uint32_t fwupdate1; // 0x00 pointer to valid update 27 | uint32_t fwupdate2; // 0x04 pointer to valid update 28 | hash32 hash; // 0x08 SHA-256 hash of valid update 29 | 30 | uint8_t rfu[24]; // 0x28 RFU 31 | } boot_config; 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/arm/stm32lx/boottab.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016-2019 Semtech (International) AG. All rights reserved. 2 | // 3 | // This file is subject to the terms and conditions defined in file 'LICENSE', 4 | // which is part of this source code package. 5 | 6 | #ifndef _boottab_h_ 7 | #define _boottab_h_ 8 | 9 | #include "bootloader.h" 10 | 11 | // Bootloader information table on STM32 12 | 13 | typedef struct { 14 | uint32_t version; // version of boot loader (values below 256 are reserved for legacy bootloaders) 15 | 16 | __attribute__((noreturn)) 17 | void (*panic) (uint32_t reason, uint32_t addr); // bootloader panic function 18 | 19 | uint32_t (*update) (void* ptr, hash32* hash); // function to set firmware update pointer 20 | 21 | uint32_t (*crc32) (void* buf, uint32_t nwords); // calculate CRC32 22 | 23 | void (*wr_flash) (uint32_t* dst, const uint32_t* src, // write flash 24 | uint32_t nwords, bool erase); 25 | 26 | void (*sha256) (uint32_t* hash, // SHA-256 27 | const uint8_t* msg, uint32_t len); 28 | } boot_boottab; 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /src/arm/stm32lx/ld/STM32L0.ld: -------------------------------------------------------------------------------- 1 | _estack = ORIGIN(RAM) + LENGTH(RAM); 2 | _ebl = ORIGIN(BLFLASH) + LENGTH(BLFLASH); 3 | 4 | SECTIONS { 5 | .boot : { 6 | . = ALIGN(4); 7 | KEEP(*(.boot.isr_vector)) 8 | . = ALIGN(4); 9 | *(.boot*) 10 | *(.text*) 11 | *(.rodata*) 12 | } >BLFLASH 13 | } 14 | -------------------------------------------------------------------------------- /src/arm/stm32lx/ld/STM32L0xx8.ld: -------------------------------------------------------------------------------- 1 | MEMORY { 2 | RAM(xrw) : ORIGIN = 0x20000000, LENGTH = 8K 3 | BLFLASH(rx) : ORIGIN = 0x08000000, LENGTH = 12K 4 | FWFLASH(rx) : ORIGIN = 0x08000000 + 12K, LENGTH = 64K - 12K 5 | } 6 | -------------------------------------------------------------------------------- /src/arm/stm32lx/ld/STM32L0xxB.ld: -------------------------------------------------------------------------------- 1 | MEMORY { 2 | RAM(xrw) : ORIGIN = 0x20000000, LENGTH = 20K 3 | BLFLASH(rx) : ORIGIN = 0x08000000, LENGTH = 12K 4 | FWFLASH(rx) : ORIGIN = 0x08000000 + 12K, LENGTH = 128K - 12K 5 | } 6 | -------------------------------------------------------------------------------- /src/arm/stm32lx/ld/STM32L0xxZ.ld: -------------------------------------------------------------------------------- 1 | MEMORY { 2 | RAM(xrw) : ORIGIN = 0x20000000, LENGTH = 20K 3 | BLFLASH(rx) : ORIGIN = 0x08000000, LENGTH = 12K 4 | FWFLASH(rx) : ORIGIN = 0x08000000 + 12K, LENGTH = 192K - 12K 5 | } 6 | -------------------------------------------------------------------------------- /src/arm/stm32lx/startup.S: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016-2019 Semtech (International) AG. All rights reserved. 2 | // 3 | // This file is subject to the terms and conditions defined in file 'LICENSE', 4 | // which is part of this source code package. 5 | 6 | #include "bootloader.h" 7 | 8 | // -------------------------------------------- 9 | // assembler settings 10 | .syntax unified 11 | .thumb 12 | 13 | 14 | // -------------------------------------------- 15 | // Max. number of IRQn 16 | #if defined(STM32L0) 17 | #define MAX_IRQn 32 /* see PM0223, 2.3.4, pg. 29 */ 18 | #elif defined(STM32L1) 19 | #define MAX_IRQn 68 /* see PM0056, 2.3.4, pg. 36 */ 20 | #else 21 | #error "Unsupported MCU" 22 | #endif 23 | 24 | 25 | // -------------------------------------------- 26 | // interrupt vector 27 | .section .boot.isr_vector,"a",%progbits 28 | .type isr_vector, %object 29 | isr_vector: 30 | .word _estack 31 | .word reset_handler 32 | 33 | .rept 14 34 | .word default_handler 35 | .endr 36 | 37 | .rept MAX_IRQn 38 | .word default_handler 39 | .endr 40 | 41 | .size isr_vector, .-isr_vector 42 | 43 | 44 | // -------------------------------------------- 45 | // default handler 46 | .section .boot.default_handler,"ax",%progbits 47 | .thumb_func 48 | default_handler: 49 | movs r0, #4 50 | mov r1, lr 51 | tst r0, r1 52 | bne 1f 53 | mrs r2, msp 54 | b 2f 55 | 1: mrs r2, psp 56 | 2: ldr r2, [r2, #0x18] // return address 57 | movs r0, BOOT_PANIC_TYPE_EXCEPTION 58 | mrs r1, ipsr // exception number 59 | b boot_panic 60 | 61 | .size default_handler, .-default_handler 62 | 63 | 64 | // -------------------------------------------- 65 | // reset handler (entry point) 66 | .section .boot.reset_handler,"ax",%progbits 67 | .thumb_func 68 | reset_handler: 69 | ldr r0, =_estack 70 | mov sp, r0 71 | 72 | // call boot loader 73 | bl bootloader 74 | 75 | // call entry point (returned from boot loader) 76 | mov r1, r0 77 | ldr r0, =boottab 78 | mov lr, pc 79 | mov pc, r1 80 | 81 | // should not be reached 82 | movs r0, BOOT_PANIC_TYPE_BOOTLOADER 83 | movs r1, BOOT_PANIC_REASON_FWRETURN 84 | movs r2, #0 // no return address 85 | b boot_panic 86 | 87 | .size reset_handler, .-reset_handler 88 | -------------------------------------------------------------------------------- /src/arm/stm32lx/util.S: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016-2019 Semtech (International) AG. All rights reserved. 2 | // 3 | // This file is subject to the terms and conditions defined in file 'LICENSE', 4 | // which is part of this source code package. 5 | 6 | #include "bootloader.h" 7 | 8 | // -------------------------------------------- 9 | // assembler settings 10 | .syntax unified 11 | .thumb 12 | 13 | 14 | // -------------------------------------------- 15 | // void delay (uint32_t length) 16 | .section .boot.delay,"ax",%progbits 17 | .thumb_func 18 | delay: 19 | lsls r0, r0, #16 20 | 1: subs r0, #1 21 | bne 1b 22 | bx lr 23 | 24 | .size delay, .-delay 25 | .global delay 26 | 27 | 28 | // -------------------------------------------- 29 | // void wr_fl_hp (uint32_t* dst, const uint32_t* src) 30 | // write flash half-page (DO NOT CALL DIRECTLY!) 31 | // r0: dst*, r1: src*, r2-r5: scratch 32 | .section .boot.wr_fl_hp,"ax",%progbits 33 | wr_fl_hp_begin: 34 | .thumb_func 35 | wr_fl_hp: 36 | push {r4-r5, lr} 37 | // copy aligned data from src (RAM) to dst (FLASH) 38 | ldmia r1!, {r2-r5} 39 | stmia r0!, {r2-r5} 40 | ldmia r1!, {r2-r5} 41 | stmia r0!, {r2-r5} 42 | ldmia r1!, {r2-r5} 43 | stmia r0!, {r2-r5} 44 | ldmia r1!, {r2-r5} 45 | stmia r0!, {r2-r5} 46 | // wait for flash busy flag to clear 47 | ldr r0, 2f 48 | 1: ldr r1, [r0, #24] 49 | lsls r1, r1, #31 50 | bmi 1b 51 | // return 52 | pop {r4-r5, pc} 53 | .p2align(2) 54 | 2: .word 0x40022000 55 | wr_fl_hp_end: 56 | 57 | .size wr_fl_hp_begin, .-wr_fl_hp_begin 58 | .global wr_fl_hp_begin 59 | .global wr_fl_hp_end 60 | -------------------------------------------------------------------------------- /src/arm/unicorn/bootloader.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016-2019 Semtech (International) AG. All rights reserved. 2 | // 3 | // This file is subject to the terms and conditions defined in file 'LICENSE', 4 | // which is part of this source code package. 5 | 6 | #include 7 | 8 | #include "update.h" 9 | #include "boottab.h" 10 | #include "sha2.h" 11 | 12 | 13 | // ------------------------------------------------ 14 | // Memory 15 | 16 | extern uint32_t _estack; 17 | extern uint32_t _ebl; 18 | 19 | #define RAM_BASE 0x10000000 20 | #define RAM_SIZE (16 * 1024) 21 | #define FLASH_BASE 0x20000000 22 | #define FLASH_SIZE (128 * 1024) 23 | #define EEPROM_BASE 0x30000000 24 | #define EEPROM_SIZE (8 * 1024) 25 | 26 | #define FLASH_PAGE_SZ 128 27 | #define ROUND_PAGE_SZ(sz) (((sz) + (FLASH_PAGE_SZ - 1)) & ~(FLASH_PAGE_SZ - 1)) 28 | #define ISMULT_PAGE_SZ(sz) (((sz) & (FLASH_PAGE_SZ - 1)) == 0) 29 | 30 | #define FW_BASE ((uint32_t) (&_ebl)) 31 | #define CONFIG_BASE EEPROM_BASE 32 | 33 | 34 | // ------------------------------------------------ 35 | // CRC-32 36 | 37 | static void crc32 (uint32_t* pcrc, unsigned char* buf, uint32_t len) { 38 | int i; 39 | uint32_t byte, crc, mask; 40 | 41 | crc = ~(*pcrc); 42 | while (len-- != 0) { 43 | byte = *buf++; 44 | crc = crc ^ byte; 45 | for (i = 7; i >= 0; i--) { 46 | mask = -(crc & 1); 47 | crc = (crc >> 1) ^ (0xEDB88320 & mask); 48 | } 49 | } 50 | *pcrc = ~crc; 51 | } 52 | 53 | static uint32_t boot_crc32 (void* buf, uint32_t nwords) { 54 | uint32_t crc = 0; 55 | crc32(&crc, buf, nwords * 4); 56 | return crc; 57 | } 58 | 59 | 60 | // ------------------------------------------------ 61 | // Panic 62 | 63 | static void svc (uint32_t id, uint32_t p1, uint32_t p2, uint32_t p3); // fwd decl 64 | 65 | __attribute__((noreturn, naked, noinline)) 66 | static void fw_panic (uint32_t reason, uint32_t addr) { 67 | svc(BOOT_SVC_PANIC, BOOT_PANIC_TYPE_FIRMWARE, reason, addr); 68 | __builtin_unreachable(); 69 | } 70 | 71 | __attribute__((noreturn, naked, noinline)) 72 | static void boot_panic (uint32_t reason) { 73 | svc(BOOT_SVC_PANIC, BOOT_PANIC_TYPE_BOOTLOADER, reason, 0); 74 | __builtin_unreachable(); 75 | } 76 | 77 | 78 | // ------------------------------------------------ 79 | // Supervisor call 80 | 81 | __attribute__((naked, noinline)) 82 | static void svc (uint32_t id, uint32_t p1, uint32_t p2, uint32_t p3) { 83 | asm("svc 0"); 84 | // SVC call should not return, but might if not handled correctly 85 | boot_panic(0xdeadbeef); 86 | } 87 | 88 | 89 | // ------------------------------------------------ 90 | // Flash functions 91 | 92 | void wr_flash (uint32_t* dst, const uint32_t* src, uint32_t nwords, bool erase) { 93 | if( ((uintptr_t) dst & 3) == 0 ) { 94 | while( nwords > 0 ) { 95 | if( erase && (((uintptr_t) dst) & (FLASH_PAGE_SZ-1)) == 0 96 | && (uintptr_t) dst >= FLASH_BASE && (uintptr_t) dst < (FLASH_BASE + FLASH_SIZE) ) { 97 | memset(dst, 0, FLASH_PAGE_SZ); 98 | } 99 | int wtw; 100 | if( nwords > (FLASH_PAGE_SZ >> 2)) { 101 | wtw = (FLASH_PAGE_SZ >> 2); 102 | } else { 103 | wtw = nwords; 104 | } 105 | if( src ) { 106 | memcpy(dst, src, wtw << 2); 107 | src += wtw; 108 | } 109 | dst += wtw; 110 | nwords -= wtw; 111 | } 112 | } 113 | } 114 | 115 | 116 | // ------------------------------------------------ 117 | // Update glue functions 118 | 119 | typedef struct { 120 | boot_uphdr* fwup; 121 | bool unlocked; 122 | } up_ctx; 123 | 124 | uint32_t up_install_init (void* ctx, uint32_t fwsize, void** pfwdst, uint32_t tmpsize, void** ptmpdst, boot_fwhdr** pcurrentfw) { 125 | up_ctx* uc = ctx; 126 | if (!ISMULT_PAGE_SZ(fwsize) || fwsize > ((uintptr_t) uc->fwup - FW_BASE)) { 127 | // new firmware is not multiple of page size or would overwrite update 128 | return BOOT_E_SIZE; 129 | } 130 | 131 | // assume dependency on current firmware when temp storage is requested 132 | if (tmpsize) { 133 | boot_fwhdr* fwhdr = (boot_fwhdr*) FW_BASE; 134 | uint32_t fwmax = (fwsize > fwhdr->size) ? fwsize : fwhdr->size; 135 | if (!ISMULT_PAGE_SZ(tmpsize) || fwmax + ROUND_PAGE_SZ(tmpsize) > ((uintptr_t) uc->fwup - FW_BASE)) { 136 | return BOOT_E_SIZE; 137 | } 138 | } 139 | 140 | // set installation address for new firmware 141 | *pfwdst = (void*) FW_BASE; 142 | 143 | // set address for temporary storage 144 | if (tmpsize && ptmpdst) { 145 | *ptmpdst = (unsigned char*) uc->fwup - tmpsize; 146 | } 147 | 148 | // set pointer to current firmware header 149 | if (pcurrentfw) { 150 | *pcurrentfw = (boot_fwhdr*) FW_BASE; 151 | } 152 | 153 | return BOOT_OK; 154 | } 155 | 156 | void up_flash_wr_page (void* ctx, void* dst, void* src) { 157 | up_ctx* uc = ctx; 158 | if( uc->unlocked ) { 159 | wr_flash(dst, src, FLASH_PAGE_SZ >> 2, true); 160 | } 161 | } 162 | 163 | void up_flash_unlock (void* ctx) { 164 | up_ctx* uc = ctx; 165 | uc->unlocked = true; 166 | } 167 | 168 | void up_flash_lock (void* ctx) { 169 | up_ctx* uc = ctx; 170 | uc->unlocked = false; 171 | } 172 | 173 | static void ee_write (uint32_t* dst, uint32_t val) { 174 | if( (uintptr_t) dst >= EEPROM_BASE && (uintptr_t) dst < (EEPROM_BASE + EEPROM_SIZE) ) { 175 | *dst = val; 176 | } 177 | } 178 | 179 | // ------------------------------------------------ 180 | // Update functions 181 | 182 | typedef struct { 183 | uint32_t fwupdate1; // 0x00 pointer to valid update 184 | uint32_t fwupdate2; // 0x04 pointer to valid update 185 | hash32 hash; // 0x08 SHA-256 hash of valid update 186 | 187 | uint8_t rfu[24]; // 0x28 RFU 188 | } boot_config; 189 | 190 | static void do_install (boot_uphdr* fwup) { 191 | up_ctx uc = { 192 | .fwup = fwup, 193 | }; 194 | if (update(&uc, fwup, true) != BOOT_OK) { 195 | boot_panic(BOOT_PANIC_REASON_UPDATE); 196 | } 197 | } 198 | 199 | static bool check_update (boot_uphdr* fwup) { 200 | uint32_t flash_sz = FLASH_SIZE; 201 | 202 | return ( ((intptr_t) fwup & 3) == 0 203 | && (intptr_t) fwup >= FLASH_BASE 204 | && sizeof(boot_uphdr) <= flash_sz - ((intptr_t) fwup - FLASH_BASE) 205 | && fwup->size >= sizeof(boot_uphdr) 206 | && (fwup->size & 3) == 0 207 | && fwup->size <= flash_sz - ((intptr_t) fwup - FLASH_BASE) 208 | && boot_crc32(((unsigned char*) fwup) + 8, (fwup->size - 8) >> 2) == fwup->crc 209 | && true /* TODO hardware id match */ ); 210 | } 211 | 212 | static uint32_t set_update (void* ptr, hash32* hash) { 213 | uint32_t rv; 214 | if( ptr == NULL ) { 215 | rv = BOOT_OK; 216 | } else { 217 | up_ctx uc = { 218 | .fwup = ptr, 219 | }; 220 | rv = check_update((boot_uphdr*) ptr) ? update(&uc, ptr, false) : BOOT_E_SIZE; 221 | } 222 | if( rv == BOOT_OK ) { 223 | boot_config* cfg = (boot_config*) CONFIG_BASE; 224 | if( hash ) { 225 | for( int i = 0; i < 8; i++ ) { 226 | ee_write(&cfg->hash.w[i], hash->w[i]); 227 | } 228 | } 229 | // set update pointer 230 | ee_write(&cfg->fwupdate1, (uint32_t) ptr); 231 | ee_write(&cfg->fwupdate2, (uint32_t) ptr); 232 | } 233 | return rv; 234 | } 235 | 236 | 237 | // ------------------------------------------------ 238 | // Bootloader information table 239 | 240 | static const boot_boottab boottab = { 241 | .version = 0x108, 242 | .update = set_update, 243 | .panic = fw_panic, 244 | .crc32 = boot_crc32, 245 | .svc = svc, 246 | .wr_flash = wr_flash, 247 | .sha256 = sha256, 248 | }; 249 | 250 | // ------------------------------------------------ 251 | // Bootloader main entry point 252 | 253 | void* bootloader (void) { 254 | boot_fwhdr* fwh = (boot_fwhdr*) FW_BASE; 255 | boot_config* cfg = (boot_config*) CONFIG_BASE; 256 | 257 | // check presence and integrity of firmware update 258 | if (cfg->fwupdate1 == cfg->fwupdate2) { 259 | boot_uphdr* fwup = (boot_uphdr*) cfg->fwupdate1; 260 | if (fwup != NULL && check_update(fwup)) { 261 | do_install(fwup); 262 | } 263 | } 264 | 265 | // verify integrity of current firmware 266 | if (fwh->size < sizeof(boot_fwhdr) 267 | || fwh->size > (FLASH_SIZE - (FW_BASE - FLASH_BASE)) 268 | || boot_crc32(((unsigned char*) fwh) + 8, (fwh->size - 8) >> 2) != fwh->crc) { 269 | boot_panic(BOOT_PANIC_REASON_CRC); 270 | } 271 | 272 | // clear fwup pointer in EEPROM if set 273 | if (cfg->fwupdate1 != 0 || cfg->fwupdate2 != 0) { 274 | set_update(NULL, NULL); 275 | } 276 | 277 | // call entry point 278 | ((void (*) (const boot_boottab*)) fwh->entrypoint)(&boottab); 279 | 280 | // not reached 281 | boot_panic(BOOT_PANIC_REASON_FWRETURN); 282 | } 283 | 284 | 285 | // ------------------------------------------------ 286 | // Bootloader header 287 | 288 | __attribute__((section(".boot.header"))) const struct { 289 | uint32_t init_sp; 290 | uint32_t init_pc; 291 | } boothdr = { 292 | .init_sp = (uint32_t) &_estack, 293 | .init_pc = (uint32_t) bootloader, 294 | }; 295 | -------------------------------------------------------------------------------- /src/arm/unicorn/bootloader_impl.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016-2019 Semtech (International) AG. All rights reserved. 2 | // 3 | // This file is subject to the terms and conditions defined in file 'LICENSE', 4 | // which is part of this source code package. 5 | 6 | #ifndef _bootloader_impl_h_ 7 | #define _bootloader_impl_h_ 8 | 9 | #include "bootloader.h" 10 | #include "boottab.h" 11 | 12 | extern uint32_t _ebl; 13 | #define BOOT_FW_BASE ((uint32_t) (&_ebl)) 14 | 15 | #define BOOT_CONFIG_BASE 0x30000000 16 | #define BOOT_CONFIG_SZ 64 17 | 18 | 19 | // ------------------------------------------------ 20 | // Bootloader configuration 21 | 22 | typedef struct { 23 | uint32_t fwupdate1; // 0x00 pointer to valid update 24 | uint32_t fwupdate2; // 0x04 pointer to valid update 25 | hash32 hash; // 0x08 SHA-256 hash of valid update 26 | 27 | uint8_t rfu[24]; // 0x28 RFU 28 | } boot_config; 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /src/arm/unicorn/boottab.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016-2019 Semtech (International) AG. All rights reserved. 2 | // 3 | // This file is subject to the terms and conditions defined in file 'LICENSE', 4 | // which is part of this source code package. 5 | 6 | #ifndef _boottab_h_ 7 | #define _boottab_h_ 8 | 9 | #include "bootloader.h" 10 | 11 | // Bootloader information table on unicorn 12 | 13 | typedef struct { 14 | uint32_t version; // version of boot loader 15 | __attribute__((noreturn)) 16 | void (*panic) (uint32_t reason, uint32_t addr); // bootloader panic function 17 | uint32_t (*update) (void* ptr, hash32* hash); // function to set firmware update pointer 18 | uint32_t (*crc32) (void* buf, uint32_t nwords); // calculate CRC32 19 | void* svc; // supervisor call 20 | void (*wr_flash) (uint32_t* dst, const uint32_t* src, // write flash 21 | uint32_t nwords, bool erase); 22 | void (*sha256) (uint32_t* hash, // SHA-256 23 | const uint8_t* msg, uint32_t len); 24 | } boot_boottab; 25 | 26 | 27 | // Supervisor call IDs 28 | 29 | enum { 30 | BOOT_SVC_PANIC, // panic: p1=type, p2=reason, p3=addr 31 | 32 | BOOT_SVC_FWBASE = 0x80 // all supervisor call ids below are reserved for bootloader 33 | }; 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /src/arm/unicorn/ld/bootloader.ld: -------------------------------------------------------------------------------- 1 | _estack = ORIGIN(RAM) + LENGTH(RAM); 2 | _ebl = ORIGIN(BLFLASH) + LENGTH(BLFLASH); 3 | 4 | SECTIONS { 5 | .boot : { 6 | . = ALIGN(4); 7 | KEEP(*(.boot.header)) 8 | . = ALIGN(4); 9 | *(.boot*) 10 | *(.text*) 11 | *(.rodata*) 12 | } >BLFLASH 13 | } 14 | -------------------------------------------------------------------------------- /src/arm/unicorn/ld/mem.ld: -------------------------------------------------------------------------------- 1 | MEMORY { 2 | RAM(xrw) : ORIGIN = 0x10000000, LENGTH = 16K 3 | BLFLASH(rx) : ORIGIN = 0x20000000, LENGTH = 4K 4 | FWFLASH(rx) : ORIGIN = 0x20000000 + 4K, LENGTH = 128K - 4K 5 | } 6 | -------------------------------------------------------------------------------- /src/common/.gitignore: -------------------------------------------------------------------------------- 1 | sha2test 2 | -------------------------------------------------------------------------------- /src/common/Makefile: -------------------------------------------------------------------------------- 1 | sha2test: sha2.c 2 | gcc -DSHA2_TEST $< -o $@ 3 | 4 | 5 | clean: 6 | rm -f *.o sha2test 7 | 8 | .PHONY: clean 9 | -------------------------------------------------------------------------------- /src/common/bootloader.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016-2019 Semtech (International) AG. All rights reserved. 2 | // 3 | // This file is subject to the terms and conditions defined in file 'LICENSE', 4 | // which is part of this source code package. 5 | 6 | #ifndef _bootloader_h_ 7 | #define _bootloader_h_ 8 | 9 | 10 | // This is the public "API" of the bootloader, 11 | // i.e. the way the firmware and outside world 12 | // interact with it. Since a bootloader doesn't 13 | // change once installed and deployed, utmost 14 | // care must be taken when modifying this API! 15 | 16 | 17 | // Panic types 18 | #define BOOT_PANIC_TYPE_EXCEPTION 0 // Exception handler 19 | #define BOOT_PANIC_TYPE_BOOTLOADER 1 // Bootloader (reason codes see below) 20 | #define BOOT_PANIC_TYPE_FIRMWARE 2 // Firmware (reason codes are application defined) 21 | 22 | 23 | // Panic reason codes for type bootloader 24 | #define BOOT_PANIC_REASON_FWRETURN 0 // firmware returned unexpectedly 25 | #define BOOT_PANIC_REASON_CRC 1 // firmware CRC verification failed 26 | #define BOOT_PANIC_REASON_FLASH 2 // error writing flash 27 | #define BOOT_PANIC_REASON_UPDATE 3 // error updating firmware 28 | 29 | 30 | // Update type codes 31 | #define BOOT_UPTYPE_PLAIN 0 // plain update 32 | #define BOOT_UPTYPE_LZ4 1 // lz4-compressed self-contained update 33 | #define BOOT_UPTYPE_LZ4DELTA 2 // lz4-compressed block-delta update 34 | 35 | 36 | // Magic numbers 37 | #define BOOT_MAGIC_SIZE 0xff1234ff // place-holder for firmware size 38 | 39 | 40 | #ifndef ASSEMBLY 41 | 42 | #include 43 | #include 44 | #include 45 | 46 | 47 | // Bootloader return values (don't change values!) 48 | enum { 49 | BOOT_OK, 50 | BOOT_E_GENERAL, // general error 51 | BOOT_E_NOIMPL, // not implemented error 52 | BOOT_E_SIZE, // size error 53 | }; 54 | 55 | 56 | // SHA-256 hash 57 | typedef union { 58 | uint8_t b[32]; 59 | uint32_t w[8]; 60 | } hash32; 61 | 62 | _Static_assert(sizeof(hash32) == 32, "sizeof(hash32) must be 32"); 63 | 64 | 65 | // Firmware header 66 | typedef struct { 67 | uint32_t crc; // firmware CRC 68 | uint32_t size; // firmware size (in bytes, including this header) 69 | /* -- everything below until end (size-8) is included in CRC -- */ 70 | uint32_t entrypoint; // address of entrypoint 71 | } boot_fwhdr; 72 | 73 | _Static_assert(sizeof(boot_fwhdr) == 12, "sizeof(boot_fwhdr) must be 12"); 74 | 75 | 76 | // Hardware identifier (EUI-48, native byte order) 77 | typedef union { 78 | struct __attribute__((packed)) { 79 | uint32_t a; 80 | uint16_t b; 81 | }; 82 | uint8_t bytes[6]; 83 | } eui48; 84 | 85 | _Static_assert(sizeof(eui48) == 6, "sizeof(eui48) must be 6"); 86 | 87 | static inline uint64_t eui2int (eui48* eui) { 88 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 89 | return ((uint64_t) eui->b << 32) | eui->a; 90 | #else 91 | return ((uint64_t) eui->a << 16) | eui->b; 92 | #endif 93 | } 94 | 95 | 96 | // Update header 97 | typedef struct { 98 | uint32_t crc; // update CRC 99 | uint32_t size; // update size (in bytes, including this header) 100 | /* -- everything below until end (size-8) is included in CRC -- */ 101 | uint32_t fwcrc; // firmware CRC (once unpacked) 102 | uint32_t fwsize; // firmware size (in bytes, including header) 103 | eui48 hwid; // hardware target 104 | uint8_t uptype; // update type 105 | uint8_t rfu; // RFU 106 | } boot_uphdr; 107 | 108 | _Static_assert(sizeof(boot_uphdr) == 24, "sizeof(boot_uphdr) must be 24"); 109 | 110 | // Update delta header 111 | typedef struct { 112 | uint32_t refcrc; // referenced firmware CRC 113 | uint32_t refsize; // referenced firmware size 114 | uint32_t blksize; // block size (multiple of flash page size, e.g. 4096) 115 | } boot_updeltahdr; 116 | 117 | _Static_assert(sizeof(boot_updeltahdr) == 12, "sizeof(boot_updeltahdr) must be 12"); 118 | 119 | // Update delta block 120 | typedef struct __attribute__((packed)) { 121 | uint32_t hash[2]; // block hash (sha256[0-7]) 122 | uint8_t blkidx; // block number 123 | uint8_t dictidx; // dictionary block number 124 | uint16_t dictlen; // length of dictionary data (in bytes) 125 | uint16_t lz4len; // length of lz4-compressed block data (in bytes, up to block size) 126 | uint8_t lz4data[]; // lz4-compressed block data 127 | } boot_updeltablk; 128 | 129 | _Static_assert(sizeof(boot_updeltablk) == 14, "sizeof(boot_updeltablk) must be 14"); 130 | 131 | #endif 132 | #endif 133 | -------------------------------------------------------------------------------- /src/common/lz4.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016-2019 Semtech (International) AG. All rights reserved. 2 | // 3 | // This file is subject to the terms and conditions defined in file 'LICENSE', 4 | // which is part of this source code package. 5 | 6 | // The same code can be used for bootloader, 7 | // mkupdate tool, or standalone test 8 | 9 | #include 10 | #include "lz4.h" 11 | #include "update.h" 12 | 13 | 14 | // ------------------------------------------------ 15 | // LZ4 decompression function with flash writing 16 | // and page-buffer support 17 | 18 | #ifdef LZ4_PAGEBUFFER_SZ 19 | #if ((LZ4_PAGEBUFFER_SZ & 3) != 0) || ((LZ4_PAGEBUFFER_SZ & (LZ4_PAGEBUFFER_SZ - 1)) != 0) 20 | #error "LZ4_PAGEBUFFER_SZ must be a multiple of 4 and a power of 2" 21 | #endif 22 | #endif 23 | 24 | typedef struct { 25 | unsigned char* dst; 26 | int dstlen; 27 | unsigned char* dictend; 28 | #ifdef LZ4_PAGEBUFFER_SZ 29 | uint32_t pagebuf[LZ4_PAGEBUFFER_SZ / 4]; 30 | void* ctx; 31 | #endif 32 | } lz4state; 33 | 34 | // store byte in output buffer (negative b is match offset, else literal) 35 | // auto-flush buffer on page boundaries 36 | static void putbyte (lz4state* z, int b) { 37 | #ifdef LZ4_PAGEBUFFER_SZ 38 | int pageoff = z->dstlen & (LZ4_PAGEBUFFER_SZ - 1); 39 | // check for match reference 40 | if (b < 0) { // use referenced byte at distance 1..65535 41 | b = (pageoff+b >= 0) ? 42 | ((unsigned char*) z->pagebuf)[pageoff + b] : // referenced byte in page buffer 43 | ((z->dstlen + b < 0) ? z->dictend[z->dstlen + b] : z->dst[z->dstlen + b]); // referenced byte in dict or in previous output 44 | } 45 | // store byte in page buffer 46 | ((unsigned char*) z->pagebuf)[pageoff] = (unsigned char) b; 47 | // flush page when last byte is set 48 | if (pageoff == (LZ4_PAGEBUFFER_SZ - 1)) { 49 | // z->dst+z->dstlen still points to current page! 50 | up_flash_wr_page(z->ctx, (z->dst + (z->dstlen & ~(LZ4_PAGEBUFFER_SZ - 1))), z->pagebuf); 51 | } 52 | #else 53 | z->dst[z->dstlen] = (b < 0) ? ((z->dstlen + b < 0) ? z->dictend[z->dstlen + b] : z->dst[z->dstlen + b]) : (unsigned char) b; 54 | #endif 55 | z->dstlen++; 56 | } 57 | 58 | // decompress from src to dst optionally using dict, return uncompressed size 59 | // depending on configuration the uncompressed data is written directly or 60 | // buffered to ram, or buffered to flash 61 | // if buffering is used, the last page will be padded with FF 62 | int lz4_decompress (void* ctx, unsigned char* src, int srclen, unsigned char* dst, unsigned char* dict, int dictlen) { 63 | unsigned char* srcend = src + srclen; 64 | lz4state z; 65 | 66 | // init state 67 | z.dst = dst; 68 | z.dstlen = 0; 69 | z.dictend = dict + dictlen; 70 | #ifdef LZ4_PAGEBUFFER_SZ 71 | z.ctx = ctx; 72 | #endif 73 | 74 | // decode sequences 75 | while (src < srcend) { 76 | // get token 77 | unsigned char token = *src++; 78 | // get literal length 79 | int l, len = token >> 4; 80 | if (len == 15) do { l = *src++; len += l; } while (l == 255); 81 | // copy literals 82 | while (len--) { 83 | putbyte(&z, *src++); 84 | } 85 | if (src < srcend) { // last sequence is incomplete and stops after the literals 86 | // get offset 87 | int offset = *src++; 88 | offset = (*src++ << 8) | offset; // 16-bit LSB-first 89 | // get match length 90 | len = token & 0x0F; 91 | if (len == 15) do { l = *src++; len += l; } while(l == 255); 92 | len += 4; // minmatch 93 | // copy matches from output stream or from dict 94 | while (len--) { 95 | putbyte(&z, -offset); 96 | } 97 | } 98 | } 99 | 100 | // fill and flush last page 101 | int n = z.dstlen; 102 | #ifdef LZ4_PAGEBUFFER_SZ 103 | while (z.dstlen & (LZ4_PAGEBUFFER_SZ - 1)) { 104 | putbyte(&z, 0xFF); 105 | } 106 | #endif 107 | return n; 108 | } 109 | 110 | 111 | #ifdef LZ4_standalone 112 | // ------------------------------------------------ 113 | // Standalone test program 114 | // gcc lz4.c -DLZ4_standalone -DLZ4_compress -o lz4 -llz4 -Wall 115 | 116 | #include 117 | #include 118 | 119 | // compress src buffer to dst buffer optionally using dict buffer, return compressed size 120 | int lz4_compress (unsigned char* src, int srclen, unsigned char* dict, int dictlen, unsigned char* dst, int dstlen) { 121 | unsigned char buf[srclen+64]; 122 | LZ4_streamHC_t* lz4; 123 | 124 | // init LZ4 stream 125 | if( (lz4 = LZ4_createStreamHC()) == NULL ) { 126 | return -1; 127 | } 128 | LZ4_resetStreamHC(lz4, 9); 129 | 130 | // set dictionary 131 | if(dictlen) { 132 | LZ4_loadDictHC(lz4, (char*)dict, dictlen); 133 | } 134 | 135 | // compress 136 | dstlen = LZ4_compress_HC_continue(lz4, (char*)src, (char*)dst, srclen, dstlen); 137 | LZ4_freeStreamHC(lz4); 138 | 139 | // verify 140 | int len = lz4_decompress(dst, dstlen, buf, dict, dictlen); 141 | if(len != srclen || memcmp(buf, src, srclen) != 0) { 142 | return -1; 143 | } 144 | 145 | return dstlen; 146 | } 147 | 148 | // static buffers 149 | static unsigned char data[1024*1024], dict[1024*1024], zdata[1024*1024]; 150 | 151 | int main (int argc, char **argv) { 152 | int datalen, dictlen = 0, zlen; 153 | FILE *fp; 154 | 155 | // check usage 156 | if (argc < 3) { 157 | printf("usage %s: []\n", argv[0]); 158 | return 1; 159 | } 160 | 161 | // load input file 162 | if ((fp = fopen(argv[1], "rb")) == NULL) { 163 | printf("can't open input file '%s'\n", argv[1]); 164 | return 1; 165 | } 166 | datalen = fread(data, 1, sizeof(data), fp); 167 | if (!feof(fp)) { 168 | printf("input file too large!\n"); 169 | fclose(fp); 170 | return 1; 171 | } 172 | fclose(fp); 173 | printf("input file '%s': %d bytes\n", argv[1], datalen); 174 | 175 | // load dictionary file 176 | if (argc == 4) { 177 | if ((fp = fopen(argv[3], "rb")) == NULL) { 178 | printf("can't open dictionary file '%s'\n", argv[3]); 179 | return 1; 180 | } 181 | dictlen = fread(dict, 1, sizeof(dict), fp); 182 | if (!feof(fp)) { 183 | printf("dictionary file too large!\n"); 184 | fclose(fp); 185 | return 1; 186 | } 187 | fclose(fp); 188 | printf("dictionary file '%s': %d bytes\n", argv[3], dictlen); 189 | } 190 | 191 | // compress with liblz4hc, verify with own decompressor 192 | if ((zlen = lz4_compress(data, datalen, dict, dictlen, zdata, sizeof(zdata))) < 0) { 193 | printf("compression / verification failed!\n"); 194 | return 1; 195 | } 196 | 197 | // write output file 198 | if ((fp = fopen(argv[2], "wb")) == NULL || 199 | fwrite(zdata, zlen, 1, fp) != 1 || 200 | fclose(fp)) { 201 | printf("cannot write output file '%s'\n", argv[2]); 202 | return 1; 203 | } 204 | printf("output file '%s': %d bytes\n", argv[2], zlen); 205 | 206 | // print results 207 | printf("compression: %d / %d = %d%%\n", zlen, datalen, zlen*100/datalen); 208 | return 0; 209 | } 210 | #endif 211 | -------------------------------------------------------------------------------- /src/common/lz4.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016-2019 Semtech (International) AG. All rights reserved. 2 | // 3 | // This file is subject to the terms and conditions defined in file 'LICENSE', 4 | // which is part of this source code package. 5 | 6 | #ifndef _lz4_h_ 7 | #define _lz4_h_ 8 | 9 | int lz4_decompress (void* ctx, unsigned char* src, int srclen, unsigned char* dst, unsigned char* dict, int dictlen); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /src/common/sha2.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016-2019 Semtech (International) AG. All rights reserved. 2 | // 3 | // This file is subject to the terms and conditions defined in file 'LICENSE', 4 | // which is part of this source code package. 5 | 6 | #include 7 | 8 | #include "sha2.h" 9 | 10 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 11 | #define ENDIAN_n2b32(x) __builtin_bswap32(x) 12 | #else 13 | #define ENDIAN_n2b32(x) (x) 14 | #endif 15 | 16 | // ------------------------------------------------ 17 | // SHA-256 18 | 19 | #define ROR(a,b) (((a) >> (b)) | ((a) << (32 - (b)))) 20 | 21 | #define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z))) 22 | #define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) 23 | #define EP0(x) (ROR(x, 2) ^ ROR(x, 13) ^ ROR(x, 22)) 24 | #define EP1(x) (ROR(x, 6) ^ ROR(x, 11) ^ ROR(x, 25)) 25 | #define SIG0(x) (ROR(x, 7) ^ ROR(x, 18) ^ ((x) >> 3)) 26 | #define SIG1(x) (ROR(x, 17) ^ ROR(x, 19) ^ ((x) >> 10)) 27 | 28 | static void sha256_do (uint32_t* state, const uint8_t* block) { 29 | static const uint32_t K[64] = { 30 | 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 31 | 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 32 | 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 33 | 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 34 | 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 35 | 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 36 | 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 37 | 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 38 | 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 39 | 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 40 | 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 41 | 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 42 | 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 43 | 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 44 | 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 45 | 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 46 | }; 47 | 48 | uint32_t a, b, c, d, e, f, g, h, i, j, t1, t2, w[64]; 49 | 50 | for (i = 0, j = 0; i < 16; i++, j += 4) { 51 | w[i] = (block[j] << 24) | (block[j + 1] << 16) | (block[j + 2] << 8) | (block[j + 3]); 52 | } 53 | for ( ; i < 64; i++) { 54 | w[i] = SIG1(w[i - 2]) + w[i - 7] + SIG0(w[i - 15]) + w[i - 16]; 55 | } 56 | 57 | a = state[0]; 58 | b = state[1]; 59 | c = state[2]; 60 | d = state[3]; 61 | e = state[4]; 62 | f = state[5]; 63 | g = state[6]; 64 | h = state[7]; 65 | 66 | for (i = 0; i < 64; i++) { 67 | t1 = h + EP1(e) + CH(e, f, g) + K[i] + w[i]; 68 | t2 = EP0(a) + MAJ(a, b, c); 69 | h = g; 70 | g = f; 71 | f = e; 72 | e = d + t1; 73 | d = c; 74 | c = b; 75 | b = a; 76 | a = t1 + t2; 77 | } 78 | 79 | state[0] += a; 80 | state[1] += b; 81 | state[2] += c; 82 | state[3] += d; 83 | state[4] += e; 84 | state[5] += f; 85 | state[6] += g; 86 | state[7] += h; 87 | } 88 | 89 | #undef ROR 90 | #undef CH 91 | #undef MAJ 92 | #undef EP0 93 | #undef EP1 94 | #undef SIG0 95 | #undef SIG1 96 | 97 | void sha256 (uint32_t* hash, const uint8_t* msg, uint32_t len) { 98 | uint32_t state[8] = { 99 | 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 100 | 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 101 | }; 102 | 103 | uint32_t bitlen = len << 3; 104 | while (1) { 105 | if (len < 64) { 106 | union { 107 | uint8_t bytes[64]; 108 | uint32_t words[16]; 109 | } tmp; 110 | memset(tmp.words, 0, sizeof(tmp)); 111 | memcpy(tmp.bytes, msg, len); 112 | tmp.bytes[len] = 0x80; 113 | if (len < 56) { 114 | last: 115 | tmp.words[15] = ENDIAN_n2b32(bitlen); 116 | sha256_do(state, tmp.bytes); 117 | for (int i = 0; i < 8; i++) { 118 | hash[i] = ENDIAN_n2b32(state[i]); 119 | } 120 | return; 121 | } else { 122 | sha256_do(state, tmp.bytes); 123 | memset(tmp.words, 0, sizeof(tmp)); 124 | goto last; 125 | } 126 | } else { 127 | sha256_do(state, msg); 128 | msg += 64; 129 | len -= 64; 130 | } 131 | } 132 | } 133 | 134 | #ifdef SHA2_TEST 135 | 136 | #include 137 | 138 | static int readfully (int fd, unsigned char* buf, size_t bufsz) { 139 | while( bufsz ) { 140 | ssize_t n = read(fd, buf, bufsz); 141 | if( n <= 0 ) { 142 | return -1; 143 | } 144 | buf += n; 145 | bufsz -= n; 146 | } 147 | return 0; 148 | } 149 | 150 | static int writefully (int fd, unsigned char* buf, size_t bufsz) { 151 | while( bufsz ) { 152 | ssize_t n = write(fd, buf, bufsz); 153 | if( n <= 0 ) { 154 | return -1; 155 | } 156 | buf += n; 157 | bufsz -= n; 158 | } 159 | return 0; 160 | } 161 | 162 | int main (void) { 163 | unsigned char buf[128*1024]; 164 | union { 165 | uint8_t bytes[32]; 166 | uint32_t words[8]; 167 | } hash; 168 | while( 1 ) { 169 | uint32_t sz; 170 | if( readfully(STDIN_FILENO, (unsigned char*) &sz, sizeof(uint32_t)) < 0 171 | || sz > sizeof(buf) 172 | || readfully(STDIN_FILENO, buf, sz) < 0 ) { 173 | break; 174 | } 175 | sha256(hash.words, buf, sz); 176 | writefully(STDOUT_FILENO, hash.bytes, 32); 177 | } 178 | return 0; 179 | } 180 | 181 | #endif 182 | -------------------------------------------------------------------------------- /src/common/sha2.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016-2019 Semtech (International) AG. All rights reserved. 2 | // 3 | // This file is subject to the terms and conditions defined in file 'LICENSE', 4 | // which is part of this source code package. 5 | 6 | #ifndef _sha2_h_ 7 | #define _sha2_h_ 8 | 9 | #include 10 | 11 | void sha256 (uint32_t* hash, const uint8_t* msg, uint32_t len); 12 | 13 | #endif 14 | 15 | -------------------------------------------------------------------------------- /src/common/update.c: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016-2019 Semtech (International) AG. All rights reserved. 2 | // 3 | // This file is subject to the terms and conditions defined in file 'LICENSE', 4 | // which is part of this source code package. 5 | 6 | #include "bootloader.h" 7 | #include "update.h" 8 | #include "sha2.h" 9 | #include "lz4.h" 10 | 11 | #if !defined(UP_PAGEBUFFER_SZ) || ((UP_PAGEBUFFER_SZ & 3) != 0) || ((UP_PAGEBUFFER_SZ & (UP_PAGEBUFFER_SZ - 1)) != 0) 12 | #error "UP_PAGEBUFFER_SZ must be defined as a multiple of 4 and a power of 2" 13 | #endif 14 | 15 | #define PB_WORDS (UP_PAGEBUFFER_SZ >> 2) 16 | 17 | 18 | // ------------------------------------------------ 19 | // Update functions 20 | 21 | // write flash pages (src can be in flash too) 22 | static void flashcopy (void* ctx, uint32_t* dst, const uint32_t* src, uint32_t nwords) { 23 | while (nwords > 0) { 24 | uint32_t buf[PB_WORDS]; 25 | int i, m = (nwords < PB_WORDS) ? nwords : PB_WORDS; 26 | nwords -= m; 27 | for (i = 0; i < m; i++) { 28 | buf[i] = *src++; 29 | } 30 | for (; i < PB_WORDS; i++) { 31 | buf[i] = 0; // pad last page with 0 32 | } 33 | up_flash_wr_page(ctx, dst, buf); 34 | dst += PB_WORDS; 35 | } 36 | } 37 | 38 | static uint32_t update_plain (void* ctx, boot_uphdr* fwup, bool install) { 39 | uint32_t* src = (uint32_t*) (fwup + 1); 40 | uint32_t* dst; 41 | uint32_t rv; 42 | 43 | // perform size check and get install address 44 | if ((rv = up_install_init(ctx, fwup->fwsize, (void**) &dst, 0, NULL, NULL)) != BOOT_OK) { 45 | return rv; 46 | } 47 | 48 | // copy new firmware to destination 49 | if (install) { 50 | up_flash_unlock(ctx); 51 | flashcopy(ctx, dst, src, fwup->fwsize >> 2); 52 | up_flash_lock(ctx); 53 | } 54 | return BOOT_OK; 55 | } 56 | 57 | // process LZ4-compressed self-contained update 58 | static uint32_t update_lz4 (void* ctx, boot_uphdr* fwup, bool install) { 59 | uint8_t* dst; 60 | uint8_t* src = (uint8_t*) fwup + sizeof(boot_uphdr); 61 | uint32_t srclen = fwup->size - sizeof(boot_uphdr); 62 | uint32_t lz4len = srclen - src[srclen-1]; // strip word padding 63 | uint32_t rv; 64 | 65 | // perform size check and get install address 66 | if ((rv = up_install_init(ctx, fwup->fwsize, (void**) &dst, 0, NULL, NULL)) != BOOT_OK) { 67 | return rv; 68 | } 69 | 70 | if (install) { 71 | up_flash_unlock(ctx); 72 | // uncompress new firmware and replace current firmware at destination 73 | lz4_decompress(ctx, src, lz4len, dst, NULL, 0); 74 | up_flash_lock(ctx); 75 | } 76 | 77 | return BOOT_OK; 78 | } 79 | 80 | static bool checkhash (const uint8_t* msg, uint32_t len, uint32_t* hash) { 81 | uint32_t tmp[8]; 82 | sha256(tmp, msg, len); 83 | return (tmp[0] == hash[0] && tmp[1] == hash[1]); 84 | } 85 | 86 | // process LZ4-compressed block-delta update 87 | static uint32_t update_lz4delta (void* ctx, boot_uphdr* fwup, bool install) { 88 | boot_updeltahdr* dhdr = (boot_updeltahdr*) ((uint8_t*) fwup + sizeof(boot_uphdr)); 89 | uint8_t* src = (uint8_t*) dhdr + sizeof(boot_updeltahdr); 90 | uint8_t* end = (uint8_t*) fwup + fwup->size; 91 | uint32_t blksize = dhdr->blksize; 92 | uint8_t* dst; 93 | uint8_t* tmp; 94 | boot_fwhdr* fwhdr; 95 | uint32_t rv; 96 | 97 | // perform size check and get install address and temp area 98 | if ((rv = up_install_init(ctx, fwup->fwsize, (void**) &dst, blksize, (void**) &tmp, &fwhdr)) != BOOT_OK) { 99 | return rv; 100 | } 101 | 102 | // check reference firmware crc and size before installing (will be overwritten during install) 103 | if (!install && (dhdr->refcrc != fwhdr->crc || dhdr->refsize != fwhdr->size)) { 104 | return BOOT_E_GENERAL; 105 | } 106 | 107 | // process delta blocks 108 | while (src < end) { 109 | boot_updeltablk* b = (boot_updeltablk*) src; // delta block 110 | uint32_t boff = b->blkidx * blksize; 111 | uint32_t doff = b->dictidx * blksize; 112 | if (boff > fwup->fwsize || doff + b->dictlen > dhdr->refsize) { 113 | return BOOT_E_SIZE; 114 | } 115 | uint8_t* baddr = dst + boff; 116 | uint32_t bsz = (fwup->fwsize - boff < blksize) ? fwup->fwsize - boff : blksize; // current block size (last block might be shorter) 117 | if (install) { 118 | // verify target block 119 | if (!checkhash(baddr, bsz, b->hash)) { 120 | up_flash_unlock(ctx); 121 | // verify temp block 122 | if (!checkhash(tmp, bsz, b->hash)) { 123 | // uncompress delta to temp block 124 | if (lz4_decompress(ctx, b->lz4data, b->lz4len, tmp, (uint8_t*) fwhdr + doff, b->dictlen) != bsz) { 125 | return BOOT_E_GENERAL; // unrecoverable error - should not happen! 126 | } 127 | // verify temp block 128 | if (!checkhash(tmp, bsz, b->hash)) { 129 | return BOOT_E_GENERAL; // unrecoverable error - should not happen! 130 | } 131 | } 132 | // copy temp block to target 133 | flashcopy(ctx, (uint32_t*) baddr, (uint32_t*) tmp, bsz >> 2); 134 | up_flash_lock(ctx); 135 | } 136 | } 137 | // advance to next delta block (4-aligned) 138 | src += (sizeof(boot_updeltablk) + b->lz4len + 3) & ~0x3; 139 | } 140 | 141 | return BOOT_OK; 142 | } 143 | 144 | uint32_t update (void* ctx, boot_uphdr* fwup, bool install) { 145 | // Note: The integrity of the update pointed to by fwup has 146 | // been verified at this point. 147 | 148 | switch (fwup->uptype) { 149 | case BOOT_UPTYPE_PLAIN: 150 | return update_plain(ctx, fwup, install); 151 | case BOOT_UPTYPE_LZ4: 152 | return update_lz4(ctx, fwup, install); 153 | case BOOT_UPTYPE_LZ4DELTA: 154 | return update_lz4delta(ctx, fwup, install); 155 | default: 156 | return BOOT_E_NOIMPL; 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /src/common/update.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2016-2019 Semtech (International) AG. All rights reserved. 2 | // 3 | // This file is subject to the terms and conditions defined in file 'LICENSE', 4 | // which is part of this source code package. 5 | 6 | #ifndef _update_h_ 7 | #define _update_h_ 8 | 9 | #include "bootloader.h" 10 | 11 | uint32_t update (void* ctx, boot_uphdr* fwup, bool install); 12 | 13 | // glue functions 14 | extern uint32_t up_install_init (void* ctx, uint32_t fwsize, void** pfwdst, uint32_t tmpsize, void** ptmpdst, boot_fwhdr** pcurrentfw); 15 | extern void up_flash_wr_page (void* ctx, void* dst, void* src); 16 | extern void up_flash_unlock (void* ctx); 17 | extern void up_flash_lock (void* ctx); 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /tools/fwtool/.gitignore: -------------------------------------------------------------------------------- 1 | .mypy_cache 2 | __pycache__ 3 | -------------------------------------------------------------------------------- /tools/fwtool/signtool.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import struct 3 | from Crypto.Hash import SHA256 4 | from Crypto.PublicKey import ECC 5 | from Crypto.Signature import DSS 6 | 7 | if len(sys.argv) != 5: 8 | print('usage: signtool UPFILE KEYFILE PASSPHRASE OUTFILE') 9 | else: 10 | upd = open(sys.argv[1], 'rb').read() 11 | usz = struct.unpack(' 0 30 | o += n 31 | self.proc.stdin.flush() 32 | 33 | def read(self, n): 34 | b = b'' 35 | while len(b) < n: 36 | d = self.proc.stdout.read(n - len(b)) 37 | assert len(d) 38 | b += d 39 | return b 40 | 41 | def digest(self, msg): 42 | self.write(struct.pack('I', len(msg)) + msg) 43 | return self.read(32) 44 | 45 | class SHAVS: 46 | class MsgTest: 47 | def __init__(self, m, h): 48 | self.m = m 49 | self.h = h 50 | 51 | def steps(self): 52 | return 1 53 | 54 | def run(self, hobj, pb): 55 | assert hobj.digest(self.m) == self.h 56 | pb.update(1) 57 | 58 | class MonteCarloTest: 59 | def __init__(self, seed): 60 | self.seed = seed 61 | self.mds = list() 62 | 63 | def steps(self): 64 | return 1000 * 100 65 | 66 | def addmd(self, ct, md): 67 | assert len(self.mds) == ct 68 | self.mds.append(md) 69 | 70 | def run(self, hobj, pb): 71 | h = self.seed 72 | for i in range(100): 73 | mc_1 = h 74 | mc_2 = h 75 | for _ in range(1000): 76 | msg = mc_2 + mc_1 + h 77 | mc_2 = mc_1 78 | mc_1 = h 79 | h = hobj.digest(msg) 80 | pb.update(1) 81 | assert h == self.mds[i] 82 | 83 | def __init__(self, zipfile, prefix, hobj): 84 | self.hobj = hobj 85 | self.tests = list() 86 | with zip.ZipFile(zipfile) as zf: 87 | for fn in zf.namelist(): 88 | p = pathlib.Path(fn) 89 | if p.suffix == '.rsp' and p.name.startswith(prefix): 90 | with zf.open(fn) as f: 91 | d = {} 92 | for l in f: 93 | m = re.match(r'(\w+)\s*=\s*(\w+)', l.decode()) 94 | if m: 95 | k,v = m.groups() 96 | if k == 'MD': 97 | if 'Seed' in d: 98 | # new Monte Carlo 99 | self.tests.append(SHAVS.MonteCarloTest( 100 | bytes.fromhex(d['Seed']))) 101 | if 'COUNT' in d: 102 | self.tests[-1].addmd(int(d['COUNT']), bytes.fromhex(v)) 103 | else: 104 | self.tests.append(SHAVS.MsgTest( 105 | bytes.fromhex(d['Msg'])[:int(d['Len'])//8], 106 | bytes.fromhex(v))) 107 | d.clear() 108 | else: 109 | d[k] = v 110 | 111 | def run(self): 112 | steps = sum(t.steps() for t in self.tests) 113 | with tqdm.tqdm(total=steps) as pb: 114 | for t in self.tests: 115 | t.run(self.hobj, pb) 116 | print('All tests passed.') 117 | 118 | #SHAVS('shabytetestvectors.zip', 'SHA256', HashlibHash(hashlib.sha256)).run() 119 | SHAVS('shabytetestvectors.zip', 'SHA256', ProcessHash('../../src/common/sha2test')).run() 120 | --------------------------------------------------------------------------------