Current layout (RTEMS 4.9 and the rce405 BSP)
The RCE memory is divided into several contiguous regions:
- Exception vectors. Thus region contains small pieces of code
- Core. This is our name for the code and data used by RTEMS plus our support code from the BSP and the repository directories
rce/
andrceapp/core/
. - ISR stack. The stack used by interrupt handlers.
- Init stack. The stack used by the first task created by RTEMS, the Init task.
- RTEMS workspace. This is where RTEMS allocates the storage for run-time objects such as semaphores, API extensions, barriers, task control blocks, and so on. It may also be used for task stack space.
- Heap. RTEMS sees this a just a big heap for dynamic storage allocation. Dynamically linked software modules are allocated space here. So are objects allocated with
malloc()
or the default C++ implementation of thenew
operator. - System log. A region of memory used for three circular buffers; one for console messages, one for tracebacks and one for exception information.
Allocation
The location and size of the regions is determined by several methods. Here's a brief summary.
Region |
Start |
Size |
Allocation method |
---|---|---|---|
Exception vectors |
0x00000000 |
0x2000 |
ld script and BSP |
Core |
0x00002000 |
Variable |
Laid out by ld |
RTEMS workspace |
Just after the core |
Variable |
BSP, RTEMS and |
Interrupt stack |
Just after the workspace |
Variable |
BSP |
Heap |
Just after the interrupt stack |
Everything up to the init stack |
RTEMS + ld script |
Init stack |
Just after the heap |
0x10000 |
BSP |
System log |
0x07f00000 |
0x00100000 |
ld script and BSP |
Exception vectors
The size of this region is fixed by the processor although its location can vary (by setting a special register). Our ld script places it at the default location of zero and our BSP doesn't change the default power-on setting of the register.
Core
This region contains RTEMS itself, startup and libstdc++ code from the compiler, newlib and code from the libraries made under the RCE project in the repository. Our ld script makes the starting location at 0x2000 (just after the exception vectors). Its size depends on the total size of the code and data emitted by the compiler.
RTEMS workspace
The size and location of this region is determined by the BSP together with choices made in the RTEMS configuration; see chapter 23 of the RTEMS C User's Guide. In our builds the configuration is in one of two files: rtems_config_prod.cc
and rtems_config_devel.cc
; the former doesn't configure the RTEMS shell and the latter does.
A lot of the storage for RTEMS-provided service objects such as semaphores is allocated in the workspace, which in RTEMS 4.9 is always separate from the general-purpose heap used by the application code. Our RTEMS configurations specify fixed allocations for for these objects. It's possible to make them adjustable but, for tasks at least, the code that maintains our system log requires a fixed limit. There are also always-fixed limits for the number of device drivers and the number of open files. I believe that directory nodes for the in-memory filesystem are allocated in the workspace as well.
By default RTEMS will allocate task stacks in the workspace. It sets aside the minimum stack space per task times the maximum number of tasks, but you can add an adjustment to this if you know your application will need more stack space.
Normally RTEMS will calculate the size of the workspace based on the various allocations made in the configuration, but in the configuration you can override that by giving the total workspace size. Normally RTEMS will locate the workspace in high memory but your configuration can specify the starting address provided you know it at compile time. All the information in the configuration file gets compiled into a global structure.
Our BSP puts the workspace right after the core. In bspstart.c
:
#define INIT_STACK_SIZE 0x10000 void bsp_start( void ) { extern uint8_t __bsp_ram_start[]; extern uint8_t __bsp_ram_end[]; uint32_t addr; BSP_output_char = rce_outchar_to_memory; addr = CPU_UP_ALIGN((uint32_t)__bsp_ram_start); /* Assign different chunks of memory : */ /* work-space area */ Configuration.work_space_start = (char*)addr; addr += Configuration.work_space_size; /* Interrupt/exception stack; at the same time * initialize exceptions. */ ppc_exc_initialize( PPC_INTERRUPT_DISABLE_MASK_DEFAULT, addr, rtems_configuration_get_interrupt_stack_size()); addr += rtems_configuration_get_interrupt_stack_size(); /* reserve init stack */ bsp_heap_end = (uint32_t)__bsp_ram_end - INIT_STACK_SIZE; /* rest for the heap */ bsp_heap_start = addr; }
where I've cut out the parts not relevant to memory layout. __bsp_ram_start
is a symbol set by our ld script to be the first unused address after the core; __bsp_ram_end
is set by the script to 0x07f00000 where the system log area begins.
Interrupt stack
As you can see from the code for function bsp_start()
in the section on the RTEMS workspace, the interrupt stack is allocated right after the workspace. The size is set in the RTEMS configuration file; if you don't set the macro BSP_INTERRUPT_STACK_SIZE
you'll get the value of CONFIGURE_MINIMUM_TASK_STACK_SIZE
. If you didn't set a value for that you'll get the value of CPU_STACK_MINIMUM_SIZE
which is 8K for PowerPC.
Heap
As you can see from the code for function bsp_start()
in the section on the RTEMS workspace, the heap is allocated right after the interrupt stack and runs right up to the system log area.
Init stack
This is the stack allocated for the first task, the Init task, created and run by RTEMS. It is allocated by our bsp_start()
function just underneath the system log area and given a fixed sized of 0x10000 (64K). Other tasks will have their stacks allocated in the workspace since we don't specify a stack allocation function in the RTEMS configuration.
System log area
Our ld script sets __bsp_ram_end
to 1 MB below the true end of RAM (__phy_ram_end
== 128 MB). The BSP leaves that upper 1 MB free; it gets used by the RCE debugging package in /rce/debug/src/Manager.cc
. The first 256 KB are used as a circular buffer for printout that would have come out on the operator's console if there was one. The second 256 KB are unused. The last 512 KB are used for a circular buffer of exception information (exception in the C++ sense).