Added demo update via BLE (GATT server on nRF52/RiotOS)

pull/5/head
Daniele Lacamera 2021-01-15 15:59:11 +01:00
parent b09c5e1291
commit 9b6f5dfa36
23 changed files with 2417 additions and 0 deletions

6
.gitmodules vendored
View File

@ -13,3 +13,9 @@
[submodule "freeRTOS-Freescale-K64F-https-TLS1.3/picotcp"]
path = freeRTOS-Freescale-K64F-https-TLS1.3/picotcp
url = https://gitlab.com/insane-adding-machines/picotcp.git
[submodule "contiki-ng-nrf52/contiki-ng"]
path = contiki-ng-nrf52/contiki-ng
url = https://github.com/contiki-ng/contiki-ng.git
[submodule "riotOS-nrf52840dk-ble/RIOT"]
path = riotOS-nrf52840dk-ble/RIOT
url = https://github.com/RIOT-OS/RIOT

@ -0,0 +1 @@
Subproject commit 0f3956a14eec28e9a8ca007dd95be8c0f832096f

View File

@ -0,0 +1,54 @@
CROSS_COMPILE:=arm-none-eabi-
OBJCOPY:=$(CROSS_COMPILE)objcopy
JLINK_OPTS = -Device NRF52840_xxAA -if swd -speed 1000
APP_SRC:=$(PWD)/nrf52-gatt-service
BOOT_ELF:=nrf52-gatt-service/bin/nrf52840dk/nrf52-gatt-service.elf
BOOT_IMG:=nrf52-gatt-service/bin/nrf52840dk/nrf52-gatt-service_v1_signed.bin
UPDATE_IMG:=$(PWD)/nrf52-gatt-service/bin/nrf52840dk/nrf52-gatt-service_v2_signed.bin
WOLFBOOT=../wolfBoot
WOLFBOOT_BIN=$(WOLFBOOT)/wolfboot.bin
all: $(BOOT_IMG) $(WOLFBOOT_BIN)
$(BOOT_IMG):
make wolfboot -C $(APP_SRC) IMAGE_VERSION=1
$(WOLFBOOT_BIN): FORCE
@cp -f ./wolfboot-config $(WOLFBOOT)/.config
@make -C $(WOLFBOOT) clean
@make -C $(WOLFBOOT) wolfboot.bin
clean: FORCE
make -C $(WOLFBOOT) clean
make -C $(APP_SRC) clean
rm -f $(APP_SRC)/*.bin
rm -f *.bin
rm -f tags
rm -rf linux-bluez/__pycache__
distclean: clean
rm -rf $(APP_SRC)/bin
flash: $(WOLFBOOT_BIN) $(BOOT_IMG)
JLinkExe $(JLINK_OPTS) -CommanderScript flash_all.jlink
reset: FORCE
JLinkExe $(JLINK_OPTS) -CommanderScript reset.jlink
update: FORCE
@make wolfboot -C $(APP_SRC) IMAGE_VERSION=2
@echo UPDATE ready. Please execute
@echo linux-bluez/fwupdate.py $(UPDATE_IMG)
@echo as root.
erase: FORCE
JLinkExe $(JLINK_OPTS) -CommanderScript flash_erase.jlink
.PHONY: FORCE

@ -0,0 +1 @@
Subproject commit bb1a3470d786b5b7e19c4fb59c5094d525862a4e

View File

@ -0,0 +1,5 @@
loadbin ../wolfBoot/wolfboot.bin 0x0
loadbin nrf52-gatt-service/bin/nrf52840dk/nrf52-gatt-service_v1_signed.bin 0x20000
r
g
q

View File

@ -0,0 +1,4 @@
erase
r
q

View File

@ -0,0 +1,50 @@
# bluez-utils
# SPDX-License-Identifier: LGPL-2.1-or-later
import dbus
SERVICE_NAME = "org.bluez"
ADAPTER_INTERFACE = SERVICE_NAME + ".Adapter1"
DEVICE_INTERFACE = SERVICE_NAME + ".Device1"
def get_managed_objects():
bus = dbus.SystemBus()
manager = dbus.Interface(bus.get_object("org.bluez", "/"),
"org.freedesktop.DBus.ObjectManager")
return manager.GetManagedObjects()
def find_adapter(pattern=None):
return find_adapter_in_objects(get_managed_objects(), pattern)
def find_adapter_in_objects(objects, pattern=None):
bus = dbus.SystemBus()
for path, ifaces in objects.items():
adapter = ifaces.get(ADAPTER_INTERFACE)
if adapter is None:
continue
if not pattern or pattern == adapter["Address"] or \
path.endswith(pattern):
obj = bus.get_object(SERVICE_NAME, path)
return dbus.Interface(obj, ADAPTER_INTERFACE)
raise Exception("Bluetooth adapter not found")
def find_device(device_address, adapter_pattern=None):
return find_device_in_objects(get_managed_objects(), device_address,
adapter_pattern)
def find_device_in_objects(objects, device_address, adapter_pattern=None):
bus = dbus.SystemBus()
path_prefix = ""
if adapter_pattern:
adapter = find_adapter_in_objects(objects, adapter_pattern)
path_prefix = adapter.object_path
for path, ifaces in objects.items():
device = ifaces.get(DEVICE_INTERFACE)
if device is None:
continue
if (device["Address"] == device_address and
path.startswith(path_prefix)):
obj = bus.get_object(SERVICE_NAME, path)
return dbus.Interface(obj, DEVICE_INTERFACE)
raise Exception("Bluetooth device not found")

View File

@ -0,0 +1,286 @@
#!/usr/bin/env python3
#
# fwupdate.py
#
# Copyright (C) 2021 wolfSSL Inc.
#
# wolfBoot fw-update example, Bluez client for Linux.
#
# wolfBoot is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# wolfBoot is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
import os
import sys
import dbus
try:
from gi.repository import GObject
except ImportError:
import gobject as GObject
import sys
import time
from dbus.mainloop.glib import DBusGMainLoop
import bluezutils
import struct
import keyboard
# Settings
FWUPDATE_TARGET="nRF52_UPDATE"
HCI="hci1"
bus = None
mainloop = None
BLUEZ_SERVICE_NAME = 'org.bluez'
DBUS_OM_IFACE = 'org.freedesktop.DBus.ObjectManager'
DBUS_PROP_IFACE = 'org.freedesktop.DBus.Properties'
GATT_SERVICE_IFACE = 'org.bluez.GattService1'
GATT_CHRC_IFACE = 'org.bluez.GattCharacteristic1'
FWUPDATE_SVC_UUID = '38f28386-3070-4f3b-ba38-27507e991760'
FWUPDATE_CHR_WRITE_UUID = '38f28386-3070-4f3b-ba38-27507e991762'
FWUPDATE_CHR_READ_UUID = '38f28386-3070-4f3b-ba38-27507e991764'
FWUPDATE_BOOT_NOTIFY_UUID = '38f28386-3070-4f3b-ba38-27507e991766'
FWUPDATE_CHUNK_SIZE=128
# The objects that we interact with.
fwupdate_service = None
fwupdate_ctrl_chrc = None
fwupdate_read_chrc = None
fwupdate_notify_chrc = None
bt_write_in_progress = False
fwup_off = 0
fwup_filename = None
fwup_file = None
fwup_filesize = 0
def bt_write(wbuf):
global bt_write_in_progress
bt_write_in_progress = True
fwupdate_ctrl_chrc[0].WriteValue(wbuf, {}, reply_handler=ctrl_write_cb,
error_handler=generic_error_cb,
dbus_interface=GATT_CHRC_IFACE)
#print("SND")
def ctrl_write_cb():
global bt_write_buffer
#print("ACK")
bt_write_in_progress = False
fwupdate_ctrl_chrc[0].ReadValue({}, reply_handler=update_off_cb,
error_handler=generic_error_cb,
dbus_interface=GATT_CHRC_IFACE)
def generic_error_cb(error):
print('D-Bus call failed: ' + str(error))
mainloop.quit()
def update_off_cb(value):
global fwup_off
global fwup_filename
global fwup_file
global fwup_filesize
x = struct.unpack("I", bytes(value))[0]
fwup_off = x
print("Update offset: " + str(x))
if (fwup_file is None):
if (fwup_filename is None):
print ("No update filename provided. Terminating...\n");
sys.exit(0)
fwup_filesize = os.path.getsize(fwup_filename)
try:
fwup_file = open(fwup_filename, "rb")
except:
print("Cannot open "+fwup_filename+". Exiting...")
sys.exit(1)
fwup_file.seek(fwup_off, 0)
wbuf = struct.pack("I", fwup_off)
wbuf += fwup_file.read(FWUPDATE_CHUNK_SIZE)
bt_write(wbuf)
def read_info_cb(value):
x = struct.unpack("I", bytes(value))[0]
print('Current version: '+ str(x))
def fwupdate_read_start_notify_cb():
print('notification enabled')
def fwupdate_read_changed_cb(iface, changed_props, invalidated_props):
if iface != GATT_CHRC_IFACE:
return
if not len(changed_props):
return
value = changed_props.get('Value', None)
if not value:
return
fwupdate_read_chrc[0].ReadValue({}, reply_handler=read_info_cb,
error_handler=generic_error_cb,
dbus_interface=GATT_CHRC_IFACE)
def sensors_start_notify_cb():
print("Sensors notifications: enabled.")
def start_client():
fwupdate_read_chrc[0].ReadValue({}, reply_handler=read_info_cb,
error_handler=generic_error_cb,
dbus_interface=GATT_CHRC_IFACE)
fwupdate_read_prop_iface = dbus.Interface(fwupdate_notify_chrc[0], DBUS_PROP_IFACE)
fwupdate_read_prop_iface.connect_to_signal("PropertiesChanged", fwupdate_read_changed_cb)
fwupdate_notify_chrc[0].StartNotify(reply_handler=sensors_start_notify_cb,
error_handler=generic_error_cb,
dbus_interface=GATT_CHRC_IFACE)
fwupdate_ctrl_chrc[0].ReadValue({}, reply_handler=update_off_cb,
error_handler=generic_error_cb,
dbus_interface=GATT_CHRC_IFACE)
def process_chrc(chrc_path):
chrc = bus.get_object(BLUEZ_SERVICE_NAME, chrc_path)
chrc_props = chrc.GetAll(GATT_CHRC_IFACE,
dbus_interface=DBUS_PROP_IFACE)
uuid = chrc_props['UUID']
if uuid == FWUPDATE_CHR_WRITE_UUID:
global fwupdate_ctrl_chrc
fwupdate_ctrl_chrc = (chrc, chrc_props)
elif uuid == FWUPDATE_CHR_READ_UUID:
global fwupdate_read_chrc
fwupdate_read_chrc = (chrc, chrc_props)
elif uuid == FWUPDATE_BOOT_NOTIFY_UUID:
global fwupdate_notify_chrc
fwupdate_notify_chrc = (chrc, chrc_props)
else:
print('Unrecognized characteristic: ' + uuid)
return True
def process_fwupdate_service(service_path, chrc_paths):
service = bus.get_object(BLUEZ_SERVICE_NAME, service_path)
service_props = service.GetAll(GATT_SERVICE_IFACE,
dbus_interface=DBUS_PROP_IFACE)
uuid = service_props['UUID']
if uuid != FWUPDATE_SVC_UUID:
return False
print('fwupdate GATT service found: ' + service_path)
global fwupdate_service
fwupdate_service = (service, service_props, service_path)
# Process the characteristics.
for chrc_path in chrc_paths:
process_chrc(chrc_path)
return True
def interfaces_removed_cb(object_path, interfaces):
if not fwupdate_service:
return
if object_path == fwupdate_service[2]:
print('Service was removed')
mainloop.quit()
def main():
# Set up the main loop.
DBusGMainLoop(set_as_default=True)
global bus
bus = dbus.SystemBus()
global mainloop
mainloop = GObject.MainLoop()
address = None
if (len(sys.argv) > 1):
global fwup_filename
fwup_filename = sys.argv[1]
om = dbus.Interface(bus.get_object(BLUEZ_SERVICE_NAME, '/'), DBUS_OM_IFACE)
om.connect_to_signal('InterfacesRemoved', interfaces_removed_cb)
print('Getting objects...')
objects = om.GetManagedObjects()
chrcs = []
# List devices found
for path, interfaces in objects.items():
device = interfaces.get("org.bluez.Device1")
if (device is None):
continue
try:
if (device["Name"] == FWUPDATE_TARGET):
print("Found FWUPDATE TARGET!")
address = device["Address"]
break
except:
continue
if address is None:
print("device not found.")
return
device = bluezutils.find_device(address, HCI)
if (device is None):
print("Cannot 'find_device'")
else:
device.Connect()
print("Connected")
# List characteristics found
for path, interfaces in objects.items():
if GATT_CHRC_IFACE not in interfaces.keys():
continue
chrcs.append(path)
# List sevices found
for path, interfaces in objects.items():
if GATT_SERVICE_IFACE not in interfaces.keys():
continue
chrc_paths = [d for d in chrcs if d.startswith(path + "/")]
if process_fwupdate_service(path, chrc_paths):
break
if not fwupdate_service:
print('No FWUPDATE found.')
sys.exit(1)
start_client()
mainloop.run()
if __name__ == '__main__':
main()

View File

@ -0,0 +1,4 @@
tar rem:3333
file bin/nrf52840dk/nrf52-gatt-service.elf
foc c

View File

@ -0,0 +1,63 @@
# name of your application
APPLICATION = nrf52-gatt-service
#debug
DEBUG=0
# If no BOARD is found in the environment, use this default:
BOARD ?= nrf52840dk
#BOARD ?= arduino-nano-33-iot
WOLFBOOT_OFFSET=131072
WOLFBOOT_PARTITION_SIZE=262144
IMAGE_VERSION=514
# This has to be the absolute path to the RIOT base directory:
RIOTBASE ?= $(CURDIR)/../RIOT/
# Require uart module
FEATURES_REQUIRED += periph_uart
EXTERNAL_MODULE_DIRS += $(CURDIR)/libwolfboot
USEMODULE += libwolfboot
# Some RIOT modules needed for this example
USEMODULE += event_timeout
# Network
USEMODULE += nimble
USEMODULE += nimble_addr
USEMODULE += nimble_scanner
USEMODULE += nimble_scanlist
USEMODULE += nimble_svc_gap
USEMODULE += nimble_svc_gatt
USEMODULE += nimble_drivers_nrf5x
USEMODULE += random
USEMODULE += periph_flashpage
#USEMODULE += usbus
#USEMODULE += stdio_cdc_acm
#USEMODULE += auto_init_usbus
USEMODULE += shell
USEMODULE += shell_commands
USEMODULE += ps
# Comment this out to disable code in RIOT that does safety checking
# which is not needed in a production environment but helps in the
# development process:
DEVELHELP ?= 0
CFLAGS+=-Wno-missing-field-initializers -Wno-unused-parameter -Wno-unused-variable -Wno-unused-function -I$(CURDIR)/include -Wno-missing-include-dirs
CFLAGS+=-DWOLFBOOT_HASH_SHA256 -DWOLFBOOT_SIGN_ECC256
WOLFBOOT_DIR=$(abspath $(RIOTBASE)/../../wolfBoot)
USEMODULE_INCLUDES+=-I$(WOLFBOOT_DIR)/include
# Change this to 0 show compiler invocation lines by default:
QUIET ?= 1
include $(RIOTBASE)/Makefile.include
include nimble.inc.mk
include ../wolfboot.mk

View File

@ -0,0 +1,41 @@
## BLE Firmware update with wolfBoot on nRF52
### Components
- BLE GATT server application, running RIOT-OS
- Python firmware update client, running on GNU/Linux
### Usage
- Compile wolfBoot and the GATT server application using:
```
make
```
- Connect the nRF52840 Development Kit and use the following command to upload the
bootloader and the version 1 of the signed application to the board:
```
make flash
```
- Prepare an update package using:
```
make update
```
- You can check the current version running on the target, either from a USB-serial console on `/dev/ttyACM0` by typing `info` into the shell, or
by reading the BLE GATT characteristics of the device.
- Use the fwupdate.py python application to transfer the update via BLE:
```
linux-bluez/fwupdate.py nrf52-gatt-service/bin/nrf52840dk/nrf52-gatt-service_v2_signed.bin
```

View File

@ -0,0 +1,482 @@
/* gatt_srv.c
*
* Copyright (C) 2021 wolfSSL Inc.
*
* wolfBoot fw-update example RIOT application, running on nRF52840.
*
* wolfBoot is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfBoot is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*
*/
#include <stdio.h>
#include <stdint.h>
#include "assert.h"
#include "event/timeout.h"
#include "nimble_riot.h"
#include "net/bluetil/ad.h"
#include "periph/gpio.h"
#include "timex.h"
#include "wolfboot/wolfboot.h"
#include "hal.h"
#include "board.h"
#include "host/ble_hs.h"
#include "host/ble_gatt.h"
#include "services/gap/ble_svc_gap.h"
#include "services/gatt/ble_svc_gatt.h"
static const char *_device_name = "nRF52_UPDATE";
static const char *_manufacturer_name = "wolfSSL";
static const char *_model_number = "PCA10056";
static const char *_serial_number = "dab1b30a11-ed218-x1";
static const char *_hw_ver = "1";
static event_queue_t _eq;
static event_t _update_evt;
static event_timeout_t _update_timeout_evt;
static uint16_t _conn_handle;
static uint16_t _reboot_val_handle;
static void reboot(void)
{
# define SCB_AIRCR (*((volatile uint32_t *)(0xE000ED0C)))
# define AIRCR_VECTKEY (0x05FA0000)
# define SYSRESET (1 << 2)
SCB_AIRCR = AIRCR_VECTKEY | SYSRESET;
}
static int _devinfo_handler(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg);
static int _fwupdate_handler(
uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg);
static int _fwupdate_info_handler(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg);
static int _bas_handler(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg);
static void _start_advertising(void);
/* UUID = 38f28386-3070-4f3b-ba38-27507e991760 */
static const ble_uuid128_t gatt_svr_svc_fwupdate = BLE_UUID128_INIT(
0x60, 0x17, 0x99, 0x7e, 0x50, 0x27, 0x38, 0xba,
0x3b, 0x4f, 0x70, 0x30, 0x86, 0x83, 0xf2, 0x38
);
/* UUID = 38f28386-3070-4f3b-ba38-27507e991762 */
static const ble_uuid128_t gatt_svr_chr_fwupdate = BLE_UUID128_INIT(
0x62, 0x17, 0x99, 0x7e, 0x50, 0x27, 0x38, 0xba,
0x3b, 0x4f, 0x70, 0x30, 0x86, 0x83, 0xf2, 0x38
);
/* UUID = 38f28386-3070-4f3b-ba38-27507e991764 */
static const ble_uuid128_t gatt_svr_chr_fwupdate_info = BLE_UUID128_INIT(
0x64, 0x17, 0x99, 0x7e, 0x50, 0x27, 0x38, 0xba,
0x3b, 0x4f, 0x70, 0x30, 0x86, 0x83, 0xf2, 0x38
);
/* UUID = 38f28386-3070-4f3b-ba38-27507e991766 */
static const ble_uuid128_t gatt_svr_chr_fwupdate_info_notify = BLE_UUID128_INIT(
0x66, 0x17, 0x99, 0x7e, 0x50, 0x27, 0x38, 0xba,
0x3b, 0x4f, 0x70, 0x30, 0x86, 0x83, 0xf2, 0x38
);
/* GATT service definitions */
static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
{
/* Firmware update controls */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = (ble_uuid_t*) &gatt_svr_svc_fwupdate.u,
.characteristics = (struct ble_gatt_chr_def[]) { {
/* Characteristic: FWUPDATE */
.uuid = (ble_uuid_t*) &gatt_svr_chr_fwupdate.u,
.access_cb = _fwupdate_handler,
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE,
}, {
/* Characteristic: Firmware info */
.uuid = (ble_uuid_t*) &gatt_svr_chr_fwupdate_info.u,
.access_cb = _fwupdate_info_handler,
.flags = BLE_GATT_CHR_F_READ,
}, {
/* Characteristic: Reboot notification */
.uuid = (ble_uuid_t*) &gatt_svr_chr_fwupdate_info_notify.u,
.access_cb = _fwupdate_info_handler,
.val_handle = &_reboot_val_handle,
.flags = BLE_GATT_CHR_F_NOTIFY,
}, {
0, /* no more characteristics in this service */
}, }
},
{
/* Device Information Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(BLE_GATT_SVC_DEVINFO),
.characteristics = (struct ble_gatt_chr_def[]) { {
.uuid = BLE_UUID16_DECLARE(BLE_GATT_CHAR_MANUFACTURER_NAME),
.access_cb = _devinfo_handler,
.flags = BLE_GATT_CHR_F_READ,
}, {
.uuid = BLE_UUID16_DECLARE(BLE_GATT_CHAR_MODEL_NUMBER_STR),
.access_cb = _devinfo_handler,
.flags = BLE_GATT_CHR_F_READ,
}, {
.uuid = BLE_UUID16_DECLARE(BLE_GATT_CHAR_SERIAL_NUMBER_STR),
.access_cb = _devinfo_handler,
.flags = BLE_GATT_CHR_F_READ,
}, {
.uuid = BLE_UUID16_DECLARE(BLE_GATT_CHAR_FW_REV_STR),
.access_cb = _devinfo_handler,
.flags = BLE_GATT_CHR_F_READ,
}, {
.uuid = BLE_UUID16_DECLARE(BLE_GATT_CHAR_HW_REV_STR),
.access_cb = _devinfo_handler,
.flags = BLE_GATT_CHR_F_READ,
}, {
0, /* no more characteristics in this service */
}, }
},
{
/* Battery Level Service */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = BLE_UUID16_DECLARE(BLE_GATT_SVC_BAS),
.characteristics = (struct ble_gatt_chr_def[]) { {
.uuid = BLE_UUID16_DECLARE(BLE_GATT_CHAR_BATTERY_LEVEL),
.access_cb = _bas_handler,
.flags = BLE_GATT_CHR_F_READ,
}, {
0, /* no more characteristics in this service */
}, }
},
{
0, /* no more services */
},
};
static int _fwupdate_info_handler(
uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg)
{
int rc = 0;
uint16_t om_len;
ble_uuid_t* read_uuid = (ble_uuid_t*) &gatt_svr_chr_fwupdate_info.u;
static uint8_t ch;
uint32_t ver = wolfBoot_current_firmware_version();
(void) conn_handle;
(void) attr_handle;
(void) arg;
if (ble_uuid_cmp(ctxt->chr->uuid, read_uuid) == 0) {
puts("access to characteristic 'fwupdate_info'");
rc = os_mbuf_append(ctxt->om, &ver, sizeof(uint32_t));
return rc;
}
puts("unhandled uuid!");
return 1;
}
#define FWUP_CHUNK_SIZE 128
#define FWUP_PKT_SIZE (FWUP_CHUNK_SIZE + sizeof(uint32_t))
static uint32_t fwup_cur_off = 0;
static uint32_t fwup_size = 0;
static uint8_t fwup_page_buffer[WOLFBOOT_SECTOR_SIZE];
static uint8_t fwup_pkt_buffer[FWUP_PKT_SIZE];
static uint32_t fwup_pkt_len = 0;
static void parse_update(void)
{
uint32_t *sz;
uint32_t *seq;
const uint32_t zero = 0;
if (fwup_size > 0)
printf("Update: %lu / %lu \n", fwup_cur_off, fwup_size);
else
printf("Update: first packet\n");
if (fwup_cur_off == 0) {
if (memcmp(&zero, fwup_pkt_buffer, 4) != 0) {
printf("wrong packet recvd: %lu\n", *(uint32_t *)(fwup_pkt_buffer));
return;
}
if (memcmp(fwup_pkt_buffer + 4, "WOLF", 4) != 0) {
puts("wrong packet hdr");
return;
}
sz = (uint32_t *)(fwup_pkt_buffer + 8);
if ((*sz < 256) || (*sz > WOLFBOOT_PARTITION_SIZE)) {
printf("Wrong firmware size %lu\n", *sz);
return;
}
fwup_size = *sz + IMAGE_HEADER_SIZE;
printf("Total firmware len: %lu\n", fwup_size);
hal_flash_lock();
hal_flash_erase(WOLFBOOT_PARTITION_UPDATE_ADDRESS, WOLFBOOT_PARTITION_SIZE);
hal_flash_unlock();
memset(fwup_page_buffer, 0xFF, WOLFBOOT_SECTOR_SIZE);
}
if (fwup_size > 0) {
uint32_t in_page_off = fwup_cur_off % WOLFBOOT_SECTOR_SIZE;
seq = (uint32_t *)(fwup_pkt_buffer);
if (*seq != fwup_cur_off) {
printf("Wrong seq %lu expecting %lu \n", *seq, fwup_cur_off);
return;
}
memcpy(fwup_page_buffer + in_page_off, fwup_pkt_buffer + 4, fwup_pkt_len - 4);
fwup_cur_off += fwup_pkt_len - 4;
if (((fwup_cur_off % WOLFBOOT_SECTOR_SIZE) == 0) || (fwup_cur_off >= fwup_size)) {
hal_flash_unlock();
if (fwup_cur_off >= fwup_size) {
uint32_t last_chunk_size = fwup_cur_off % WOLFBOOT_SECTOR_SIZE;
uint32_t last_chunk_addr = fwup_cur_off - last_chunk_size;
if (last_chunk_size > 0) {
hal_flash_write(WOLFBOOT_PARTITION_UPDATE_ADDRESS + last_chunk_addr, fwup_page_buffer, last_chunk_size);
}
} else {
hal_flash_write(WOLFBOOT_PARTITION_UPDATE_ADDRESS + (fwup_cur_off - WOLFBOOT_SECTOR_SIZE), fwup_page_buffer, WOLFBOOT_SECTOR_SIZE);
}
hal_flash_lock();
memset(fwup_page_buffer, 0xFF, WOLFBOOT_SECTOR_SIZE);
if (fwup_cur_off + fwup_pkt_len >= fwup_size) {
printf("Update complete (%lu/%lu).\n", fwup_cur_off, fwup_size);
wolfBoot_update_trigger();
reboot();
while(1)
;
}
}
}
return;
}
static int _fwupdate_handler(
uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg)
{
int rc = 0;
uint16_t om_len;
ble_uuid_t* write_uuid = (ble_uuid_t*) &gatt_svr_chr_fwupdate.u;
(void) conn_handle;
(void) attr_handle;
(void) arg;
if (ble_uuid_cmp(ctxt->chr->uuid, write_uuid) == 0) {
switch (ctxt->op) {
case BLE_GATT_ACCESS_OP_READ_CHR:
rc = os_mbuf_append(ctxt->om, &fwup_cur_off, sizeof(uint32_t));
fwup_pkt_len = 0;
//printf("ACK offset: %lx\n", fwup_cur_off);
break;
case BLE_GATT_ACCESS_OP_WRITE_CHR:
om_len = OS_MBUF_PKTLEN(ctxt->om);
if (om_len <= FWUP_PKT_SIZE) {
rc = ble_hs_mbuf_to_flat(ctxt->om, fwup_pkt_buffer, FWUP_PKT_SIZE, &om_len);
fwup_pkt_len = om_len;
parse_update();
} else {
printf("wrong OM LEN: %d !\n", om_len);
}
break;
case BLE_GATT_ACCESS_OP_READ_DSC:
puts("read from descriptor");
break;
case BLE_GATT_ACCESS_OP_WRITE_DSC:
puts("write to descriptor");
break;
default:
puts("unhandled operation!");
rc = 1;
break;
}
return rc;
}
puts("unhandled uuid!");
return 1;
}
static int _devinfo_handler(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg)
{
(void)conn_handle;
(void)attr_handle;
(void)arg;
char version[20] = "";
const char *str;
switch (ble_uuid_u16(ctxt->chr->uuid)) {
case BLE_GATT_CHAR_MANUFACTURER_NAME:
puts("[READ] device information service: manufacturer name value");
str = _manufacturer_name;
break;
case BLE_GATT_CHAR_MODEL_NUMBER_STR:
puts("[READ] device information service: model number value");
str = _model_number;
break;
case BLE_GATT_CHAR_SERIAL_NUMBER_STR:
puts("[READ] device information service: serial number value");
str = _serial_number;
break;
case BLE_GATT_CHAR_FW_REV_STR:
puts("[READ] device information service: firmware revision value");
snprintf(version, 20, "%08x", (unsigned int)wolfBoot_current_firmware_version());
str = version;
break;
case BLE_GATT_CHAR_SW_REV_STR:
puts("[READ] device information service: software revision value");
snprintf(version, 20, "%08x", (unsigned int)wolfBoot_update_firmware_version());
str = version;
break;
case BLE_GATT_CHAR_HW_REV_STR:
puts("[READ] device information service: hardware revision value");
str = _hw_ver;
break;
default:
return BLE_ATT_ERR_UNLIKELY;
}
int res = os_mbuf_append(ctxt->om, str, strlen(str));
return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
}
static int _bas_handler(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg)
{
(void)conn_handle;
(void)attr_handle;
(void)arg;
puts("[READ] battery level service: battery level value");
uint8_t level = 50; /* this battery will never drain :-) */
int res = os_mbuf_append(ctxt->om, &level, sizeof(level));
return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
}
static int gap_event_cb(struct ble_gap_event *event, void *arg)
{
(void)arg;
switch (event->type) {
case BLE_GAP_EVENT_CONNECT:
printf("Ev: connect, Status: %d\n", event->connect.status);
if (event->connect.status) {
_start_advertising();
LED2_OFF;
return 0;
}
LED2_ON;
_conn_handle = event->connect.conn_handle;
break;
case BLE_GAP_EVENT_DISCONNECT:
_start_advertising();
break;
case BLE_GAP_EVENT_SUBSCRIBE:
if (event->subscribe.attr_handle == _reboot_val_handle) {
if (event->subscribe.cur_notify == 1) {
}
else {
}
}
break;
}
return 0;
}
static void _start_advertising(void)
{
struct ble_gap_adv_params advp;
int res;
memset(&advp, 0, sizeof advp);
advp.conn_mode = BLE_GAP_CONN_MODE_UND;
advp.disc_mode = BLE_GAP_DISC_MODE_GEN;
advp.itvl_min = BLE_GAP_ADV_FAST_INTERVAL1_MIN;
advp.itvl_max = BLE_GAP_ADV_FAST_INTERVAL1_MAX;
res = ble_gap_adv_start(nimble_riot_own_addr_type, NULL, BLE_HS_FOREVER,
&advp, gap_event_cb, NULL);
assert(res == 0);
(void)res;
}
static void notify_boot(void)
{
struct os_mbuf *om;
unsigned int version;
version = (unsigned int) wolfBoot_current_firmware_version();
printf("[GATT] Sending boot notification.\n");
/* send data notification to GATT client */
om = ble_hs_mbuf_from_flat(&version, sizeof(unsigned int));
if (!om) {
printf("[GATT] Error incapsulating version data in frame \n");
return;
}
ble_gattc_notify_custom(_conn_handle, _reboot_val_handle, om);
}
void *gatt_srv(void *arg)
{
puts("NimBLE GATT server starting");
int res = 0;
msg_t msg;
(void)res;
notify_boot();
wolfBoot_success();
/* verify and add our custom services */
res = ble_gatts_count_cfg(gatt_svr_svcs);
assert(res == 0);
res = ble_gatts_add_svcs(gatt_svr_svcs);
assert(res == 0);
/* set the device name */
ble_svc_gap_device_name_set(_device_name);
/* reload the GATT server to link our added services */
ble_gatts_start();
/* configure and set the advertising data */
uint8_t buf[BLE_HS_ADV_MAX_SZ];
bluetil_ad_t ad;
bluetil_ad_init_with_flags(&ad, buf, sizeof(buf), BLUETIL_AD_FLAGS_DEFAULT);
bluetil_ad_add_name(&ad, _device_name);
ble_gap_adv_set_data(ad.buf, ad.pos);
/* start to advertise this node */
_start_advertising();
while (1) {
if (msg_receive(&msg) >= 0) {
(void)msg;
}
}
return 0;
}

