Initial commit

Initial commit.
This commit is contained in:
kntran1
2026-03-23 14:40:39 -05:00
parent e84b2b4166
commit 4e2a5258a5
872 changed files with 165227 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
*.bin
test-images.zip

View File

@@ -0,0 +1,295 @@
###########################################################################
# Sample multi-part application Makefile
#
# Copyright (c) 2017 Linaro Limited
# Copyright (c) 2017 Open Source Foundries Limited
#
# Licensed 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.
###########################################################################
# This is an example Makefile to demonstrate how to use mcuboot to
# deploy and upgrade images. The image building should work on any
# supported target, however flashing will likely require changes to
# the flash addresses, depending on the partition layout of the device
# in question.
#
# running
#
# make BOARD=frdm_k64f all
#
# should generate three "*.bin" files in this directory:
#
# mcuboot.bin: The bootloader itself
# signed-hello1.bin: A signed sample.
# signed-hello2.bin: An upgrade image, signed and marked for
# upgrade.
#
# "make flash_boot" should flash the bootloader into the flash,
# erasing the rest of the device. If you examine the device at this
# time, you should see a message about the bootloader not being able
# to find a bootable image.
#
# "make flash_hello1" will then flash the first application into the
# "primary slot". This should boot into this app, print a small message, and
# give the zephyr console.
#
# "make flash_hello2" will flash hello2 into the "secondary slot". The
# reset should upgrade and run the new image. Resetting again should
# then revert back to the first app, since we did not mark this image
# as good.
# Extra .conf fragments to merge into the MCUboot .config, as a
# semicolon-separated list (i.e., a CMake list).
BOOTLOADER_OVERLAY_CONFIG ?=
BOARD ?= frdm_k64f
SLOT_SIZE ?= 0x60000
BOOT_ADDR ?= 0x0
IMG0_ADDR ?= 0x20000
IMG1_ADDR ?= 0x80000
.PHONY: check boot hello1 clean_boot clean_hello1 \
hello2 clean_hello2 flash_boot flash_hello1 flash_hello2
# For signing, use the default RSA demo key, to match the default in
# the mcuboot Makefile.
SIGNING_KEY ?= ../../root-rsa-2048.pem
# The header size should match that in hello1/prj.conf
# CONFIG_TEXT_SECTION_OFFSET. This value needs to be a power of two
# that is at least as large as the size of the vector table. The
# value given here of 0x200 should be sufficient for any supported
# devices, but it can be made smaller, as long as this value matches
# that used to build the app.
BOOT_HEADER_LEN = 0x200
# For upgrades, the signing tool needs to know the device alignment.
# This requirement will be going away soon.
FLASH_ALIGNMENT = 8
IMGTOOL = ../../scripts/imgtool.py
ASSEMBLE = ../../scripts/assemble.py
PYOCD = pyocd
SOURCE_DIRECTORY := $(CURDIR)
BUILD_DIRECTORY := $(CURDIR)/build/$(BOARD)
BUILD_DIR_BOOT := $(BUILD_DIRECTORY)/mcuboot
BUILD_DIR_HELLO1 := $(BUILD_DIRECTORY)/hello1
BUILD_DIR_HELLO2 := $(BUILD_DIRECTORY)/hello2
help:
@echo "make <target> BOARD=<board>"
@echo "<target>: all, boot, hello1, full.bin"
@echo "<board>: frdm_k64f only for now"
all: boot hello1 hello2
full.bin: boot hello1 hello2
$(ASSEMBLE) -b $(BUILD_DIR_BOOT) \
-z $(ZEPHYR_BASE) \
-p signed-hello1.bin \
-s signed-hello2.bin \
-o full.bin
clean: clean_boot clean_hello1 clean_hello2
@rm -f signed-hello1.bin
@rm -f signed-hello2.bin
@rm -f mcuboot.bin
boot: check
@rm -f mcuboot.bin
(mkdir -p $(BUILD_DIR_BOOT) && \
cd $(BUILD_DIR_BOOT) && \
cmake -DOVERLAY_CONFIG=$(BOOTLOADER_OVERLAY_CONFIG) \
-G"Ninja" \
-DBOARD=$(BOARD) \
$(SOURCE_DIRECTORY)/../../boot/zephyr && \
ninja)
cp $(BUILD_DIR_BOOT)/zephyr/zephyr.bin mcuboot.bin
clean_boot: check
rm -rf $(BUILD_DIR_BOOT)
# Build and sign "hello1".
hello1: check
(mkdir -p $(BUILD_DIR_HELLO1) && \
cd $(BUILD_DIR_HELLO1) && \
cmake -DFROM_WHO=hello1 \
-G"Ninja" \
-DBOARD=$(BOARD) \
$(SOURCE_DIRECTORY)/hello-world && \
ninja)
$(IMGTOOL) sign \
--key $(SIGNING_KEY) \
--header-size $(BOOT_HEADER_LEN) \
--align $(FLASH_ALIGNMENT) \
--version 1.2 \
--slot-size $(SLOT_SIZE) \
$(BUILD_DIR_HELLO1)/zephyr/zephyr.bin \
signed-hello1.bin
clean_hello1: check
rm -rf $(BUILD_DIR_HELLO1)
# Build and sign "hello2".
# This is the same signing command as above, except that it adds the
# "--pad" argument. This will also add the trailer that indicates
# this image is intended to be an upgrade. It should be flashed into
# the secondary slot instead of the primary slot.
hello2: check
(mkdir -p $(BUILD_DIR_HELLO2) && \
cd $(BUILD_DIR_HELLO2) && \
cmake -DFROM_WHO=hello2 \
-G"Ninja" \
-DBOARD=$(BOARD) \
$(SOURCE_DIRECTORY)/hello-world && \
ninja)
$(IMGTOOL) sign \
--key $(SIGNING_KEY) \
--header-size $(BOOT_HEADER_LEN) \
--align $(FLASH_ALIGNMENT) \
--version 1.2 \
--slot-size $(SLOT_SIZE) \
--pad \
$(BUILD_DIR_HELLO2)/zephyr/zephyr.bin \
signed-hello2.bin
clean_hello2: check
rm -rf $(BUILD_DIR_HELLO2)
# These flash_* targets use pyocd to flash the images. The addresses
# are hardcoded at this time.
flash_boot:
$(PYOCD) flash -e chip -a $(BOOT_ADDR) mcuboot.bin
flash_hello1:
$(PYOCD) flash -a $(IMG0_ADDR) signed-hello1.bin
flash_hello2:
$(PYOCD) flash -a $(IMG1_ADDR) signed-hello2.bin
flash_full:
$(PYOCD) flash -e chip -a $(BOOT_ADDR) full.bin
# These test- targets reinvoke make with the configuration set to test
# various configurations. This will generally be followed by using
# the above flash targets.
# Test a good image, with a good upgrade, using RSA signatures.
# flash_boot: Unable to find bootable image
# flash_hello1: hello1 runs
# flash_hello2: hello2 runs
# reset: hello1 runs
test-good-rsa: clean
$(MAKE) \
BOOTLOADER_OVERLAY_CONFIG=$(PWD)/overlay-rsa.conf \
all
# Test a good image, with a good upgrade, using ECDSA signatures.
# flash_boot: Unable to find bootable image
# flash_hello1: hello1 runs
# flash_hello2: hello2 runs
# reset: hello1 runs
test-good-ecdsa: clean
$(MAKE) \
BOOTLOADER_OVERLAY_CONFIG=$(PWD)/overlay-ecdsa-p256.conf \
SIGNING_KEY=../../root-ec-p256.pem \
all
# Test (with RSA) that overwrite-only works. This should boot,
# upgrade correctly, but not revert once the upgrade has been done.
# flash_boot: Unable to find bootable image
# flash_hello1: hello1 runs
# flash_hello2: hello2 runs
# reset: hello2 runs
test-overwrite: clean
$(MAKE) \
BOOTLOADER_OVERLAY_CONFIG=$(PWD)/overlay-upgrade-only.conf \
all
# Test that when configured for RSA, a wrong signature in the upgrade
# image will fail to upgrade.
# flash_boot: Unable to find bootable image
# flash_hello1: hello1 runs
# flash_hello2: hello1 runs
# reset: hello1 runs
test-bad-rsa-upgrade: clean
$(MAKE) \
BOOTLOADER_OVERLAY_CONFIG=$(PWD)/overlay-rsa.conf \
boot hello1
$(MAKE) \
BOOTLOADER_OVERLAY_CONFIG=$(PWD)/overlay-rsa.conf \
SIGNING_KEY=../../root-ec-p256.pem \
hello2
# Test that when configured for ECDSA, a wrong signature in the upgrade
# image will fail to upgrade.
# flash_boot: Unable to find bootable image
# flash_hello1: hello1 runs
# flash_hello2: hello1 runs
# reset: hello1 runs
test-bad-ecdsa-upgrade: clean
$(MAKE) \
BOOTLOADER_OVERLAY_CONFIG=$(PWD)/overlay-ecdsa-p256.conf \
SIGNING_KEY=../../root-ec-p256.pem \
boot hello1
$(MAKE) \
BOOTLOADER_OVERLAY_CONFIG=$(PWD)/overlay-ecdsa-p256.conf \
SIGNING_KEY=../../root-rsa-2048.pem \
hello2
# Test that when configured to not validate the primary slot, we still boot, but
# don't upgrade.
# flash_boot: tries to boot and resets
# flash_hello1: hello1 runs
# flash_hello2: hello1 runs
# reset: hello1 runs
test-no-bootcheck: clean
$(MAKE) \
BOOTLOADER_OVERLAY_CONFIG=$(PWD)/overlay-skip-primary-slot-validate.conf \
SIGNING_KEY=../../root-ec-p256.pem \
all
# Test a good image, with a wrong-signature upgrade, using RSA signatures.
# flash_boot: Unable to find bootable image
# flash_hello1: hello1 runs
# flash_hello2: hello1 runs
# reset: hello1 runs
test-wrong-rsa: clean
$(MAKE) \
BOOTLOADER_OVERLAY_CONFIG=$(PWD)/overlay-rsa.conf \
boot hello1
$(MAKE) \
BOOTLOADER_OVERLAY_CONFIG=$(PWD)/overlay-rsa.conf \
SIGNING_KEY=bad-keys/bad-rsa-2048.pem \
hello2
# Test a good image, with a wrong-signature upgrade, using ECDSA signatures.
# flash_boot: Unable to find bootable image
# flash_hello1: hello1 runs
# flash_hello2: hello1 runs
# reset: hello1 runs
test-wrong-ecdsa: clean
$(MAKE) \
BOOTLOADER_OVERLAY_CONFIG=$(PWD)/overlay-ecdsa-p256.conf \
SIGNING_KEY=../../root-ec-p256.pem \
boot hello1
$(MAKE) \
BOOTLOADER_OVERLAY_CONFIG=$(PWD)/overlay-ecdsa-p256.conf \
SIGNING_KEY=bad-keys/bad-ec-p256.pem \
hello2
check:
@if [ -z "$$ZEPHYR_BASE" ]; then echo "Zephyr environment not set up"; false; fi
@if [ -z "$(BOARD)" ]; then echo "You must specify BOARD=<board>"; false; fi

