diff --git a/Makefile b/Makefile index 4722f6121aa1fa0de8ea460521bcde7c78543460..6c8092c395ce60ea16c806f71d2a1011ae067d4a 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ SUBDIRS := miosix ## List here your source files (both .s, .c and .cpp) ## SRC := \ -main.cpp pool_allocator.cpp +main.cpp ## ## List here additional static libraries with relative path diff --git a/app_template/Makefile b/app_template/Makefile index 103b25409e85b0c87b666f67a0d11251c43ef299..d27419d1ea8077628c031476ed91691824b477d2 100644 --- a/app_template/Makefile +++ b/app_template/Makefile @@ -28,7 +28,7 @@ all: $(OBJ) crt0.o $(CXX) $(LFLAGS) -o main.elf $(OBJ) crt0.o $(LINK_LIBS) $(SZ) main.elf @arm-miosix-eabi-objdump -Dslx main.elf > main.txt - @mx-postlinker main.elf --ramsize=20480 --stacksize=2048 --strip-sectheader + @mx-postlinker main.elf --ramsize=16384 --stacksize=2048 --strip-sectheader @xxd -i main.elf | sed 's/unsigned char/const unsigned char __attribute__((aligned(8)))/' > prog3.h clean: diff --git a/app_template/prog3.h b/app_template/prog3.h index 17c4af007efb5a433d92a54af598470efc7abc0e..a7a34f4a927292447b84f09e07c22e9b7264599d 100644 --- a/app_template/prog3.h +++ b/app_template/prog3.h @@ -29,7 +29,7 @@ const unsigned char __attribute__((aligned(8))) main_elf[] = { 0x70, 0x47, 0x04, 0x23, 0x00, 0xdf, 0x70, 0x47, 0x05, 0x23, 0x00, 0xdf, 0x70, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x50, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x08, 0x00, 0x00, 0x4d, 0x69, 0x6f, 0x73, 0x69, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3d, 0x64, 0x69, 0x76, 0x7a, 0x65, 0x72, diff --git a/miosix/Makefile b/miosix/Makefile index 78f53e7e9a4a4f0829669e32865fac0c785dce07..559c5cc08a430802946c9ea7a340eb26a511d861 100644 --- a/miosix/Makefile +++ b/miosix/Makefile @@ -19,6 +19,7 @@ kernel/stage_2_boot.cpp \ kernel/syscalls.cpp \ kernel/elf_program.cpp \ kernel/process.cpp \ +kernel/process_pool.cpp \ kernel/scheduler/priority/priority_scheduler.cpp \ kernel/scheduler/control/control_scheduler.cpp \ kernel/scheduler/edf/edf_scheduler.cpp \ diff --git a/miosix/arch/cortexM3_stm32f2/stm32f207ig_stm3220g-eval/stm32_1m+128k_xram_processes.ld b/miosix/arch/cortexM3_stm32f2/stm32f207ig_stm3220g-eval/stm32_1m+128k_xram_processes.ld new file mode 100644 index 0000000000000000000000000000000000000000..3b00c3b09df422098399799c2df18859b919d5f5 --- /dev/null +++ b/miosix/arch/cortexM3_stm32f2/stm32f207ig_stm3220g-eval/stm32_1m+128k_xram_processes.ld @@ -0,0 +1,171 @@ +/* + * C++ enabled linker script for stm32 (1M FLASH, 128K RAM) + 2MB xram + * Developed by TFT: Terraneo Federico Technologies + * Optimized for use with the Miosix kernel + */ + +/* + * This linker script puts: + * - read only data and code (.text, .rodata, .eh_*) in flash + * - stack for interrupt handling, sections .data and .bss in the internal ram + * - heap and stack of threads in the external ram + * - 1MB of process pool, for allocation of processes + */ + +/* + * 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. + * Note: if increasing the main stack size also increase the ORIGIN value in + * the MEMORY definitions below accordingly. + */ +_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 external RAM (1MB as the second half is for the + * process pool) */ +_end = 0x64000000; +_heap_end = 0x64100000; +_process_pool_start = _heap_end; +_process_pool_end = 0x64200000; + +/* identify the Entry Point */ +ENTRY(_Z13Reset_Handlerv) + +/* specify the memory areas */ +MEMORY +{ + flash(rx) : ORIGIN = 0, LENGTH = 1M + + /* + * 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 = 0x20000200, LENGTH = 128K-0x200 +} + +/* now define the output sections */ +SECTIONS +{ + . = 0; + + /* .text section: code goes to flash */ + .text : + { + /* Startup code must go at address 0 */ + 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); + __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 = .; + + . = ALIGN(8); + _etext = .; + + /* .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 + + /* .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/config/Makefile.inc b/miosix/config/Makefile.inc index ef5b472f868c36c3e4a30fde3ee3f7bf09e44f1d..d9604d7e8f478cece00c8d8e0142193f382a619c 100644 --- a/miosix/config/Makefile.inc +++ b/miosix/config/Makefile.inc @@ -27,8 +27,8 @@ OPT_BOARD := stm32f207ig_stm3220g-eval ## -O2 is recomended otherwise, as it provides a good balance between code ## size and speed ## -OPT_OPTIMIZATION := -O0 -#OPT_OPTIMIZATION := -O2 +#OPT_OPTIMIZATION := -O0 +OPT_OPTIMIZATION := -O2 #OPT_OPTIMIZATION := -O3 #OPT_OPTIMIZATION := -Os @@ -154,12 +154,15 @@ ifeq ($(OPT_BOARD),stm32f207ig_stm3220g-eval) ## *very* slow compared to FLASH. Works only with a booloader that ## forwards interrrupts @ 0x64000000 (see miosix/bootloaders for one). ## The microcontroller must have an external memory interface. + ## 4) Same as 3) but space has been reserved for a process pool, allowing + ## to configure the kernel with "#define WITH_PROCESSES" ## Warning! enable external ram if you use a linker script that requires it ## (see the XRAM flag below) LINKER_SCRIPT_PATH := arch/cortexM3_stm32f2/stm32f207ig_stm3220g-eval/ #LINKER_SCRIPT := $(LINKER_SCRIPT_PATH)stm32_1m+128k_rom.ld #LINKER_SCRIPT := $(LINKER_SCRIPT_PATH)stm32_1m+128k_xram.ld - LINKER_SCRIPT := $(LINKER_SCRIPT_PATH)stm32_1m+128k_all_in_xram.ld + #LINKER_SCRIPT := $(LINKER_SCRIPT_PATH)stm32_1m+128k_all_in_xram.ld + LINKER_SCRIPT := $(LINKER_SCRIPT_PATH)stm32_1m+128k_xram_processes.ld ## Enable/disable initialization of external RAM at boot. Three options: ## __ENABLE_XRAM : If you want the heap in xram (with an appropriate linker @@ -651,10 +654,13 @@ else ifeq ($(ARCH),cortexM3_stm32f2) ## error message saying that 'make program' is not supported for that ## board. ifeq ($(LINKER_SCRIPT),$(LINKER_SCRIPT_PATH)stm32_1m+128k_all_in_xram.ld) - PROGRAM_CMDLINE := miosix/bootloaders/stm32/pc_loader/pc_loader \ - /dev/ttyUSB0 main.bin + PROGRAM_CMDLINE := miosix/bootloaders/stm32/pc_loader/pc_loader \ + /dev/ttyUSB0 main.bin + else ifeq ($(LINKER_SCRIPT),$(LINKER_SCRIPT_PATH)stm32_1m+128k_xram_processes.ld) + PROGRAM_CMDLINE := miosix/bootloaders/stm32/pc_loader/pc_loader \ + /dev/ttyUSB0 main.bin else - PROGRAM_CMDLINE := qstlink2 -cqewV ./main.bin + PROGRAM_CMDLINE := qstlink2 -cqewV ./main.bin endif ##------------------------------------------------------------------------- diff --git a/miosix/kernel/elf_program.cpp b/miosix/kernel/elf_program.cpp index 85d81f199cfa54bce572034e69c865e27b3d3916..caaeace23d70e22547c9c1cead85c53fa88a8008 100644 --- a/miosix/kernel/elf_program.cpp +++ b/miosix/kernel/elf_program.cpp @@ -26,6 +26,7 @@ ***************************************************************************/ #include "elf_program.h" +#include "process_pool.h" #include <stdexcept> #include <cstring> #include <cstdio> @@ -43,6 +44,17 @@ namespace miosix { ///By convention, in an elf file for Miosix, the data segment starts @ this addr static const unsigned int DATA_START=0x10000000; +ProcessPool& getProcessPool() +{ + //These are defined in the linker script + extern unsigned int _process_pool_start asm("_process_pool_start"); + extern unsigned int _process_pool_end asm("_process_pool_end"); + static ProcessPool pool( + reinterpret_cast<unsigned int*>(_process_pool_start), + _process_pool_end-_process_pool_start); + return pool; +} + // // class ElfProgram // @@ -228,7 +240,7 @@ bool ElfProgram::validateDynamicSegment(const Elf32_Phdr *dynamic, void ProcessImage::load(const ElfProgram& program) { - if(image) delete[] image; + if(image) getProcessPool().deallocate(image); size=MAX_PROCESS_IMAGE_SIZE; const unsigned int base=program.getElfBase(); const Elf32_Phdr *phdr=program.getProgramHeaderTable(); @@ -262,7 +274,7 @@ void ProcessImage::load(const ElfProgram& program) dtRelsz=dyn->d_un.d_val; break; case DT_MX_RAMSIZE: - image=new unsigned int[dyn->d_un.d_val/4]; + image=getProcessPool().allocate(dyn->d_un.d_val); default: break; } @@ -306,7 +318,7 @@ void ProcessImage::load(const ElfProgram& program) ProcessImage::~ProcessImage() { - if(image) delete[] image; + if(image) getProcessPool().deallocate(image); } } //namespace miosix diff --git a/process_pool.cpp b/miosix/kernel/process_pool.cpp similarity index 86% rename from process_pool.cpp rename to miosix/kernel/process_pool.cpp index 36e3fa4e7a906fae5c2a1a72b40275bc4f024f11..714831e0c1a7629f51279e45bad08dfc0444452d 100644 --- a/process_pool.cpp +++ b/miosix/kernel/process_pool.cpp @@ -13,7 +13,7 @@ ProcessPool::ProcessPool(unsigned int *poolBase, unsigned int poolSize) memset(bitmap,0,numBytes); } -unsigned int *ProcessPool::allocate(int size) +unsigned int *ProcessPool::allocate(unsigned int size) { #ifndef TEST_ALLOC miosix::Lock<miosix::FastMutex> l(mutex); @@ -25,21 +25,21 @@ unsigned int *ProcessPool::allocate(int size) unsigned int offset=0; if(reinterpret_cast<unsigned int>(poolBase) % size) offset=size-(reinterpret_cast<unsigned int>(poolBase) % size); - int startBit=offset/blockSize; - int sizeBit=size/blockSize; + unsigned int startBit=offset/blockSize; + unsigned int sizeBit=size/blockSize; - for(int i=startBit;i<=poolSize/blockSize;i+=sizeBit) + for(unsigned int i=startBit;i<=poolSize/blockSize;i+=sizeBit) { bool notEmpty=false; - for(int j=0;j<sizeBit;j++) + for(unsigned int j=0;j<sizeBit;j++) { - if(testBit(i+j)==0)continue; + if(testBit(i+j)==0) continue; notEmpty=true; break; } if(notEmpty) continue; - for(int j=0;j<sizeBit;j++) setBit(i+j); + for(unsigned int j=0;j<sizeBit;j++) setBit(i+j); unsigned int *result=poolBase+i*blockSize/4; allocatedBlocks[result]=size; return result; @@ -57,7 +57,7 @@ void ProcessPool::deallocate(unsigned int *ptr) unsigned int size =(it->second)/blockSize; unsigned int firstBit=(reinterpret_cast<unsigned int>(ptr)- reinterpret_cast<unsigned int>(poolBase))/blockSize; - for(int i=firstBit;i<firstBit+size;i++) clearBit(i); + for(unsigned int i=firstBit;i<firstBit+size;i++) clearBit(i); allocatedBlocks.erase(it); } diff --git a/process_pool.h b/miosix/kernel/process_pool.h similarity index 93% rename from process_pool.h rename to miosix/kernel/process_pool.h index 8b95af8b6e9b5edb210d927708018e784743189c..e21b97df7d75495bf68b7cfcdaa06c5e5dbdde33 100644 --- a/process_pool.h +++ b/miosix/kernel/process_pool.h @@ -37,7 +37,7 @@ public: * \throws runtime_error in case the requested allocation is invalid, * or bad_alloc if out of memory */ - unsigned int *allocate(int size); + unsigned int *allocate(unsigned int size); /** * Deallocate a memory block. @@ -85,9 +85,9 @@ public: ///This constant specifies the size of the minimum allocatable block, ///in bits. So for example 10 is 1KB. - static const int blockBits=10; + static const unsigned int blockBits=10; ///This constant is the the size of the minimum allocatable block, in bytes. - static const int blockSize=1<<blockBits; + static const unsigned int blockSize=1<<blockBits; private: ProcessPool(const ProcessPool&); @@ -97,7 +97,7 @@ private: * \param bit bit to test, from 0 to poolSize/blockSize * \return true if the bit is set */ - bool testBit(int bit) + bool testBit(unsigned int bit) { return (bitmap[bit/(sizeof(unsigned int)*8)] & 1<<(bit % (sizeof(unsigned int)*8))) ? true : false; @@ -106,7 +106,7 @@ private: /** * \param bit bit to set, from 0 to poolSize/blockSize */ - void setBit(int bit) + void setBit(unsigned int bit) { bitmap[(bit/(sizeof(unsigned int)*8))] |= 1<<(bit % (sizeof(unsigned int)*8)); @@ -115,7 +115,7 @@ private: /** * \param bit bit to clear, from 0 to poolSize/blockSize */ - void clearBit(int bit) + void clearBit(unsigned int bit) { bitmap[bit/(sizeof(unsigned int)*8)] &= ~(1<<(bit % (sizeof(unsigned int)*8)));