Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Firmware swapping #6450

Closed
wants to merge 44 commits into from
Closed
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
647cde9
cpu/stm32f1/include: add cpu defines for FW slots
kYc0o Jan 20, 2017
529c71c
sys: Add fw_slots module
kYc0o Nov 30, 2016
0b6d336
Makefile.dep: add dependencies for fw_slots
kYc0o Jan 23, 2017
019812f
examples: Add bootloader example
kYc0o Oct 24, 2016
aa235e7
cpu/stm32f1/ldscripts: add bootloader and slots linker scripts
kYc0o Oct 24, 2016
2ac7dc7
Makefile.include: add FW slots and Bootlaoder specific rules
kYc0o Oct 24, 2016
52e0c8b
cpu/stm32f1/ldscripts: add gitignore to ignore C linker files
kYc0o Oct 24, 2016
675c879
cpu/Makefile.include.cortexm_common: add rules for linking FW slots
kYc0o Oct 24, 2016
e692a47
cpu/stm32f1: avoid clock initialisation for FW slots
kYc0o Nov 30, 2016
2778f72
dist/tools: Add firmware metadata generator
kYc0o Nov 30, 2016
fda0cd0
dist/tools: add NaCl key generator
kYc0o Jan 4, 2017
b35a4ec
examples: add firmware swapping example
kYc0o Jan 20, 2017
bf998ac
examples/firmware_swapping: ignore helpers
kYc0o Jan 20, 2017
d1769bc
examples/gcoap: ignore crypto keys
kYc0o Jan 20, 2017
5223f4a
examples/bootloader: ignore crypto keys
kYc0o Jan 20, 2017
a2f738b
f dist/tools/firmware_metadata: remove tweetnacl
kYc0o Jan 23, 2017
41ff852
f dist/tools: remove NaCl key generator
kYc0o Jan 23, 2017
cc1ccd9
f examples/bootloader: remove tweetnacl
kYc0o Jan 23, 2017
1ef2ba7
f examples/firmware_swapping: remove tweetnacl
kYc0o Jan 23, 2017
d1de5b5
f examples/gcoap: remove tweetnacl
kYc0o Jan 23, 2017
aeddcbe
f sys/fw_slots: remove tweetnacl
kYc0o Jan 23, 2017
6027cd4
f examples/bootloader: prefix fw_slots functions
kYc0o Jan 24, 2017
01ecff6
f sys/fw_slots: prefix fw_slots functions
kYc0o Jan 24, 2017
ce13450
examples/firmware_swapping: add second fw slot
kYc0o Jan 24, 2017
de9143d
f cpu/stm32f1/include: fix doxygen issues
kYc0o Jan 25, 2017
adf699d
f dist/tools/firmware_metadata: fix whitespaces
kYc0o Jan 25, 2017
cb26788
f examples/firmware_swapping: fix whitespaces
kYc0o Jan 25, 2017
cf1a085
f sys/include: fix fw_slots.h doxygen
kYc0o Jan 25, 2017
3e9fdc3
f sys/include: fix fw_slots.h cpp compat
kYc0o Jan 25, 2017
8bb151f
f sys/fw_slots: fix integer size in printf
kYc0o Jan 25, 2017
511a852
cpu/stm32f1: add periph_slots as a feature
kYc0o Jan 25, 2017
0b8f264
f Makefile.dep: require periph_slots feature
kYc0o Jan 25, 2017
7eeafc5
f cpu/Makefile.include.cortexm_common: no need of ld
kYc0o Mar 1, 2017
6e99a86
f Makefile.include: remove ld generation
kYc0o Mar 1, 2017
f3c0b13
f expamples/firmware_swapping: reduce address defines
kYc0o Mar 1, 2017
0c83e30
f cpu/stm32f1/ldscripts: no more ld generation
kYc0o Mar 1, 2017
600d964
cpu/stm32f1/ldscripts: add fixed slot ld scripts
kYc0o Mar 1, 2017
281c1c8
f Makefile.include: alignment
kYc0o Mar 1, 2017
f7021b8
f examples/bootloader: boot newest image
kYc0o Mar 2, 2017
9648d6a
f sys/fw_slots: fix bug finding newest image
kYc0o Mar 2, 2017
5b3cb9f
f examples/bootloader: fix style
kYc0o Mar 2, 2017
98ace9e
f examples/firmware_swapping: change versions to 1 and 2
kYc0o Mar 20, 2017
1f54964
firmware_swapping: compile to an elf file
cladmi Apr 4, 2017
487f8af
Merge pull request #3 from cladmi/firmware_swapping
kYc0o Apr 6, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions Makefile.dep
Expand Up @@ -611,6 +611,12 @@ ifneq (,$(filter vfs,$(USEMODULE)))
endif
endif

