diff --git a/examples/mcuboot/.gitignore b/examples/mcuboot/.gitignore new file mode 100644 index 000000000..9e1d2593e --- /dev/null +++ b/examples/mcuboot/.gitignore @@ -0,0 +1 @@ +/Kconfig diff --git a/examples/mcuboot/Make.defs b/examples/mcuboot/Make.defs new file mode 100644 index 000000000..fea6548f9 --- /dev/null +++ b/examples/mcuboot/Make.defs @@ -0,0 +1,21 @@ +############################################################################ +# apps/examples/mcuboot/Make.defs +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +include $(wildcard $(APPDIR)/examples/mcuboot/*/Make.defs) diff --git a/examples/mcuboot/Makefile b/examples/mcuboot/Makefile new file mode 100644 index 000000000..3bd6703c2 --- /dev/null +++ b/examples/mcuboot/Makefile @@ -0,0 +1,23 @@ +############################################################################ +# apps/examples/mcuboot/Makefile +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +MENUDESC = "MCUboot Examples" + +include $(APPDIR)/Directory.mk diff --git a/examples/mcuboot/swap_test/Kconfig b/examples/mcuboot/swap_test/Kconfig new file mode 100644 index 000000000..2d0a791ad --- /dev/null +++ b/examples/mcuboot/swap_test/Kconfig @@ -0,0 +1,13 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +config EXAMPLES_MCUBOOT_SWAP_TEST + tristate "MCUboot SWAP Test image example" + default n + select BOOT_MCUBOOT + ---help--- + Example application to demonstrate the firmware image swap + and the image rollback processes of MCUboot using the boot + swap and test method. diff --git a/examples/mcuboot/swap_test/Make.defs b/examples/mcuboot/swap_test/Make.defs new file mode 100644 index 000000000..e4d015532 --- /dev/null +++ b/examples/mcuboot/swap_test/Make.defs @@ -0,0 +1,23 @@ +############################################################################ +# apps/examples/mcuboot/swap_test/Make.defs +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +ifneq ($(CONFIG_EXAMPLES_MCUBOOT_SWAP_TEST),) +CONFIGURED_APPS += $(APPDIR)/examples/mcuboot/swap_test +endif diff --git a/examples/mcuboot/swap_test/Makefile b/examples/mcuboot/swap_test/Makefile new file mode 100644 index 000000000..ad91a8804 --- /dev/null +++ b/examples/mcuboot/swap_test/Makefile @@ -0,0 +1,29 @@ +############################################################################ +# apps/examples/mcuboot/swap_test/Makefile +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +include $(APPDIR)/Make.defs + +MAINSRC += confirm_main.c set_img_main.c version_main.c + +PROGNAME += mcuboot_confirm mcuboot_set_img mcuboot_version +PRIORITY += SCHED_PRIORITY_DEFAULT +STACKSIZE += $(CONFIG_DEFAULT_TASK_STACKSIZE) + +include $(APPDIR)/Application.mk diff --git a/examples/mcuboot/swap_test/README.md b/examples/mcuboot/swap_test/README.md new file mode 100644 index 000000000..6a43a069a --- /dev/null +++ b/examples/mcuboot/swap_test/README.md @@ -0,0 +1,138 @@ +# Examples / MCUboot / `swap_test` + +## Description + +MCUboot Swap Image is an application to demostrate firmware upgrade using +internal flash memory. It simulate MCUboot API steps to switch between two +valid images. + +This application add 3 Builtin Apps to NuttX NSH: version, set_img and confirm. +After application is build and `nuttx.bin` be generated, the binary must be +signed. Consult your board README file to get instructions how to do it. + +## How to build and flash + +First step is build your board configuraton using `mcuboot-loader` as target. +That create the bootloader itself. The `nuttx.bin` must be flash as usual. + +After that, clean up environment and set `mcuboot-swap-test` as target. The +build output will generate the `nuttx.bin` file. You should execute the MCUboot +script called `imgtool.py` and sign the binary file two times. + +The first time you will use `--version 1.0.0` and `signedv1.bin` as output file. +Then, the second sign you need change to `--version 2.0.0` and `signedv2.bin` +as output file. + +The `signedv1.bin` file must be at MCUboot Slot-0 partition and `signedv2.bin` +at Slot-1. + +More instructions about how to sign and flash can be found at board README file. + +## Running swap image test + +Open you terminal and reboot your board. You can see a similar output as below. +You can check builtin apps using command `?`. + +```bash +*** Booting MCUboot build 7c890f4b075aed73e4c825ccf875b2fb9ebf2ded *** +NuttShell (NSH) NuttX-10.2.0 +nsh> ? +help usage: help [-v] [] + + . cd echo hexdump mv rmdir true xd + [ cp exec kill printf set truncate + ? cmp exit ls ps sleep uname + basename dirname false mkdir pwd source umount + break dd free mkrd reboot test unset + cat df help mount rm time usleep + +Builtin Apps: + mcuboot_set_img mcuboot_confirm sh + mcuboot_version ramtest nsh +nsh> +``` + +First step (check version): + +```bash +nsh> mcuboot_version +Image version 1.0.0.0 +nsh> +``` + +Second step (mark image as good because it is running). This is an optional +step that must be executed if you ran `imgtool.py` without optional parameter +`--confirm`. + +```bash +nsh> mcuboot_confirm +Application Image successfully confirmed! +nsh> +``` + +Third step (let's reboot and see whats happen): + +```bash +nsh> reboot +*** Booting MCUboot build 7c890f4b075aed73e4c825ccf875b2fb9ebf2ded *** +NuttShell (NSH) NuttX-10.2.0 +nsh> mcuboot_version +Image version 1.0.0.0 +nsh> +``` + +Fourth step (let's switch image): + +```bash +nsh> mcuboot_set_img +Requested update for next boot. Restarting... +*** Booting MCUboot build 7c890f4b075aed73e4c825ccf875b2fb9ebf2ded *** +NuttShell (NSH) NuttX-10.2.0 +nsh> mcuboot_version +Image version 2.0.0.0 +nsh> +``` + +Now, we switched from image version 1.0.0 to image 2.0.0. However, we intentionaly +will not run `mcuboot_confirm` app. + +```bash +nsh> reboot +*** Booting MCUboot build 7c890f4b075aed73e4c825ccf875b2fb9ebf2ded *** +NuttShell (NSH) NuttX-10.2.0 +nsh> mcuboot_version +Image version 1.0.0.0 +nsh> +``` + +This means that if for any reason App reboot, have a malfunctioning or not boot, +MCUboot will switch back to old `good` image! Remember that we executed +`mcuboot_confirm` at step two. + +Fifth step (switch to image version 2 and mark as permanent): + +```bash +nsh> mcuboot_set_img +Requested update for next boot. Restarting... +*** Booting MCUboot build 7c890f4b075aed73e4c825ccf875b2fb9ebf2ded *** +NuttShell (NSH) NuttX-10.2.0 +nsh> mcuboot_confirm +Application Image successfully confirmed! +nsh> mcuboot_version +Image version 2.0.0.0 +nsh> +``` + +Sixth step (Reboot and confirm V2 image): + +```bash +nsh> reboot +*** Booting MCUboot build 7c890f4b075aed73e4c825ccf875b2fb9ebf2ded *** +NuttShell (NSH) NuttX-10.2.0 +nsh> mcuboot_version +Image version 2.0.0.0 +nsh> +``` + +Conclusion, once we boot a newer image and confirm it MCUboot always run that +image, unless you instruct it to swap again! diff --git a/examples/mcuboot/swap_test/confirm_main.c b/examples/mcuboot/swap_test/confirm_main.c new file mode 100644 index 000000000..c8a29c179 --- /dev/null +++ b/examples/mcuboot/swap_test/confirm_main.c @@ -0,0 +1,46 @@ +/**************************************************************************** + * apps/examples/mcuboot/swap_test/confirm_main.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * mcuboot_confirm_main + ****************************************************************************/ + +int main(int argc, FAR char *argv[]) +{ + boot_set_confirmed_multi(0); + + printf("Application Image successfully confirmed!\n"); + + return 0; +} diff --git a/examples/mcuboot/swap_test/set_img_main.c b/examples/mcuboot/swap_test/set_img_main.c new file mode 100644 index 000000000..7c6d7c20f --- /dev/null +++ b/examples/mcuboot/swap_test/set_img_main.c @@ -0,0 +1,55 @@ +/**************************************************************************** + * apps/examples/mcuboot/swap_test/set_img_main.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * mcuboot_set_img_main + ****************************************************************************/ + +int main(int argc, FAR char *argv[]) +{ + boot_set_pending_multi(0, 0); + + printf("Requested update for next boot. Restarting...\n"); + + fflush(stdout); + fflush(stderr); + + usleep(1000); + + boardctl(BOARDIOC_RESET, 0); + + return 0; +} diff --git a/examples/mcuboot/swap_test/version_main.c b/examples/mcuboot/swap_test/version_main.c new file mode 100644 index 000000000..932112493 --- /dev/null +++ b/examples/mcuboot/swap_test/version_main.c @@ -0,0 +1,127 @@ +/**************************************************************************** + * apps/examples/mcuboot/swap_test/version_main.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define BOOT_HEADER_MAGIC_V1 0x96f3b83d +#define BOOT_HEADER_SIZE_V1 32 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +begin_packed_struct struct mcuboot_raw_version_v1_s +{ + uint8_t major; + uint8_t minor; + uint16_t revision; + uint32_t build_num; +} end_packed_struct; + +begin_packed_struct struct mcuboot_raw_header_v1_s +{ + uint32_t header_magic; + uint32_t image_load_address; + uint16_t header_size; + uint16_t pad; + uint32_t image_size; + uint32_t image_flags; + struct mcuboot_raw_version_v1_s version; + uint32_t pad2; +} end_packed_struct; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int boot_read_v1_header(uint8_t area_id, + struct mcuboot_raw_header_v1_s *raw_header) +{ + const struct flash_area *fa; + int rc; + + rc = flash_area_open(area_id, &fa); + if (rc) + { + return rc; + } + + rc = flash_area_read(fa, 0, raw_header, + sizeof(struct mcuboot_raw_header_v1_s)); + flash_area_close(fa); + if (rc) + { + return rc; + } + + raw_header->header_magic = le32toh(raw_header->header_magic); + raw_header->image_load_address = le32toh(raw_header->image_load_address); + raw_header->header_size = le16toh(raw_header->header_size); + raw_header->image_size = le32toh(raw_header->image_size); + raw_header->image_flags = le32toh(raw_header->image_flags); + raw_header->version.revision = le16toh(raw_header->version.revision); + raw_header->version.build_num = le32toh(raw_header->version.build_num); + + if ((raw_header->header_magic != BOOT_HEADER_MAGIC_V1) + || (raw_header->header_size < BOOT_HEADER_SIZE_V1)) + { + return -EIO; + } + + return 0; +} + +/**************************************************************************** + * mcuboot_version_main + ****************************************************************************/ + +int main(int argc, FAR char *argv[]) +{ + int rc; + struct mcuboot_raw_header_v1_s raw_header; + + rc = boot_read_v1_header(0, &raw_header); + if (rc) + { + printf("Only header version 1 can be read. Abort!\n"); + return rc; + } + + printf("Image version %d.%d.%d.%ld\n", raw_header.version.major, + raw_header.version.minor, + raw_header.version.revision, + raw_header.version.build_num); + + return 0; +}