Add user callbacks to rom_secure_call

This commit is contained in:
William Vinnicombe 2025-12-04 12:00:30 +00:00
parent 362f83ed2c
commit cd11286868
2 changed files with 83 additions and 0 deletions

View file

@ -289,6 +289,46 @@ int __noinline rom_secure_call(uint a, uint b, uint c, uint d, uint func) {
return (int)r0;
}
struct rom_secure_call_user_callback_slot {
uint16_t fn_mask;
rom_secure_call_callback_t callback;
} rom_secure_call_user_callback_slots[PICO_MAX_SECURE_CALL_USER_CALLBACKS];
int rom_secure_call_add_user_callback(rom_secure_call_callback_t callback, uint16_t fn_mask) {
int first_unused = PICO_MAX_SECURE_CALL_USER_CALLBACKS;
for (int i=0; i < PICO_MAX_SECURE_CALL_USER_CALLBACKS; i++) {
if (!rom_secure_call_user_callback_slots[i].fn_mask) {
if (first_unused == PICO_MAX_SECURE_CALL_USER_CALLBACKS) first_unused = i;
continue;
}
// Check new function is not an existing function mask
if (rom_secure_call_user_callback_slots[i].fn_mask == fn_mask) {
return BOOTROM_ERROR_INVALID_ARG;
}
}
if (first_unused == PICO_MAX_SECURE_CALL_USER_CALLBACKS) {
// No free slots
return BOOTROM_ERROR_BUFFER_TOO_SMALL;
}
rom_secure_call_user_callback_slots[first_unused].callback = callback;
rom_secure_call_user_callback_slots[first_unused].fn_mask = fn_mask;
return BOOTROM_OK;
}
void rom_secure_call_remove_user_callback(rom_secure_call_callback_t callback) {
for (int i=0; i < PICO_MAX_SECURE_CALL_USER_CALLBACKS; i++) {
if (rom_secure_call_user_callback_slots[i].callback == callback) {
rom_secure_call_user_callback_slots[i].callback = NULL;
rom_secure_call_user_callback_slots[i].fn_mask = 0;
return;
}
}
}
#if PICO_ALLOW_NONSECURE_STDIO
#include "pico/stdio/driver.h"
@ -450,6 +490,17 @@ int pio_request_unused_pio_from_secure(void) {
#include "hardware/structs/accessctrl.h"
int rom_default_callback(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t fn) {
if (fn >> 31) {
// User callbacks all start with 0b1xxx, as specified by the rom_secure_call() documentation
for (int i=0; i < PICO_MAX_SECURE_CALL_USER_CALLBACKS; i++) {
if ((fn >> 16) == rom_secure_call_user_callback_slots[i].fn_mask) {
return rom_secure_call_user_callback_slots[i].callback(a, b, c, d, fn);
}
}
return BOOTROM_ERROR_INVALID_ARG;
}
switch (fn) {
#if PICO_ALLOW_NONSECURE_STDIO
case SECURE_CALL_stdio_out_chars: {

View file

@ -1047,6 +1047,38 @@ int rom_secure_call(uint a, uint b, uint c, uint d, uint func);
int rom_default_callback(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t fn);
// PICO_CONFIG: PICO_MAX_SECURE_CALL_USER_CALLBACKS, Maximum number of secure call user callbacks, default=4, advanced=true, group=pico_bootrom
#ifndef PICO_MAX_SECURE_CALL_USER_CALLBACKS
#define PICO_MAX_SECURE_CALL_USER_CALLBACKS 4
#endif
/*! Callback function type for user handled rom_secure_call
* \ingroup pico_bootrom
*/
typedef int (*rom_secure_call_callback_t)(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t fn);
/*!
* \brief Add user ROM callback function
* \ingroup pico_bootrom
*
* Add a user callback for rom_secure_call called if using a function code starting with `0b1xxx`,
* which is a "unique" or "private" function as specified by the rom_secure_call() documentation.
*
* \param callback pointer to the callback function
* \param fn_mask first 16 bits of fn codes this callback handles
*/
int rom_secure_call_add_user_callback(rom_secure_call_callback_t callback, uint16_t fn_mask);
/*!
* \brief Remove user ROM callback function
* \ingroup pico_bootrom
*
* Remove a user callback for rom_secure_call which was previously added with rom_secure_call_add_user_callback()
*
* \param callback pointer to the callback function
*/
void rom_secure_call_remove_user_callback(rom_secure_call_callback_t callback);
// PICO_CONFIG: PICO_ALLOW_NONSECURE_STDIO, Allow non-secure to use stdio, type=bool, default=0, group=pico_bootrom
#ifndef PICO_ALLOW_NONSECURE_STDIO
#define PICO_ALLOW_NONSECURE_STDIO 0