View File

@@ -0,0 +1,24 @@
# Zephyr sample application.
In order to successfully deploy an application using MCUboot, it is
necessary to build at least one other binary: the application itself.
It is beyond the scope of this documentation to describe what an
application is able to do, however a working example is certainly
useful.
Please see the comments in the Makefile in this directory for more
details on how to build and test this application.
Note that this sample uses the "ninja" build tool, which can be
installed on most systems using the system package manager, e.g., for
a Debian-based distro:
```
$ sudo apt-get install ninja
```
or in Fedora:
```
$ sudo dnf install ninja
```

View File

@@ -0,0 +1,6 @@
# Bad keys for testing
This directory contains some alternate keys that can be used for
testing. Signing the images with either of these keys, but leaving
the demo keys's public keys in the bootloader should result in it not
upgrading, or not booting.

View File

@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEILmqmiH6y3EGhLkTcnNtU7hZ1wnc51MIL53npseRX7vJoAoGCCqGSM49
AwEHoUQDQgAEcX9ExNjZfsckp6AdutjPjVJsvP6ZZkKfLsGnRpKR+9OpO9/qmJHs
ks+ZXo70SEANjWnNlxKNAVci8aUm8UskLw==
-----END EC PRIVATE KEY-----

View File

@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAzXhCIc6kig0DRWEyKj4N8v/bfvh/RmU73Jo0Z0RAFSLnFrE5
5W5C9tsdDalhN5HV7xBQCzr7GSW1C6MNvtw/lVr4+x4LvgwYD6kl+9IZc5udPIJ1
R7aLBP2o4r6rJWtCj9Y6bifsMlVkHCONIHDGhp3bSl+9C2EqfwqJENg3mHYyZcbr
kBfLhILE24T+MhxkPZiI3Ox6XthwT7Is8ZCXF6VCYaK6N8jXAXz8OiEhIpMl3Z3m
DqxaM0ovSXfXvOfMeKN76iI9m8S4JnPbuzu+/5GdSnNbIxoluzXU7e52FoKgthNM
2mArAak5x3IqsStY0qDCODSlNnSha9+jfk8ULwIDAQABAoIBAQC7Z6dx7GdY3vuP
yVIXA1h3vfP2gDKeA3GxCRko4zBL1vTNVsJGx+XeAAYk0suwAp0NGmTXiWlDC4hw
37yGy55W3I3hhQsSwTck+ZOCdqPuNQ4aBadwzEdKOw5SGbRCQe2JAc1zcYhWdFoF
7EspPpNkbxB3apEjkvFOxE42Be/XZrwxig1OQJ9DpOhTeV8+jljg6aSzOuQxdR4G
ZXTzACnb20jnefnwmC5lhZxRWYEXkc96onYIvrDpIMdTzTnTbshJjg5HNPOEEgpF
U1x2iCRB3tN9QHbzdH/XrnRBr9Yy62SUIDXf4LBqin/pRQPodh9ZM7zanrhzsuiy
Tro2WKhRAoGBANoAT73haGrUb9ZSdzpu5qOD0eaQZPCIlubRrT5BCXPS2xVIGe+g
eDaBljdlXDJnKvBqjOVQyU7lrZAIVWgz6qD1HNIQZI30WivXejL4GeoXnAnp/ohh
1QmjMVvlcGe/22jpDmJa3Qgm4leaUxnxxilO/pQlZzzndBP88Df4/hIJAoGBAPFI
xBRq0SdBWhSydeEFvm8n37/icrN+V9f/Ka9tbPZcJaowzqQPrAHtu2CBD1JVyo2G
sKxFy867vCHntFu8zq2KSpCPVyeR+pDvwknr9PDm+DiLScBCGdyKqjBazT5+mHzP
fKk6nRV8uoNXLZQtnqKJzN61bYrnFaOQx6GZM6J3AoGAUHqA9bY7GAUo7FQxU88R
Mhg96wIvYWTrYHbToAHefXXAD1E40e/JsUWRsQ2oRas0fOC49wcl6gx8UInjDb7s
xVL3usz2cjlc+IZpxFs3JeZlYnuRzcNgJFispiJDpul7FHXFK6YjpxjDwldkilVp
NGLHNOXCAQfpIF/mRqOTGBECgYAmb7kMp5d58WcwNN2iYw/bFTcHkkNDZLUJq5Qw
ZfYdqMA3RF8ms3hrNjvLO8P9Eb2angI270dwP2fQ3uBUXNdvvb/zF2KC4zZPMGJ6
9COo3KJeH5I4Fk+YWl6SJWTct74C4+qv6q5rZdswYQrZuAq1Sc5hC/XPUtCXpdCn
ZYhcMQKBgEHN3ZYe7gOfxR4rqk+OIsAUN9P3zyu6kQzUL1BQ7t7Gwi1dv6+E+BGQ
vGUt4RGG10g3K9twfhOHnwAiruEk6CK2+1G/ZsGCrPIE21KCcucUCPvzUGhintO+
b+Q5kAeZFg5CB9b616SY/GvlzPraNx5OZfI8nw39U9do7N/yFiKT
-----END RSA PRIVATE KEY-----