ifneq (,$(filter fw_slots,$(USEMODULE)))
FEATURES_REQUIRED += periph_flashpage
FEATURES_REQUIRED += periph_slots
USEMODULE += hashes
endif

# include package dependencies
-include $(USEPKG:%=$(RIOTPKG)/%/Makefile.dep)

Expand Down
18 changes: 18 additions & 0 deletions Makefile.include
Expand Up @@ -11,6 +11,7 @@ RIOTBOARD ?= $(RIOTBASE)/boards
RIOTPKG ?= $(RIOTBASE)/pkg
RIOTPROJECT ?= $(shell git rev-parse --show-toplevel 2>/dev/null || pwd)
GITCACHE ?= $(RIOTBASE)/dist/tools/git/git-cache
FW_METADATA ?= $(RIOTBASE)/dist/tools/firmware_metadata
APPDIR ?= $(CURDIR)
BINDIRBASE ?= $(APPDIR)/bin
BINDIR ?= $(BINDIRBASE)/$(BOARD)
Expand All @@ -26,6 +27,7 @@ override RIOTBOARD := $(abspath $(RIOTBOARD))
override RIOTPKG := $(abspath $(RIOTPKG))
override RIOTPROJECT := $(abspath $(RIOTPROJECT))
override GITCACHE := $(abspath $(GITCACHE))
override FW_METADATA := $(abspath $(FW_METADATA))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: missing space

override APPDIR := $(abspath $(APPDIR))
override BINDIRBASE := $(abspath $(BINDIRBASE))
override BINDIR := $(abspath $(BINDIR))
Expand Down Expand Up @@ -261,6 +263,10 @@ BASELIBS += $(APPDEPS)
ELFFILE ?= $(BINDIR)/$(APPLICATION).elf
HEXFILE ?= $(ELFFILE:.elf=.hex)

ifeq ($(FW_SLOTS),1)
BINFILE = $(ELFFILE:.elf=.bin)
endif

# variables used to compile and link c++
CPPMIX ?= $(if $(wildcard *.cpp),1,)

Expand All @@ -280,6 +286,12 @@ ifeq ($(BUILDOSXNATIVE),1)
$(Q)$(if $(CPPMIX),$(CXX),$(LINK)) $(UNDEF) -o $(ELFFILE) $$(find $(BASELIBS) -size +8c) $(LINKFLAGS) $(LINKFLAGPREFIX)-no_pie
else
$(Q)$(if $(CPPMIX),$(CXX),$(LINK)) $(UNDEF) -o $(ELFFILE) $(LINKFLAGPREFIX)--start-group $(BASELIBS) -lm $(LINKFLAGPREFIX)--end-group $(LINKFLAGPREFIX)-Map=$(BINDIR)/$(APPLICATION).map $(LINKFLAGPREFIX)--cref $(LINKFLAGS)
endif
ifeq ($(FW_SLOTS),1)
$(STRIP) --strip-unneeded --strip-debug $(ELFFILE)
$(OBJCOPY) -O binary $(ELFFILE) $(BINFILE)
$(FW_METADATA)/bin/./generate-metadata $(BINFILE) $(VERSION) $(UUID)
srec_cat $(BINFILE) -binary -offset $(FW_METADATA_SPACE) firmware-metadata.bin -binary -o $(BINDIR)/slot-image-$(UUID)-$(VERSION).bin -binary
endif
$(Q)$(SIZE) $(ELFFILE)
$(Q)$(OBJCOPY) $(OFLAGS) $(ELFFILE) $(HEXFILE)
Expand All @@ -294,6 +306,12 @@ endif # BUILD_IN_DOCKER

