The Vector Table offset register on a Cortex M7 allows to relocate the Vector Table.
I am wondering how the Vector Table is managed when it is relocated and a soft reset occurs.
The ARM programming manual mentions that the value of VTOR after reset is "unknown".
What reset handler is used after a soft reset: the "original" one from the vector table in Flash ? Or the "relocated" one set through VTOR ?
Same question for the Stack Pointer. The Programming manual states that "On reset, the processor loads the MSP with the value from address 0x00000000". Does that mean that the Stack Pointer in a relocated Vector Table is never used ?
Does that mean that the Stack Pointer in a relocated Vector Table is
never used ?
It is not used by the hardware. It is used by bootloader when launching the application.
What reset handler is used after a soft reset: the "original" one from
the vector table in Flash
The one selected by the boot pins & boot option bytes.
The ARM programming manual mentions that the value of VTOR after reset
is "unknown".
I do not think so, my programming manual shows:
Which is quite well defined :)
I am wondering how the Vector Table is managed when it is relocated
and a soft reset occurs.
Same as during the hardware reset.
Related
uC/OS-III says:
When calling OSTaskCreate(), uC/OS-III initializes the top of the
task's stack with a copy of the CPU register in the same stacking
order as if they were all saved at the beginning of
an ISR.
Here is the arm Complete ARM register set.
FYI: I'm using cortex-a8 which is based on v7 architecture, but I believe that v7 core's register layout is the same as following image
Here is the debug info before executing OSTaskCreate statement:
Here is the debug info after executing OSTaskCreate statement:
It's obvious that these values the stack saves is totally different from core register.
How could it be?
This is probably the reference you need, context switching, indicating that SR/PC are saved first, then the other registers r0-r13. For a definative answer, you can refer to the source in os_cpu_a.asm.
I've created an application which has 2 firmware slots in its memory mapping. It works pretty fine and both slots are executed correctly based on a 32-bit sequencer number stored in FLASH.
The problem appears when I'm trying to use FreeRTOS. By default, firmware is compiled for the first slot... and there's no any problem in running this slot. However when the device starts firmware saved in the second slot, when RTOS starts its first task in prvPortStartFirstTask, then jumps to vPortSVCHandler it switches to the task in the first slot.
What am I doing wrong? I thought function addresses are relative after compilation, so there should be no difficulties running this application with 2 firmware slots.
EDIT
My flow during switching from bootloader to main application is as follows:
1. Check which firmware slot should be used.
2. Disable IRQs.
2. Copy vector table to RAM. That part of RAM is the same for both slots. During copying process I'm changing offset for each address, so they will be compatible with particular firmware slot. By default addresses don't have offset, it's removed in post-compiling stage.
3. Set stack pointer, according to the first word in vector table in RAM. That addresses is not changed while copying vector table to RAM.
4. Set SCB->VTOR.
5. Execute Data Sync Barrier DSB().
6. Jump to the Reset Handler from vector table copied to RAM.
EDIT 2
When I compile application with changed FLASH memory address range to the secondary slot, it works properly.
Is it possible compile code such that application will be PC independent, at least it will work in that case?
EDIT 3
# Generate position independent code.
-fPIC
# Access bss via the GOT.
-mno-pic-data-is-text-relative
# GOT is not PC-relative; store GOT location in a register.
-msingle-pic-base
# Store GOT location in r9.
-mpic-register=r9
However, now this slot stopped working.
I think my problem is similar to that one.
Generally, firmwares aren't built position independent, so I wouldn't trust that all "function addresses are relative after compilation". You compile firmware for a specific start location (either the first or the second firmware slot).
As for your main question, have you done anything to switch the interrupt handlers / interrupt vector from one firmware slot to the other? Or are you jumping to the first firmware's interrupt handlers when you call the SVC handler?
How to change the interrupt vector varies between architectures. For an stm32f429, you could perhaps look here
What are the appropriate steps to write add a custom bootloader for stm32l0 in IAR? The following questions are not clear:
Do I make a new IAR Project?
If yes, do I write the bootloader like a normal project and just change my original .icf file so there is a small ROM and an small RAM region for the bootloader?
if no, what things do I have to configure in the IAR proejct apart from icf file and code?
what other things do I need to think of?
I'm having trouble starting into this.
So the icf would be for the main project:
__region_ROM_start__ = 0x08000000;
__region_ROM_end__ = 0x08008FFF;
So the icf would be for the bootloader project:
__region_Bootloader_ROM_start__ = 0x08009000;
__region_Bootloader_ROM_end__ = 0x08009FFF;
and the same thing for about 0xFF of RAM?
You do not need to restrict the RAM - you can use all of it because when you switch to the application a new run-time environment will be established and the RAM will be reused.
The flash you reserve for the bootloader must be a whole number of flash pages starting from the reset address The STM32L0 has very small flash pages so there should be minimal waste, but you don't want to have to change it if your bootloader grows, because then you will have to rebuild your application code for the new start address and old application images will no longer be loadable. So consider giving yourself a little headroom.
The bootloader can be built just like any other STM32L0xx project; the application code ROM configuration must start from an address above the bootloader. So for example say you have a 1Kbyte bootloader:
Boot ROM Start: 0x0800 0000
Boot ROM End: 0x0800 03FF
Application Start: 0x0800 0400
Application End: Part size dependent.
The bootloader itself must have a means of determining that an update is available, if an update is available it must then read the application data and write it to the application flash memory, it must then disable any interrupts that may have been enabled, it may also be necessary to deinitialise any peripherals used (if they remain active when the switch to the application is made it may cause problems), then the switch to the application code is made.
It is possible if the bootloader and application both run from the same clock configuration to minimise the configuration in the application and rely on the bootloader. This is a small space saving, but less flexible. If for example you make the bootloader run using the internal RC oscillator it will be portable across multiple hardware designs that may have differing application speed and clocking requirements and different external oscillator frequencies
The switch to the application is pretty simple on Cortex-M, it simply requires the vector table to be switched to the application's vector table, then the program-counter to be loaded - the latter requires a little assembly code. The following is for Cortex-M3, it may need some adaptation for M0+ but possibly not:
Given the following in-line assembly function:
__asm void boot_jump( uint32_t address )
{
LDR SP, [R0] ;Load new stack pointer address
LDR PC, [R0, #4] ;Load new program counter address
}
The bootloader switched to the application image thus:
// Switch off core clock before switching vector table
SysTick->CTRL = 0 ;
// Switch off any other enabled interrupts too
...
// Switch vector table
SCB->VTOR = APPLICATION_START_ADDR ;
//Jump to start address
boot_jump( APPLICATION_START_ADDR ) ;
Where APPLICATION_START_ADDR is the base address of the application area; this address is the start of the application's vector table, which starts with the initial stack pointer and reset vector, the boot_jump() function loads these into the SP and PC registers to start the application as if it had been started at reset. The application's reset vector contains the application's execution start address.
Your needs may vary, but in my experience a serial bootloader (using UART) using XMODEM and decoding an image in Intel Hex format takes about 4Kb of Flash. On an STM32L0 you may want to use something simpler - 1Kb is probably feasible if you simply stream raw binary the data and use hardware flow control (you need to control data flow because erasing and programming the flash takes time and also stops the CPU from running because you cannot on STM32 write flash memory while simultaneously fetching instructions from it).
See also: How to jump between programs in Stellaris
Currently, I'm working on a beaglebone black and I'm trying to implement interrupts.
To launch my program, I'm using U-boot, and I load my binary to the 0x80000000 address.
But, even if I've defined my Interrupt Vector table at the beginning of the RAM (adress 0x80000000), when an interruption occurs, like a "data abort", the interruption isn't caught by my interrupt table, but by the U-boot table. So, for example, I can't call my "data_abort" function when this interruption occurs...
Do you know a way to solve this ? For example to move the address of the Vector table or to rewrite this table ?
I know that arm reset vectors can be low(0x00000000) or high(0xffff0000).
But some SoC's codes in linux kernel saying the reset vectors can be changed.
For example, in mach-imx
static int __cpuinit imx_boot_secondary(unsigned int cpu, struct task_struct *idle)
{
imx_set_cpu_jump(cpu, v7_secondary_startup);
imx_enable_cpu(cpu, true);
return 0;
}
void imx_set_cpu_jump(int cpu, void *jump_addr)
{
cpu = cpu_logical_map(cpu);
writel_relaxed(virt_to_phys(jump_addr),
src_base + SRC_GPR1 + cpu * 8);
}
They say that secondary cpu can jump where you want by jump_addr.
Could you tell me how it works?
On ARMv7 cores implementing the security extensions for TrustZone - which as far as I'm aware is all of them - the "low vectors" address (when SCTLR.V == 0) is not hard-coded to 0, but instead set with the VBAR system register. VBAR is banked between secure and non-secure states, so that their vector tables can each be placed at any 32-byte aligned virtual address without interfering with each other, even with the MMU off in both states.
Note that whilst that's the question you asked, the code here isn't actually that at all. This is just stashing an entry point address in a non-volatile register in the reset controller (a common alternative is using a variable in some shared memory where the bootloader loaded itself to); the secondary CPU will still come out of reset into the default ROM vector and execute a whole bunch of self-initialisation code - code which will, coincidentally, involve setting the non-secure VBAR if the CPU is going to switch into non-secure state. That startup code will eventually end with reading this entry point address from wherever it was stashed and simply jumping to it.