View File

@@ -0,0 +1,22 @@
#! /bin/bash
# Build the bootloader.
# In order to build successfully, ZEPHYR_SDK_INSTALL_DIR and
# ZEPHYR_GCC_VARIANT need to be set, as well as zephyr/zephyr-env.sh
# must be sourced.
die() {
echo error: "$@"
exit 1
}
if [ -z "$ZEPHYR_BASE" ]; then
die "Please setup for a Zephyr build before running this script."
fi
if [ -z "$BOARD" ]; then
die "Please set BOARD to a valid board before running this script."
fi
make BOARD=${BOARD} -j$(nproc) boot || die "Build mcuboot"

View File

@@ -0,0 +1,22 @@
#! /bin/bash
# Build the Sample hello program
# In order to build successfully, ZEPHYR_SDK_INSTALL_DIR and
# ZEPHYR_GCC_VARIANT need to be set, as well as zephyr/zephyr-env.sh
# must be sourced.
die() {
echo error: "$@"
exit 1
}
if [ -z "$ZEPHYR_BASE" ]; then
die "Please setup for a Zephyr build before running this script."
fi
if [ -z "$BOARD" ]; then
die "Please set BOARD to a valid board before running this script."
fi
make BOARD=${BOARD} -j$(nproc) hello1 || die "Build hello1"