..build-message:
@$(COLOR_ECHO) '${COLOR_GREEN}Building application "$(APPLICATION)" for "$(BOARD)" with MCU "$(MCU)".${COLOR_RESET}'
ifeq ($(FW_SLOTS),1)
@$(COLOR_ECHO) '${COLOR_RED}This is a build for FW slot $(FW_SLOT).${COLOR_RESET}'
endif
ifeq ($(BOOTLOADER),1)
@$(COLOR_ECHO) '${COLOR_RED}This is a Bootloader build.${COLOR_RESET}'
endif
@$(COLOR_ECHO)

# add extra include paths for packages in $(USEMODULE)
Expand Down
18 changes: 18 additions & 0 deletions cpu/Makefile.include.cortexm_common
Expand Up @@ -15,6 +15,24 @@ export CFLAGS_OPT ?= -Os
export CFLAGS += $(CFLAGS_CPU) $(CFLAGS_LINK) $(CFLAGS_DBG) $(CFLAGS_OPT)

export ASFLAGS += $(CFLAGS_CPU) $(CFLAGS_DBG)

# If the FW_SLOTS flag is set, we will generate a linker script at compile-time
# reflecting the FW_IMAGE_OFFSET and FW_IMAGE_LENGTH values defined in the
# target project's Makefile.
ifeq ($(FW_SLOTS),1)
ifeq ($(FW_SLOT),1)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about LINKER_SCRIPT = $(CPU_MODEL)_slot$(FW_SLOT).ld. Then you don't limit it to 2 (it might be a future use case).

Copy link
Contributor Author

@kYc0o kYc0o Mar 21, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea actually is to limit to 2. The next step is to try to get always slot 1 as the bootable slot, download images to slot 2 and then swap both images. The complexity of having several slots is that you need to know before compiling where are you going to put them (e.g. to know where they are the current images to don't overwrite them).

LINKER_SCRIPT = $(CPU_MODEL)_slot1.ld
endif
ifeq ($(FW_SLOT),2)
LINKER_SCRIPT = $(CPU_MODEL)_slot2.ld
endif
endif

# If we compile a bootloader, set the correct linker script
ifeq ($(BOOTLOADER),1)
export LINKER_SCRIPT = $(CPU_MODEL)-bootloader.ld
endif

export LINKFLAGS += -L$(RIOTCPU)/$(CPU)/ldscripts -L$(RIOTCPU)/cortexm_common/ldscripts
export LINKER_SCRIPT ?= $(CPU_MODEL).ld
export LINKFLAGS += -T$(LINKER_SCRIPT) -Wl,--fatal-warnings
Expand Down
1 change: 1 addition & 0 deletions cpu/Makefile.include.gnu
Expand Up @@ -16,3 +16,4 @@ export OBJCOPY = true
endif
export OBJDUMP = $(PREFIX)objdump
export DBG = $(GDBPREFIX)gdb
export STRIP = $(PREFIX)strip
1 change: 1 addition & 0 deletions cpu/stm32f1/Makefile.features
@@ -1 +1,2 @@
FEATURES_PROVIDED += periph_pm
FEATURES_PROVIDED += periph_slots
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No new line at EOF :-)

7 changes: 7 additions & 0 deletions cpu/stm32f1/cpu.c
Expand Up @@ -96,21 +96,27 @@
#endif
#endif

#ifndef FW_SLOTS
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So there's no clock configuration when using OTA?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we can consider it as an issue. If the clock is initialised again it doesn't boot.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like this... AFAIK the clock can be initialized several times but there might be registers which might need to be set to the "default" value.

EDIT: maybe a different initialization cpu is cleaner. Maybe for the bootloader only the internal oscillator and not all peripherals are needed.

static void clk_init(void);
#endif

void cpu_init(void)
{
/* initialize the Cortex-M core */
cortexm_init();

/* initialize system clocks */
#ifndef FW_SLOTS
clk_init();
#endif
/* trigger static peripheral initialization */
periph_init();
}

