Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

bootloaders/riotboot_vfs: add VFS based bootloader #17379

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
sys/riotboot: add helper functions for riotboot VFS
  • Loading branch information
benpicco committed May 26, 2022
commit 6b7a2536d7044dbaf31caea3dddb76f2fc73cd8a
5 changes: 5 additions & 0 deletions sys/auto_init/auto_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,11 @@ extern void auto_init_sock_dns(void);
AUTO_INIT(auto_init_sock_dns,
AUTO_INIT_PRIO_MOD_DOCK_DNS);
#endif
#if IS_USED(MODULE_RIOTBOOT_VFS) && !IS_USED(RIOTBOOT)
extern void riotboot_vfs_cancel(void);
AUTO_INIT(riotboot_vfs_cancel,
AUTO_INIT_PRIO_RIOTBOOT_VFS);
#endif

void auto_init(void)
{
Expand Down
8 changes: 8 additions & 0 deletions sys/auto_init/include/auto_init_priorities.h
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,14 @@ extern "C" {
#define AUTO_INIT_PRIO_MOD_DOCK_DNS 1550
#endif

/**
* @brief Remove RIOTBOOT canary after successful boot
* This must always be the last step
*/
#ifndef AUTO_INIT_PRIO_RIOTBOOT_VFS
#define AUTO_INIT_PRIO_RIOTBOOT_VFS 9999
#endif

#ifdef __cplusplus
}
#endif
Expand Down
91 changes: 91 additions & 0 deletions sys/include/riotboot/vfs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Copyright (C) 2021 ML!PA Consulting GmbH
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/

/**
* @defgroup sys_riotboot_vfs VFS Image loader
* @ingroup sys
* @{
*
* @file
* @brief riotboot as a VFS based bootloader
*
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
*
* @}
*/

#ifndef RIOTBOOT_VFS_H
#define RIOTBOOT_VFS_H

#ifdef __cplusplus
extern "C" {
#endif

#include <string.h>

#include "vfs_util.h"
#include "vfs_default.h"

/**
* @brief File that contains the path to the new image
*
* If this file is present, riotboot will attempt to load it
* as the new firmware.
*/
#ifndef RIOTBOOT_VFS_UPDATE_FILE
#define RIOTBOOT_VFS_UPDATE_FILE VFS_DEFAULT_DATA "/do_update"
#endif

/**
* @brief File that contains the previous firmware
*
* Riotboot will make a backup of the current firmware to
* restore the old image if the new one fails to boot.
*/
#ifndef RIOTBOOT_VFS_BACKUP_FILE
#define RIOTBOOT_VFS_BACKUP_FILE VFS_DEFAULT_DATA "/old_image.bin"
#endif

/**
* @brief Mark the image behind @p file as the one that should be flashed
* the next time riotboot runs.
*
* This only creates the @ref RIOTBOOT_VFS_UPDATE_FILE, it will not perform a reboot.
*
* @param[in] file Path to the firmware image
*
* @return 0 on success
* <0 on error
*/
static inline int riotboot_vfs_schedule(const char *file)
{
return vfs_file_from_buffer(RIOTBOOT_VFS_UPDATE_FILE, file, strlen(file));
}

/**
* @brief Unschedule a pending firmware update
*
* This removes the flag file created by @ref riotboot_vfs_schedule
*/
void riotboot_vfs_cancel(void);

/**
* @brief Dump the current firmware image to a file
*
* @param[in] file Path where the firmware image should be written to
*
* @return 0 on success
* <0 on error
*/
int riotboot_vfs_dump_rom(const char *file);

#ifdef __cplusplus
}
#endif

#endif /* RIOTBOOT_VFS_H */
69 changes: 69 additions & 0 deletions sys/riotboot/vfs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright (C) 2021 ML!PA Consulting GmbH
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/

/**
* @ingroup sys_riotboot_vfs
* @{
*
* @file
* @brief VFS Bootloader helpers
*
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
*
* @}
*/

#include <string.h>

#include "architecture.h"
#include "vfs_util.h"
#include "periph/flashpage.h"
#include "riotboot/vfs.h"

/* try to guess the end of the firmware */
static const void *_first_free_chunk(const void *start)
{
const uword_t *cur = start;
const uword_t *end = flashpage_addr(FLASHPAGE_NUMOF);
uword_t empty;
unsigned const chunk_size = 256;
memset(&empty, FLASHPAGE_ERASE_STATE, sizeof(empty));

/* try to find the first unused page */
while (cur < end) {
if (cur[0] == empty && cur[1] == empty &&
cur[2] == empty && cur[3] == empty) {
break;
}
cur += chunk_size;
}

return cur;
}

int riotboot_vfs_dump_rom(const char *file)
{
const void *start, *end;

if (IS_ACTIVE(RIOTBOOT)) {
start = (void *)(uintptr_t)SLOT0_OFFSET;
end = _first_free_chunk(start);
} else {
start = (void *)cpu_get_image_baseaddr();
end = flashpage_addr(flashpage_first_free());
}

return vfs_file_from_buffer(file, start, end - start);
}

void riotboot_vfs_cancel(void)
{
#ifdef MODULE_VFS
vfs_unlink(RIOTBOOT_VFS_UPDATE_FILE);
#endif
}