diff --git a/cmake/plugin.cmake b/cmake/plugin.cmake index 204ec16..3a7320f 100644 --- a/cmake/plugin.cmake +++ b/cmake/plugin.cmake @@ -37,6 +37,8 @@ function(picokeys_add_plugin TARGET) target_link_options(${TARGET} PRIVATE "LINKER:--defsym=__picokeys_plugin_flash_base=${PICOKEYS_PLUGIN_FLASH_BASE}" "LINKER:--defsym=__picokeys_plugin_flash_size=${PICOKEYS_PLUGIN_FLASH_SIZE}" + "LINKER:--defsym=__picokeys_plugin_ram_base=${PICOKEYS_PLUGIN_RAM_BASE}" + "LINKER:--defsym=__picokeys_plugin_ram_size=${PICOKEYS_PLUGIN_RAM_SIZE}" "LINKER:-T,${PK_PLUGIN_LINKER}" "LINKER:-n" "LINKER:--gc-sections" @@ -71,6 +73,8 @@ function(picokeys_add_plugin TARGET) target_compile_definitions(${TARGET} PRIVATE PICOKEYS_PLUGIN_FLASH_BASE=${PICOKEYS_PLUGIN_FLASH_BASE} PICOKEYS_PLUGIN_FLASH_SIZE=${PICOKEYS_PLUGIN_FLASH_SIZE} + PICOKEYS_PLUGIN_RAM_BASE=${PICOKEYS_PLUGIN_RAM_BASE} + PICOKEYS_PLUGIN_RAM_SIZE=${PICOKEYS_PLUGIN_RAM_SIZE} ) endfunction() diff --git a/picokeys_sdk_import.cmake b/picokeys_sdk_import.cmake index 78dfa11..d60da51 100644 --- a/picokeys_sdk_import.cmake +++ b/picokeys_sdk_import.cmake @@ -118,6 +118,8 @@ endif() if(PICO_RP2350 OR ENABLE_EMULATION) set(PICOKEYS_PLUGIN_FLASH_BASE "0x10112000" CACHE STRING "XIP address where the premium plugin UF2 starts" FORCE) set(PICOKEYS_PLUGIN_FLASH_SIZE "0x000fa000" CACHE STRING "Maximum premium plugin size in bytes" FORCE) + set(PICOKEYS_PLUGIN_RAM_BASE "0x2007c000" CACHE STRING "RAM base reserved for premium plugin mutable state" FORCE) + set(PICOKEYS_PLUGIN_RAM_SIZE "0x00004000" CACHE STRING "Maximum premium plugin RAM usage in bytes" FORCE) set(PICOKEYS_PLUGIN_DIR "" CACHE PATH "Optional external PicoKeys plugin source directory") include(${CMAKE_CURRENT_LIST_DIR}/cmake/plugin.cmake) endif() @@ -693,9 +695,13 @@ if(PICO_RP2350) target_compile_definitions(${CMAKE_PROJECT_NAME} PRIVATE PICOKEYS_PLUGIN_FLASH_BASE=${PICOKEYS_PLUGIN_FLASH_BASE} PICOKEYS_PLUGIN_FLASH_SIZE=${PICOKEYS_PLUGIN_FLASH_SIZE} + PICOKEYS_PLUGIN_RAM_BASE=${PICOKEYS_PLUGIN_RAM_BASE} + PICOKEYS_PLUGIN_RAM_SIZE=${PICOKEYS_PLUGIN_RAM_SIZE} ) target_link_options(${CMAKE_PROJECT_NAME} PRIVATE "LINKER:--defsym=__picokeys_plugin_flash_base=${PICOKEYS_PLUGIN_FLASH_BASE}" + "LINKER:--defsym=__picokeys_plugin_ram_base=${PICOKEYS_PLUGIN_RAM_BASE}" + "LINKER:--defsym=__picokeys_plugin_ram_size=${PICOKEYS_PLUGIN_RAM_SIZE}" "LINKER:-T,${CMAKE_CURRENT_LIST_DIR}/src/plugin/core_plugin_region_assert.ld" ) if(NOT IS_CYW43) diff --git a/src/plugin/core_plugin_region_assert.ld b/src/plugin/core_plugin_region_assert.ld index a7a6548..190852b 100644 --- a/src/plugin/core_plugin_region_assert.ld +++ b/src/plugin/core_plugin_region_assert.ld @@ -1,2 +1,11 @@ ASSERT(!DEFINED(__picokeys_plugin_flash_base) || __flash_binary_end <= __picokeys_plugin_flash_base, "pico_fido flash image overlaps the premium plugin region") + +ASSERT(!DEFINED(__picokeys_plugin_ram_base) || __end__ <= __picokeys_plugin_ram_base, + "pico_fido RAM image overlaps the premium plugin RAM region") + +ASSERT(!DEFINED(__picokeys_plugin_ram_base) || !DEFINED(__picokeys_plugin_ram_size) || + ((__picokeys_plugin_ram_base + __picokeys_plugin_ram_size) <= 0x20080000), + "premium plugin RAM region exceeds RP2350 main RAM") + +__HeapLimit = DEFINED(__picokeys_plugin_ram_base) ? __picokeys_plugin_ram_base : __HeapLimit; diff --git a/src/plugin/picokeys_plugin_api.h b/src/plugin/picokeys_plugin_api.h index d38644b..c4e14c2 100644 --- a/src/plugin/picokeys_plugin_api.h +++ b/src/plugin/picokeys_plugin_api.h @@ -42,7 +42,7 @@ #endif #define PICOKEYS_PLUGIN_MAGIC 0x504b504cUL /* PKPL */ -#define PICOKEYS_PLUGIN_ABI_VERSION 1u +#define PICOKEYS_PLUGIN_ABI_VERSION 2u #ifndef PICOKEYS_PLUGIN_FLASH_BASE #define PICOKEYS_PLUGIN_FLASH_BASE 0x10112000UL @@ -52,6 +52,14 @@ #define PICOKEYS_PLUGIN_FLASH_SIZE 0x000fa000UL #endif +#ifndef PICOKEYS_PLUGIN_RAM_BASE +#define PICOKEYS_PLUGIN_RAM_BASE 0x2007c000UL +#endif + +#ifndef PICOKEYS_PLUGIN_RAM_SIZE +#define PICOKEYS_PLUGIN_RAM_SIZE 0x00004000UL +#endif + typedef struct pk_plugin_imports { uint32_t abi_version; uint32_t struct_size; @@ -59,13 +67,18 @@ typedef struct pk_plugin_imports { int (*signal_add)(uint8_t code, signal_flag_t flags, signal_handler_t handler); } pk_plugin_imports_t; -typedef void (*pk_plugin_init_fn)(const pk_plugin_imports_t *imports); +typedef void (*pk_plugin_init_fn)(pk_plugin_imports_t *imports); typedef struct pk_plugin_header { uint32_t magic; uint32_t abi_version; uint32_t header_size; uint32_t image_size; + uintptr_t data_load_start; + uintptr_t data_start; + uint32_t data_size; + uintptr_t bss_start; + uint32_t bss_size; pk_plugin_init_fn init; } pk_plugin_header_t; diff --git a/src/plugin/plugin_loader.c b/src/plugin/plugin_loader.c index 3457d04..d04b675 100644 --- a/src/plugin/plugin_loader.c +++ b/src/plugin/plugin_loader.c @@ -20,6 +20,9 @@ #include #include +#include + +static pk_plugin_imports_t plugin_imports; #ifdef ENABLE_EMULATION #ifdef _WIN32 @@ -108,10 +111,55 @@ static int pk_plugin_ptr_in_range(const void *ptr) { addr < ((uintptr_t)PICOKEYS_PLUGIN_FLASH_BASE + (uintptr_t)PICOKEYS_PLUGIN_FLASH_SIZE); } +static int pk_plugin_ram_range_valid(uintptr_t start, uint32_t size) { + uintptr_t ram_base = (uintptr_t)PICOKEYS_PLUGIN_RAM_BASE; + uintptr_t ram_end = ram_base + (uintptr_t)PICOKEYS_PLUGIN_RAM_SIZE; + uintptr_t end = start + (uintptr_t)size; + + if (size == 0u) { + return 1; + } + if (end < start) { + return 0; + } + return start >= ram_base && end <= ram_end; +} + +static int pk_plugin_flash_range_valid(uintptr_t start, uint32_t size) { + uintptr_t flash_base = (uintptr_t)PICOKEYS_PLUGIN_FLASH_BASE; + uintptr_t flash_end = flash_base + (uintptr_t)PICOKEYS_PLUGIN_FLASH_SIZE; + uintptr_t end = start + (uintptr_t)size; + + if (size == 0u) { + return 1; + } + if (end < start) { + return 0; + } + return start >= flash_base && end <= flash_end; +} + +static int pk_plugin_runtime_init(const pk_plugin_header_t *plugin) { + if (!pk_plugin_ram_range_valid(plugin->data_start, plugin->data_size) || + !pk_plugin_ram_range_valid(plugin->bss_start, plugin->bss_size) || + !pk_plugin_flash_range_valid(plugin->data_load_start, plugin->data_size)) { + printf("Plugin rejected: bad RAM image\n"); + return 0; + } + + if (plugin->data_size != 0u) { + memcpy((void *)plugin->data_start, (const void *)plugin->data_load_start, plugin->data_size); + } + if (plugin->bss_size != 0u) { + memset((void *)plugin->bss_start, 0, plugin->bss_size); + } + return 1; +} + static const pk_plugin_header_t *pk_plugin_get_valid(void) { const pk_plugin_header_t *plugin = pk_plugin_header(); - printf("Plugin header @ 0x%08lx: magic=0x%08lx abi=%lu header=%lu image=%lu hello=0x%08lx\n", + printf("Plugin header @ 0x%08lx: magic=0x%08lx abi=%lu header=%lu image=%lu init=0x%08lx\n", (unsigned long)PICOKEYS_PLUGIN_FLASH_BASE, (unsigned long)plugin->magic, (unsigned long)plugin->abi_version, @@ -149,12 +197,18 @@ void plugin_init(void) { printf("No valid plugin found\n"); return; } +#ifndef ENABLE_EMULATION + if (!pk_plugin_runtime_init(plugin)) { + printf("No valid plugin found\n"); + return; + } +#endif - const pk_plugin_imports_t imports = { + plugin_imports = (pk_plugin_imports_t){ .abi_version = PICOKEYS_PLUGIN_ABI_VERSION, - .struct_size = sizeof(imports), + .struct_size = sizeof(plugin_imports), .printf = printf, .signal_add = signal_add, }; - plugin->init(&imports); + plugin->init(&plugin_imports); } diff --git a/src/signal.h b/src/signal.h index 161b30b..b5cf527 100644 --- a/src/signal.h +++ b/src/signal.h @@ -40,7 +40,7 @@ typedef enum { SIGNAL_FLAG_MAY_DUPLICATE = 0x2, } signal_flag_t; -typedef int (*signal_handler_t)(uint8_t, void *); +typedef int (*signal_handler_t)(uint8_t code, void *data); typedef struct { uint32_t timeout;