Reputation: 21
I am working with an ARM chip on IAR. Its linker file describes a RAM section like this:
The stack and RW global variables are stored at the end of the RAM region of physical memory. Having it at the end is important to my SW design albeit not necessarily relevant to this particular question.
My application consumes a rather large file that I want to store outside of the RAM section, like so:
The reason I want to put this "BLOB_FS" outside is because I only use it once at the beginning. That way, I can recycle that memory for other purposes later, which I prefer over permanently reserving a giant heap. For example, let's say the stack and RW data go from 0x0175000-0x017FFFF. I would want to populate the BLOB_FS data by doing something like:
(uint32_t*) blob_fs_base_ptr = (0x0175000 - sizeof(blob_fs));
memcpy(blob_fs_base_ptr, blob_fs, sizeof(blob_fs));
I do not know the size of the blob_fs until runtime.
The problem is the lower address of the RAM section varies depending on whatever global variables you may have so I don't know what exactly the "xxxxx" in 0x017xxxxx-0x017FFFFF is ahead of time. The relevant section of my IAR ICF file looks like this:
define symbol __ICFEDIT_region_RAM_start__ = 0x01000000;
define symbol __ICFEDIT_region_RAM_end__ = 0x017FFFFF; // 8192K
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__];
"RAM": place at end of RAM_region { readwrite,
block CSTACK, block SVC_STACK, block IRQ_STACK, block FIQ_STACK,
block UND_STACK, block ABT_STACK, block HEAP };
Which generates a map file like this:
"RAM": 0x11'21d8
rw-1 0x16e'de28 0xbc <Init block>
.data inited 0x16e'de28 0x9c main.cpp.obj [1]
.data inited 0x16e'dec4 0x1c rom_cmd_handler.cpp.obj [12]
.data inited 0x16e'dee0 0x4 system_cmsis_falcon2.c.obj [8]
.bss zero 0x16e'dee4 0x40 main.cpp.obj [1]
.bss zero 0x16e'df24 0x400 rom_cmd_handler.cpp.obj [12]
.bss zero 0x16e'e324 0x28 source.cpp.obj [11]
.bss zero 0x16e'e34c 0x4 blob_fs.cpp.obj [5]
.bss zero 0x16e'e350 0x4 blob_fs.cpp.obj [5]
.bss zero 0x16e'e354 0x8 rom_spi2c_handler.cpp.obj [12]
.bss zero 0x16e'e35c 0x2a0 spi2c_falcon2.cpp.obj [13]
.bss zero 0x16e'e5fc 0x7c vmem_falcon2.cpp.obj [14]
.bss zero 0x16e'e678 0x80 buffer_manager_common.cpp.obj [6]
.bss zero 0x16e'e6f8 0x24 drv_irq_cortex_m3.c.obj [10]
.bss zero 0x16e'e71c 0xe0 drv_irq_common.c.obj [10]
.bss zero 0x16e'e7fc 0x1 buffer_manager_falcon2.cpp.obj [6]
.bss zero 0x16e'e7fd 0x1 rom_spi2c_handler.cpp.obj [12]
.noinit uninit 0x16e'e800 0x11'0000 main.cpp.obj [1]
.noinit uninit 0x17f'e800 0x800 main.cpp.obj [1]
CSTACK 0x17f'f000 0x1000 <Block>
CSTACK uninit 0x17f'f000 0x1000 <Block tail>
- 0x180'0000 0x11'21d8
This configuration corresponds to the RAM section from 0x017xxxxx-0x017FFFFF.
Is there a way to get the exact value of 0x017xxxxx at runtime?
Upvotes: 0
Views: 4296
Reputation: 21
I got it working by doing pretty much what Blue suggested. I turned my ICF file into (new in bold):
define symbol __ICFEDIT_region_RAM_start__ = 0x01000000;
define symbol __ICFEDIT_region_RAM_end__ = 0x017FFFFF; // 8192K
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__];
"RAM": place at end of RAM_region { **readwrite section .blobfssizeword,** readwrite,
block CSTACK, block SVC_STACK, block IRQ_STACK, block FIQ_STACK,
block UND_STACK, block ABT_STACK, block HEAP };
The new section .blobfssizeword ensures that I know the name of the section that I'm looking for. And by placing it first in the "RAM" memory block (is that the right word?), I make sure that .blobfssizeword occupies the lowest-value address in that group.
Next, I get the size of the blobfs at runtime from the user via a 32-bit integer. So in my main.cpp I make sure to declare that in the .blobfssizeword section:
#define BLOBFS_SIZE_WORD_LENGTH 4 //The blobfs size is stored in a 32-bit value
static uint8_t __attribute__((section(".blobfssizeword"))) blobfs_size_word[BLOBFS_SIZE_WORD_LENGTH] = {0};
#pragma section = ".blobfssizeword"
void calculate_blobfs_starting_address() {
uint32_t blobfs_size = *(reinterpret_cast<uint32_t*>(blobfs_size_word));
memcpy(blobfs_size_word, (uint8_t*)&blobfs_size, sizeof(blobfs_size_word));
//Write to array to make sure compiler doesn't optimize it out. There's probably a better way to do this, but I'm just trying to make it work
size_t blobfs_size_word_start = (size_t)__section_begin(".blobfssizeword");
size_t blobfs_start_addr = blobfs_size_word_start - (size_t)blobfs_size;
return blobfs_start_addr;
}
After doing the above, I ensure the compiler compiles in the .blobfssizeword section, so the map file looks like this (new in bold):
"RAM": 0x1'21d4
**.blobfssizeword 0x15e'de2c 0x4 <Block>
.blobfssizeword-1 0x15e'de2c 0x4 <Init block>
.blobfssizeword inited 0x15e'de2c 0x4 main.cpp.obj [1]**
rw-1 0x15e'de30 0x28 <Init block>
.data inited 0x15e'de30 0x4 main.cpp.obj [1]
.data inited 0x15e'de34 0x20 rom_cmd_handler.cpp.obj [13]
.data inited 0x15e'de54 0x4 system_cmsis_falcon2.c.obj [8]
.bss zero 0x15e'de58 0x40 main.cpp.obj [1]
.bss zero 0x15e'de98 0x4 main.cpp.obj [1]
.bss zero 0x15e'de9c 0xc main.cpp.obj [1]
.bss zero 0x15e'dea8 0x6c main.cpp.obj [1]
.bss zero 0x15e'df14 0x24 main.cpp.obj [1]
.bss zero 0x15e'df38 0x400 rom_cmd_handler.cpp.obj [13]
.bss zero 0x15e'e338 0x10 source.cpp.obj [12]
.bss zero 0x15e'e348 0x4 blob_fs.cpp.obj [5]
.bss zero 0x15e'e34c 0x8 rom_spi2c_handler.cpp.obj [13]
.bss zero 0x15e'e354 0x2a0 spi2c_falcon2.cpp.obj [14]
.bss zero 0x15e'e5f4 0x7c vmem_falcon2.cpp.obj [15]
.bss zero 0x15e'e670 0x8 real_otp.cpp.obj [11]
.bss zero 0x15e'e678 0x80 buffer_manager_common.cpp.obj [6]
.bss zero 0x15e'e6f8 0x24 drv_irq_cortex_m3.c.obj [10]
.bss zero 0x15e'e71c 0xe0 drv_irq_common.c.obj [10]
.bss zero 0x15e'e7fc 0x1 buffer_manager_falcon2.cpp.obj [6]
.bss zero 0x15e'e7fd 0x1 rom_spi2c_handler.cpp.obj [13]
.noinit uninit 0x15e'e800 0x1'0000 main.cpp.obj [1]
.noinit uninit 0x15f'e800 0x800 main.cpp.obj [1]
CSTACK 0x15f'f000 0x1000 <Block>
CSTACK uninit 0x15f'f000 0x1000 <Block tail>
- 0x160'0000 0x1'21d4
Upvotes: 0
Reputation: 887
If you know a upper size limit for your blob_fs and have enough RAM available, you could let the linker reserve space for it by defining a separate block as recommended in the IAR C/C++ Development Guide section RESERVING SPACE IN RAM:
Often, an application must have an empty uninitialized memory area to be used for temporary storage, for example, a heap or a stack. It is easiest to achieve this at link time. You must create a block with a specified size and then place it in a memory.
In the linker configuration file, it can look like this:
define block TempStorage with size = 0x1000, alignment = 4 { }; place in RAM { block TempStorage };
With the special operators __section_begin()
, __section_end()
and __section_size()
you can then get access to the start address and the first address after the block as well as the size of the block.
The IAR manual has the following example:
To retrieve the start of the allocated memory from the application, the source code could look like this:
/* Define a section for temporary storage. */ #pragma section = "TempStorage" char *GetTempStorageStartAddress() { /* Return start address of section TempStorage. */ return __section_begin("TempStorage"); }
If you cannot define an explicit block for you blob_fs, it should also be possible to define a block for all other sections that should be placed at the end of the RAM. I think it should look like this (untested):
define block RAMDATA { readwrite, block CSTACK, block SVC_STACK, block IRQ_STACK,
block FIQ_STACK, block UND_STACK,
block ABT_STACK, block HEAP };
"RAM": place at end of RAM_region { readwrite, block RAMDATA };
Again you should then be able to use __section_being("RAMDATA")
to determine the starting address of the RAM area reserved for variables etc. at link time and use that for address calculations at runtime.
Upvotes: 1