CodeViser JTag Debugger: how it knows u-boot's relocated offset in RAM? - u-boot

I am currently using CodeViser Jtag debugger connecting to a FPGA for debugging firmware for an Armv8 processor. From within the CodeViser GUI client (called CVD64 on windows) I can set break points at absolute addresses.
One thing I noticed that, when I set a break point at some functions in u-boot, I use the address as shown in u-boot.map, which reflects the initial loading address of u-boot. In my case, the u-boot text section is initially loaded to 0x20408000.
When the break point I set hits, the actual address the PC stops is not what I specified from GUI, but another address, which is the relocated one (i.e., after u-boot relocation).
For example, I set break point from GUI at 0x20413040, and CVD64 stops at 0x207ae040, the offset is 0x39b000. This offset is exactly the same as u-boot itself printed to serial port:
Relocation Offset is: 0039b000
Relocating to 207a3000, new gd at 2075edf0, sp at 2075ede0
This is nice. I am just wondering how CVD64 knows the relocate offset and automatically place HLT instruction in relocated address?
Thanks!

Related

Cortex M33 unable to get stack pointer and pc from word offset 0/1 with qemu

I tried to bringup cortex m33 with QEMU, and I used board MPS2-AN505, but QEMU always abort with HardFault error, so I checked system registers with GDB and I found that the T bit of ESPR reg is 0 after CPU boot, and the pc/sp is 0 too, but I have already write SP value and PC value into memory word offset 0/1
I also checked VTOR which defines the vector tables and it is 0, so sp /pc should be read out from word offset 0/1
But if I used GDB to load elf files again, the T bit of ESPR is 1 but pc/sp still not be loaded. so the program start from address 0.
I also tried with board type MPS3-AN547 which used corte-m55 with the same software code and vector table, and it works fine. PC / SP can be loaded correctly from word offset 0/1.
the QEMU version that I used is 6.2.0, and I used option -kernel xxx.bin to load my software image.
qemu error
as described above ...
qemu error debug info

Second firmware slot jumps to first slot during FreeRTOS first task run

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

IAP Bootloader could not load RTX application image

I have splitted software into two parts: Bootloader(without RTX), Application image with RTX.
But the bootloader could not load the application image with RTX.
The Flash settings are:
--------------------------------------------------------------------
start address size
IROM 1: 0x08000000 0x2800 - Bootloader (without RTX)
IROM 2: 0x08002800 0xD000 - Application Image (with RTX)
I have test 3 ways:
(1) Use another App without RTX. The bootloader could load the app successfully.
(2) Change the application with RTX project IROM setting. I change the application project IROM start address from 0x08002800 to 0x08000000. And I download the application image into flash from the address 0x08000000. Ihe image could run from 0x08000000 successfully.
(3) The application image IROM start address setting is 0x08002800. After downloading bootloader and app image into flash, I debug the app project in keil step by step. I found that there is a "osTimerthread stack overflow" error. Then the main thread stack is also overflowed. I have tried to increase the stack size, but it doesn't work.
I found that the app starks in the RTX kernel switching. All threads are in the waiting state, and are not running.
Ps, when I am debugging in the keil,test item(2) also have stack overflow errors during kernel initialization. The item(2) works fine till now. So I just put any information needed here.
This is the debugging picture for item (3).
Are you actually changing the linker script to link starting at 0x08002800 when using the bootloader or just loading the application (linked at 0x08000000) at an offset of 0x2800? Double check this (look in the map file) for your linked output to ensure that all your symbols are not linked in the 0x08000000 - 0x08002800 range.
Additionally, make sure you are using the correct entry point and stack pointer. The application's stack pointer should be at 0x08002800, and the reset vector will be at 0x08002804. Your bootloader will need to setup the MSP register with the correct stack pointer before jumping to the application. Here is some example code from ST's USB DFU bootloader:
typedef void (*pFunction)(void);
pFunction JumpToApplication;
uint32_t JumpAddress;
/* Jump to user application */
JumpAddress = *(__IO uint32_t*) (USBD_DFU_APP_DEFAULT_ADD + 4);
JumpToApplication = (pFunction) JumpAddress;
/* Initialize user application's Stack Pointer */
__set_MSP(*(__IO uint32_t*) USBD_DFU_APP_DEFAULT_ADD);
JumpToApplication();
Additionally, depending on how much your bootloader configures before jumping to the application, you may need to 'deconfigure' certain peripherals. As an example, if you setup your clocks in the bootloader before deciding to jump to the application, you may run into problems in your application if it assumes that the clocks are in the default configuration already. Similar things can happen with the NVIC and SysTick if your bootloader is using these before jumping to the application.
Lastly, along the same lines as the previous section, the application may be making assumptions about the state of peripherals being default, but it also may be making assumptions that the peripheral defaults are correct. For example: SCB->VTOR has a default value (I believe it is always 0x00000000), and this points to the vector table. Your bootloader will be linked to have its vector table at that location. You'll need to make sure that when your application is starting up, it updates the VTOR register to point to the actual location of its vector table.
Hopefully one of these sections helps you identify the problem.

ARM start address

Hi I’m newbie to ARM and am using a SAM3S4A ARM processor, with the IAR compiler.
Understanding that the flash code is from 0x00400000 – 0x0043FFFF and that the processor start at address zero (0x00000000), how does the PC jump to 0x00400000 as the VTOR register is zero at default.
From what I could understand from the document, ARM proc goes to 0x0 on reset. The 4K address space at 0x00000000 can be mapped to either ROM or FLASH using GPNVM register. So at reset ARM starts executing code either from ROM or FLASH. (ROM contains some proprietary bootloader and you can have your own OS/Bootloader at Flash). Once control reaches the code you have written to flash, you can setup a new Vector Table and update VTOR so that new exceptions are routed there.

How to correctly use a startup-ipi to start an application processor?

My goal is to let my own kernel start an application cpu. It uses the same mechanism as the linux kernel:
Send asserting and level triggered init-IPI
Wait...
Send deasserting and level triggered init-IPI
Wait...
Send up to two startup-IPIs with vector number (0x40000 >> 12) (the entry code for the application processor lies there)
Currently I'm just interested in making it work with QEMU. Unfortunately, instead of jumping to 0x40000, the application cpu jumps to 0x0 with the cs register set to 0x4000. (I checked with gdb).
The Intel MultiProcessor Specification (B.4.2) explains that the behavior that I noticed is valid if the target processor is halted immediately after RESET or INIT. But shouldn't this also apply to the code of the linux kernel? It sends the startup-IPI after the init-IPI. Or do I misunderstand the specification?
What can I do to have the application processor jump to 0x000VV000 and not to 0x0 with the cs register set to 0xVV00? I really can't see, where linux does something that changes the behavior.
It seems that I really misunderstood the specification: Since the application cpu is started in real mode 0x000VV000 is equivalent to 0xVV00:0x0000. It is not possible to represent the address just in the 16 bit ip register. Therefore a segment offset for the code segment is required.
Additionally, debugging real mode code with gdb is comparable complicated because it does not respect the segment offset. When required to see the disassembled code of the trampoline at the current position, it is necessary to calculate the physical location:
x/20i $eip+0xVV000
This makes gdb print the next 20 instructions at 0xVV00:$eip.

Resources