I have an embedded system that I am designing using a GNU toolchain. One of the requirements is that it needs to calculate the checksum of the executable code (ROM) at runtime, and compare it to a known value. Depending on weather the calculated value is equal to the known value it will throw an error or not. I need to place the known value in flash memory( where my executable code is stored) in a way that won't change the executable code. AKA I cannot write the value to the flash in my executable code.
I know there are tools that can modify output files to place a checksum in a known address, but for IT reasons external tools are not an option. I decided to use the SHORT() command in the linker and just edit the linker to place the known checksum in a known address at write time. It is not working, and I do not know why.
Relevent Portions of the Linker Script I have:
MEMORY {
m_interrupts (RX) : ORIGIN = 0x00000000, LENGTH = 0x00000400
m_flash_config (RX) : ORIGIN = 0x00000400, LENGTH = 0x00000010
m_interrupts_ram (RW) : ORIGIN = 0x1FFF0000, LENGTH = 0x00000400
m_text (RX) : ORIGIN = 0x00000410, LENGTH = 0x000FFBE0
m_data (RX) : ORIGIN = 0x1FFF0400, LENGTH = 0x0000FC00
m_data_2 (RW) : ORIGIN = 0x20000000, LENGTH = 0x00030000
}
SECTIONS
{
.text :
{
. = ALIGN(4);
*(.fill)
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
} > m_text
.... More similar sections
....down at the bottom right before stack/heap definition
__ChecksumStart = 0xFFFE0;
.checksum : AT(__ChecksumStart)
{
. = ALIGN (0x4);
SHORT(0xABCD)
} > m_text
__ChecksumSize = SIZEOF(.checksum);
.heap :
{
. = ALIGN(8);
__end__ = .;
PROVIDE(end = .);
__HeapBase = .;
. += HEAP_SIZE;
__HeapLimit = .;
} > m_data_2
.stack :
{
. = ALIGN(8);
. += STACK_SIZE;
} > m_data_2
__StackTop = ORIGIN(m_data_2) + LENGTH(m_data_2);
__StackLimit = __StackTop - STACK_SIZE;
PROVIDE(__stack = __StackTop);
.ARM.attributes 0 : { *(.ARM.attributes) }
} //end of SECTIONS block here
I should be able to look at location 0xFFFE0 in my executable code and see 0xABCD. I do not. I see 0xFFFFFFFF the default value. What do I need to change to make this work? I have looked at this tutorial to get this far
Related
I want to write a library to a specific address in the flash, I have a entire sector for this, than I will calculate crc16 value of that library, I tried to add a new section in linker file but it couldn't work. i am using Atollic Truestudio as IDE and stm32f4 as mcu.
MEMORY
{
FLASH(rx) = : ORIGIN = 0x08020000, LENGTH = 2048K
IP_CODE(x) = : ORIGIN = 0x08060000, LENGTH = 256K
MY_FUNCTION(rxw) = : ORIGIN = 0x080C0000, LENGTH = 128K//section for the library
RAM(rxw) = : ORIGIN = 0x20000000, LENGTH = 192K
MEMORY_B1(rx) = : ORIGIN = 0x60000000, LENGTH = 0K
CCMRAM(rx) = : ORIGIN = 0x10000000, LENGTH = 64K
}
SECTIONS
{
.isr_vector :
{
.=ALIGN(4);
KEEP(*(.isr_vector))
.ALIGN(4);
} >FLASH
.text:
{
.ALIGN(4);
*(.text)
*(.text*)
*(.glue_7)
*(.glue_7t)
*(.eh_frame)
KEEP(*(.init))
KEEP(*(.fini))
.=ALIGN(4);
_etext=.;
} >FLASH
.mysection :
{
.= ALIGN(4);
KEEP(*(.mysection*))
} >MY_FUNCTION
.
.
. so on..
.
.
}
I have a linker script for an embedded system that's doing some relocations (code that is loaded onto the flash of the device, but copied to RAM on boot for execution). It's using the AT feature of the linker, which seems designed to do this.
The problem is that the size of the relocation section is currently only charged to the ram memory region, when in practice it should be charged to both the rom and ram regions (it occupies the former when the device is at rest and the latter when it's active). Currently, if the data alone fits in rom but the data + relocation exceeds rom, you won't get any errors or warnings.
How do I get the .relocate section to charge its size to both the rom and ram memory regions?
Minimalized linker script:
MEMORY
{
rom (rx) : ORIGIN = ROM_ORIGIN, LENGTH = ROM_LENGTH
ram (rwx) : ORIGIN = RAM_ORIGIN, LENGTH = RAM_LENGTH
}
__stack_size__ = DEFINED(__stack_size__) ? __stack_size__ : 0x1000;
SECTIONS
{
.text :
{
. = ALIGN(4);
_stext = .; /* First of standard s,e (start/end) pair */
KEEP(*(.vectors .vectors.*))
KEEP(*(.irqs))
*(.text .text.* .gnu.linkonce.t.*)
*(.rodata .rodata* .gnu.linkonce.r.*)
} > rom
/* Mark the end of static elements */
. = ALIGN(4);
_etext = .;
/* This is program data that is exepected to live in SRAM, but is
* initialized with a value. This data is physically placed into flash and
* is copied into SRAM at boot. The symbols here will be defined with
* addresses in SRAM.
*
* This is the section that needs to be charged to BOTH rom and ram */
.relocate : AT (_etext)
{
. = ALIGN(4);
_srelocate = .;
*(.ramfunc .ramfunc.*);
*(.data .data.*);
. = ALIGN(4);
_erelocate = .;
} > ram
.sram (NOLOAD) :
{
. = ALIGN(8);
_sstack = .;
. = . + __stack_size__;
. = ALIGN(8);
_estack = .;
/* BSS section. Memory that is expected to be initialized to zero. */
. = ALIGN(4);
_szero = .;
*(.bss .bss.*)
*(COMMON)
. = ALIGN(4);
_ezero = .;
} > ram
}
Or here is the complete linker script file.
We managed to solve this. The solution is to change how the location of the relocate section is specified, specifically, this is wrong:
# Bad:
.relocate : AT (_etext)
{
...
} > ram
Rather, the AT directive should go at the end, like this:
# Correct
.relocate :
{
...
} > ram AT > rom
This will cause the linker to charge the size of .relocate to both ram and rom, while placing the section "physically" in rom.
(Final applied patch to the full linker script linked in the question)
I am currently trying to reserve a sector of the flash memory in the linker file, to save some data to it (using the driverlib API). I first flash the script writing to the specific memory addresses, then I run my application which reads the saved data.
Unfortunately whenever I flash, the data is lost. Therefore I am trying to change the linker file and reserve some space but I am not sure if I am doing it correctly. I will appreciate any help or hints.
MEMORY
{
/* Flash Size 128 KB minus the CCA area below (88 bytes) */
/* OLD: FLASH (RX) : ORIGIN = 0x00000000, LENGTH = 0x0001FFA8 */
FLASH (RX) : ORIGIN = 0x00000000, LENGTH = 0x0001FF88
/*
* Custom reserved memory space with size of 32 bytes
*/
CNVM (RX) : ORIGIN = 0x0001FF88, LENGTH = 32
/*
* Customer Configuration Area and Bootloader Backdoor configuration
* in flash, up to 88 bytes
*/
FLASH_CCFG (RX) : ORIGIN = 0x0001FFA8, LENGTH = 88
/* RAM Size 20KB */
SRAM (RWX) : ORIGIN = 0x20000000, LENGTH = 0x00005000
/* Application can use GPRAM region as RAM if cache is disabled in CCFG */
GPRAM (RWX) : ORIGIN = 0x11000000, LENGTH = 0x00002000
}
/*. Highest address of the stack. Used in startup file .*/
_estack = ORIGIN(SRAM) + LENGTH(SRAM); /* End of SRAM */
/*. Generate a link error if heap and stack don’t fit into RAM .*/
_Min_Heap_Size = 0;
_Min_Stack_Size = 0x100;
SECTIONS
{
.text :
{
_text = .;
KEEP(*(.vectors))
*(.text*)
*(.rodata*)
_etext = .;
} > FLASH = 0
.text:
{
*(.rodata*)
} > CNVM
.data :
{
_data = .;
*(vtable)
*(.data*)
_edata = .;
} > SRAM AT > FLASH
.ARM.exidx :
{
*(.ARM.exidx*)
} > FLASH
.bss :
{
_bss = .;
*(.bss*)
*(COMMON)
_ebss = .;
} > SRAM
.ccfg :
{
KEEP(*(.ccfg))
} > FLASH_CCFG
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(4);
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(4);
} > SRAM
.gpram :
{
} > GPRAM
}
Using the linker approach didn't provide the desired result in my case. What I ended up doing instead is editing the generated binary file from my code before flashing the sensortag.
Using the hexdump command on linux as follows hexdump generated_binary_file.bin one can notice that each line includes the start memory address (for a certain range of addresses) followed by the data written to this range.
And so using a small python script one can change the values in a certain line and generate its own modified binary file that will be later flashed to the sensortag. The memory address content can be read with a certain function that you include in your initial code (before bin generation & editing) such memcpy() for example.
First of all, I hope I'm not asking something that has already been asked before. I've searched as much as I can but I haven't found an answer to my specific problem or something useful.
I'm working on a FRDM-KL82Z board which runs a Cortex M0+ core. I'm using MCUXpresso IDE v10.0.2 and a Segger J-Link programmer, although I think this is not relevant for this question.
This project will need a custom bootloader and app coded by different developers, each block with its own flash memory space: 8K for the bootloader and 120K for the app (this may change in the future but it's no big deal at the moment).
Once the bootloader is completed, it will manage the jump to App space and the app will change de Vector Table Offset Register (VTOR) so that the Interrupt Vector Table changes form the Boot IVT to the App IVT. This has already been tested successfully.
My aim is to set up the linker script file so that the app developers can build and debug their project on the board before the bootloader is completed, as they will be developed at the same time. The reason for this is that they can work with the App space as it will be in the final version.
I think the Reset vector and the Config bits must be at their default position because the hardware will go to the same position every time it needs to read them.
My first idea consist in disabling the automatic linker script generation and modifying the MyProject_Debug.ld file.
What the script automatically generates:
INCLUDE "LEDTest_Debug_library.ld"
INCLUDE "LEDTest_Debug_memory.ld"
ENTRY(ResetISR)
SECTIONS
{
/* MAIN TEXT SECTION */
.text : ALIGN(4)
{
FILL(0xff)
__vectors_start__ = ABSOLUTE(.) ;
KEEP(*(.isr_vector))
/* Global Section Table */
. = ALIGN(4) ;
__section_table_start = .;
__data_section_table = .;
LONG(LOADADDR(.data));
LONG( ADDR(.data));
LONG( SIZEOF(.data));
LONG(LOADADDR(.data_RAM2));
LONG( ADDR(.data_RAM2));
LONG( SIZEOF(.data_RAM2));
__data_section_table_end = .;
__bss_section_table = .;
LONG( ADDR(.bss));
LONG( SIZEOF(.bss));
LONG( ADDR(.bss_RAM2));
LONG( SIZEOF(.bss_RAM2));
__bss_section_table_end = .;
__section_table_end = . ;
/* End of Global Section Table */
*(.after_vectors*)
/* Kinetis Flash Configuration data */
. = 0x400 ;
PROVIDE(__FLASH_CONFIG_START__ = .) ;
KEEP(*(.FlashConfig))
PROVIDE(__FLASH_CONFIG_END__ = .) ;
ASSERT(!(__FLASH_CONFIG_START__ == __FLASH_CONFIG_END__), "Linker Flash Config Support Enabled, but no .FlashConfig section provided within application");
/* End of Kinetis Flash Configuration data */
} >PROGRAM_FLASH
.text : ALIGN(4)
{
*(.text*)
*(.rodata .rodata.* .constdata .constdata.*)
. = ALIGN(4);
} > PROGRAM_FLASH
/*
* for exception handling/unwind - some Newlib functions (in common
* with C++ and STDC++) use this.
*/
.ARM.extab : ALIGN(4)
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > PROGRAM_FLASH
__exidx_start = .;
.ARM.exidx : ALIGN(4)
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > PROGRAM_FLASH
__exidx_end = .;
_etext = .;
/* USB_RAM */
.m_usb_data (NOLOAD) :
{
*(m_usb_bdt)
*(m_usb_global)
} > USB_RAM
/* possible MTB section for USB_RAM */
.mtb_buffer_RAM2 (NOLOAD) :
{
KEEP(*(.mtb.$RAM2*))
KEEP(*(.mtb.$USB_RAM*))
} > USB_RAM
/* DATA section for USB_RAM */
.data_RAM2 : ALIGN(4)
{
FILL(0xff)
PROVIDE(__start_data_RAM2 = .) ;
*(.ramfunc.$RAM2)
*(.ramfunc.$USB_RAM)
*(.data.$RAM2*)
*(.data.$USB_RAM*)
. = ALIGN(4) ;
PROVIDE(__end_data_RAM2 = .) ;
} > USB_RAM AT>PROGRAM_FLASH
/* MAIN DATA SECTION */
/* Default MTB section */
.mtb_buffer_default (NOLOAD) :
{
KEEP(*(.mtb*))
} > SRAM
.uninit_RESERVED : ALIGN(4)
{
KEEP(*(.bss.$RESERVED*))
. = ALIGN(4) ;
_end_uninit_RESERVED = .;
} > SRAM
/* Main DATA section (SRAM) */
.data : ALIGN(4)
{
FILL(0xff)
_data = . ;
*(vtable)
*(.ramfunc*)
*(.data*)
. = ALIGN(4) ;
_edata = . ;
} > SRAM AT>PROGRAM_FLASH
/* BSS section for USB_RAM */
.bss_RAM2 : ALIGN(4)
{
PROVIDE(__start_bss_RAM2 = .) ;
*(.bss.$RAM2*)
*(.bss.$USB_RAM*)
. = ALIGN (. != 0 ? 4 : 1) ; /* avoid empty segment */
PROVIDE(__end_bss_RAM2 = .) ;
} > USB_RAM
/* MAIN BSS SECTION */
.bss : ALIGN(4)
{
_bss = .;
*(.bss*)
*(COMMON)
. = ALIGN(4) ;
_ebss = .;
PROVIDE(end = .);
} > SRAM
/* NOINIT section for USB_RAM */
.noinit_RAM2 (NOLOAD) : ALIGN(4)
{
*(.noinit.$RAM2*)
*(.noinit.$USB_RAM*)
. = ALIGN(4) ;
} > USB_RAM
/* DEFAULT NOINIT SECTION */
.noinit (NOLOAD): ALIGN(4)
{
_noinit = .;
*(.noinit*)
. = ALIGN(4) ;
_end_noinit = .;
} > SRAM
.heap : ALIGN(4)
{
_pvHeapStart = .;
. += 0x1000;
. = ALIGN(4);
_pvHeapLimit = .;
} > SRAM
.heap2stackfill :
{
. += 0x1000;
} > SRAM
.stack ORIGIN(SRAM) + LENGTH(SRAM) - 0x1000 - 0: ALIGN(4)
{
_vStackBase = .;
. = ALIGN(4);
_vStackTop = . + 0x1000;
} > SRAM
}
I've tried to find information in this guide about de GNU linker but my ideas haven't worked so far.
What I've tried:
Setting the location counter to a different value after the Config Words and copying the ISR_vector code snipped before the text section:
...
/* End of Kinetis Flash Configuration data */
} >PROGRAM_FLASH
.text : ALIGN(4)
{
/* MODIFIED CODE */
. = 0x2000; /* First position of App code */
FILL(0xff)
__vectors_start__ = ABSOLUTE(.) ;
KEEP(*(.isr_vector))
/* END OF MODIFIED CODE */
*(.text*)
*(.rodata .rodata.* .constdata .constdata.*)
. = ALIGN(4);
} > PROGRAM_FLASH
...
When I do this and I open the .hex file, the space between the Config Words (0x400) and the start of the App space (0x2000) is effectively empty (full of 0xFF) but the code after 0x2000 is nothing like the IVT table.
If I move location counter to 0x2000 before the IVT code lines it effectively moves the IVT adresses to the 0x2000 position. To do this, I move the Config Words part before the IVT part because de location counter can't move backwards.
I've tried creating a Bootloader section in the memory map, with the correct starting and length positions, and copying every line that by default gets placeD in the PROGRAM_FLASH section into a new one that goes to BOOTLOADER (the same code with ">BOOTLOADER" at the end). In this case de IVT only appears in the Boot space.
Is it possible that the linker script places de IVT only in the first place it is indicated and then ignores every other call? What am I doing wrong? Should I try another way to achieve this?
Thank you very much, I know it's quite a long!
I don't think it's possible to make a copy of the vector table using only linker shenanigans. The linker script will not let you match the same symbol multiple times so that you can output it twice.
From the binutils 2.29 manual:
If a file name matches more than one wildcard pattern, or if a file name appears explicitly and is also matched by a wildcard pattern, the linker will use the first match in the linker script.
I tested it without using any wildcard patterns at all with similar results, so I don't think the linker will ever let you output the same symbol twice.
I also tried using objcopy to create a renamed copy of the vector table that could referenced from the linker script but that table ended up as all zeroes and the whole approach was rather convoluted, so I don't think that's worth pursuing.
If you want to keep the application code as similar as possible between now and when the bootloader is completed, I would suggest a different approach:
Make use of the __vectors_start__ symbol provided by the existing linker script so that your code always knows where the vector table is placed, even if you make changes to the linker script.
void relocate_vector_table(void) {
extern unsigned __vectors_start__;
SCB->VTOR = (unsigned)&__vectors_start__;
}
This will allow the same code to work with your current configuration (no bootloader, ROM starting at 0x0) and your eventual bootloader configuration (ROM starting at 0x2000).
My experience with M4 application and bootloader shows that it is enough to set the Flash start at some offset address, and then in the application to initialize VTOR to this address.
From linker script:
#
/* Specify the memory areas */
MEMORY
{
CLASSBRAM (rw) : ORIGIN = 0x20000000, LENGTH = 0x80
/*RAM length = 192K - CLASSBRAM-length */
RAM (xrw) : ORIGIN = 0x20000080, LENGTH = 0x2FF80
CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K
/* FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K */
FLASH (rx) : ORIGIN = 0x08010000, LENGTH = 448K /*in case of 64K for Bootloader*/
}
/* Define output sections */
SECTIONS
{
/* The startup code goes first into FLASH */
.isr_vector :
{
. = ALIGN(4);
PROVIDE( _Rom_Start = . );
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >FLASH
.....
#
code:
extern const uint32_t _Rom_Start;
....
#define ROM_START ((uint32_t *)&_Rom_Start)
...
SCB->VTOR = (uint32_t)ROM_START;
My MCU projects typically have Makefile targets that will actually flash the chip (with building as a dependency of course), so what I did for this was make a special target that flashes the main firmware "solo".
My openocd-driven programmers can flash flat binaries and not just hex files, so I was able to do this by using dd to copy just the vector table off the start of the main firmware binary into its own file. I then write this to the start of flash, and the main firmware to its usual location in separate operations. The chip boots, gets the reset and stack addresses out of the copied vector table, starts the main firmware, and that then repoints the vector table address to its own copy at the higher address.
If your programmer doesn't support flat binaries you can use objdump or some other tool to turn a flat binary back into a hex file, or likely to change the base address of a hex file / fragment.
I am using an STM32F103ZG with the STM32F10x_StdPeriph Library. I started the development of the project with Keil ARM-MDK but now moved over to GCC.
The switch over has gone pretty smooth until now. I use the last page of FLASH as a configuration page to store product specific parameters. This is page is obviously situated in bank 2. In certain instances these configuration parameters need to be updated at runtime, but now that I have moved over to GCC, the second memory bank goes into a busy state as soon as I try to write to it and then it stays busy until I cycle the power. Erase works fine, but writing fails.
I do unlock all the FLASH and make sure that all the clocks are initialized to access the FLASH. Some other posts on several forums suggest a problem with my linker file, but all the examples I use make no difference.
If anyone can tell me what I am doing wrong I will be very grateful.
Thanks,
H
_Min_Heap_Size = 0x800; /* required amount of heap */
_Min_Stack_Size = 0x800; /* required amount of stack */
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 0x10000
FLASH_CFG (rx) : ORIGIN = 0x080FF800, LENGTH = 0x80
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x18000
}
SECTIONS
{
.text :
{
_stext = .; /* Provide the name for the start of this section */
CREATE_OBJECT_SYMBOLS
KEEP(*(.vectors))
*(.text)
*(.text.*)
. = ALIGN(4); /* Align the start of the rodata part */
*(.rodata)
*(.rodata.*)
*(.glue_7)
*(.glue_7t)
. = ALIGN(4); /* Align the end of the section */
} > FLASH
_etext = .; /* Provide the name for the end of this section */
.data : AT (_etext)
{
. = ALIGN(4); /* Align the start of the section */
_sdata = .; /* Provide the name for the start of this section */
*(.data)
*(.data.*)
. = ALIGN(4); /* Align the start of the fastrun part */
*(.fastrun)
*(.fastrun.*)
. = ALIGN(4); /* Align the end of the section */
} > RAM
_edata = .; /* Provide the name for the end of this section */
.bss :
{
. = ALIGN(4); /* Align the start of the section */
_sbss = .; /* Provide the name for the start of this section */
*(.bss)
*(.bss.*)
. = ALIGN(4); /* Align the end of the section */
} > RAM
_ebss = .; /* Provide the name for the end of this section */
._user_heap_stack :
{
. = ALIGN(4);
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(4);
} >RAM
_estack = ORIGIN(RAM) + LENGTH(RAM);
.static_cfg :
{
. = ALIGN(4);
*(.static_cfg)
*(.static_cfg.*)
. = ALIGN(4);
} > FLASH_CFG
_estatic_cfg = .;
_end = .;
PROVIDE (end = .);
}
Well I managed to solve my problem.
When I moved over to GCC, I obviously had to recompile the STM32F10x Peripheral library and I lef the optimization setting to -O3. This was not allowed initially as the __STREXH and __STREXL core functions needed to be changed in order to build for the selected optimization. I found the following solution on a forum:
change __ASM volatile ("strexh %0, %2, [%1]" : "=r" (result) : "r" (addr), "r" (value) ); to
__ASM volatile ("strexh %0, %2, [%1]" : "=&r" (result) : "r" (addr), "r" (value) );
Several comments related to this solution specified that this solution does not cause any errors.
When I use the original code and set the optimization to -O0, everything works just fine. The access to the on-chip FLASH interface is 16bit and therefore if you screw up the above mentioned functions, all 16bit write accesses will be screwed up.
As I don't need optimization at this stage, I will stay without it.
Any suggestions about how to update these functions correctly for use with optimization will be appreciated.
Enjoy,
H