View File

@@ -0,0 +1,26 @@
# Top-level CMakeLists.txt for the skeleton application.
#
# Copyright (c) 2017 Open Source Foundries Limited
# Copyright (c) 2018 Foundries.io Ltd
#
# SPDX-License-Identifier: Apache-2.0
#
# This provides a basic application structure suitable for loading by
# mcuboot, which is easy to customize on a per-board basis. It can be
# used as a starting point for new applications.
cmake_minimum_required(VERSION 3.8)
# find_package(Zephyr) in order to load application boilerplate:
# https://docs.zephyrproject.org/latest/develop/application/index.html
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(NONE)
# This string ends up getting printed in the device console
if (NOT DEFINED FROM_WHO)
set(FROM_WHO Zephyr)
endif()
target_compile_definitions(app PRIVATE "-DMCUBOOT_HELLO_WORLD_FROM=\"${FROM_WHO}\"")
target_sources(app PRIVATE src/main.c)

View File

@@ -0,0 +1,6 @@
This is a "Hello world" skeleton application which can be used as a
starting point for Zephyr application development using mcuboot.
It includes the configuration "glue" needed to make the application
loadable by mcuboot in addition to a basic Zephyr hello world
application's code.

View File

@@ -0,0 +1 @@
*-local.conf

View File

