Setting up Interrupt Vector Table, ARMv6 - arm

I'm trying to use usermode and SVC in my ARMv6 bare metal application, but for this I need to set up the SVC entry of the ARMv6 interrupt vector table to branch to my interrupt handler. But, I can't find a good example on how to do this (ie: what memory address exactly I need to set, and to what). I have done similar things in the past, but always with a more comprehensive bootloader (RedBoot) that set up some of this for me. Any help would be appreciated.
I am testing my application using:
qemu-system-arm -M versatilepb -cpu arm1176

Are you talking about the SWI interrupt? Or one of the others (FIQ, IRQ). In either case I think I know what the problem is. Qemu is for running linux, your binary is not loaded at address 0x00000 so your entry points are not used by qemu for handling exceptions.
I have an example that uses qemu and implements a solution. Go to the qemu directory of http://github.com/dwelch67/yagbat. The qemu example is not really related to the gba thing in the yagbat repo, the gba is a 32 bit ARM thing so it was easy to borrow code from so I stuck it there.
The example was specifically written for your question as I tried to figure out how to use qemu in this manner. It appears that the address 0x00000000 space is simulated as ram, so you can re-write the qemu exception table and have the exceptions call code in the 0x10000 address space that your binary loads.
A quick and dirty solution is to make the entry point of the binary (that qemu loads to 0x10000) resemble a vector table at address 0x00000. The ldr pc instruction is relative to the program counter, the disassembly might show that it is loading an address at 0x10000 but it is really relative to the pc and the disassembler used the pc assuming the linked address being used.
.globl _start
_start:
ldr pc,start_vector_add
ldr pc,undef_vector_add
ldr pc,swi_vector_add
start_vector_add: .word start_vector
undef_vector_add: .word undef_vector
swi_vector_add: .word swi_vector
Then before you want to cause any interrupts, in the example I use the swi instruction to cause an swi interrupt. You copy enough of the code from 0x10000 to 0x00000 to include the exception table and the list of addresses that it loads into the pc. by linking your program to 0x10000 those addresses are in the 0x10000 range. When the interrupt occurs, the exception handler that you have now modified will load the 0x10000 based address into the pc and your handler in the 0x10000 range will get called.
Using this command line to run the binary in my example
qemu-system-arm -M versatilepb -m 128M -kernel hello_world.bin
and then ctrl-alt-3 (not F3 but 3) will switch to the serial console and you can see the output, and close that window to close out of qemu and stop the simulation.

Related

Hard fault RP2040 pico Zephyr

