Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
13 changes: 13 additions & 0 deletions cpu/cortexm_common/include/thread_arch.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
extern "C" {
#endif

#define THREAD_API_INLINED

Check failure on line 25 in cpu/cortexm_common/include/thread_arch.h

View workflow job for this annotation

GitHub Actions / static-tests

Member THREAD_API_INLINED (macro definition) of file thread_arch.h is not documented.

#ifndef DOXYGEN /* Doxygen is in core/include/thread.h */

Expand All @@ -38,6 +38,19 @@

#endif /* DOXYGEN */

/**
* @brief Default SVC dispatch handler (weak function).
*
* @param[in] svc_number The svc number to handle.
* @param[in] svc_args Supervisor call arguments.
*
* @retval >= 0 when svc_number has been handled.
* @retval < 0 otherwise.
*
* @see _svc_dispatch
*/
int svc_dispatch_handler(unsigned int svc_number, unsigned int *svc_args);

#ifdef __cplusplus
}
#endif
Expand Down
9 changes: 9 additions & 0 deletions cpu/cortexm_common/include/vectors_cortexm.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
* @brief Use this macro to make interrupt functions overridable with the
* dummy_handler as fallback in case they are not implemented
*/
#define WEAK_DEFAULT __attribute__((weak,alias("dummy_handler")))

Check warning on line 28 in cpu/cortexm_common/include/vectors_cortexm.h

View workflow job for this annotation

GitHub Actions / static-tests

comma should be followed by whitespace

/**
* @brief Use this macro to define the parts of the vector table
Expand All @@ -34,7 +34,7 @@
* (numeric) value given for `x`. The Cortex-M base vectors are always defined
* with `ISR_VECTOR(0)`, so the CPU specific vector(s) **must** start from 1.
*/
#define ISR_VECTOR(x) __attribute__((used,section(".vectors." # x )))

Check warning on line 37 in cpu/cortexm_common/include/vectors_cortexm.h

View workflow job for this annotation

GitHub Actions / static-tests

comma should be followed by whitespace

/**
* @brief Number of Cortex-M non-ISR exceptions
Expand Down Expand Up @@ -90,6 +90,15 @@
/* The following four exceptions are only present for Cortex-M3 and -M4 CPUs */
#if defined(CPU_CORE_CORTEX_M3) || defined(CPU_CORE_CORTEX_M4) || \
defined(CPU_CORE_CORTEX_M4F) || defined(CPU_CORE_CORTEX_M7)

/**
* @brief Default memory manager behavior callback (weak function)
*
* @retval >=0 when the memory fault has been handled,
* @retval < 0 otherwise.
*/
int mem_manage_handler(void);

/**
* @brief Memory management exception handler
*
Expand Down
17 changes: 17 additions & 0 deletions cpu/cortexm_common/thread_arch.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
*/

#include <stdio.h>
#include <errno.h>

#include "sched.h"
#include "thread.h"
Expand Down Expand Up @@ -274,6 +275,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 +494,14 @@ void __attribute__((naked)) __attribute__((used)) isr_svc(void)
#endif
}

__attribute__((weak)) int
svc_dispatch_handler(unsigned int svc_number, unsigned int *svc_args)
{
(void)svc_number;
(void)svc_args;
return -ENOTSUP;
}

static void __attribute__((used)) _svc_dispatch(unsigned int *svc_args)
{
/* stack frame:
Expand All @@ -514,6 +528,9 @@ static void __attribute__((used)) _svc_dispatch(unsigned int *svc_args)
SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
break;
default:
if (svc_dispatch_handler(svc_number, svc_args) >= 0) {
return;
}
DEBUG("svc: unhandled SVC #%u\n", svc_number);
break;
}
Expand Down
10 changes: 10 additions & 0 deletions cpu/cortexm_common/vectors_cortexm.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <stdint.h>
#include <stdio.h>
#include <inttypes.h>
#include <errno.h>

#include "cpu.h"
#include "periph_cpu.h"
Expand Down Expand Up @@ -75,7 +76,7 @@
/**
* @brief Allocation of the interrupt stack
*/
__attribute__((used,section(".isr_stack"))) uint8_t isr_stack[ISR_STACKSIZE];

Check warning on line 79 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 +473,17 @@
#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)

__attribute__((weak)) int mem_manage_handler(void)
{
return -ENOTSUP;
}

void mem_manage_default(void)
{
if (mem_manage_handler() >= 0) {
return;
}
core_panic(PANIC_MEM_MANAGE, "MEM MANAGE HANDLER");
}

Expand Down
9 changes: 9 additions & 0 deletions examples/advanced/xipfs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,23 @@ 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

# XIPFS MPU support
CFLAGS += -DXIPFS_ENABLE_SAFE_EXEC_SUPPORT
# XIPFS MPU ISR stack requirement
CFLAGS += -DISR_STACKSIZE=1024

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.
127 changes: 52 additions & 75 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) 2024-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 */
/* 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=22ff164f1fb9097f272540836c3f111ecf8cde10
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
USEMODULE += 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