Which mode does the ARM SVC handler start in? Basically, I want to know which mode the ARM core is in when an SVC exception is raised?
Can't seem to find it in the ARM ARM, but my guess would be that it starts in Supervisor.
Are you talking about the SWI handler? Yes, I see some places they refer to it as the SWI instruction but sometimes the SVC instruction.
Note: In older versions of the ARM architecture, SVC was called SWI, Software Interrupt.
From the ARM ARM
Exception type Mode Address
----------------------------------------------
Reset Supervisor 0x00000000
Undefined Instruction Undefined 0x00000004
Software Interrupt (SWI) Supervisor 0x00000008
Prefetch Abort Abort 0x0000000C
Data Abort Abort 0x00000010
IRQ IRQ 0x00000018
FIQ FIQ 0x0000001C
...
Software Interrupt exception
The Software Interrupt instruction (SWI) enters Supervisor mode to request a particular supervisor (operating system) function. When a SWI is executed, the following actions are performed:
R14_svc = address of next instruction after the SWI instruction
SPSR_svc = CPSR
CPSR[4:0] = 0b10011 /* Enter Supervisor mode */
CPSR[5] = 0 /* Execute in ARM state */
/* CPSR[6] is unchanged */
CPSR[7]= 1 /* Disable normal interrupts */
/* CPSR[8] is unchanged */
CPSR[9] = CP15_reg1_EEbit /* Endianness on exception entry */
PC = 0x00000008
To return after performing the SWI operation, use the following instruction to restore the PC (from R14_svc) and CPSR (from SPSR_svc) and return to the instruction following the SWI:
MOVS PC,R14
Related
I'm using Tiva TM4C129XNCZAD based on 32-bit ARM® Cortex®-M4F in a TI_RTOS environment. I'm getting an unexpected reset during the normal flow of the system. After reset, I get the following register values. How can I understand what caused the reset using the below register values?
0xffffffff
R1 = 0x00000000 R9 = 0xffffffff
R2 = 0x2000a26c R10 = 0xffffffff
R3 = 0x2000a26c R11 = 0xffffffff
R4 = 0x2003ee54 R12 = 0x00000000
R5 = 0x20000a80 SP(R13) = 0x20034e18
R6 = 0x2003d664 LR(R14) = 0x00073135
R7 = 0x2003bbc4 PC(R15) = 0x00000000
PSR = 0x60000000
ICSR = 0x0440f803
MMFSR = 0x00
BFSR = 0x00
UFSR = 0x0002
HFSR = 0x40000000
DFSR = 0x00000001
MMAR = 0xe000ed34
BFAR = 0xe000ed38
AFSR = 0x00000000
Terminating execution...
The ARM core register values after reset are unlikely to be relevant.
The TM4C129XNCZAD specifically has a RESC (Reset Cause) register in the System Control register block. That will tell you whether the last reset was a POR, Watchdog, brown-out, oscillator fail etc. The register is at address: 0x400FE05C; refer to the data sheet p.280 for details.
Determining the direct cause of the reset will inform you of where you need to look for the indirect cause (software error, hardware fault, inadequate power-supply etc.) For example if you have a Bus Fault exception, and the exception handler is an infinite loop, you may get a watchdog reset - or the handler may simply issue a software (NVIC) reset. Placing a breakpoint in the exception handler(s) is a good place to start. If you are getting an fault exception you can inspect the state in the exception handler rather than after reset.
Confusingly the data sheet refers to the exception handler registers with unconventional names: FAULTSTAT, HFAULTSTAT, MMADDR, FAULTADDR. These are in fact the CFSR, HFSR, MMAR and BFAR respectively in your register dump (actually the dump has no CFSR but that is simply a combination of MFSR, UFSR and DFSR). Details of the exception registers can be found here.
Your register dump shows that the the processor is in debug HALT at PC address 0x0000000. UFSR = 0x0002 indicates an attempt to switch to ARM mode from Thumb mode (Cortex-M does not support ARM mode). This occurs when a jump/branch occurs without the address LSB=1 (Thumb bit). However I don't think the UFSR is valid after a reset - you need to inspect it from within the fault handler itself. Moreover address 0x0000000 is the location of the vector table and specifically, on reset:
Address at 0x00000000 is loaded to SP
Address at 0x00000004 is loaded to PC
As such it is hard to see how PC=0x00000000 can be a valid state. It suggests that you have no valid start address.
If this register dump is in fact from the fault handler and not after reset as you suggest, then perhaps you have a jump/branch to an invalid even address which would cause the UFSR = 0x0002 - in Thumb all jump targets are odd (the LSB is ignored as the actual address is always even).
Once you have determined the RESC value you might then post a further question on how to diagnose or locate the error if it is not clear. The simplest and fastest method to determining a software cause of a reset/exception is to use the Embedded Trace Macrocell (ETM) with suitable debugger hardware/software to record the code execution immediately prior to the event. However your board may not expose the trace pins or you may not possess suitable debug tools.
I'm researching the the Arm Architecture Reference Manual ARMv7-A ARMv7-R edition document these days. When I read about the exception handling part of this manual, it comes across a confusions to me. The problem is about how to decide the LR value when ARMv7-A architecture implementation takes an IRQ exception.
EXAMPLE: Suppose that the processor is executing an instruction at the address of 0x_0000_1000 and an IRQ is taken.First, we have to calculate some parameters to be used to calculate the LR.
preferred return address,which is the Address of next instruction to execute in this case. So preferred return address = 0x_0000_1002 in thumb instruction set or preferred return address = 0x_0000_1004 for arm instruction set.preferred return address for the exception
PC,which is the program counter and holds the current program address.In this case, PC = 0x_0000_1004 in thumb instruction state or PC = 0x_0000_1008 in arm instruction state.how to calculate PC
Then, here are 2 methods mentioned in the document to decide the LR value when taking this IRQ exception.
by using preferred return address. LR = preferred return address + offset that depends on the instruction set state when the exception was taken.In this case LR = 0x_0000_1002 + 4 in thumb instruction state or LR = 0x_0000_1004 + 4 in arm instruction state.Offsets applied to Link value for exceptions taken to PL1 modes
by using PC. LR = PC-0 if in thumb instruction set or LR = PC-4 when in arm instruction set.In this case LR = 0x_0000_1004 - 0 in thumb instruction set or LR = 0x_0000_1008 - 4 in arm instruction state. Pseudocode description of taking the IRQ exception
Problem:the LR results calculated by the 2 methods are different both in thumb set state and arm set state(with first method we get LR = 0x_0000_1006 or LR = 0x_0000_1008,but second method we get LR = 0x_0000_1004 or LR = 0x_0000_1004). which one is correct or is there any wrong with my understanding?
TL;DR - the IRQ LR will point to the next instruction to complete work as would normally be run without an interrupt. Otherwise, code would not execute the same in the presence of interrupts.
It is confusing as the ARM documents may refer to PC in many different contexts and they are not the same.
EXAMPLE:Suppose that the processor is executing an instruction at the address of 0x_0000_1000 and an IRQ is taken. First, we have to calculate some parameters to be used to calculate the LR.
preferred return address,which is the Address of next instruction to execute in this case. So preferred return address = 0x_0000_1002 in thumb instruction set or preferred return address = 0x_0000_1004 for arm instruction set.preferred return address for the exception
This is not correct. The ARM cpu has a pipeline and the last instruction that it has deemed to have completed is the next instruction. Take for example this sequence,
0: cmp r1, #42
1: bne 4f ; interrupt happens as this completes.
2: add r2, r2, #4
3: b 5f
4: sub r2, r2, #2
5: ; more code.
If the interrupt happens as label '1:' happens, the next instruction will be either '2:' or '4:'. If you followed your rule this would either increase interrupt latency by never allowing an interrupt in such cases, or interrupts would cause incorrect code. Specifically, your link says next instruction to execute.
PC,which is the program counter and holds the current program address.In this case, PC = 0x_0000_1004 in thumb instruction state or PC = 0x_0000_1008 in arm instruction state.how to calculate PC
Here you are mixing concepts. One is when you use a value like ldr r0, [pc, #42]. When you calculate the offset, you must add two to the current ldr instruction. The actual PC is not necessarily this value. At some point (original version), the ARM was a two stage pipeline. In order to keep behaviour the same, subsequent ARM cpus follow the rule of being two ahead when calculating ldr r0, [pc, #42] type addresses. However, the actual PC may be much different inside the CPU. The concept above describes the programmer visible PC for use with addressing.
The CPU will make a decision, sometimes base on configuration, on what work to complete. For instance, ldm sp!, {r0-r12} may take some time to complete. The CPU may decide to abort this instruction to keep interrupt latency low. Alternatively, it may perform 12 memory reads which could have wait states. The LR_irq will be set to the ldm instruction or the next instruction depending whether it is aborted or not.
I'm confused about the returning process of SVC mode's program after svc instruction. Assuming currently the processor is running on SVC mode, then it's interrupted by software interrupt by svc instruction, hardware would help save CPSR into SPSR_svc, and load svc handler into PC, load the program address where it's interrupted into LR_svc. To return to SVC mode normal program where it's interrupted, we need to load LR_svc into PC, and load SPSR_svc into CPSR.
My question is that, in svc handler, LR_svc is changed, it's context is the program address where it's interrupted, so after the program returns to the normal SVC mode program, the program's LR is changed, how can the program return to the function where it's called???
so after the program returns to the normal SVC mode program, the program's LR is changed
Wrong assumtion. The LR is banked for SVC mode, so you changing it in SVC handler does not change the register value for user mode.
Assuming currently the processor is running on SVC
mode, then it's interrupted by software interrupt by svc instruction,
...
how can the program return to the function where it's called???
There are 2 ways to make sure that the program returns to the function that called into supervisor mode.
One way is to very carefully write the SVC handler and all the functions it calls (supervisor-mode code that runs in SVC mode), making sure that code has no SVC instructions in it.
Another way, as suggested by the "ARM Developer Suite Developer Guide: Using SWIs in Supervisor mode":
If the processor is already in Supervisor mode, lr_SVC and spsr_SVC
are corrupted.
If you call a SWI while in Supervisor mode you must store lr_SVC and
spsr_SVC to ensure that the original values of the link register and
the SPSR are not lost.
SVC handlers that take this approach typically start by pushing those values to the supervisor stack.
After those are saved away, then it is safe to use the SVC instruction.
Then later, when the SVC handler is ready to return,
it uses those values on the stack (not the values currently in the lr_SVC and spsr_SVC registers) to return to the correct place.
That way the SVC handler works and then returns correctly either way -- whether it was called using SVC from user-mode code, or whether it was called using SVC from SVC-mode code.
This is similar to the way typical a typical user-mode ARM Thumb or ARM32 subroutine -- let's call it S() -- deals with the return address in LR that it needs to return correctly -- even though LR is overwritten every time S() calls any other user-mode subroutine.
Following the ARM Thumb or the ARM32 calling conventions,
S() begins with instructions that push a copy of the link register to the stack.
When S() is finished, it doesn't return to the address currently in the link register (an address that was overwritten and lost when it called some other subroutine).
Instead, S() pulls the return address it earlier saved to the stack, so then M() can correctly return to the correct location in the subroutine that called it.
p.s.:
For future readers looking for information on SVC:
The SVC instruction was once called the SWI instruction.
FreeRTOS port.c includes the SVC handler
"ARM Cortex-M RTOS Context Switching"
"The M3/M4/M7 ports of FreeRTOS [use] ... The SVC (SuperVisor Call) instruction ... the SVC instruction ... is not used for M0."
"Service Time – ARM Cortex-M SVC Exception"
"CMSIS-RTOS: SVC Functions"
"The... RTOS ... and ... the bootloader, each component has its own SVC handler"
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.
Can you explain how the ARM mode get changed in case of a system call handling?
I heard ARM mode change can happen only in privileged mode, but in case of a system call handling while the ARM is in user mode (which is a non-privileged mode), how does the ARM mode change?
Can anybody explain the whole action flow for the user mode case, and also more generally the system call handling (especially how the ARM mode change)?
Thanks in advance.
In the case of system calls on ARM, normally the system call causes a SWI instruction to be executed. Anytime the processor executes a SWI (software interrupt) instruction, it goes into SVC mode, which is privileged, and jumps to the SWI exception handler. The SWI handler then looks at the cause of the interrupt (embedded in the instruction) and then does whatever the OS programmer decided it should do. The other exceptions - reset, undefined instruction, prefetch abort, data abort, interrupt, and fast interrupt - all also cause the processor to enter privileged modes.
How file handling works is entirely up to whoever wrote your operating system - there's nothing ARM specific about that at all.
You need to get a copy of the ARM ARM (Architectural Reference Manual).
http://infocenter.arm.com -> ARM Architecture -> Reference Manuals -> ARMv5 Architectural Reference Manual then download the pdf.
It used to be a single ARM ARM for the ARM world but there are too many cores and starting to diverge so they split off the old one as ARMv5 ARM and made new Architectural Reference Manuals for each of the major ARM processor families.
In the Programmers Model chapter it talks about the modes, it says that you can change freely among the modes other than user. ARM startup code will often go through a series of mode changes so that the stack pointers, etc can be configured. Then as needed go back to System mode or User mode.
In that same chapter look at the Exceptions section, this describes the exceptions and what mode the processor switches to for each exception.
The Software interrupt exception which happens when an SWI instruction is executed, is a way to implement system calls. The processor is put in Supervisor mode and if in thumb mode switches to arm mode.
There needs to be code to support that exception handler of course. You need to verify with the operating system, if any, you are running, what is supported and what the calling convention is, etc.
Not all ARM processors work this way. The Cortex-M (ARMv7-M) does not have the same modes and same exception table, etc. As with any time you are using an ARM (at this level) you need to get the ARM ARM for the family you are using and you need to get the TRM (Techincal Reference Manual) for the core(s) you are using, ideally the exact revision, even if ARM marks the TRM as having been replaced by a newer version the chip manufacturer has purchased and uses a specific rev of the core and there can be enough differences between revs that you will want the correct manual.
When an SVC instruction is encountered by the PC, the following behaviour takes place:
The current status (CPSR) is saved (to the supervisor SPSR)
The mode is switched to supervisor mode
Normal (IRQ) interrupts are disabled
ARM mode is entered (if not already in use)
The address of the following instruction (the return address) is saved into the link register (R14) - It's worth noting that this is
the link register that belongs to the supervisor mode
The PC is altered to jump to address 0x00000008
An exception vector (just a branch instruction) should be at the address 0x0000008, which will branch the program to another area of code used to determine which supervisor call has been made.
Determining which supervisor call has been made is usually accomplished by loading the SVC instruction into a register (by offsetting the LR by one word - since the LR is still pointing to the instruction next to the supervisor call), bit clearing the last 8 bits and using the value in the remaining 24 bits of the register to calculate an offset in a jump table, to branch to the corresponding SVC code.
When the supervisor call code wishes to return to the user application, the processor needs to context switch back into user mode and return to the address contained within the LR (which is only available in supervisor mode, since certain registers are banked for both modes). This problem is overcome using the MOVS instruction, as illustrated below:
(consider this to also be your explanation on how to change mode)
MRS R0, CPSR ; load CPSR into R0
BIC R0, R0, #&1F ; clear mode field
ORR R0, R0, #&10 ; user mode code
MSR SPSR, R0 ; store modified CPSR into SPSR
MOVS PC, LR ; context switch and branch
The MRS and MSR instructions are used to transfer content between an ARM register and the CPSR or SPSR.
The MOVS instruction is a special instruction, which operates as a standard MOV instruction, but also sets the CPSR equal to the SPSR upon branching. This allows the processor to branch back (since we're moving the LR into the PC) and change mode to the mode specified by the SPSR.
I quote from the ARM documentation available here:
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0471c/BABDCIEH.html
When an exception is generated, the processor performs the following
actions:
Copies the CPSR into the appropriate SPSR. This saves the current mode, interrupt mask, and condition flags.
Switches state automatically if the current state does not match the instruction set used in the exception vector table.
Changes the appropriate CPSR mode bits to:
Change to the appropriate mode, and map in the appropriate banked out registers for that mode.
Disable interrupts. IRQs are disabled when any exception occurs. FIQs are disabled when an FIQ occurs and on reset.
Sets the appropriate LR to the return address.
Sets the PC to the vector address for the exception.
where, CPSR refers to Current Program Status Register and SPSR to Saved Program Status register used to restore the state of the process that was interrupted. Thus, as seen in point 3, the processor circuitry is designed in a way that the hardware itself changes the mode when user mode executes a Supervisor call instruction.
"I heard ARM mode change can happen only in privileged mode". You are partly right here. By partly I mean the control field of the CPSR register can be manually modified (manually modified means through code) in the privileged modes only not in the unprivileged mode (i.e. user mode). When a system call happens in the user mode it happens because of SWI instruction. An SWI instruction has inbuilt mechanism to change the mode to supervisor mode.
So to conclude , there are two ways to change the mode:
1) Explicitly through code. Only allowed in a privileged mode.
2) Implicitly through IRQ, FIQ, SWI, RESET, undefined instruction encountered, data abort, prefetch abort. This is allowed in all the modes.