I'm using RP2040 under Zephyr and MCUboot. The final goal is to be able to update the firmware using MCUMGR over an UART bus. MCUboot use A/B seamless (dual slot memory) method to provide a safe update algorithm. When device reboot, MCUboot check if a new firmware is available and in this case boot on new firmware. To do this, a swap algorithm place the target firmware in slot 0. As this algorithm manipulate flash, some function has to be mapped inside SRAM to be sure that function doesn't erase his own code. Normally, code is directly executed from flash thanks to Direct-XIP on RP2040.
The problem is that SRAM seams to not be executable. When the program enter inside the function located in SRAM and execute the very first instruction this cause a hard fault:
0x2000c144 <flash_range_erase>: push {r4, r5, r6, r7, lr}
Fortunately, Zephyr crash's handler give some informations:
E: ***** HARD FAULT *****
E: r0/a1: 0x0003d000 r1/a2: 0x00002000 r2/a3: 0x00002000
E: r3/a4: 0x00000000 r12/ip: 0x2000c145 r14/lr: 0x100022e5
E: xpsr: 0x21000000
E: Faulting instruction address (r15/pc): 0x2000c144
E: >>> ZEPHYR FATAL ERROR 0: CPU exception on CPU 0
E: Current thread: 0x2000c3d0 (unknown)
E: Halting system
Everything seems normal and the address of the pc is correct. I strongly suspect a MPU misconfiguration which crash the program when executing code located in SRAM.
My question is:
Can MPU cause Hardfault ? How can i configure SRAM in Zephyr to execute code from SRAM ?
First, i tried to check if the function same is executable from flash. I removed the macro that indicate to located on flash.
Before:
void __no_inline_not_in_flash_func(flash_range_erase)(uint32_t flash_offs, size_t count) {
...
After:
void flash_range_erase(uint32_t flash_offs, size_t count) {
...
And ... it works ! The functions is executed as expected. I'm quite sure right now that the MPU is unhappy to let me execute code inside SRAM.
I searched informations about how to configure MPU to let me execute code in SRAM and i found this page: https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/zephyr/hardware/arch/arm_cortex_m.html
That explain how to configure fixed regions. I added the following lines in my device tree overlay:
&sram0 {
/delete-property/ compatible ;
/delete-property/ reg ;
compatible = "zephyr,memory-region", "mmio-sram";
zephyr,memory-region = "RAM_EXECUTABLE";
zephyr,memory-region-mpu = "RAM";
reg = < 0x20000000 0x10000 >; //Configure SRAM for MCUboot fixed for MPU
// RAM size has to match with BOOTLOADER_SRAM_SIZE (see menuconfig)
};
But this didn't solve the problem.
It was an issue in flash controller of the RP2040 in Zephyr.
The flash controller has to disable XiP to run flash operations (r/w). During this process the controller tried to run a function that was not linked in RAM (was in flash).
To resume, the controller tried to call a function that was in flash after disabling the flash execution.
I'll probably post a patch soon.
More infos on Zephyr's discord here:
https://discord.com/channels/720317445772017664/938474761405726800/1060917537405157446
Note in my question i tried to use the MPU but i had to disable on bootloader configuration.

How can I trace the cause of an invalid PC fault on Cortex M3?

I have an STM32 Cortex M3 that is experiencing an intermittent invalid PC (INVPC) fault. Unfortunately it takes a day or more to manifest and I don't know the cause.
I have the device paused in the debugger after the fault happened. The INVPC flag is set. The stacked registers are as follows:
0x08003555 xPSR
0x08006824 PC
0x08006824 LR
0x00000000 R12
0x08003341 R3
0x08006824 R2
0xFFFFFFFD R2
0x0000FFFF R0
Unfortunately the return address 0x08006824 is just past the end of the firmware image. The decompilation of that region is as follows:
Region$$Table$$Base
0x08006804: 08006824 $h.. DCD 134244388
0x08006808: 20000000 ... DCD 536870912
0x0800680c: 000000bc .... DCD 188
0x08006810: 08005b30 0[.. DCD 134241072
0x08006814: 080068e0 .h.. DCD 134244576
0x08006818: 200000bc ... DCD 536871100
0x0800681c: 00001a34 4... DCD 6708
0x08006820: 08005b40 #[.. DCD 134241088
Region$$Table$$Limit
** Section #2 'RW_IRAM1' (SHT_PROGBITS) [SHF_ALLOC + SHF_WRITE]
Size : 188 bytes (alignment 4)
Address: 0x20000000
I'm not sure this address is valid. The disassembly of that address in the debugger looks like nonsense, maybe data interpreted as code or something.
Is there any way I can trace this back to see where the exception happened? If necessary I can add some additional code to capture more information.
Don't sure how it works on Cortex M3, but on some other ARMs PSR register holds processor mode bits that could help you find out when it happens (in user mode, IRQ, FIQ etc). Each mode generally have it's own stack.
For user mode, if you use some RTOS with multi-tasking, you probably have many stacks for each task, but you could try to find out which task is current one (was running before crash).
When you find crashed task (or IRQ) you could try to look at it's stack for addresses of all routines and find out what was called before accident. Of course if stack was not unrecoverably corrupted.
This is what I'd start investigation from. If you find crashed task or even function but still have no idea what happens, you could make something like small circular history buffer where you write some codes on every step of your program, so you could find what it does last even if stack was destroyed.

How to observe aarch64 system registers in QEMU?

I have some baremetal AARCH64 software running in QEMU. I connect GDB to it as a remote target. GDB multi-arch shows general purpose registers from x0 to x30, the SP, and PC.
However, I can't find a way to access the system registers to inspect things like the DAIF system register, the Fault Address Register, Fault Syndrome Register, etc. These are essential for debugging. I've tried within QEMU using info all-registers but the output doesn't seem relevant.
Am I missing something obvious?
PS, the QEMU model is the following:
qemu-system-aarch64 -machine virt,gic_version=3 -cpu cortex-a57 -smp 4
-m 4096
No, you dont missing anything: it is impossible to view aarch64 system registers with the stock qemu as a gdb remote target.
But you could add a small changes to qemu to view them.
Gdb client connects to QEMU over GDB RSP protocol. Server part of this protocol implemented at QEMU is called "gdb stub" (also it is common term for many other simulators/embedded software).
At the very beginning of client and stub communications, stub sends to client a target desription - a xml file with all registers that client allowed to request. Here is a such file for qemu aarch64 target. As you can see, info all-registers command at client prints all this registers, not more.
If you simple add required registers to that file it doesn`t work, you also need to add a few lines to aarch64_cpu_gdb_read_register - that functions reads registers from qemu internals and pass them to gdbstub.
After that build qemu, and you got it.
Also that question
will help you to view a client/stub communication details, if something goes wrong.
QEMU 3.x+ exposes the aarch64 system registers in the normal info registers command. For example:
(gdb) info registers
...
MVFR1_EL1 0x12111111 303108369
MDRAR_EL1 0x0 0
OSLSR_EL1 0xa 10
CTR_EL0 0x8444c004 2219098116
REVIDR_EL1 0x0 0
SCTLR 0xc50838 12912696
ACTLR_EL1 0x0 0
CPACR 0x0 0
...
It was implemented in https://github.com/qemu/qemu/commit/200bf5b7ffe.
QEMU tells GDB which registers it knows about by sending XML files in GDB's Target Description format: https://sourceware.org/gdb/onlinedocs/gdb/Target-Descriptions.html#Target-Descriptions
Some of those, are simply tracked in-tree as XML files directly: https://github.com/qemu/qemu/tree/v3.0.0/gdb-xml and may be from the GDB tree: https://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=gdb/features/aarch64-core.xml;h=eb6364eb0996313420a4098509cb7f0e0fc32bec
But others are generated on the fly to reflect system configuration.
In particular, system registers are generated on the fly and sent as system-registers.xml, see: https://github.com/qemu/qemu/blob/v3.0.0/target/arm/gdbstub.c#L174
So, whatever registers you are missing, you should add them to that XML, and populate them with the correct values like the others.
And then send a patch to upstream QEMU :-)

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.

Enabling Interrupts in U-boot for ARM cortex A-9

I am trying to configure a GPIO interrupt in the uboot, This it to test the Interrupt response time without any OS intervention (Bare-metal). I was able to configure the pin-muxing and also successful in setting up the interrupt with the GPIO pin.
My question is regarding the registering of the interrupt service routine. I see that the Interrupt vector table for my platform is at address 0xFFFF0000 ( I read the System Control Register to find out this). The interrupt Id for the GPIO was 56 and with that i just calculated the address where my interrupt service routine should reside and just tried writing the address with the pointer to my ISR routine. Is this the right way of doing it? or i have to take care of the all the other things like context saving etc by myself?
Note : I am using an ARM Cortex A-9.
Edit :
Based on the answers i went through the code i have the following questions. The definition of
do_irq for my architecture( arm v7) is not doing much and the CONFIG_USE_IRQ does not work for me since functions like arch_interrupt_init are not defined for me. So i can conclude interrupts are not supported for my architecture. Now If i have to define this on my own what all functions i need to implement to get this working? Since this is a very small part of my proj and i would want to see if i can do this is feasible to implement. I just want to know if this requires few lines of code or requires some effort to implement this interrupt support.
The ARM vectors all interrupts to address 0xFFFF0018 (or 0x00000018). This is typically an unconditional branch. Then the code will inspect some interrupt controller hardware to determine the number 56. Typically, there is a routine to set the handler for the interrupt number, so you don't manually patch the code; this table is dependent on how the u-boot interrupt handling is implemented.
In my u-boot sourcenote, the interrupt table looks like this,
.globl _start
_start:
b reset
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq
...
_irq:
.word irq
So _irq is a label to install a routine for interrupt handling; it does some assembler in the same file and then calls do_irq(), based on CONFIG_USE_IRQ. Part of the API is in *lib_arm/interrupts.c*. Some CPUs are defined to handler irqs, such as cpu/arm720t/interrupts.c, for a S3C4510B. Here you can see that the code gets a register from this controller and then branches to a table.
So by default u-boot doesn't seem to have support for interrupts. This is not surprising as a boot loader is usually polling based for simplicity and speed.
Note: My u-boot is base on 2009.01-rc3.

Resources