@@ -0,0 +1,2 @@
You can place per-board configuration here. See the comments in the
CMakeLists.txt for more information.

View File

@@ -0,0 +1,12 @@
# Print a banner on the UART on startup.
CONFIG_BOOT_BANNER=y
# Enable console and printk()
CONFIG_PRINTK=y
CONFIG_STDOUT_CONSOLE=y
# Enable Zephyr application to be booted by MCUboot
CONFIG_BOOTLOADER_MCUBOOT=y
# Use the default MCUBoot PEM key file (BOOT_SIGNATURE_KEY_FILE)
CONFIG_MCUBOOT_SIGNATURE_KEY_FILE="bootloader/mcuboot/root-rsa-2048.pem"

View File

@@ -0,0 +1,9 @@
sample:
name: Application Skeleton
description: Basic "hello world" application, but loadable by mcuboot
platforms: all
tests:
- test:
build_only: true
tags: samples tests
min_ram: 16

View File

@@ -0,0 +1 @@
obj-y = main.o

View File

@@ -0,0 +1,14 @@
/*
* Copyright (c) 2017 Linaro, Ltd.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
void main(void)
{
printk("Hello World from %s on %s!\n",
MCUBOOT_HELLO_WORLD_FROM, CONFIG_BOARD);
}

View File

@@ -0,0 +1,281 @@
// Package mcutests
package mcutests // github.com/mcu-tools/mcuboot/samples/zephyr/mcutests
// The main driver of this consists of a series of tests. Each test
// then contains a series of commands and expect results.
var Tests = []struct {
Name string
ShortName string
Tests []OneTest
}{
{
Name: "Good RSA",
ShortName: "good-rsa",
Tests: []OneTest{
{
Build: [][]string{
{"make", "test-good-rsa"},
},
Commands: [][]string{
{"make", "flash_boot"},
},
Expect: "Unable to find bootable image",
},
{
Commands: [][]string{
{"make", "flash_hello1"},
},
Expect: "Hello World from hello1",
},
{
Commands: [][]string{
{"make", "flash_hello2"},
},
Expect: "Hello World from hello2",
},
{
Commands: [][]string{
{"pyocd", "commander", "-c", "reset"},
},
Expect: "Hello World from hello1",
},
},
},
{
Name: "Good ECDSA",
ShortName: "good-ecdsa",
Tests: []OneTest{
{
Build: [][]string{
{"make", "test-good-ecdsa"},
},
Commands: [][]string{
{"make", "flash_boot"},
},
Expect: "Unable to find bootable image",
},
{
Commands: [][]string{
{"make", "flash_hello1"},
},
Expect: "Hello World from hello1",
},
{
Commands: [][]string{
{"make", "flash_hello2"},
},
Expect: "Hello World from hello2",
},
{
Commands: [][]string{
{"pyocd", "commander", "-c", "reset"},
},
Expect: "Hello World from hello1",
},
},
},
{
Name: "Overwrite",
ShortName: "overwrite",
Tests: []OneTest{
{
Build: [][]string{
{"make", "test-overwrite"},
},
Commands: [][]string{
{"make", "flash_boot"},
},
Expect: "Unable to find bootable image",
},
{
Commands: [][]string{
{"make", "flash_hello1"},
},
Expect: "Hello World from hello1",
},
{
Commands: [][]string{
{"make", "flash_hello2"},
},
Expect: "Hello World from hello2",
},
{
Commands: [][]string{
{"pyocd", "commander", "-c", "reset"},
},
Expect: "Hello World from hello2",
},
},
},
{
Name: "Bad RSA",
ShortName: "bad-rsa-upgrade",
Tests: []OneTest{
{
Build: [][]string{
{"make", "test-bad-rsa-upgrade"},
},
Commands: [][]string{
{"make", "flash_boot"},
},
Expect: "Unable to find bootable image",
},
{
Commands: [][]string{
{"make", "flash_hello1"},
},
Expect: "Hello World from hello1",
},
{
Commands: [][]string{
{"make", "flash_hello2"},
},
Expect: "Hello World from hello1",
},
{
Commands: [][]string{
{"pyocd", "commander", "-c", "reset"},
},
Expect: "Hello World from hello1",
},
},
},
{
Name: "Bad RSA",
ShortName: "bad-ecdsa-upgrade",
Tests: []OneTest{
{
Build: [][]string{
{"make", "test-bad-ecdsa-upgrade"},
},
Commands: [][]string{
{"make", "flash_boot"},
},
Expect: "Unable to find bootable image",
},
{
Commands: [][]string{
{"make", "flash_hello1"},
},
Expect: "Hello World from hello1",
},
{
Commands: [][]string{
{"make", "flash_hello2"},
},
Expect: "Hello World from hello1",
},
{
Commands: [][]string{
{"pyocd", "commander", "-c", "reset"},
},
Expect: "Hello World from hello1",
},
},
},
{
Name: "No bootcheck",
ShortName: "no-bootcheck",
Tests: []OneTest{
{
Build: [][]string{
{"make", "test-no-bootcheck"},
},
Commands: [][]string{
{"make", "flash_boot"},
},
Expect: "Unable to find bootable image",
},
{
Commands: [][]string{
{"make", "flash_hello1"},
},
Expect: "Hello World from hello1",
},
{
Commands: [][]string{
{"make", "flash_hello2"},
},
Expect: "Hello World from hello1",
},
{
Commands: [][]string{
{"pyocd", "commander", "-c", "reset"},
},
Expect: "Hello World from hello1",
},
},
},
{
Name: "Wrong RSA",
ShortName: "wrong-rsa",
Tests: []OneTest{
{
Build: [][]string{
{"make", "test-wrong-rsa"},
},
Commands: [][]string{
{"make", "flash_boot"},
},
Expect: "Unable to find bootable image",
},
{
Commands: [][]string{
{"make", "flash_hello1"},
},
Expect: "Hello World from hello1",
},
{
Commands: [][]string{
{"make", "flash_hello2"},
},
Expect: "Hello World from hello1",
},
{
Commands: [][]string{
{"pyocd", "commander", "-c", "reset"},
},
Expect: "Hello World from hello1",
},
},
},
{
Name: "Wrong ECDSA",
ShortName: "wrong-ecdsa",
Tests: []OneTest{
{
Build: [][]string{
{"make", "test-wrong-ecdsa"},
},
Commands: [][]string{
{"make", "flash_boot"},
},
Expect: "Unable to find bootable image",
},
{
Commands: [][]string{
{"make", "flash_hello1"},
},
Expect: "Hello World from hello1",
},
{
Commands: [][]string{
{"make", "flash_hello2"},
},
Expect: "Hello World from hello1",
},
{
Commands: [][]string{
{"pyocd", "commander", "-c", "reset"},
},
Expect: "Hello World from hello1",
},
},
},
}
type OneTest struct {
Build [][]string
Commands [][]string
Expect string
}

View File

@@ -0,0 +1,4 @@
# Kconfig overlay for building with ECDSA-P256 signatures
CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256=y
CONFIG_BOOT_SIGNATURE_KEY_FILE="root-ec-p256.pem"
CONFIG_BOOT_SWAP_USING_MOVE=y

View File

@@ -0,0 +1,3 @@
# Kconfig overlay for building with RSA signatures
CONFIG_BOOT_SIGNATURE_TYPE_RSA=y
CONFIG_BOOT_SWAP_USING_MOVE=y

View File

@@ -0,0 +1,4 @@
# Kconfig overlay for building without validating primary slot.
# CONFIG_BOOT_VALIDATE_SLOT0 is not set
CONFIG_BOOT_SWAP_USING_MOVE=y

View File

@@ -0,0 +1,2 @@
# Kconfig overlay for building in upgrade-only mode.
CONFIG_BOOT_UPGRADE_ONLY=y

View File

@@ -0,0 +1,290 @@
// +build ignore
//
// Build multiple configurations of MCUboot for Zephyr, making sure
// that they run properly.
//
// Run as:
//
// go run run-tests.go [flags]
//
// Add -help as a flag to get help. See comment below for logIn on
// how to configure terminal output to a file so this program can see
// the output of the Zephyr device.
package main
import (
"archive/zip"
"bufio"
"flag"
"fmt"
"io"
"log"
"os"
"os/exec"
"strings"
"time"
"github.com/mcu-tools/mcuboot/samples/zephyr/mcutests"
)
// logIn gives the pathname of the log output from the Zephyr device.
// In order to see the serial output, but still be useful for human
// debugging, the output of the terminal emulator should be teed to a
// file that this program will read from. This can be done with
// something like:
//
// picocom -b 115200 /dev/ttyACM0 | tee /tmp/zephyr.out
//
// Other terminal programs should also have logging options.
var logIn = flag.String("login", "/tmp/zephyr.out", "File name of terminal log from Zephyr device")
// Output from this test run is written to the given log file.
var logOut = flag.String("logout", "tests.log", "Log file to write to")
var preBuilt = flag.String("prebuilt", "", "Name of file with prebuilt tests")
func main() {
err := run()
if err != nil {
log.Fatal(err)
}
}
func run() error {
flag.Parse()
lines := make(chan string, 30)
go readLog(lines)
// Write output to a log file
logFile, err := os.Create(*logOut)
if err != nil {
return err
}
defer logFile.Close()
lg := bufio.NewWriter(logFile)
defer lg.Flush()
var extractor *Extractor
if *preBuilt != "" {
// If there are pre-built images, open them.
extractor, err = NewExtractor(*preBuilt)
if err != nil {
return err
}
defer extractor.Close()
}
for _, group := range mcutests.Tests {
fmt.Printf("Running %q\n", group.Name)
fmt.Fprintf(lg, "-------------------------------------\n")
fmt.Fprintf(lg, "---- Running %q\n", group.Name)
for _, test := range group.Tests {
if *preBuilt == "" {
// No prebuilt, build the tests
// ourselves.
err = runCommands(test.Build, lg)
if err != nil {
return err
}
} else {
// Extract the build artifacts from
// the zip file.
err = extractor.Extract(group.ShortName)
if err != nil {
return err
}
}
err = runCommands(test.Commands, lg)
if err != nil {
return err
}
err = expect(lg, lines, test.Expect)
if err != nil {
return err
}
fmt.Fprintf(lg, "---- Passed\n")
}
fmt.Printf(" Passed!\n")
}
return nil
}
// Run a set of commands
func runCommands(cmds [][]string, lg io.Writer) error {
for _, cmd := range cmds {
fmt.Printf(" %s\n", cmd)
fmt.Fprintf(lg, "---- Run: %s\n", cmd)
err := runCommand(cmd, lg)
if err != nil {
return err
}
}
return nil
}
// Run a single command.
func runCommand(cmd []string, lg io.Writer) error {
c := exec.Command(cmd[0], cmd[1:]...)
c.Stdout = lg
c.Stderr = lg
return c.Run()
}
// Expect the given string.
func expect(lg io.Writer, lines <-chan string, exp string) error {
// Read lines, and if we hit a timeout before seeing our
// expected line, then consider that an error.
fmt.Fprintf(lg, "---- expect: %q\n", exp)
stopper := time.NewTimer(10 * time.Second)
defer stopper.Stop()
outer:
for {
select {
case line := <-lines:
fmt.Fprintf(lg, "---- target: %q\n", line)
if strings.Contains(line, exp) {
break outer
}
case <-stopper.C:
fmt.Fprintf(lg, "timeout, didn't receive output\n")
return fmt.Errorf("timeout, didn't receive expected string: %q", exp)
}
}
return nil
}
// Read things from the log file, discarding everything already there.
func readLog(sink chan<- string) {
file, err := os.Open(*logIn)
if err != nil {
log.Fatal(err)
}
_, err = file.Seek(0, 2)
if err != nil {
log.Fatal(err)
}
prefix := ""
for {
// Read lines until EOF, then delay a bit, and do it
// all again.
rd := bufio.NewReader(file)
for {
line, err := rd.ReadString('\n')
if err == io.EOF {
// A partial line can happen because
// we are racing with the writer.
if line != "" {
prefix = line
}
break
}
if err != nil {
log.Fatal(err)
}
line = prefix + line
prefix = ""
sink <- line
// fmt.Printf("line: %q\n", line)
}
// Pause a little
time.Sleep(250 * time.Millisecond)
}
}
// An Extractor holds an opened Zip file, and is able to extract files
// based on the directory name.
type Extractor struct {
file *os.File
zip *zip.Reader
}
// NewExtractor returns an Extractor based on the contents of a zip
// file.
func NewExtractor(name string) (*Extractor, error) {
f, err := os.Open(name)
if err != nil {
return nil, err
}
size, err := f.Seek(0, 2)
if err != nil {
f.Close()
return nil, err
}
rd, err := zip.NewReader(f, size)
if err != nil {
f.Close()
return nil, err
}
return &Extractor{
file: f,
zip: rd,
}, nil
}
func (e *Extractor) Close() error {
return e.file.Close()
}
// Extract extracts the files of the given directory name into the
// current directory. These files will overwrite any files of these
// names that already exist (presumably from previous extractions).
func (e *Extractor) Extract(dir string) error {
prefix := dir + "/"
count := 0
for _, file := range e.zip.File {
if len(file.Name) > len(prefix) && strings.HasPrefix(file.Name, prefix) {
outName := file.Name[len(prefix):len(file.Name)]
fmt.Printf("->%q\n", outName)
err := e.single(file, outName)
if err != nil {
return err
}
count += 1
}
}
if count == 0 {
return fmt.Errorf("File for %s missing from archive", dir)
}
return nil
}
// single extracts a single file from the zip archive, writing the
// results to a file 'outName'.
func (e *Extractor) single(file *zip.File, outName string) error {
inf, err := file.Open()
if err != nil {
return err
}
outf, err := os.Create(outName)
if err != nil {
return err
}
defer outf.Close()
_, err = io.Copy(outf, inf)
return err
}

View File

@@ -0,0 +1,4 @@
#!/bin/bash
echo "Please use the new test runner: go run run-tests.go"
exit 1

View File

@@ -0,0 +1,156 @@
// +build ignore
//
// Build all of the tests.
//
// Run as:
//
// go run test-compile.go -out name.tar
package main
import (
"archive/zip"
"flag"
"fmt"
"io"
"log"
"os"
"os/exec"
"path"
"github.com/mcu-tools/mcuboot/samples/zephyr/mcutests"
)
var outFile = flag.String("out", "test-images.zip", "Name of zip file to put built tests into")
func main() {
err := run()
if err != nil {
log.Fatal(err)
}
}
func run() error {
flag.Parse()
zipper, err := NewBuilds()
if err != nil {
return err
}
defer zipper.Close()
for _, group := range mcutests.Tests {
fmt.Printf("Compiling %q\n", group.ShortName)
c := exec.Command("make",
fmt.Sprintf("test-%s", group.ShortName))
// TODO: Should capture the output and show it if
// there is an error.
err = c.Run()
if err != nil {
return err
}
err = zipper.Capture(group.ShortName)
if err != nil {
return err
}
}
return nil
}
// A Builds create a zipfile of the contents of various builds. The
// names will be constructed.
type Builds struct {
// The file being written to.
file *os.File
// The zip writer writing the data.
zip *zip.Writer
}
func NewBuilds() (*Builds, error) {
name := *outFile
file, err := os.OpenFile(name, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0644)
if err != nil {
return nil, err
}
z := zip.NewWriter(file)
return &Builds{
file: file,
zip: z,
}, nil
}
func (b *Builds) Close() error {
return b.zip.Close()
}
func (b *Builds) Capture(testName string) error {
// Collect stat information from the test directory, which
// should be close enough to make the zip file meaningful.
info, err := os.Stat(".")
if err != nil {
return err
}
header, err := zip.FileInfoHeader(info)
if err != nil {
return err
}
header.Name = testName + "/"
_, err = b.zip.CreateHeader(header)
if err != nil {
return err
}
for _, name := range []string{
"mcuboot.bin",
"signed-hello1.bin",
"signed-hello2.bin",
} {
err = b.add(testName, name, name)
if err != nil {
return err
}
}
return nil
}
func (b *Builds) add(baseName, zipName, fileName string) error {
inp, err := os.Open(fileName)
if err != nil {
return err
}
defer inp.Close()
info, err := inp.Stat()
if err != nil {
return err
}
header, err := zip.FileInfoHeader(info)
if err != nil {
return err
}
header.Name = path.Join(baseName, zipName)
header.Method = zip.Deflate
wr, err := b.zip.CreateHeader(header)
if err != nil {
return err
}
_, err = io.Copy(wr, inp)
if err != nil {
return err
}
return nil
}