Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
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
6 changes: 5 additions & 1 deletion cpu/cortexm_common/include/cpu_conf_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,11 @@ extern "C" {
* @{
*/
#ifndef ISR_STACKSIZE
#define ISR_STACKSIZE (512U)
# if defined(MODULE_XIPFS) && defined(XIPFS_ENABLE_SAFE_EXEC_SUPPORT)
# define ISR_STACKSIZE (1024U)
#else
# define ISR_STACKSIZE (512U)
# endif
#endif
/** @} */

Expand Down
27 changes: 27 additions & 0 deletions cpu/cortexm_common/thread_arch.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@
#define ENABLE_DEBUG 0
#include "debug.h"

#if defined(MODULE_XIPFS) && defined(XIPFS_ENABLE_SAFE_EXEC_SUPPORT)
#include "include/xipfs.h"
#endif

extern uint32_t _estack;
extern uint32_t _sstack;

Expand Down Expand Up @@ -274,6 +278,11 @@ void *thread_isr_stack_start(void)
return (void *)&_sstack;
}

void *thread_isr_stack_end(void)
{
return (void *)&_estack;
}

void NORETURN cpu_switch_context_exit(void)
{
#ifdef MODULE_CORTEXM_FPU
Expand Down Expand Up @@ -488,6 +497,11 @@ void __attribute__((naked)) __attribute__((used)) isr_svc(void)
#endif
}

#if (defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__)) && \
defined(XIPFS_ENABLE_SAFE_EXEC_SUPPORT)
#undef XIPFS_ENABLE_SAFE_EXEC_SUPPORT
#endif

static void __attribute__((used)) _svc_dispatch(unsigned int *svc_args)
{
/* stack frame:
Expand All @@ -513,6 +527,19 @@ static void __attribute__((used)) _svc_dispatch(unsigned int *svc_args)
case 1: /* SVC number used by cpu_switch_context_exit */
SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
break;
#if defined(MODULE_XIPFS) && defined(XIPFS_ENABLE_SAFE_EXEC_SUPPORT)
case XIPFS_ENTER_SVC_NUMBER: {
void *crt0_ctx = (void *)svc_args[0];
void *entry_point = (void *)svc_args[1];
void *stack_top = (void *)svc_args[2];
xipfs_safe_exec_enter(crt0_ctx, entry_point, stack_top);
break;
}
case XIPFS_SYSCALL_SVC_NUMBER: {
xipfs_syscall_dispatcher(svc_args);
break;
}
#endif
default:
DEBUG("svc: unhandled SVC #%u\n", svc_number);
break;
Expand Down
17 changes: 17 additions & 0 deletions cpu/cortexm_common/vectors_cortexm.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@
#ifdef MODULE_DBGPIN
#include "dbgpin.h"
#endif
#if defined(MODULE_XIPFS) && defined(XIPFS_ENABLE_SAFE_EXEC_SUPPORT)
#include "include/xipfs.h"
#endif

#ifndef SRAM_BASE
#define SRAM_BASE 0
Expand Down Expand Up @@ -75,7 +78,7 @@
/**
* @brief Allocation of the interrupt stack
*/
__attribute__((used,section(".isr_stack"))) uint8_t isr_stack[ISR_STACKSIZE];

Check warning on line 81 in cpu/cortexm_common/vectors_cortexm.c

View workflow job for this annotation

GitHub Actions / static-tests

comma should be followed by whitespace

/**
* @brief Pre-start routine for CPU-specific settings
Expand Down Expand Up @@ -472,8 +475,22 @@
#if defined(CPU_CORE_CORTEX_M3) || defined(CPU_CORE_CORTEX_M33) || \
defined(CPU_CORE_CORTEX_M4) || defined(CPU_CORE_CORTEX_M4F) || \
defined(CPU_CORE_CORTEX_M7)

#if (defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__)) && \
defined(XIPFS_ENABLE_SAFE_EXEC_SUPPORT)
#undef XIPFS_ENABLE_SAFE_EXEC_SUPPORT
#endif

void mem_manage_default(void)
{
#if defined(MODULE_XIPFS) && defined(XIPFS_ENABLE_SAFE_EXEC_SUPPORT)
uint32_t mmfar = SCB->MMFAR;
uint32_t cfsr = SCB->CFSR;
uintptr_t psp = __get_PSP();
if (xipfs_mem_manage_handler((void *)psp, mmfar, cfsr) == 0) {
return;
}
#endif
core_panic(PANIC_MEM_MANAGE, "MEM MANAGE HANDLER");
}

Expand Down
6 changes: 6 additions & 0 deletions examples/advanced/xipfs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,20 @@ QUIET ?= 1
TOOLCHAINS_BLACKLIST += llvm

BLOBS += hello-world.fae
BLOBS += dumper.fae

# Modules to include:
USEMODULE += shell
USEMODULE += shell_cmds_default
USEMODULE += ps
USEMODULE += saul_default
USEMODULE += cortexm_svc

FEATURES_REQUIRED += cortexm_mpu

# Use xipfs file system
USEMODULE += xipfs

CFLAGS += -DXIPFS_ENABLE_SAFE_EXEC_SUPPORT

include $(RIOTBASE)/Makefile.include
25 changes: 3 additions & 22 deletions examples/advanced/xipfs/Makefile.ci
Original file line number Diff line number Diff line change
@@ -1,24 +1,5 @@
BOARD_INSUFFICIENT_MEMORY := \
blackpill-stm32f103c8 \
bluepill-stm32f030c8 \
bluepill-stm32f103c8 \
i-nucleo-lrwan1 \
nucleo-c031c6 \
nucleo-f030r8 \
nucleo-f031k6 \
nucleo-f042k6 \
nucleo-f302r8 \
nucleo-f303k8 \
nucleo-f334r8 \
nucleo-l011k4 \
nucleo-l031k6 \
nucleo-l053r8 \
samd10-xmini \
slstk3400a \
stk3200 \
stm32f030f4-demo \
stm32f0discovery \
stm32g0316-disco \
stm32l0538-disco \
weact-g030f6 \
e104-bt5010a-tb \
e104-bt5011a-tb \
im880b \
#
Binary file added examples/advanced/xipfs/dumper.fae
Binary file not shown.
Binary file modified examples/advanced/xipfs/hello-world.fae
Binary file not shown.
123 changes: 50 additions & 73 deletions examples/advanced/xipfs/main.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2024 Université de Lille
* Copyright (C) 2025 Université de Lille
*
* 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
Expand Down Expand Up @@ -51,12 +51,12 @@
/*
* Allocate a new contiguous space for the nvme0p0 file system
*/
XIPFS_NEW_PARTITION(nvme0p0, "/dev/nvme0p0", NVME0P0_PAGE_NUM);
XIPFS_NEW_PARTITION(nvme0p0, "/nvme0p0", NVME0P0_PAGE_NUM);

/*
* Allocate a new contiguous space for the nvme0p1 file system
*/
XIPFS_NEW_PARTITION(nvme0p1, "/dev/nvme0p1", NVME0P1_PAGE_NUM);
XIPFS_NEW_PARTITION(nvme0p1, "/nvme0p1", NVME0P1_PAGE_NUM);

#ifdef BOARD_DWM1001

Expand All @@ -71,113 +71,90 @@ XIPFS_NEW_PARTITION(nvme0p1, "/dev/nvme0p1", NVME0P1_PAGE_NUM);
*/
#include "blob/hello-world.fae.h"

#define FILENAME_OF_HELLO_WORLD_FAE "/dev/nvme0p0/hello-world.fae"
#define FILENAME_OF_HELLO_WORLD_FAE "/nvme0p0/hello-world.fae"
#define SIZEOF_HELLO_WORLD_FAE (sizeof(hello_world_fae) / sizeof(hello_world_fae[0]))

/**
* @brief Execution in-place demonstrator.
*
* This shell command handler will create a file hello-world.fae on /dev/nvme0p0,
* if none exists yet from the data blob above.
* Then, it will execute this file.
*
* Once the file has been created, execute command can be used to rerun
* the executable file as many times as wanted.
*
* ```bash
* 2025-01-14 09:48:36,303 # main(): This is RIOT! (Version: 2024.10)
* 2025-01-14 09:48:36,307 # vfs_mount: "/dev/nvme0p0": OK
* 2025-01-14 09:48:36,313 # vfs_mount: "/dev/nvme0p1": OK
* > help
* 2025-01-14 09:48:42,300 # help
* 2025-01-14 09:48:42,302 # Command Description
* 2025-01-14 09:48:42,305 # ---------------------------------------
* 2025-01-14 09:48:42,309 # exec Execute Hello World
* 2025-01-14 09:48:42,314 # create_executable Create an XIPFS executable file
* 2025-01-14 09:48:42,317 # execute Execute an XIPFS file
* 2025-01-14 09:48:42,320 # ls list files
* 2025-01-14 09:48:42,325 # pm interact with layered PM subsystem
* 2025-01-14 09:48:42,331 # ps Prints information about running threads.
* 2025-01-14 09:48:42,334 # reboot Reboot the node
* 2025-01-14 09:48:42,338 # version Prints current RIOT_VERSION
* 2025-01-14 09:48:42,343 # vfs virtual file system operations
* > exec
* 2025-01-14 09:48:49,572 # exec
* 2025-01-14 09:48:49,573 # Hello World!
* > ls /dev/nvme0p0
* 2025-01-14 09:48:59,997 # ls /dev/nvme0p0
* 2025-01-14 09:48:59,999 # hello-world.fae 896 B
* 2025-01-14 09:49:00,000 # total 1 files
* > vfs df
* 2025-01-14 09:49:04,957 # vfs df
* 2025-01-14 09:49:04,962 # Mountpoint Total Used Available Use%
* 2025-01-14 09:49:04,968 # /dev/nvme0p0 40 KiB 4 KiB 36 KiB 10%
* 2025-01-14 09:49:04,974 # /dev/nvme0p1 60 KiB 0 B 60 KiB 0%
* execute /dev/nvme0p0/hello-world.fae ipsum dolores it
* 2025-01-14 09:49:14,223 # execute /dev/nvme0p0/hello-world.fae Lorem ipsum dolor sit amet
* 2025-01-14 09:49:14,225 # Hello World!
* 2025-01-14 09:49:14,225 # Lorem
* 2025-01-14 09:49:14,226 # ipsum
* 2025-01-14 09:49:14,226 # dolor
* 2025-01-14 09:49:14,227 # sit
* 2025-01-14 09:49:14,227 # amet
* ```
*/
int execution_handler(int argc, char **argv) {
(void)argc;
(void)argv;
#include "blob/dumper.fae.h"

#define FILENAME_OF_DUMPER_FAE "/nvme0p0/dumper.fae"
#define SIZEOF_DUMPER_FAE (sizeof(dumper_fae) / sizeof(dumper_fae[0]))

int file_handle = vfs_open(FILENAME_OF_HELLO_WORLD_FAE, O_RDONLY, 0);
typedef struct {
const char *filename;
const int bytesize;
const unsigned char *data;
const bool is_executable;
} file_to_drop_t;

static const file_to_drop_t files_to_drop[2] = {
{FILENAME_OF_HELLO_WORLD_FAE, SIZEOF_HELLO_WORLD_FAE, hello_world_fae, true },
{FILENAME_OF_DUMPER_FAE, SIZEOF_DUMPER_FAE, dumper_fae, true },
};

static int drop_file(const file_to_drop_t *file_to_drop) {
if (file_to_drop == NULL) {
return EXIT_FAILURE;
}

int file_handle = vfs_open(file_to_drop->filename, O_RDONLY, 0);
if (file_handle < 0) {

/** There's no executable file yet, let's drop one */
int ret = xipfs_extended_driver_new_file(
FILENAME_OF_HELLO_WORLD_FAE, SIZEOF_HELLO_WORLD_FAE, 1
file_to_drop->filename, file_to_drop->bytesize, file_to_drop->is_executable
);
if (ret < 0) {
printf("xipfs_extended_driver_new_file : failed to create '%s' : error=%d\n",
FILENAME_OF_HELLO_WORLD_FAE, ret);
file_to_drop->filename, ret);
return EXIT_FAILURE;
}

/**
* Fill it with blob data
* Fill it with data
* Take care : vfs does not support O_APPEND with vfs_write, only O_WRONLY or O_RDWR
*/
file_handle = vfs_open(FILENAME_OF_HELLO_WORLD_FAE, O_WRONLY, 0);
file_handle = vfs_open(file_to_drop->filename, O_WRONLY, 0);
if (file_handle < 0) {
printf("vfs_open : failed to open '%s' : error =%d\n",
FILENAME_OF_HELLO_WORLD_FAE, file_handle);
file_to_drop->filename, file_handle);
return EXIT_FAILURE;
}

ssize_t write_ret = vfs_write(file_handle, hello_world_fae, SIZEOF_HELLO_WORLD_FAE);
ssize_t write_ret = vfs_write(file_handle, file_to_drop->data, file_to_drop->bytesize);
if (write_ret < 0) {
printf("vfs_write : failed to fill '%s' : error=%d\n",
FILENAME_OF_HELLO_WORLD_FAE, write_ret);
file_to_drop->filename, write_ret);
vfs_close(file_handle);
return EXIT_FAILURE;
}
}

vfs_close(file_handle);
return EXIT_SUCCESS;
}