/**
* @brief Configure the clock system of the stm32f1
*/
#ifndef FW_SLOTS
static void clk_init(void)
{
/* Reset the RCC clock configuration to the default reset state(for debug purpose) */
Expand Down Expand Up @@ -162,3 +168,4 @@ static void clk_init(void)
while ((RCC->CR & RCC_CR_HSIRDY) != 0) {}
#endif
}
#endif
119 changes: 115 additions & 4 deletions cpu/stm32f1/include/cpu_conf.h
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2013 INRIA
* Copyright (C) 2013, 2016 Inria
* Copyright (C) 2014 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser General
Expand All @@ -18,6 +18,7 @@
*
* @author Alaeddine Weslati <alaeddine.weslati@intia.fr>
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Francisco Acosta <francisco.acosta@inria.fr>
*/

#ifndef CPU_CONF_H
Expand All @@ -35,13 +36,123 @@
extern "C" {
#endif

/**
* @brief Flash page configuration
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about factoring the firmware upgrade stuff out of cpu_conf.h?

CPU specific defines, like FLASHPAGE_*, could stay.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What defines do you mean specifically? I agree we could move FW_SLOT* defines to maybe cortex_common. Otherwise you prefer to create another .h file containing these on something like cpu/include?

* @{
*/
#define FLASHPAGE_SIZE (2048U)

#if defined(CPU_MODEL_STM32F103CB) || defined(CPU_MODEL_STM32F103RB)
#define FLASHPAGE_NUMOF (64U)
#elif defined(CPU_MODEL_STM32F103RE)
#define FLASHPAGE_NUMOF (256U)
#endif
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tip: we solved this in one project by defining them in the linker file and the define was just pointing there.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK I will try that.

/** @} */

/**
* @brief Offset to reset handler on VTOR
* @{
*/
#define VTOR_RESET_HANDLER 0x4 /** One pointer after the beginning */
/** @} */

#if defined(CPU_MODEL_STM32F103RE)
/*
* @brief Flash partitioning for FW slots
* @{
*/

#ifndef FW_METADATA_SPACE
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think all of this should be project specific and not coded in cpu_conf.h

#define FW_METADATA_SPACE (0x100)
#endif

#define MAX_FW_SLOTS (2)
#define FW_SLOT_PAGES (120)
#define BOOTLOADER_SPACE (0x4000)
#define FW_SLOT_SIZE FLASHPAGE_SIZE * FW_SLOT_PAGES
#define FW_SLOT_1 FLASH_BASE + BOOTLOADER_SPACE
#define FW_SLOT_1_END FW_SLOT_1 + FW_SLOT_SIZE
#define FW_SLOT_1_PAGE (8)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can some of these be calculated from others? Feels like there's redundant information, especially in combination with FLASHPAGE_SIZE.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I can try, I just did a straightforward define.

#define FW_SLOT_2 FW_SLOT_1_END
#define FW_SLOT_2_END FW_SLOT_2 + FW_SLOT_SIZE
#define FW_SLOT_2_PAGE (128)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as for the Makefile, I suggest to use FW_SLOT(x) to allow flexibility. Maybe you find a FW_SLOT(x) which can be used to compute all of this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, as I said before the goal is to limit this to 2 slots so we don't need to deal with such complexity...


#ifdef FW_SLOTS
#if FW_SLOT == 1
#define CURRENT_FIRMWARE_ADDR FW_SLOT_1
#define CURRENT_FIRMWARE_PAGE FW_SLOT_1_PAGE
#define CURRENT_FIRMWARE_END FW_SLOT_1_END
#endif

#if FW_SLOT == 2
#define CURRENT_FIRMWARE_ADDR FW_SLOT_2
#define CURRENT_FIRMWARE_PAGE FW_SLOT_2_PAGE
#define CURRENT_FIRMWARE_END FW_SLOT_2_END
#endif

#endif /* FW_SLOTS */

/** @} */

/**
* @brief Get FW internal address for a given slot
*
* @param[in] slot FW slot
*
* @return FW slot address
*/
static inline uint32_t get_slot_address(uint8_t slot)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest to move this to the fw_slots.h since will be the same for all mcus

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree!

{
switch (slot) {
case 1:
return FW_SLOT_1;
break;

case 2:
return FW_SLOT_2;
break;
}

return 0;
}

/**
* @brief Get internal page for a given slot
*
* @param[in] slot FW slot
*
* @return FW slot page
*/
static inline uint32_t get_slot_page(uint8_t slot)
{
switch (slot) {
case 1:
return FW_SLOT_1_PAGE;
break;

case 2:
return FW_SLOT_2_PAGE;
break;
}

return 0;
}

#endif /* defined(CPU_MODEL_STM32F103RE) */
/** @} */

/**
* @brief ARM Cortex-M specific CPU configuration
* @{
*/
#define CPU_DEFAULT_IRQ_PRIO (1U)
#define CPU_IRQ_NUMOF (60U)
#define CPU_FLASH_BASE FLASH_BASE
#define CPU_DEFAULT_IRQ_PRIO (1U)
#define CPU_IRQ_NUMOF (60U)

#ifdef FW_SLOTS
#define CPU_FLASH_BASE (CURRENT_FIRMWARE_ADDR + FW_METADATA_SPACE)
#else
#define CPU_FLASH_BASE FLASH_BASE
#endif
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The flash base doesn't change for the MCU, the address of the firmware changes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will change with #6638 .

/** @} */

/**
Expand Down
30 changes: 30 additions & 0 deletions cpu/stm32f1/ldscripts/stm32f103re-bootloader.ld
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2015 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/

/**
* @addtogroup cpu_stm32f1
* @{
*
* @file
* @brief Memory definitions for the STM32F103RE
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*
* @}
*/

MEMORY
{
rom (rx) : ORIGIN = 0x08000000, LENGTH = 16K
ram (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
cpuid (r) : ORIGIN = 0x1ffff7e8, LENGTH = 12
}

_cpuid_address = ORIGIN(cpuid);

INCLUDE cortexm_base.ld
30 changes: 30 additions & 0 deletions cpu/stm32f1/ldscripts/stm32f103re_slot1.ld
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2017 Inria
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/

/**
* @addtogroup cpu_stm32f1
* @{
*
* @file
* @brief Memory definitions for the STM32F103RE Slot 0
*
* @author Francisco Acosta <francisco.acosta@inria.fr>
*
* @}
*/

MEMORY
{
rom (rx) : ORIGIN = 0x08004100, LENGTH = 0x3C000
ram (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
cpuid (r) : ORIGIN = 0x1ffff7e8, LENGTH = 12
}

_cpuid_address = ORIGIN(cpuid);

INCLUDE cortexm_base.ld
30 changes: 30 additions & 0 deletions cpu/stm32f1/ldscripts/stm32f103re_slot2.ld
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2017 Inria
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/

/**
* @addtogroup cpu_stm32f1
* @{
*
* @file
* @brief Memory definitions for the STM32F103RE Slot 1
*
* @author Francisco Acosta <francisco.acosta@inria.fr>
*
* @}
*/

MEMORY
{
rom (rx) : ORIGIN = 0x08040100, LENGTH = 0x3C000
ram (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
cpuid (r) : ORIGIN = 0x1ffff7e8, LENGTH = 12
}

_cpuid_address = ORIGIN(cpuid);

INCLUDE cortexm_base.ld
3 changes: 3 additions & 0 deletions dist/tools/firmware_metadata/.gitignore
@@ -0,0 +1,3 @@
/generate-metadata
/git-fetch-tweetnacl
tweetnacl
19 changes: 19 additions & 0 deletions dist/tools/firmware_metadata/Makefile
@@ -0,0 +1,19 @@
RIOTBASE := ../../..
RIOT_INCLUDE = $(RIOTBASE)/sys/include
SHA256_DIR := $(RIOTBASE)/sys/hashes
SHA256_INCLUDE := $(RIOT_INCLUDE)/hashes
METADATA_SRC := generate-metadata.c $(SHA256_DIR)/sha256.c
METADATA_HDR := $(RIOT_INCLUDE)/fw_slots.h $(RIOT_INCLUDE)/hashes/sha256.h

CFLAGS += -g -O3 -Wall -Wextra -pedantic -std=c99

all: bin bin/generate-metadata

bin:
mkdir bin

bin/generate-metadata:
$(CC) $(CFLAGS) -I$(RIOT_INCLUDE) $(METADATA_SRC) -o $@

clean:
rm -rf bin/generate-metadata