From f8775dce3a4cd3118910e84d42495c39dfa91316 Mon Sep 17 00:00:00 2001 From: Terraneo Federico <fede.tft@miosix.org> Date: Thu, 9 Jan 2025 11:35:31 +0100 Subject: [PATCH] Towards supporting processes on Cortex M0+ --- .../interfaces-impl/arch_registers_impl.h | 6 +- .../rp2040_2M+264k_processes.ld | 169 ++++++++++++++++++ .../rp2040_2M+264k_rom.ld | 2 +- miosix/config/Makefile.inc | 14 +- miosix/libsyscalls/crt1.cpp | 16 ++ 5 files changed, 199 insertions(+), 8 deletions(-) create mode 100644 miosix/arch/cortexM0plus_rp2040/rp2040_raspberry_pi_pico/rp2040_2M+264k_processes.ld diff --git a/miosix/arch/cortexM0plus_rp2040/common/interfaces-impl/arch_registers_impl.h b/miosix/arch/cortexM0plus_rp2040/common/interfaces-impl/arch_registers_impl.h index a4bd9777..100cfa2b 100644 --- a/miosix/arch/cortexM0plus_rp2040/common/interfaces-impl/arch_registers_impl.h +++ b/miosix/arch/cortexM0plus_rp2040/common/interfaces-impl/arch_registers_impl.h @@ -4,12 +4,10 @@ #include "../rp2040/hardware/rp2040.h" #include "../rp2040/hardware/properties.h" #include "../rp2040/hardware/platform.h" -#if defined(BOARD_VARIANT_PICO) -#include "../rp2040/hardware/boards/pico.h" -#elif defined(BOARD_VARIANT_PICO_W) +#if defined(BOARD_VARIANT_PICO_W) #include "../rp2040/hardware/boards/pico_w.h" #else -#error "Unknown board variant" +#include "../rp2040/hardware/boards/pico.h" #endif //Peripheral interrupt start from 0 and the last one is 25, so there are 26 diff --git a/miosix/arch/cortexM0plus_rp2040/rp2040_raspberry_pi_pico/rp2040_2M+264k_processes.ld b/miosix/arch/cortexM0plus_rp2040/rp2040_raspberry_pi_pico/rp2040_2M+264k_processes.ld new file mode 100644 index 00000000..c5a168ea --- /dev/null +++ b/miosix/arch/cortexM0plus_rp2040/rp2040_raspberry_pi_pico/rp2040_2M+264k_processes.ld @@ -0,0 +1,169 @@ +/* + * Linker script for RP2040 (2MB external flash, 264K RAM) + * Optimized for use with the Miosix kernel + */ + +/* + * This linker script puts: + * - read only data and code (.text, .rodata, .eh_*) in flash + * - stacks, heap and sections .data and .bss in ram + */ + +/* + * The main stack is used for interrupt handling by the kernel. + * + * *** Readme *** + * This linker script places the main stack (used by the kernel for interrupts) + * at the bottom of the ram, instead of the top. This is done for two reasons: + * + * - as an optimization for microcontrollers with little ram memory. In fact + * the implementation of malloc from newlib requests memory to the OS in 4KB + * block (except the first block that can be smaller). This is probably done + * for compatibility with OSes with an MMU and paged memory. To see why this + * is bad, consider a microcontroller with 8KB of ram: when malloc finishes + * up the first 4KB it will call _sbrk_r asking for a 4KB block, but this will + * fail because the top part of the ram is used by the main stack. As a + * result, the top part of the memory will not be used by malloc, even if + * available (and it is nearly *half* the ram on an 8KB mcu). By placing the + * main stack at the bottom of the ram, the upper 4KB block will be entirely + * free and available as heap space. + * + * - In case of main stack overflow the cpu will fault because access to memory + * before the beginning of the ram faults. Instead with the default stack + * placement the main stack will silently collide with the heap. + */ +_main_stack_size = 0x00000200; /* main stack = 512Bytes */ +_main_stack_top = 0x20000000 + _main_stack_size; +ASSERT(_main_stack_size % 8 == 0, "MAIN stack size error"); + +/* Mapping the heap into the bottom 128KB of the RAM */ +_heap_end = 0x20020000; +/* Mapping the process pool into the upper 136KB of the RAM */ +_process_pool_start = _heap_end; +_process_pool_end = 0x20042000; /* end of available ram */ + +ENTRY(_ZN6miosix13Reset_HandlerEv) + +/* specify the memory areas */ +MEMORY +{ + flash(rx) : ORIGIN = 0x10000000, LENGTH = 2048k + /* + * Note, the ram starts at 0x20000000 but it is necessary to add the size + * of the main stack, so it is 0x20000200. + */ + ram(wx) : ORIGIN = 0x20000000+_main_stack_size, LENGTH = 128k-_main_stack_size +} + +/* now define the output sections */ +SECTIONS +{ + . = 0; + + /* .text section: code goes to flash */ + .text : + { + /* Stage 2 bootloader must be at the base address of flash */ + KEEP(*(.boot2)) + /* Interrupt vectors go at address 0x100 */ + KEEP(*(.isr_vector)) + + *(.text) + *(.text.*) + *(.gnu.linkonce.t.*) + /* these sections for thumb interwork? */ + *(.glue_7) + *(.glue_7t) + /* these sections for C++? */ + *(.gcc_except_table) + *(.gcc_except_table.*) + *(.ARM.extab*) + *(.gnu.linkonce.armextab.*) + + . = ALIGN(4); + /* .rodata: constant data */ + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + + /* C++ Static constructors/destructors (eabi) */ + . = ALIGN(4); + KEEP(*(.init)) + + . = ALIGN(4); + __miosix_init_array_start = .; + KEEP (*(SORT(.miosix_init_array.*))) + KEEP (*(.miosix_init_array)) + __miosix_init_array_end = .; + + . = ALIGN(4); + __preinit_array_start = .; + KEEP (*(.preinit_array)) + __preinit_array_end = .; + + . = ALIGN(4); + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; + + . = ALIGN(4); + KEEP(*(.fini)) + + . = ALIGN(4); + __fini_array_start = .; + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __fini_array_end = .; + + /* C++ Static constructors/destructors (elf) */ + . = ALIGN(4); + _ctor_start = .; + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*crtend.o(.ctors)) + _ctor_end = .; + + . = ALIGN(4); + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*crtend.o(.dtors)) + } > flash + + /* .ARM.exidx is sorted, so has to go in its own output section. */ + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > flash + __exidx_end = .; + + /* .data section: global variables go to ram, but also store a copy to + flash to initialize them */ + .data : ALIGN(8) + { + _data = .; + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + . = ALIGN(8); + _edata = .; + } > ram AT > flash + _etext = LOADADDR(.data); + + /* .bss section: uninitialized global variables go to ram */ + _bss_start = .; + .bss : + { + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + . = ALIGN(8); + } > ram + _bss_end = .; + + _end = .; + PROVIDE(end = .); +} diff --git a/miosix/arch/cortexM0plus_rp2040/rp2040_raspberry_pi_pico/rp2040_2M+264k_rom.ld b/miosix/arch/cortexM0plus_rp2040/rp2040_raspberry_pi_pico/rp2040_2M+264k_rom.ld index 84018e2a..c3be498e 100644 --- a/miosix/arch/cortexM0plus_rp2040/rp2040_raspberry_pi_pico/rp2040_2M+264k_rom.ld +++ b/miosix/arch/cortexM0plus_rp2040/rp2040_raspberry_pi_pico/rp2040_2M+264k_rom.ld @@ -49,7 +49,7 @@ MEMORY * Note, the ram starts at 0x20000000 but it is necessary to add the size * of the main stack, so it is 0x20000200. */ - ram(rwx) : ORIGIN = 0x20000000+_main_stack_size, LENGTH = 264k-_main_stack_size + ram(wx) : ORIGIN = 0x20000000+_main_stack_size, LENGTH = 264k-_main_stack_size } /* now define the output sections */ diff --git a/miosix/config/Makefile.inc b/miosix/config/Makefile.inc index 6ebf760f..c10843b4 100644 --- a/miosix/config/Makefile.inc +++ b/miosix/config/Makefile.inc @@ -812,6 +812,14 @@ ifeq ($(OPT_BOARD),rp2040_raspberry_pi_pico) #BOARD_VARIANT := BOARD_VARIANT_PICO BOARD_VARIANT := BOARD_VARIANT_PICO_W + ## Linker script type, there are two options + ## 1) Code in FLASH, stack + heap in internal RAM (file *_rom.ld) + ## 2) Same as 1) but space has been reserved for a process pool, allowing + ## to configure the kernel with "#define WITH_PROCESSES" + LINKER_SCRIPT_PATH := arch/cortexM0plus_rp2040/rp2040_raspberry_pi_pico/ + LINKER_SCRIPT := $(LINKER_SCRIPT_PATH)rp2040_2M+264k_rom.ld + #LINKER_SCRIPT := $(LINKER_SCRIPT_PATH)rp2040_2M+264k_processes.ld + endif ##--------------------------------------------------------------------------- @@ -3325,7 +3333,7 @@ else ifeq ($(ARCH),cortexM0plus_rp2040) BOARD_INC := arch/cortexM0plus_rp2040/rp2040_raspberry_pi_pico ## Select linker script - LINKER_SCRIPT := $(BOARD_INC)/rp2040_2M+264k_rom.ld + #LINKER_SCRIPT := already selected in board options ## Select architecture specific files ## These are the files in arch/<arch name>/<board name> @@ -3352,8 +3360,8 @@ else ifeq ($(ARCH),cortexM0plus_rp2040) ## Select compiler PREFIX := arm-miosix-eabi- - ## This architecture does not support processes - #POSTLD := + ## This architecture supports processes + POSTLD := mx-postlinker CPU_INC := arch/cpu/armv6m ## Select appropriate compiler flags for both ASM/C/C++/linker diff --git a/miosix/libsyscalls/crt1.cpp b/miosix/libsyscalls/crt1.cpp index 6bcbdfea..c39f5164 100644 --- a/miosix/libsyscalls/crt1.cpp +++ b/miosix/libsyscalls/crt1.cpp @@ -432,6 +432,8 @@ pid_t wait(int *status) return waitpid(-1,status,0); } +#if __CORTEX_M != 0 + static int __LDREXW(volatile int *addr) { int result; @@ -461,6 +463,20 @@ static int atomicCompareAndSwap(volatile int *p, int prev, int next) return result; } +#else //__CORTEX_M != 0 + +inline int atomicCompareAndSwap(volatile int *p, int prev, int next) +{ + //FIXME: not atomic at all, we can't even disable interrupts in a process + //we'll need a syscall to let the kernel do this operation atomically + int result = *p; + if(*p == prev) *p = next; + asm volatile("":::"memory"); + return result; +} + +#endif //__CORTEX_M != 0 + static void enterCriticalSection(pthread_mutex_t *m) { //TODO: when we add the flag in the mutex stop using the global flag -- GitLab