From 4f59610a00da78639c1909acb09c7dfde4519a28 Mon Sep 17 00:00:00 2001 From: Clyne Sullivan Date: Wed, 27 Jan 2021 11:18:33 -0500 Subject: [PATCH] sandboxed user algorithm --- Makefile | 4 +- STM32H723xG.ld | 55 +++++----------- cfg/mcuconf.h | 2 +- source/common.hpp | 61 ----------------- source/main.cpp | 141 ++++++++++++++++++++++++++++++---------- source/samplebuffer.cpp | 52 +++++++++++++++ source/samplebuffer.hpp | 39 +++++++++++ 7 files changed, 219 insertions(+), 135 deletions(-) delete mode 100644 source/common.hpp create mode 100644 source/samplebuffer.cpp create mode 100644 source/samplebuffer.hpp diff --git a/Makefile b/Makefile index efb47ad..178b026 100644 --- a/Makefile +++ b/Makefile @@ -148,7 +148,9 @@ CPPWARN = -Wall -Wextra -Wundef # # List all user C define here, like -D_DEBUG=1 -UDEFS = -DCORTEX_ENABLE_WFI_IDLE=TRUE -DPORT_USE_SYSCALL=TRUE +UDEFS = -DCORTEX_ENABLE_WFI_IDLE=TRUE \ + -DPORT_USE_SYSCALL=TRUE \ + -DPORT_USE_GUARD_MPU_REGION=MPU_REGION_0 # Define ASM defines here UADEFS = diff --git a/STM32H723xG.ld b/STM32H723xG.ld index eb3d63b..e59c900 100644 --- a/STM32H723xG.ld +++ b/STM32H723xG.ld @@ -15,19 +15,18 @@ */ /* - * STM32H743xI generic setup. - * * AXI SRAM - BSS, Data, Heap. * SRAM1 - SIGGEN. * SRAM2 - DAC. * SRAM4 - ADC. - * DTCM-RAM - Main Stack, Process Stack. + * DTCM-RAM - Unprivileged Stack, Main Stack, Process Stack. * ITCM-RAM - STMDSP Algorithm. * BCKP SRAM - None. */ MEMORY { - flash0 (rx) : org = 0x08000000, len = 1M /* Flash bank1+bank2 */ + flash0 (rx) : org = 0x08000000, len = 1M /* Flash bank1 + bank2 */ + flashc (rx) : org = 0x0807F000, len = 4K /* Unprivileged firmware */ flash1 (rx) : org = 0x08000000, len = 512K /* Flash bank 1 */ flash2 (rx) : org = 0x08080000, len = 512K /* Flash bank 2 */ flash3 (rx) : org = 0x00000000, len = 0 @@ -35,14 +34,15 @@ MEMORY flash5 (rx) : org = 0x00000000, len = 0 flash6 (rx) : org = 0x00000000, len = 0 flash7 (rx) : org = 0x00000000, len = 0 - ram0 (wx) : org = 0x24000000, len = 320k /* AXI SRAM */ - ram1 (wx) : org = 0x30000000, len = 16k /* AHB SRAM1 */ - ram2 (wx) : org = 0x30004000, len = 16k /* AHB SRAM2 */ - ram3 (wx) : org = 0x38000000, len = 16k /* AHB SRAM4 */ + ram0 (wx) : org = 0x24000000, len = 320K /* AXI SRAM */ + ram1 (wx) : org = 0x30000000, len = 16K /* AHB SRAM1 */ + ram2 (wx) : org = 0x30004000, len = 16K /* AHB SRAM2 */ + ram3 (wx) : org = 0x38000000, len = 16K /* AHB SRAM4 */ ram4 (wx) : org = 0x00000000, len = 0 - ram5 (wx) : org = 0x20000000, len = 128k /* DTCM-RAM */ - ram6 (wx) : org = 0x00000000, len = 64k /* ITCM-RAM */ - ram7 (wx) : org = 0x38800000, len = 4k /* BCKP SRAM */ + ramc (wx) : org = 0x20000000, len = 4K /* Unprivileged data */ + ram5 (wx) : org = 0x20001000, len = 124K /* DTCM-RAM */ + ram6 (wx) : org = 0x00000000, len = 64K /* ITCM-RAM */ + ram7 (wx) : org = 0x38800000, len = 4K /* BCKP SRAM */ } /* For each data/text section two region are defined, a virtual region @@ -92,40 +92,19 @@ REGION_ALIAS("HEAP_RAM", ram0); /* Stack rules inclusion.*/ INCLUDE rules_stacks.ld -/*===========================================================================*/ -/* Custom sections for STM32H7xx. */ -/* SRAM3 is assumed to be marked non-cacheable using MPU. */ -/*===========================================================================*/ - -/* RAM region to be used for nocache segment.*/ -/*REGION_ALIAS("NOCACHE_RAM", ram3);*/ - -/* RAM region to be used for eth segment.*/ -/*REGION_ALIAS("ETH_RAM", ram3);*/ - SECTIONS { - /* Special section for non cache-able areas.*/ - /*.nocache (NOLOAD) : ALIGN(4) + .convdata : ALIGN(4) { - __nocache_base__ = .; - *(.nocache) - *(.nocache.*) - *(.bss.__nocache_*) + *(.convdata) . = ALIGN(4); - __nocache_end__ = .; - } > NOCACHE_RAM*/ + } > ramc - /* Special section for Ethernet DMA non cache-able areas.*/ - /*.eth (NOLOAD) : ALIGN(4) + .convcode : ALIGN(4) { - __eth_base__ = .; - *(.eth) - *(.eth.*) - *(.bss.__eth_*) + *(.convcode) . = ALIGN(4); - __eth_end__ = .; - } > ETH_RAM*/ + } > flashc } /* Code rules inclusion.*/ diff --git a/cfg/mcuconf.h b/cfg/mcuconf.h index 27a2939..1fb3655 100644 --- a/cfg/mcuconf.h +++ b/cfg/mcuconf.h @@ -44,7 +44,7 @@ /* * Memory attributes settings. */ -#define STM32_NOCACHE_MPU_REGION MPU_REGION_6 +#define STM32_NOCACHE_MPU_REGION MPU_REGION_1 #define STM32_NOCACHE_SRAM1_SRAM2 FALSE #define STM32_NOCACHE_SRAM3 FALSE #define STM32_NOCACHE_ALLSRAM TRUE diff --git a/source/common.hpp b/source/common.hpp deleted file mode 100644 index 876cf74..0000000 --- a/source/common.hpp +++ /dev/null @@ -1,61 +0,0 @@ -#include -#include - -using Sample = uint16_t; - -// gives 8000 -constexpr unsigned int MAX_SAMPLE_BUFFER_BYTESIZE = 16384; -constexpr unsigned int MAX_SAMPLE_BUFFER_SIZE = MAX_SAMPLE_BUFFER_BYTESIZE / sizeof(Sample); - -class SampleBuffer -{ -public: - SampleBuffer(Sample *buffer) : - m_buffer(buffer) {} - - void clear() { - std::fill(m_buffer, m_buffer + m_size, 2048); - } - void modify(Sample *data, unsigned int srcsize) { - auto size = srcsize < m_size ? srcsize : m_size; - std::copy(data, data + size, m_buffer); - m_modified = m_buffer; - } - void midmodify(Sample *data, unsigned int srcsize) { - auto size = srcsize < m_size / 2 ? srcsize : m_size / 2; - std::copy(data, data + size, middata()); - m_modified = middata(); - } - - void setSize(unsigned int size) { - m_size = size < MAX_SAMPLE_BUFFER_SIZE ? size : MAX_SAMPLE_BUFFER_SIZE; - } - - Sample *data() { - return m_buffer; - } - Sample *middata() { - return m_buffer + m_size / 2; - } - uint8_t *bytedata() { - return reinterpret_cast(m_buffer); - } - - Sample *modified() { - auto m = m_modified; - m_modified = nullptr; - return m; - } - unsigned int size() const { - return m_size; - } - unsigned int bytesize() const { - return m_size * sizeof(Sample); - } - -private: - Sample *m_buffer = nullptr; - unsigned int m_size = MAX_SAMPLE_BUFFER_SIZE; - Sample *m_modified = nullptr; -}; - diff --git a/source/main.cpp b/source/main.cpp index 97612f4..1a89c93 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -15,13 +15,12 @@ static_assert(sizeof(adcsample_t) == sizeof(uint16_t)); static_assert(sizeof(dacsample_t) == sizeof(uint16_t)); -#include "common.hpp" -#include "error.hpp" - #include "adc.hpp" #include "cordic.hpp" #include "dac.hpp" #include "elf_load.hpp" +#include "error.hpp" +#include "samplebuffer.hpp" #include "sclock.hpp" #include "usbserial.hpp" @@ -45,30 +44,44 @@ static RunStatus run_status = RunStatus::Idle; #define MSG_FOR_FIRST(m) (m & 1) #define MSG_FOR_MEASURE(m) (m > 2) -static msg_t conversionMBBuffer[4]; -static MAILBOX_DECL(conversionMB, conversionMBBuffer, 4); +static ErrorManager EM; -static THD_WORKING_AREA(conversionThreadWA, 2048); +static msg_t conversionMBBuffer[2]; +static MAILBOX_DECL(conversionMB, conversionMBBuffer, 2); + +// Thread for LED status and wakeup hold +static THD_WORKING_AREA(monitorThreadWA, 128); +static THD_FUNCTION(monitorThread, arg); +// Thread for managing the conversion task +static THD_WORKING_AREA(conversionThreadMonitorWA, 128); +static THD_FUNCTION(conversionThreadMonitor, arg); +// Thread for unprivileged algorithm execution +static THD_WORKING_AREA(conversionThreadWA, 128); static THD_FUNCTION(conversionThread, arg); +__attribute__((section(".convdata"))) +static THD_WORKING_AREA(conversionThreadUPWA, 256); -static time_measurement_t conversion_time_measurement; - -static ErrorManager EM; +static thread_t *conversionThreadHandle = nullptr; +__attribute__((section(".convdata"))) +static thread_t *conversionThreadMonitorHandle = nullptr; +__attribute__((section(".convdata"))) +static time_measurement_t conversion_time_measurement; +__attribute__((section(".convdata"))) static SampleBuffer samplesIn (reinterpret_cast(0x38000000)); // 16k +__attribute__((section(".convdata"))) static SampleBuffer samplesOut (reinterpret_cast(0x30004000)); // 16k + static SampleBuffer samplesSigGen (reinterpret_cast(0x30000000)); // 16k static unsigned char elf_file_store[MAX_ELF_FILE_SIZE]; +__attribute__((section(".convdata"))) static ELF::Entry elf_entry = nullptr; static void signal_operate(adcsample_t *buffer, size_t count); static void signal_operate_measure(adcsample_t *buffer, size_t count); static void main_loop(); -static THD_WORKING_AREA(waThread1, 128); -static THD_FUNCTION(Thread1, arg); - int main() { // Initialize the RTOS @@ -80,6 +93,26 @@ int main() // Enable FPU SCB->CPACR |= 0xF << 20; + // Set up MPU for user algorithm + // Region 2: Data for algorithm manager thread + mpuConfigureRegion(MPU_REGION_2, + 0x20000000, + MPU_RASR_ATTR_AP_RW_RW | MPU_RASR_ATTR_NON_CACHEABLE | + MPU_RASR_SIZE_4K | + MPU_RASR_ENABLE); + // Region 3: Code for algorithm manager thread + mpuConfigureRegion(MPU_REGION_3, + 0x08080000, + MPU_RASR_ATTR_AP_RO_RO | MPU_RASR_ATTR_NON_CACHEABLE | + MPU_RASR_SIZE_4K | + MPU_RASR_ENABLE); + // Region 4: Algorithm code + mpuConfigureRegion(MPU_REGION_4, + 0x00000000, + MPU_RASR_ATTR_AP_RW_RW | MPU_RASR_ATTR_NON_CACHEABLE | + MPU_RASR_SIZE_64K | + MPU_RASR_ENABLE); + ADC::begin(); DAC::begin(); SClock::begin(); @@ -90,9 +123,14 @@ int main() ADC::setRate(SClock::Rate::R32K); chTMObjectInit(&conversion_time_measurement); - chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO, Thread1, nullptr); - chThdCreateStatic(conversionThreadWA, sizeof(conversionThreadWA), - NORMALPRIO, conversionThread, nullptr); + chThdCreateStatic(monitorThreadWA, sizeof(monitorThreadWA), + NORMALPRIO, monitorThread, nullptr); + conversionThreadMonitorHandle = chThdCreateStatic( + conversionThreadMonitorWA, sizeof(conversionThreadMonitorWA), + NORMALPRIO, conversionThreadMonitor, nullptr); + conversionThreadHandle = chThdCreateStatic( + conversionThreadWA, sizeof(conversionThreadWA), + NORMALPRIO + 1, conversionThread, nullptr); main_loop(); } @@ -278,35 +316,47 @@ void conversion_abort() run_status = RunStatus::Idle; } -THD_FUNCTION(conversionThread, arg) +THD_FUNCTION(conversionThreadMonitor, arg) { (void)arg; - while (1) { // Recover from algorithm fault if necessary - if (run_status == RunStatus::Recovering) - conversion_abort(); + //if (run_status == RunStatus::Recovering) + // conversion_abort(); + + msg_t message; + if (chMBFetchTimeout(&conversionMB, &message, TIME_INFINITE) == MSG_OK) + chMsgSend(conversionThreadHandle, message); + } +} + +__attribute__((section(".convcode"))) +static void convThdMain(); +THD_FUNCTION(conversionThread, arg) +{ + (void)arg; + elf_entry = nullptr; + port_unprivileged_jump(reinterpret_cast(convThdMain), + reinterpret_cast(conversionThreadUPWA) + 256); +} + +void convThdMain() +{ + while (1) { msg_t message; - if (chMBFetchTimeout(&conversionMB, &message, TIME_INFINITE) == MSG_OK) { - static Sample *samples = nullptr; - static unsigned int size = 0; - samples = MSG_FOR_FIRST(message) ? samplesIn.data() : samplesIn.middata(); - size = samplesIn.size() / 2; + asm("svc 0; mov %0, r0" : "=r" (message)); + if (message != 0) { + auto samples = MSG_FOR_FIRST(message) ? samplesIn.data() : samplesIn.middata(); + auto size = samplesIn.size() / 2; if (elf_entry) { if (!MSG_FOR_MEASURE(message)) { - //asm("cpsid i"); - //mpuDisable(); - //port_unprivileged_jump((uint32_t)+[] { - samples = elf_entry(samples, size); - //}, 0xF800); - //mpuEnable(MPU_CTRL_PRIVDEFENA); - //asm("cpsie i"); + samples = elf_entry(samples, size); } else { - chTMStartMeasurementX(&conversion_time_measurement); + //chTMStartMeasurementX(&conversion_time_measurement); samples = elf_entry(samples, size); - chTMStopMeasurementX(&conversion_time_measurement); + //chTMStopMeasurementX(&conversion_time_measurement); } } @@ -340,7 +390,7 @@ void signal_operate_measure(adcsample_t *buffer, [[maybe_unused]] size_t count) ADC::setOperation(signal_operate); } -THD_FUNCTION(Thread1, arg) +THD_FUNCTION(monitorThread, arg) { (void)arg; @@ -379,6 +429,29 @@ THD_FUNCTION(Thread1, arg) extern "C" { +__attribute__((naked)) +void port_syscall(struct port_extctx *ctxp, uint32_t n) +{ + switch (n) { + case 0: { + chSysLock(); + chMsgWaitS(); + auto msg = chMsgGet(conversionThreadMonitorHandle); + chMsgReleaseS(conversionThreadMonitorHandle, MSG_OK); + //chSchDoYieldS(); + chSysUnlock(); + ctxp->r0 = msg; + } + break; + default: + while (1); + break; + } + + asm("svc 0"); + while (1); +} + __attribute__((naked)) void HardFault_Handler() { diff --git a/source/samplebuffer.cpp b/source/samplebuffer.cpp new file mode 100644 index 0000000..6932392 --- /dev/null +++ b/source/samplebuffer.cpp @@ -0,0 +1,52 @@ +#include "common.hpp" + +SampleBuffer::SampleBuffer(Sample *buffer) : + m_buffer(buffer) {} + +void SampleBuffer::clear() { + std::fill(m_buffer, m_buffer + m_size, 2048); +} +__attribute__((section(".convcode"))) +void SampleBuffer::modify(Sample *data, unsigned int srcsize) { + auto size = srcsize < m_size ? srcsize : m_size; + for (Sample *d = data, *s = m_buffer; d != data + size;) + *d++ = *s++; + m_modified = m_buffer; +} +__attribute__((section(".convcode"))) +void SampleBuffer::midmodify(Sample *data, unsigned int srcsize) { + auto size = srcsize < m_size / 2 ? srcsize : m_size / 2; + for (Sample *d = data, *s = middata(); d != data + size;) + *d++ = *s++; + m_modified = middata(); +} + +void SampleBuffer::setSize(unsigned int size) { + m_size = size < MAX_SAMPLE_BUFFER_SIZE ? size : MAX_SAMPLE_BUFFER_SIZE; +} + +__attribute__((section(".convcode"))) +Sample *SampleBuffer::data() { + return m_buffer; +} +__attribute__((section(".convcode"))) +Sample *SampleBuffer::middata() { + return m_buffer + m_size / 2; +} +uint8_t *SampleBuffer::bytedata() { + return reinterpret_cast(m_buffer); +} + +Sample *SampleBuffer::modified() { + auto m = m_modified; + m_modified = nullptr; + return m; +} +__attribute__((section(".convcode"))) +unsigned int SampleBuffer::size() const { + return m_size; +} +unsigned int SampleBuffer::bytesize() const { + return m_size * sizeof(Sample); +} + diff --git a/source/samplebuffer.hpp b/source/samplebuffer.hpp new file mode 100644 index 0000000..9aabfdd --- /dev/null +++ b/source/samplebuffer.hpp @@ -0,0 +1,39 @@ +#ifndef SAMPLEBUFFER_HPP_ +#define SAMPLEBUFFER_HPP_ + +#include +#include + +using Sample = uint16_t; + +// gives 8000 +constexpr unsigned int MAX_SAMPLE_BUFFER_BYTESIZE = 16384; +constexpr unsigned int MAX_SAMPLE_BUFFER_SIZE = MAX_SAMPLE_BUFFER_BYTESIZE / sizeof(Sample); + +class SampleBuffer +{ +public: + SampleBuffer(Sample *buffer); + + void clear(); + + void modify(Sample *data, unsigned int srcsize); + void midmodify(Sample *data, unsigned int srcsize); + Sample *modified(); + + Sample *data(); + Sample *middata(); + uint8_t *bytedata(); + + void setSize(unsigned int size); + unsigned int size() const; + unsigned int bytesize() const; + +private: + Sample *m_buffer = nullptr; + unsigned int m_size = MAX_SAMPLE_BUFFER_SIZE; + Sample *m_modified = nullptr; +}; + +#endif // SAMPLEBUFFER_HPP_ +