View File

@ -0,0 +1,56 @@
/* ble_svc_gap.h
*
* Copyright (C) 2021 wolfSSL Inc.
*
* wolfBoot fw-update example RIOT application, running on nRF52840.
*
* wolfBoot is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfBoot is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*
*/
#ifndef H_BLE_SVC_GAP_
#define H_BLE_SVC_GAP_
#include <inttypes.h>
#ifdef __cplusplus
extern "C" {
#endif
#define BLE_SVC_GAP_UUID16 0x1800
#define BLE_SVC_GAP_CHR_UUID16_DEVICE_NAME 0x2a00
#define BLE_SVC_GAP_CHR_UUID16_APPEARANCE 0x2a01
#define BLE_SVC_GAP_CHR_UUID16_PERIPH_PREF_CONN_PARAMS 0x2a04
#define BLE_SVC_GAP_CHR_UUID16_CENTRAL_ADDRESS_RESOLUTION 0x2aa6
#define BLE_SVC_GAP_APPEARANCE_GEN_UNKNOWN 0
#define BLE_SVC_GAP_APPEARANCE_GEN_COMPUTER 128
#define BLE_SVC_GAP_APPEARANCE_CYC_SPEED_AND_CADENCE_SENSOR 1157
typedef void (ble_svc_gap_chr_changed_fn) (uint16_t uuid);
void ble_svc_gap_set_chr_changed_cb(ble_svc_gap_chr_changed_fn *cb);
const char *ble_svc_gap_device_name(void);
int ble_svc_gap_device_name_set(const char *name);
uint16_t ble_svc_gap_device_appearance(void);
int ble_svc_gap_device_appearance_set(uint16_t appearance);
void ble_svc_gap_init(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,42 @@
/* ble_svc_gatt.h
*
* Copyright (C) 2021 wolfSSL Inc.
*
* wolfBoot fw-update example RIOT application, running on nRF52840.
*
* wolfBoot is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfBoot is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*
*/
#ifndef H_BLE_SVC_GATT_
#define H_BLE_SVC_GATT_
#include <inttypes.h>
#ifdef __cplusplus
extern "C" {
#endif
struct ble_hs_cfg;
#define BLE_SVC_GATT_CHR_SERVICE_CHANGED_UUID16 0x2a05
void ble_svc_gatt_changed(uint16_t start_handle, uint16_t end_handle);
void ble_svc_gatt_init(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,6 @@
WOLFBOOT_DIR=$(abspath $(CURDIR)/../../../wolfBoot)
INCLUDES+=-I$(WOLFBOOT_DIR)/include
SRC+=libwolfboot.c nrf52.c
NO_AUTO_SRC = 1
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,798 @@
/* libwolfboot.c
*
* Copyright (C) 2020 wolfSSL Inc.
*
* This file is part of wolfBoot.
*
* wolfBoot is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfBoot is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#include <stdint.h>
#include <inttypes.h>
#include "hal.h"
#include "wolfboot/wolfboot.h"
#include "image.h"
#ifdef UNIT_TEST
# define unit_dbg printf
#else
# define unit_dbg(...) do{}while(0)
#endif
#ifndef TRAILER_SKIP
# define TRAILER_SKIP 0
#endif
#if defined(EXT_ENCRYPTED)
#if defined(__WOLFBOOT)
#include "encrypt.h"
#else
#include <stddef.h>
#include <string.h>
#define XMEMSET memset
#define XMEMCPY memcpy
#define XMEMCMP memcmp
#endif
#define ENCRYPT_TMP_SECRET_OFFSET (WOLFBOOT_PARTITION_SIZE - (TRAILER_SKIP + ENCRYPT_KEY_SIZE + ENCRYPT_NONCE_SIZE))
#define TRAILER_OVERHEAD (4 + 1 + (WOLFBOOT_PARTITION_SIZE / (2 * WOLFBOOT_SECTOR_SIZE))) /* MAGIC + PART_FLAG (1B) + (N_SECTORS / 2) */
#define START_FLAGS_OFFSET (ENCRYPT_TMP_SECRET_OFFSET - TRAILER_OVERHEAD)
#else
#define XMEMCPY memcpy
#define ENCRYPT_TMP_SECRET_OFFSET (WOLFBOOT_PARTITION_SIZE - (TRAILER_SKIP))
#endif
#ifndef NULL
# define NULL (void *)0
#endif
#define NVM_CACHE_SIZE WOLFBOOT_SECTOR_SIZE
#ifdef EXT_FLASH
static uint32_t ext_cache;
#endif
static const uint32_t wolfboot_magic_trail = WOLFBOOT_MAGIC_TRAIL;
/* Top addresses for FLAGS field
* - PART_BOOT_ENDFLAGS = top of flags for BOOT partition
* - PART_UPDATE_ENDFLAGS = top of flags for UPDATE_PARTITION
*/
#define PART_BOOT_ENDFLAGS (WOLFBOOT_PARTITION_BOOT_ADDRESS + ENCRYPT_TMP_SECRET_OFFSET)
#define FLAGS_BOOT_EXT() PARTN_IS_EXT(PART_BOOT)
#ifdef FLAGS_HOME
/*
* In FLAGS_HOME mode, all FLAGS live at the end of the boot partition:
* / -12 /-8 /-4 / END
* |Sn| ... |S2|S1|S0|PU| MAGIC |X|X|X|PB| MAGIC |
* ^--sectors --^ ^--update ^---boot partition
* flags partition flag
* flag
*
* */
#define PART_UPDATE_ENDFLAGS (PART_BOOT_ENDFLAGS - 8)
#define FLAGS_UPDATE_EXT() PARTN_IS_EXT(PART_BOOT)
#else
/* FLAGS are at the end of each partition */
#define PART_UPDATE_ENDFLAGS (WOLFBOOT_PARTITION_UPDATE_ADDRESS + ENCRYPT_TMP_SECRET_OFFSET)
#define FLAGS_UPDATE_EXT() PARTN_IS_EXT(PART_UPDATE)
#endif
#ifdef NVM_FLASH_WRITEONCE
#include <stddef.h>
#include <string.h>
static uint8_t NVM_CACHE[NVM_CACHE_SIZE] __attribute__((aligned(16)));
int RAMFUNCTION hal_trailer_write(uint32_t addr, uint8_t val) {
uint32_t addr_align = addr & (~(WOLFBOOT_SECTOR_SIZE - 1));
uint32_t addr_off = addr & (WOLFBOOT_SECTOR_SIZE - 1);
int ret = 0;
XMEMCPY(NVM_CACHE, (void *)addr_align, WOLFBOOT_SECTOR_SIZE);
ret = hal_flash_erase(addr_align, WOLFBOOT_SECTOR_SIZE);
if (ret != 0)
return ret;
NVM_CACHE[addr_off] = val;
ret = hal_flash_write(addr_align, NVM_CACHE, WOLFBOOT_SECTOR_SIZE);
return ret;
}
int RAMFUNCTION hal_set_partition_magic(uint32_t addr)
{
uint32_t off = addr % NVM_CACHE_SIZE;
uint32_t base = addr - off;
int ret;
XMEMCPY(NVM_CACHE, (void *)base, NVM_CACHE_SIZE);
ret = hal_flash_erase(base, WOLFBOOT_SECTOR_SIZE);
if (ret != 0)
return ret;
XMEMCPY(NVM_CACHE + off, &wolfboot_magic_trail, sizeof(uint32_t));
ret = hal_flash_write(base, NVM_CACHE, WOLFBOOT_SECTOR_SIZE);
return ret;
}
#else
# define hal_trailer_write(addr, val) hal_flash_write(addr, (void *)&val, 1)
# define hal_set_partition_magic(addr) hal_flash_write(addr, (void*)&wolfboot_magic_trail, sizeof(uint32_t));
#endif
#if defined EXT_FLASH
static uint8_t* RAMFUNCTION get_trailer_at(uint8_t part, uint32_t at)
{
if (part == PART_BOOT) {
if (FLAGS_BOOT_EXT()){
ext_flash_check_read(PART_BOOT_ENDFLAGS - (sizeof(uint32_t) + at), (void *)&ext_cache, sizeof(uint32_t));
return (uint8_t *)&ext_cache;
} else {
return (void *)(PART_BOOT_ENDFLAGS - (sizeof(uint32_t) + at));
}
}
else if (part == PART_UPDATE) {
if (FLAGS_UPDATE_EXT()) {
ext_flash_check_read(PART_UPDATE_ENDFLAGS - (sizeof(uint32_t) + at), (void *)&ext_cache, sizeof(uint32_t));
return (uint8_t *)&ext_cache;
} else {
return (void *)(PART_UPDATE_ENDFLAGS - (sizeof(uint32_t) + at));
}
} else
return NULL;
}
static void RAMFUNCTION set_trailer_at(uint8_t part, uint32_t at, uint8_t val)
{
if (part == PART_BOOT) {
if (FLAGS_BOOT_EXT()) {
ext_flash_check_write(PART_BOOT_ENDFLAGS - (sizeof(uint32_t) + at), (void *)&val, 1);
} else {
hal_trailer_write(PART_BOOT_ENDFLAGS - (sizeof(uint32_t) + at), val);
}
}
else if (part == PART_UPDATE) {
if (FLAGS_UPDATE_EXT()) {
ext_flash_check_write(PART_UPDATE_ENDFLAGS - (sizeof(uint32_t) + at), (void *)&val, 1);
} else {
hal_trailer_write(PART_UPDATE_ENDFLAGS - (sizeof(uint32_t) + at), val);
}
}
}
static void RAMFUNCTION set_partition_magic(uint8_t part)
{
if (part == PART_BOOT) {
if (FLAGS_BOOT_EXT()) {
ext_flash_check_write(PART_BOOT_ENDFLAGS - sizeof(uint32_t), (void *)&wolfboot_magic_trail, sizeof(uint32_t));
} else {
hal_set_partition_magic(PART_BOOT_ENDFLAGS - sizeof(uint32_t));
}
}
else if (part == PART_UPDATE) {
if (FLAGS_UPDATE_EXT()) {
ext_flash_check_write(PART_UPDATE_ENDFLAGS - sizeof(uint32_t), (void *)&wolfboot_magic_trail, sizeof(uint32_t));
} else {
hal_set_partition_magic(PART_UPDATE_ENDFLAGS - sizeof(uint32_t));
}
}
}
#else
static uint8_t* RAMFUNCTION get_trailer_at(uint8_t part, uint32_t at)
{
if (part == PART_BOOT)
return (void *)(PART_BOOT_ENDFLAGS - (sizeof(uint32_t) + at));
else if (part == PART_UPDATE) {
return (void *)(PART_UPDATE_ENDFLAGS - (sizeof(uint32_t) + at));
} else
return NULL;
}
static void RAMFUNCTION set_trailer_at(uint8_t part, uint32_t at, uint8_t val)
{
if (part == PART_BOOT) {
hal_trailer_write(PART_BOOT_ENDFLAGS - (sizeof(uint32_t) + at), val);
}
else if (part == PART_UPDATE) {
hal_trailer_write(PART_UPDATE_ENDFLAGS - (sizeof(uint32_t) + at), val);
}
}
static void RAMFUNCTION set_partition_magic(uint8_t part)
{
if (part == PART_BOOT) {
hal_set_partition_magic(PART_BOOT_ENDFLAGS - sizeof(uint32_t));
}
else if (part == PART_UPDATE) {
hal_set_partition_magic(PART_UPDATE_ENDFLAGS - sizeof(uint32_t));
}
}
#endif /* EXT_FLASH */
static uint32_t* RAMFUNCTION get_partition_magic(uint8_t part)
{
return (uint32_t *)get_trailer_at(part, 0);
}
static uint8_t* RAMFUNCTION get_partition_state(uint8_t part)
{
return (uint8_t *)get_trailer_at(part, 1);
}
static void RAMFUNCTION set_partition_state(uint8_t part, uint8_t val)
{
set_trailer_at(part, 1, val);
}
static void RAMFUNCTION set_update_sector_flags(uint32_t pos, uint8_t val)
{
set_trailer_at(PART_UPDATE, 2 + pos, val);
}
static uint8_t* RAMFUNCTION get_update_sector_flags(uint32_t pos)
{
return (uint8_t *)get_trailer_at(PART_UPDATE, 2 + pos);
}
int RAMFUNCTION wolfBoot_set_partition_state(uint8_t part, uint8_t newst)
{
uint32_t *magic;
uint8_t *state;
magic = get_partition_magic(part);
if (*magic != WOLFBOOT_MAGIC_TRAIL)
set_partition_magic(part);
state = get_partition_state(part);
if (*state != newst)
set_partition_state(part, newst);
return 0;
}
int RAMFUNCTION wolfBoot_set_update_sector_flag(uint16_t sector, uint8_t newflag)
{
uint32_t *magic;
uint8_t *flags;
uint8_t fl_value;
uint8_t pos = sector >> 1;
magic = get_partition_magic(PART_UPDATE);
if (*magic != wolfboot_magic_trail)
set_partition_magic(PART_UPDATE);
flags = get_update_sector_flags(pos);
if (sector == (pos << 1))
fl_value = (*flags & 0xF0) | (newflag & 0x0F);
else
fl_value = ((newflag & 0x0F) << 4) | (*flags & 0x0F);
if (fl_value != *flags)
set_update_sector_flags(pos, fl_value);
return 0;
}
int RAMFUNCTION wolfBoot_get_partition_state(uint8_t part, uint8_t *st)
{
uint32_t *magic;
uint8_t *state;
magic = get_partition_magic(part);
if (*magic != WOLFBOOT_MAGIC_TRAIL)
return -1;
state = get_partition_state(part);
*st = *state;
return 0;
}
int wolfBoot_get_update_sector_flag(uint16_t sector, uint8_t *flag)
{
uint32_t *magic;
uint8_t *flags;
uint8_t pos = sector >> 1;
magic = get_partition_magic(PART_UPDATE);
if (*magic != WOLFBOOT_MAGIC_TRAIL)
return -1;
flags = get_update_sector_flags(pos);
if (sector == (pos << 1))
*flag = *flags & 0x0F;
else
*flag = (*flags & 0xF0) >> 4;
return 0;
}
void RAMFUNCTION wolfBoot_erase_partition(uint8_t part)
{
if (part == PART_BOOT) {
if (PARTN_IS_EXT(PART_BOOT)) {
ext_flash_unlock();
ext_flash_erase(WOLFBOOT_PARTITION_BOOT_ADDRESS, WOLFBOOT_PARTITION_SIZE);
ext_flash_lock();
} else {
hal_flash_erase(WOLFBOOT_PARTITION_BOOT_ADDRESS, WOLFBOOT_PARTITION_SIZE);
}
}
if (part == PART_UPDATE) {
if (PARTN_IS_EXT(PART_UPDATE)) {
ext_flash_unlock();
ext_flash_erase(WOLFBOOT_PARTITION_UPDATE_ADDRESS, WOLFBOOT_PARTITION_SIZE);
ext_flash_lock();
} else {
hal_flash_erase(WOLFBOOT_PARTITION_UPDATE_ADDRESS, WOLFBOOT_PARTITION_SIZE);
}
}
if (part == PART_SWAP) {
if (PARTN_IS_EXT(PART_SWAP)) {
ext_flash_unlock();
ext_flash_erase(WOLFBOOT_PARTITION_SWAP_ADDRESS, WOLFBOOT_SECTOR_SIZE);
ext_flash_lock();
} else {
hal_flash_erase(WOLFBOOT_PARTITION_SWAP_ADDRESS, WOLFBOOT_SECTOR_SIZE);
}
}
}
void RAMFUNCTION wolfBoot_update_trigger(void)
{
uint8_t st = IMG_STATE_UPDATING;
#ifdef FLAGS_HOME
/* Erase last sector of boot partition prior to
* setting the partition state.
*/
uint32_t last_sector = PART_UPDATE_ENDFLAGS - (PART_UPDATE_ENDFLAGS % WOLFBOOT_SECTOR_SIZE);
hal_flash_unlock();
hal_flash_erase(last_sector, WOLFBOOT_SECTOR_SIZE);
hal_flash_lock();
#endif
if (FLAGS_UPDATE_EXT())
{
ext_flash_unlock();
wolfBoot_set_partition_state(PART_UPDATE, st);
ext_flash_lock();
} else {
hal_flash_unlock();
wolfBoot_set_partition_state(PART_UPDATE, st);
hal_flash_lock();
}
}
void RAMFUNCTION wolfBoot_success(void)
{
uint8_t st = IMG_STATE_SUCCESS;
if (FLAGS_BOOT_EXT())
{
ext_flash_unlock();
wolfBoot_set_partition_state(PART_BOOT, st);
ext_flash_lock();
} else {
hal_flash_unlock();
wolfBoot_set_partition_state(PART_BOOT, st);
hal_flash_lock();
}
#ifdef EXT_ENCRYPTED
wolfBoot_erase_encrypt_key();
#endif
}
uint16_t wolfBoot_find_header(uint8_t *haystack, uint16_t type, uint8_t **ptr)
{
uint8_t *p = haystack;
uint16_t len;
const volatile uint8_t *max_p = (haystack - IMAGE_HEADER_OFFSET) + IMAGE_HEADER_SIZE;
*ptr = NULL;
if (p > max_p) {
unit_dbg("Illegal address (too high)\n");
return 0;
}
while ((p + 4) < max_p) {
if ((p[0] == 0) && (p[1] == 0)) {
unit_dbg("Explicit end of options reached\n");
break;
}
if (*p == HDR_PADDING) {
/* Padding byte (skip one position) */
p++;
continue;
}
/* Sanity check to prevent dereferencing unaligned half-words */
if ((((unsigned long)p) & 0x01) != 0) {
p++;
continue;
}
len = p[2] | (p[3] << 8);
if ((4 + len) > (uint16_t)(IMAGE_HEADER_SIZE - IMAGE_HEADER_OFFSET)) {
unit_dbg("This field is too large (bigger than the space available in the current header)\n");
break;
}
if (p + 4 + len > max_p) {
unit_dbg("This field is too large and would overflow the image header\n");
break;
}
if ((p[0] | (p[1] << 8)) == type) {
*ptr = (p + 4);
return len;
}
p += 4 + len;
}
return 0;
}
#ifdef EXT_FLASH
static uint8_t hdr_cpy[IMAGE_HEADER_SIZE];
static uint32_t hdr_cpy_done = 0;
#endif
uint32_t wolfBoot_get_blob_version(uint8_t *blob)
{
uint32_t *version_field = NULL;
uint32_t *magic = NULL;
magic = (uint32_t *)blob;
if (*magic != WOLFBOOT_MAGIC)
return 0;
if (wolfBoot_find_header(blob + IMAGE_HEADER_OFFSET, HDR_VERSION, (void *)&version_field) == 0)
return 0;
if (version_field)
return *version_field;
return 0;
}
uint32_t wolfBoot_get_image_version(uint8_t part)
{
uint8_t *image = (uint8_t *)0x00000000;
if(part == PART_UPDATE) {
if (PARTN_IS_EXT(PART_UPDATE))
{
#ifdef EXT_FLASH
ext_flash_check_read((uintptr_t)WOLFBOOT_PARTITION_UPDATE_ADDRESS, hdr_cpy, IMAGE_HEADER_SIZE);
hdr_cpy_done = 1;
image = hdr_cpy;
#endif
} else {
image = (uint8_t *)WOLFBOOT_PARTITION_UPDATE_ADDRESS;
}
} else if (part == PART_BOOT) {
if (PARTN_IS_EXT(PART_BOOT)) {
#ifdef EXT_FLASH
ext_flash_check_read((uintptr_t)WOLFBOOT_PARTITION_BOOT_ADDRESS, hdr_cpy, IMAGE_HEADER_SIZE);
hdr_cpy_done = 1;
image = hdr_cpy;
#endif
} else {
image = (uint8_t *)WOLFBOOT_PARTITION_BOOT_ADDRESS;
}
}
/* Don't check image against NULL to allow using address 0x00000000 */
return wolfBoot_get_blob_version(image);
}
uint16_t wolfBoot_get_image_type(uint8_t part)
{
uint16_t *type_field = NULL;
uint8_t *image = NULL;
uint32_t *magic = NULL;
if(part == PART_UPDATE) {
if (PARTN_IS_EXT(PART_UPDATE))
{
#ifdef EXT_FLASH
ext_flash_check_read((uintptr_t)WOLFBOOT_PARTITION_UPDATE_ADDRESS, hdr_cpy, IMAGE_HEADER_SIZE);
hdr_cpy_done = 1;
image = hdr_cpy;
#endif
} else {
image = (uint8_t *)WOLFBOOT_PARTITION_UPDATE_ADDRESS;
}
} else if (part == PART_BOOT) {
if (PARTN_IS_EXT(PART_BOOT)) {
#ifdef EXT_FLASH
ext_flash_check_read((uintptr_t)WOLFBOOT_PARTITION_BOOT_ADDRESS, hdr_cpy, IMAGE_HEADER_SIZE);
hdr_cpy_done = 1;
image = hdr_cpy;
#endif
} else {
image = (uint8_t *)WOLFBOOT_PARTITION_BOOT_ADDRESS;
}
}
if (image) {
magic = (uint32_t *)image;
if (*magic != WOLFBOOT_MAGIC)
return 0;
if (wolfBoot_find_header(image + IMAGE_HEADER_OFFSET, HDR_IMG_TYPE, (void *)&type_field) == 0)
return 0;
if (type_field)
return *type_field;
}
return 0;
}
#if defined(ARCH_AARCH64) || defined(DUALBANK_SWAP)
int wolfBoot_fallback_is_possible(void)
{
uint32_t boot_v, update_v;
boot_v = wolfBoot_current_firmware_version();
update_v = wolfBoot_update_firmware_version();
if ((boot_v == 0) || (update_v == 0))
return 0;
return 1;
}
int wolfBoot_dualboot_candidate(void)
{
int candidate = PART_BOOT;
int fallback_possible = 0;
uint32_t boot_v, update_v;
uint8_t p_state;
/* Find the candidate */
boot_v = wolfBoot_current_firmware_version();
update_v = wolfBoot_update_firmware_version();
/* -1 means no images available */
if ((boot_v == 0) && (update_v == 0))
return -1;
if (boot_v == 0) /* No primary image */
candidate = PART_UPDATE;
else if ((boot_v > 0) && (update_v > 0)) {
fallback_possible = 1;
if (update_v > boot_v)
candidate = PART_UPDATE;
}
/* Check current status for failure (still in TESTING), and fall-back
* if an alternative is available
*/
if (fallback_possible &&
(wolfBoot_get_partition_state(candidate, &p_state) == 0) &&
(p_state == IMG_STATE_TESTING))
{
wolfBoot_erase_partition(candidate);
candidate ^= 1; /* switch to other partition if available */
}
return candidate;
}
#else
int wolfBoot_dualboot_candidate(void) { return 0; }
int wolfBoot_fallback_is_possible(void)
{
if (wolfBoot_update_firmware_version() > 0)
return 1;
return 0;
}
#endif /* ARCH_AARCH64 || DUALBANK_SWAP */
#ifdef EXT_ENCRYPTED
#include "encrypt.h"
#ifndef EXT_FLASH
#error option EXT_ENCRYPTED requires EXT_FLASH
#endif
#ifdef NVM_FLASH_WRITEONCE
#define ENCRYPT_CACHE NVM_CACHE
#else
static uint8_t ENCRYPT_CACHE[NVM_CACHE_SIZE] __attribute__((aligned(32)));
#endif
static int RAMFUNCTION hal_set_key(const uint8_t *k, const uint8_t *nonce)
{
uint32_t addr = ENCRYPT_TMP_SECRET_OFFSET + WOLFBOOT_PARTITION_BOOT_ADDRESS;
uint32_t addr_align = addr & (~(WOLFBOOT_SECTOR_SIZE - 1));
uint32_t addr_off = addr & (WOLFBOOT_SECTOR_SIZE - 1);
int ret = 0;
hal_flash_unlock();
XMEMCPY(ENCRYPT_CACHE, (void *)addr_align, WOLFBOOT_SECTOR_SIZE);
ret = hal_flash_erase(addr_align, WOLFBOOT_SECTOR_SIZE);
if (ret != 0)
return ret;
XMEMCPY(ENCRYPT_CACHE + addr_off, k, ENCRYPT_KEY_SIZE);
XMEMCPY(ENCRYPT_CACHE + addr_off + ENCRYPT_KEY_SIZE, nonce, ENCRYPT_NONCE_SIZE);
ret = hal_flash_write(addr_align, ENCRYPT_CACHE, WOLFBOOT_SECTOR_SIZE);
hal_flash_lock();
return ret;
}
int RAMFUNCTION wolfBoot_set_encrypt_key(const uint8_t *key, const uint8_t *nonce)
{
hal_set_key(key, nonce);
return 0;
}
int RAMFUNCTION wolfBoot_get_encrypt_key(uint8_t *k, uint8_t *nonce)
{
uint8_t *mem = (uint8_t *)(ENCRYPT_TMP_SECRET_OFFSET + WOLFBOOT_PARTITION_BOOT_ADDRESS);
XMEMCPY(k, mem, ENCRYPT_KEY_SIZE);
XMEMCPY(nonce, mem + ENCRYPT_KEY_SIZE, ENCRYPT_NONCE_SIZE);
return 0;
}
int RAMFUNCTION wolfBoot_erase_encrypt_key(void)
{
uint8_t ff[ENCRYPT_KEY_SIZE + ENCRYPT_NONCE_SIZE];
int i;
uint8_t *mem = (uint8_t *)ENCRYPT_TMP_SECRET_OFFSET + WOLFBOOT_PARTITION_BOOT_ADDRESS;
XMEMSET(ff, 0xFF, ENCRYPT_KEY_SIZE + ENCRYPT_NONCE_SIZE);
if (XMEMCMP(mem, ff, ENCRYPT_KEY_SIZE + ENCRYPT_NONCE_SIZE) != 0)
hal_set_key(ff, ff + ENCRYPT_KEY_SIZE);
return 0;
}
#ifdef __WOLFBOOT
static ChaCha chacha;
static int chacha_initialized = 0;
static uint8_t chacha_iv_nonce[ENCRYPT_NONCE_SIZE];
static int chacha_init(void)
{
uint8_t *key = (uint8_t *)(WOLFBOOT_PARTITION_BOOT_ADDRESS + ENCRYPT_TMP_SECRET_OFFSET);
uint8_t ff[ENCRYPT_KEY_SIZE];
uint8_t *stored_nonce = key + ENCRYPT_KEY_SIZE;
/* Check against 'all 0xff' or 'all zero' cases */
XMEMSET(ff, 0xFF, ENCRYPT_KEY_SIZE);
if (XMEMCMP(key, ff, ENCRYPT_KEY_SIZE) == 0)
return -1;
XMEMSET(ff, 0x00, ENCRYPT_KEY_SIZE);
if (XMEMCMP(key, ff, ENCRYPT_KEY_SIZE) == 0)
return -1;
XMEMCPY(chacha_iv_nonce, stored_nonce, ENCRYPT_NONCE_SIZE);
wc_Chacha_SetKey(&chacha, key, ENCRYPT_KEY_SIZE);
chacha_initialized = 1;
return 0;
}
static inline uint8_t part_address(uintptr_t a)
{
if ( 1 &&
#if WOLFBOOT_PARTITION_UPDATE_ADDRESS != 0
(a >= WOLFBOOT_PARTITION_UPDATE_ADDRESS) &&
#endif
(a <= WOLFBOOT_PARTITION_UPDATE_ADDRESS + WOLFBOOT_PARTITION_SIZE))
return PART_UPDATE;
if ( 1 &&
#if WOLFBOOT_PARTITION_SWAP_ADDRESS != 0
(a >= WOLFBOOT_PARTITION_SWAP_ADDRESS) &&
#endif
(a <= WOLFBOOT_PARTITION_SWAP_ADDRESS + WOLFBOOT_SECTOR_SIZE))
return PART_SWAP;
return PART_NONE;
}
int ext_flash_encrypt_write(uintptr_t address, const uint8_t *data, int len)
{
uint32_t iv_counter;
uint8_t block[ENCRYPT_BLOCK_SIZE];
uint8_t part;
int sz = len;
uint32_t row_address = address, row_offset;
int i;
uint8_t enc_block[ENCRYPT_BLOCK_SIZE];
row_offset = address & (ENCRYPT_BLOCK_SIZE - 1);
if (row_offset != 0) {
row_address = address & ~(ENCRYPT_BLOCK_SIZE - 1);
sz += ENCRYPT_BLOCK_SIZE - row_offset;
}
if (sz < ENCRYPT_BLOCK_SIZE) {
sz = ENCRYPT_BLOCK_SIZE;
}
if (!chacha_initialized)
if (chacha_init() < 0)
return -1;
part = part_address(address);
switch(part) {
case PART_UPDATE:
iv_counter = (address - WOLFBOOT_PARTITION_UPDATE_ADDRESS) / ENCRYPT_BLOCK_SIZE;
/* Do not encrypt last sectors */
if (iv_counter >= (START_FLAGS_OFFSET - ENCRYPT_BLOCK_SIZE) / ENCRYPT_BLOCK_SIZE) {
return ext_flash_write(address, data, len);
}
break;
case PART_SWAP:
{
uint32_t row_number;
row_number = (address - WOLFBOOT_PARTITION_SWAP_ADDRESS) / ENCRYPT_BLOCK_SIZE;
iv_counter = row_number;
break;
}
default:
return -1;
}
if (sz > len) {
int step = ENCRYPT_BLOCK_SIZE - row_offset;
if (ext_flash_read(row_address, block, ENCRYPT_BLOCK_SIZE) != ENCRYPT_BLOCK_SIZE)
return -1;
XMEMCPY(block + row_offset, data, step);
wc_Chacha_SetIV(&chacha, chacha_iv_nonce, iv_counter);
wc_Chacha_Process(&chacha, enc_block, block, ENCRYPT_BLOCK_SIZE);
ext_flash_write(row_address, enc_block, ENCRYPT_BLOCK_SIZE);
address += step;
data += step;
sz -= step;
iv_counter++;
}
for (i = 0; i < sz / ENCRYPT_BLOCK_SIZE; i++) {
wc_Chacha_SetIV(&chacha, chacha_iv_nonce, iv_counter);
XMEMCPY(block, data + (ENCRYPT_BLOCK_SIZE * i), ENCRYPT_BLOCK_SIZE);
wc_Chacha_Process(&chacha, ENCRYPT_CACHE + (ENCRYPT_BLOCK_SIZE * i), block, ENCRYPT_BLOCK_SIZE);
iv_counter++;
}
return ext_flash_write(address, ENCRYPT_CACHE, len);
}
int ext_flash_decrypt_read(uintptr_t address, uint8_t *data, int len)
{
uint32_t iv_counter = 0;
uint8_t block[ENCRYPT_BLOCK_SIZE];
uint8_t part;
int sz = len;
uint32_t row_address = address, row_offset;
int i;
row_offset = address & (ENCRYPT_BLOCK_SIZE - 1);
if (row_offset != 0) {
row_address = address & ~(ENCRYPT_BLOCK_SIZE - 1);
sz += ENCRYPT_BLOCK_SIZE - row_offset;
}
if (sz < ENCRYPT_BLOCK_SIZE) {
sz = ENCRYPT_BLOCK_SIZE;
}
if (!chacha_initialized)
if (chacha_init() < 0)
return -1;
part = part_address(row_address);
switch(part) {
case PART_UPDATE:
iv_counter = (address - WOLFBOOT_PARTITION_UPDATE_ADDRESS) / ENCRYPT_BLOCK_SIZE;
/* Do not decrypt last sector */
if (iv_counter >= (START_FLAGS_OFFSET - ENCRYPT_BLOCK_SIZE) / ENCRYPT_BLOCK_SIZE) {
return ext_flash_read(address, data, len);
}
break;
case PART_SWAP:
{
uint32_t row_number;
row_number = (address - WOLFBOOT_PARTITION_SWAP_ADDRESS) / ENCRYPT_BLOCK_SIZE;
iv_counter = row_number;
break;
}
default:
return -1;
}
if (sz > len) {
uint8_t dec_block[ENCRYPT_BLOCK_SIZE];
int step = ENCRYPT_BLOCK_SIZE - row_offset;
if (ext_flash_read(row_address, block, ENCRYPT_BLOCK_SIZE) != ENCRYPT_BLOCK_SIZE)
return -1;
wc_Chacha_SetIV(&chacha, chacha_iv_nonce, iv_counter);
wc_Chacha_Process(&chacha, dec_block, block, ENCRYPT_BLOCK_SIZE);
XMEMCPY(data, dec_block + row_offset, step);
address += step;
data += step;
sz -= step;
iv_counter++;
}
if (ext_flash_read(address, data, sz) != sz)
return -1;
for (i = 0; i < sz / ENCRYPT_BLOCK_SIZE; i++) {
wc_Chacha_SetIV(&chacha, chacha_iv_nonce, iv_counter);
XMEMCPY(block, data + (ENCRYPT_BLOCK_SIZE * i), ENCRYPT_BLOCK_SIZE);
wc_Chacha_Process(&chacha, data + (ENCRYPT_BLOCK_SIZE * i), block, ENCRYPT_BLOCK_SIZE);
iv_counter++;
}
return len;
}
#endif
#endif /* EXT_ENCRYPTED */

View File

@ -0,0 +1,119 @@
/* nrf52.c
*
* Copyright (C) 2020 wolfSSL Inc.
*
* This file is part of wolfBoot.
*
* wolfBoot is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfBoot is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#include <stdint.h>
#include "image.h"
/* Assembly helpers */
#define DMB() __asm__ volatile ("dmb")
/* Instantiation */
#define CLOCK_CONTROL_BASE (0x40000000)
#define NVMC_BASE (0x4001E000)
/* Flash write/erase control */
#define NVMC_CONFIG *((volatile uint32_t *)(NVMC_BASE + 0x504))
#define NVMC_ERASEPAGE *((volatile uint32_t *)(NVMC_BASE + 0x508))
#define NVMC_READY *((volatile uint32_t *)(NVMC_BASE + 0x400))
#define NVMC_CONFIG_REN 0
#define NVMC_CONFIG_WEN 1
#define NVMC_CONFIG_EEN 2
#define FLASH_PAGE_SIZE (4096)
/* Clock control */
#define TASKS_HFCLKSTART *((volatile uint32_t *)(CLOCK_CONTROL_BASE + 0x000))
#define TASKS_HFCLKSTOP *((volatile uint32_t *)(CLOCK_CONTROL_BASE + 0x004))
#define TASKS_HFCLKSTARTED *((volatile uint32_t *)(CLOCK_CONTROL_BASE + 0x100))
static void RAMFUNCTION flash_wait_complete(void)
{
while (NVMC_READY == 0)
;
}
int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len)
{
int i = 0;
uint32_t *src, *dst;
while (i < len) {
if ((len - i > 3) && ((((address + i) & 0x03) == 0) && ((((uint32_t)data) + i) & 0x03) == 0)) {
src = (uint32_t *)data;
dst = (uint32_t *)address;
NVMC_CONFIG = NVMC_CONFIG_WEN;
flash_wait_complete();
dst[i >> 2] = src[i >> 2];
flash_wait_complete();
i+=4;
} else {
uint32_t val;
uint8_t *vbytes = (uint8_t *)(&val);
int off = (address + i) - (((address + i) >> 2) << 2);
dst = (uint32_t *)(address - off);
val = dst[i >> 2];
vbytes[off] = data[i];
NVMC_CONFIG = NVMC_CONFIG_WEN;
flash_wait_complete();
dst[i >> 2] = val;
flash_wait_complete();
i++;
}
}
return 0;
}
void RAMFUNCTION hal_flash_unlock(void)
{
}
void RAMFUNCTION hal_flash_lock(void)
{
}
int RAMFUNCTION hal_flash_erase(uint32_t address, int len)
{
uint32_t end = address + len - 1;
uint32_t p;
for (p = address; p <= end; p += FLASH_PAGE_SIZE) {
NVMC_CONFIG = NVMC_CONFIG_EEN;
flash_wait_complete();
NVMC_ERASEPAGE = p;
flash_wait_complete();
}
return 0;
}
void hal_init(void)
{
TASKS_HFCLKSTART = 1;
while(TASKS_HFCLKSTARTED == 0)
;
}
void hal_prepare_boot(void)
{
TASKS_HFCLKSTOP = 1;
}

View File

@ -0,0 +1,123 @@
/* spi_drv_nrf52.c
*
* Driver for the SPI back-end of the SPI_FLASH module.
*
* Example implementation for nrf52F4.
*
* Pinout: see spi_drv_nrf52.h
*
* Copyright (C) 2020 wolfSSL Inc.
*
* This file is part of wolfBoot.
*
* wolfBoot is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfBoot is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#include <stdint.h>
#include "spi_drv.h"
#include "spi_drv_nrf52.h"
#define SPI0 (0x40003000)
#define SPI1 (0x40004000)
#define SPI2 (0x40023000)
#define SPI SPI0
#define SPI_TASKS_START *((volatile uint32_t *)(SPI + 0x10))
#define SPI_TASKS_STOP *((volatile uint32_t *)(SPI + 0x14))
#define SPI_EVENTS_ENDRX *((volatile uint32_t *)(SPI + 0x110))
#define SPI_EVENTS_END *((volatile uint32_t *)(SPI + 0x118))
#define SPI_EVENTS_ENDTX *((volatile uint32_t *)(SPI + 0x120))
#define SPI_EV_RDY *((volatile uint32_t *)(SPI + 0x108))
#define SPI_INTENSET *((volatile uint32_t *)(SPI + 0x304))
#define SPI_INTENCLR *((volatile uint32_t *)(SPI + 0x308))
#define SPI_ENABLE *((volatile uint32_t *)(SPI + 0x500))
#define SPI_PSEL_SCK *((volatile uint32_t *)(SPI + 0x508))
#define SPI_PSEL_MOSI *((volatile uint32_t *)(SPI + 0x50C))
#define SPI_PSEL_MISO *((volatile uint32_t *)(SPI + 0x510))
#define SPI_RXDATA *((volatile uint32_t *)(SPI + 0x518))
#define SPI_TXDATA *((volatile uint32_t *)(SPI + 0x51C))
#define SPI_FREQUENCY *((volatile uint32_t *)(SPI + 0x524))
#define SPI_CONFIG *((volatile uint32_t *)(SPI + 0x554))
#define K125 0x02000000
#define K250 0x04000000
#define K500 0x08000000
#define M1 0x10000000
#define M2 0x20000000
#define M4 0x40000000
#define M8 0x80000000
void RAMFUNCTION spi_cs_off(int pin)
{
GPIO_OUTSET = (1 << pin);
while ((GPIO_OUT & (1 << pin)) == 0)
;
}
void RAMFUNCTION spi_cs_on(int pin)
{
GPIO_OUTCLR = (1 << pin);
while ((GPIO_OUT & (1 << pin)) != 0)
;
}
uint8_t RAMFUNCTION spi_read(void)
{
volatile uint32_t reg = SPI_EV_RDY;
while (!reg)
reg = SPI_EV_RDY;
reg = SPI_RXDATA;
SPI_EV_RDY = 0;
return reg;
}
void RAMFUNCTION spi_write(const char byte)
{
uint32_t reg;
SPI_EV_RDY = 0;
SPI_TXDATA = (uint32_t)byte;
reg = SPI_EV_RDY;
while (!reg)
reg = SPI_EV_RDY;
}
void spi_init(int polarity, int phase)
{
static int initialized = 0;
if (!initialized) {
initialized++;
GPIO_PIN_CNF[SPI_CS_PIN] = GPIO_CNF_OUT;
GPIO_PIN_CNF[SPI_SCLK_PIN] = GPIO_CNF_OUT;
GPIO_PIN_CNF[SPI_MOSI_PIN] = GPIO_CNF_OUT;
GPIO_PIN_CNF[SPI_MISO_PIN] = GPIO_CNF_IN;
//GPIO_DIRSET = ((1 << SPI_CS_PIN) | (1 << SPI_SCLK_PIN) | (1 << SPI_MOSI_PIN));
GPIO_OUTSET = (1 << SPI_CS_PIN);
GPIO_OUTCLR = (1 << SPI_MOSI_PIN) | (1 << SPI_SCLK_PIN);
SPI_PSEL_MISO = SPI_MISO_PIN;
SPI_PSEL_MOSI = SPI_MOSI_PIN;
SPI_PSEL_SCK = SPI_SCLK_PIN;
SPI_FREQUENCY = M1;
SPI_CONFIG = 0; /* mode 0,0 default */
SPI_ENABLE = 1;
}
}
void spi_release(void)
{
}

View File

@ -0,0 +1,54 @@
/* spi_drv_nrf52.h
*
* wolfBoot is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfBoot is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#ifndef SPI_DRV_NRF52_H_INCLUDED
#define SPI_DRV_NRF52_H_INCLUDED
#include <stdint.h>
/** SPI settings **/
#define GPIO_BASE (0x50000000)
#define GPIO_OUT *((volatile uint32_t *)(GPIO_BASE + 0x504))
#define GPIO_OUTSET *((volatile uint32_t *)(GPIO_BASE + 0x508))
#define GPIO_OUTCLR *((volatile uint32_t *)(GPIO_BASE + 0x50C))
#define GPIO_DIRSET *((volatile uint32_t *)(GPIO_BASE + 0x518))
#define GPIO_PIN_CNF ((volatile uint32_t *)(GPIO_BASE + 0x700)) // Array
#define GPIO_CNF_IN 0
#define GPIO_CNF_OUT 3
/* Pinout (P0.x) */
#if 1
#define SPI_CS_PIN 13
#define SPI_MOSI_PIN 4
#define SPI_MISO_PIN 5
#define SPI_SCLK_PIN 30
#endif
#if 0
#define SPI_SCLK_PIN 5
#define SPI_MISO_PIN 6
#define SPI_MOSI_PIN 7
#define SPI_CS_PIN 8
#endif
#define SPI_CS_FLASH SPI_CS_PIN
#endif

View File

@ -0,0 +1,105 @@
/* main.c
*
* Copyright (C) 2021 wolfSSL Inc.
*
* wolfBoot fw-update example RIOT application, running on nRF52840.
*
* wolfBoot is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfBoot is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*
*/
#include <stdio.h>
#include "board.h"
#include "net/ipv6/addr.h"
#include "net/gnrc.h"
#include "net/gnrc/netif.h"
#include "shell.h"
#include "periph/flashpage.h"
#include "thread.h"
#include "periph/uart.h"
#include "periph/gpio.h"
#include "xtimer.h"
#include "ringbuffer.h"
#include "wolfboot/wolfboot.h"
#include "mutex.h"
#include "msg.h"
#ifndef SHELL_BUFSIZE
#define SHELL_BUFSIZE (128U)
#endif
#define DISPATCHER_PRIO (THREAD_PRIORITY_MAIN - 1)
#define BT_PRIO (THREAD_PRIORITY_MAIN - 1)
#define MSGQ_SIZE (4)
#define GPIO_WAKEUP GPIO_PIN(1,11)
// Globals
//
static mutex_t fwupdate_mutex = MUTEX_INIT;
static kernel_pid_t gatt_srv_pid;
static char gatt_srv_stack[THREAD_STACKSIZE_MAIN];
static msg_t gatt_srv_msgq[MSGQ_SIZE];
static xtimer_t quotes_msg_timer;
#define STDIO_UART_DEV (UART_UNDEF)
static int cmd_info(int argc, char **argv)
{
(void)argc;
(void)argv;
puts("GATT services for secure firmware updates\n");
printf("You are running RIOT on %s.\n", RIOT_BOARD);
printf("This board features a %s MCU.\n", RIOT_MCU);
puts("Bootloader info: \n");
printf(" - Running firmware version %08x\n", (unsigned)wolfBoot_current_firmware_version());
printf(" - Update firmware version %08x\n", (unsigned)wolfBoot_update_firmware_version());
puts("\n UART INFO:");
printf(" - Available devices: %i\n", UART_NUMOF);
if (STDIO_UART_DEV != UART_UNDEF) {
printf(" - UART used for STDIO (the shell): UART_DEV(%i)\n\n", STDIO_UART_DEV);
}
return 0;
}
void *gatt_srv(void*);
static const shell_command_t shell_commands[] = {
{ "info", "device info", cmd_info },
{ NULL, NULL, NULL }
};
int main(void)
{
/* initialize UART */
char line_buf[SHELL_BUFSIZE];
/* initialize GPIO WAKEUP */
gpio_init(GPIO_WAKEUP, GPIO_OUT);
gpio_set(GPIO_WAKEUP);
/* Gatt Server */
gatt_srv_pid = thread_create(gatt_srv_stack, sizeof(gatt_srv_stack),
DISPATCHER_PRIO - 1, 0, gatt_srv, NULL, "BLE_gatt");
/* run the shell */
shell_run(shell_commands, line_buf, SHELL_BUFSIZE);
return 0;
}

View File

@ -0,0 +1,21 @@
# For nRF51-based targets, we need to reduce buffer sizes to make this test fit
# into RAM
# Note: as the CPU variable is not set at this point, we manually 'whitelist'
# all supported nrf51-boards here
# Set the tests default configuration
APP_MTU ?= 5000
APP_BUF_CHUNKSIZE ?= 250 # must be full divider of APP_MTU
APP_BUF_NUM ?= 3
APP_CID ?= 0x0235
# Apply configuration values
CFLAGS += -DAPP_MTU=$(APP_MTU)
CFLAGS += -DAPP_BUF_CHUNKSIZE=$(APP_BUF_CHUNKSIZE)
CFLAGS += -DAPP_BUF_NUM=$(APP_BUF_NUM)
CFLAGS += -DAPP_NODENAME=$(APP_NODENAME)
CFLAGS += -DAPP_CID=$(APP_CID)
# configure NimBLE
MSYS_CNT ?= 40

View File

@ -0,0 +1,25 @@
ARCH?=ARM
TARGET?=nrf52
SIGN?=ECC256
HASH?=SHA256
DEBUG?=0
VTOR?=1
CORTEX_M0?=0
NO_ASM?=0
NO_MPU=1
EXT_FLASH?=0
SPI_FLASH?=0
ALLOW_DOWNGRADE?=0
NVM_FLASH_WRITEONCE?=0
WOLFBOOT_VERSION?=0
V?=0
SPMATH?=1
RAM_CODE?=0
DUALBANK_SWAP?=0
IMAGE_HEADER_SIZE?=256
PKA?=0
WOLFBOOT_PARTITION_SIZE?=0x40000
WOLFBOOT_SECTOR_SIZE?=0x1000
WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x20000
WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x60000
WOLFBOOT_PARTITION_SWAP_ADDRESS?=0xe0000

View File

@ -0,0 +1,71 @@
ifdef WOLFBOOT_OFFSET
WOLFBOOT:=$(abspath $(RIOTBASE)/../../wolfBoot/)
CFLAGS += -I$(WOLFBOOT)/include
SIGNTOOL ?= python3 $(WOLFBOOT)/tools/keytools/sign.py
KEYGENTOOL ?= python3 $(WOLFBOOT)/tools/keytools/keygen.py
BINFILE ?= $(BINDIR)/$(APPLICATION).bin
SIGN_BINFILE = $(BINDIR)/$(APPLICATION)_v5_signed.bin
WOLFBOOT_KEYFILE ?= $(WOLFBOOT)/ecc256.der
WOLFBOOT_BIN ?= $(WOLFBOOT)/wolfboot.bin
export IMAGE_HDR_SIZE = 256
wolfboot-create-key: $(WOLFBOOT_KEYFILE)
$(WOLFBOOT_KEYFILE):
make -C $(WOLFBOOT) clean
make -C $(WOLFBOOT) distclean
make -C $(WOLFBOOT) TARGET=nrf52 DEBUG=0 ecc256.der \
wolfboot: wolfboot-create-key link
@$(COLOR_ECHO)
@$(COLOR_ECHO) '$(COLOR_PURPLE)Re-linking for wolfBoot at $(WOLFBOOT_OFFSET)...$(COLOR_RESET)'
@$(COLOR_ECHO)
@$(COLOR_ECHO) 'sources:'
@$(COLOR_ECHO) $(SRC)
@$(COLOR_ECHO)
$(_LINK) $(LINKFLAGPREFIX)--defsym=_rom_start_addr="$$(($(WOLFBOOT_OFFSET) + $(IMAGE_HDR_SIZE)))" \
$(LINKFLAGPREFIX)--defsym=length="$$(($(WOLFBOOT_PARTITION_SIZE) - $(IMAGE_HDR_SIZE)))" \
$(LINKFLAGPREFIX)--defsym=image_header="$(IMAGE_HDR_SIZE)" -o $(ELFFILE) && \
$(OBJCOPY) $(OFLAGS) -Obinary $(ELFFILE) $(BINFILE) && \
$(SIGNTOOL) $(BINFILE) $(WOLFBOOT_KEYFILE) $(IMAGE_VERSION) $(WOLFBOOT_OFFSET)
@$(COLOR_ECHO)
@$(COLOR_ECHO) '$(COLOR_PURPLE)Signed with $(WOLFBOOT_KEYFILE) for version $(IMAGE_VERSION) \
$(COLOR_RESET)'
@$(COLOR_ECHO)
$(WOLFBOOT_BIN):
@$(COLOR_ECHO) 'sources:'
@$(COLOR_ECHO) $(SRC)
@$(COLOR_ECHO)
make -C $(WOLFBOOT) clean
make -C $(WOLFBOOT) TARGET=nrf52 DEBUG=0 BOOT0_OFFSET=$(WOLFBOOT_OFFSET) \
SIGN=ECC256 \
WOLFBOOT_SECTOR_SIZE=0x1000 \
WOLFBOOT_PARTITION_SIZE=0x40000 \
WOLFBOOT_PARTITION_BOOT_ADDRESS=0x20000 \
WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x60000 \
WOLFBOOT_PARTITION_SWAP_ADDRESS=0xE0000 \
wolfboot.bin
.PHONY: wolfboot-flash-bootloader wolfboot-flash
wolfboot-flash-bootloader: HEXFILE = $(WOLFBOOT_BIN)
wolfboot-flash-bootloader: $(WOLFBOOT_BIN) $(FLASHDEPS)
sudo $(FLASHER) $(FFLAGS) -o 0x0
wolfboot-flash: HEXFILE = $(SIGN_BINFILE)
wolfboot-flash: wolfboot $(FLASHDEPS) wolfboot-flash-bootloader
sudo $(FLASHER) $(FFLAGS) -o $(WOLFBOOT_OFFSET)
else
wolfboot:
$(Q)echo "error: wolfboot not supported on board $(BOARD)!"
$(Q)false
endif # WOLFBOOT_OFFSET