char *exec_argv[] = {
FILENAME_OF_HELLO_WORLD_FAE,
NULL
};
/**
* @brief Execution in-place demonstrator.
*
* This shell command handler will create a file hello-world.fae on /dev/nvme0p0,
* if none exists yet from the files_to_drop array.
*
*/
int drop_files_handler(int argc, char **argv) {
(void)argc;
(void)argv;

int ret = xipfs_extended_driver_execv(FILENAME_OF_HELLO_WORLD_FAE, exec_argv);
if (ret < 0) {
printf("Failed to execute '%s' : error=%d\n", FILENAME_OF_HELLO_WORLD_FAE, ret);
return EXIT_FAILURE;
for (unsigned int i = 0; i < ARRAY_SIZE(files_to_drop); ++i) {
if (drop_file(&files_to_drop[i]) != EXIT_SUCCESS) {
return EXIT_FAILURE;
}
}

return EXIT_SUCCESS;
}

static shell_command_t shell_commands[] = {
{"exec", "Execute Hello World", execution_handler},
{"drop_files", "Drop example fae files into /nvme0p0", drop_files_handler},
{NULL, NULL, NULL},
};

Expand Down
4 changes: 3 additions & 1 deletion pkg/xipfs/Makefile
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
PKG_NAME=xipfs
PKG_URL=https://github.com/2xs/xipfs.git
PKG_VERSION=962c5edc55abb6363ff2988dc3b2c3c293362e96
PKG_VERSION=837e15fb85bd3fc0fbc87d39a692ebf5c2cc9a5f
PKG_LICENSE=CeCILL-2.1

include $(RIOTBASE)/pkg/pkg.mk

CFLAGS += -DXIPFS_ENABLE_SAFE_EXEC_SUPPORT

export RIOT_INCLUDES=$(INCLUDES)
export RIOT_CFLAGS=$(CFLAGS)

Expand Down
3 changes: 3 additions & 0 deletions pkg/xipfs/Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@ ifeq (,$(filter xipfs_fs,$(DISABLE_MODULE)))
# xipfs only makes sense if the flash memory is addressable
FEATURES_REQUIRED += periph_flashpage_in_address_space
FEATURES_REQUIRED += arch_32bit arch_arm
# xipfs safe execution feature relies on MPU.
FEATURES_REQUIRED += cortexm_mpu
FEATURES_OPTIONAL += periph_flashpage_aux
USEMODULE += periph_flashpage
USEMODULE += mtd_flashpage
USEMODULE += vfs
USEMODULE += shell_cmd_xipfs
USE_MODULE += cortexm_svc
endif
11 changes: 8 additions & 3 deletions pkg/xipfs/doc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,14 @@
*
* To prevent fragmentation, when a file is deleted, subsequent files are shifted to fill the vacant space.
*
*`xipfs` is compatible with all microcontrollers featuring addressable
* flash memory and most operating systems, provided they implement the
* necessary functions to interact with the flash controller.
*`xipfs` is compatible with all ARM microcontrollers featuring addressable flash memory and
* most operating systems, provided they implement the necessary functions to interact with
* the flash controller.
*
* The filesystem is also capable to run files with memory isolation, thanks to the use of
* ARMv7-M Memory Protection Unit.
* Then, the TEXT, DATA and STACK segments of the executable are mapped to MPU regions, isolating
* the program from the rest of flash and RAM. It can only access to its legitimate contents.
*
* **To have a viable executable file within XiPFS**, please follow these steps :
* - create a file with executable flag.
Expand Down
Loading
Loading