Was going through basics of arm exception handling, and come to this doubt:
(I am taking example of abort exception)
Lets assume processor is running in user mode.
When an exception happens the processor will save the current pc to abort_mode LR and CPSR to abort mode SPSR and the execution jumps to vector address for the abort, so PC will now contain the vector address for the abort.
So what I get here is before transferring the flow to abort mode(having pc to abort vector).
CPU will perform below task:
"Current pc to abort_mode LR and CPSR to abort mode SPSR and then execution jumps to vector address for the abort," as mentioned above.
In which mode and from where instructions are executed to perform above task?
When an abort exception happens, the text you are quoting is correct. Other exceptions use different modes.
The copying of PC to the exception mode LR and the CPSR to SPSR and setting the PC to the exception vector is what the processor does for you automatically on taking the exception. There are no instructions required. It also switches to the SP used by that exception mode.
The exception handler is what comes next. and is completely in software.
Related
This is a sample code from a start up code for Tiva C, as you can see the main function is called inside the reset handler, and as i understand it's is the highest priority, so my question is how any other interrupt can be handled if we are still inside the reset handler?
```
; Reset Handler
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
```
The reset is "special". When the reset handler is invoked by a processor reset, instructions are executed in thread mode. Necessarily so, since the reset vector is invoked on a power-on-reset (POR) - if the handler had to "return" where would it return to?
Also on reset in any case registers are reset to their defined reset state, and the stack pointer set to the address at the start of the table (in the case of am ARM Cortex-M at least), so there would be nowhere from which to fetch a return address - in fact the reset signal does not cause a return address to be stacked in any case.
The whole point of a reset is to restart the processor in a known state.
Returning to the point at which the reset occurred makes little sense, and would not be likely to work given that the reset state of the processor is unlikely to be a suitable run-state for the "interrupted" code.
From the ARM Cortex-M3 User Guide (my emphasis) other ARM architectures may differ in the details, but not the general point.
2.3.2. Exception types The exception types are:
Reset
Reset is invoked on power up or a warm reset. The exception model treats reset as a special form of exception. When reset is asserted,
the operation of the processor stops, potentially at any point in an
instruction. When reset is deasserted, execution restarts from the
address provided by the reset entry in the vector table. Execution
restarts as privileged execution in Thread mode.
[...]
I've found the pseudocode in the ARM architecture reference manuals to be quite helpful for answering this type of question. By "tiva c", I assume you are talking about the TM4C line of microcontrollers which are Cortex-M4 based MCUs. This means we will want to look at the ARMv7-M architecture reference manual.
Section "B1.5.5 Reset Behavior" has the pseudocode we are interested in. Here's a snippet (with the parts not relevant to the question elided out):
Asserting reset causes the processor to abandon the current execution
state without saving it. On the deassertion of reset, all registers
that have a defined reset value contain that value, and the processor
performs the actions described by the TakeReset() pseudocode.
// TakeReset()
// ============
TakeReset()
CurrentMode = Mode_Thread;
PRIMASK<0> = '0'; /* priority mask cleared at reset */
FAULTMASK<0> = '0'; /* fault mask cleared at reset */
BASEPRI<7:0> = Zeros(8); /* base priority disabled at reset */
// [...]
From the description we can note:
If the system is running and a reset is issued, the processor will always "abandon the current execution". So it is the "highest priority" thing that can happen if the MCU is running.
However, after the MCU restarts and the "TakeReset" logic starts to run, the "CurrentMode" the processor enters is actually Thread mode. ARMv7-M has two operation modes known as Thread Mode and Handler Mode. All interrupts/exceptions run in Handler Mode and normal code runs in Thread Mode. This tells us the reset path does not actually start like an interrupt/exception would. It's just running like normal code would.
I am using STM32F746, an ARM cortex-M7 based processor. I am trying to do something hacky, which requires me to return to the program from a MemManage Fault handler.
When entering MemManage Fault handler, the PC before the fault and everything I need is stored on the stack. So I thought I can simply recover those to return to the previous execution point.
However, I cannot properly restore the xPSR.
The previous CPSR before the fault handler is saved in the stack, so I tried restoring it using MSR instruction.
I tried both MSR, xpsr, r12 and MSR, apsr, r12
However, it would only restore the flags and not the other parts of the CPSR , such as the GE or the system mode bits.
(and my mode bits seems also weird.. my xPSR shows as: 0x61070004, but this tells me that the last 5 bits cannot be 0x04)
How can I go back to the program point before the fault handler? I also tried popping the pc but it does not work and I think the problem is CPSR not getting properly restored.
When a Cortex M7 enters an exception handler, the execution context is saved as follows and of course restored when exiting the handler (from ARM Cortex M7 Programming Manual):
As you see, the xPSR is restored after the return from exception.
Furthermore
faults are a subset of the exceptions.
You can do a simple test: dereference on purpose an unvalid pointer. It will trigger a HardFault. Modify your HardFault handler to just return and do nothing. You can check that the context is restored. I tried on STM32H753, it works fine, xPSR latest bits (ISR_NUMBER) are indeed 0 (thread mode).
Be careful though: I don't know for MemManage but HardFault returns to the very same instruction that triggered the fault (and not to the following instruction like a regular exception). It means you will execute again the same instruction after the Hardfault.
I am currently doing work with the Cortex-M3 and am having trouble understanding the use of the xPSR. I am not sure why the ISR number is stored in lowest 8 bits.
Online sources and datasheets give no clue to why the number must be stored in the xPSR. On the ARM7-TDMI the current mode (FIQ, IRQ, SVC, USR, ABT, UND) is stored in the lowest 8 bits of the CPSR. I assume it is stored there so when an exception is raised and the mode is switched the processor knows which bank of registers to save the state of the CPSR to. However the Cortex-M3 doesn't have banked registers and the xPSR is saved onto the stack when an ISR is needed to be serviced.
Can anyone enlighten me?
Is this what you are talking about?
The IPSR
The processor writes to the IPSR on exception entry and exit. Software can use an MRS instruction, to read
the IPSR, but the processor ignores writes to the IPSR by an MSR instruction. The IPSR Exception Number
field is defined as follows:
• in Thread mode, the value is 0
• in Handler mode, holds the exception number of the currently-executing exception.
An exception number indicates the currently executing exception and its entry vector, see Exception number
definition on page B1-633 and The vector table on page B1-634.
On reset, the processor is in Thread mode and the Exception Number field of the IPSR is cleared to 0. As a
result, the value 1, the exception number for reset, is a transitory value, that software cannot see as a valid
IPSR Exception Number.
I would see that as similar to the cpsr in the ARMv4/ARM7TDMI as it gives you the state in which you are executing. if you are executing in an exception and if so which one. It likely has meaning to the chip designers for similar reasons and that is where that information or a copy of that information is held. Perhaps to not re-enter an exception handler if already in that exception mode for example. Or if a second exception of some type, say a prefetch abort while executing the prefetch abort perhaps the processor hangs on purpose or chooses a different exception.
Well, I'm not entirely sure I understand the question - are you asking "why is it different" or "what is the point"?
In the first case - the answer is the same as for "why does it not support the ARM instruction set", "why are there only 2 execution modes", "why is the vector table huge and contains addresses rather than instructions" and "why are there only 2 possible stack pointers": "because". Because the M-profile has a completely different exception model.
(And because the exception model is different, what was the mode bits in the CPSR was free to use for something else.)
In the second case ... well, that's up to the developer, isn't it?
There happens to be a register that holds the currently active interrupt ID. If this is of benefit to you, do use it.
You could (for example) use it to have a single interrupt handler address stored into multiple locations in the vector table and then use the interrupt ID to identify which specific device had triggered the interrupt.
It also sounds handy from the point of view of reentrant exception handling.
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/CHDBIBGJ.html
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.
Does anyone know how to enable ARM FIQ?
Other than enabling or disabling the IRQ/FIQ while you're in supervisor mode, there's no special setup you should have to do on the ARM to use it, unless the system (that the ARM chip is running in) has disabled it in hardware (based on your comment, this is not the case since you're seeing the FIQ input pin driven correctly).
For those unaware of the acronyms, FIQ is simply the last interrupt vector in the list which means it's not limited to a branch instruction as the other interrupts are. That means it can execute faster than the other IRQ handlers.
Normal IRQs are limited to a branch instruction since they have to ensure their code fits into a single word. FIQ, because it won't overwrite any other IRQ vectors, can just run the code directly without a branch instruction (hence the "fast").
The FIQ input line is just a way for external elements to kick the ARM chip into FIQ mode and start executing the correct exception. There's nothing on the ARM itself which prevents that from happening except the CPSR.
To enable FIQ in supervisor mode:
MRS r1, cpsr ; get the cpsr.
BIC r1, r1, #0x40 ; enable FIQ (ORR to disable).
MSR cpsr_c, r1 ; copy it back, control field bit update.
A similar thing can be done for normal IRQs, but using #0x80 instead of #0x40.
The FIQ can be closed off to you by the chip manufacturer using trustzone extensions.
Trustzone creates a Secure world and a normal world. The secure world has its own supervisor, user and memory space. The idea is for secure operations to be routed so they never leave the chip and cannot be traced even if you scan the pins on the bus. I think in OMAP it is used for some cryptography operations.
On Reset the core starts in secure mode. It sets up the secure monitor (gateway between secure and non-secure world) and at this time FIQ can be setup to be routed to the monitor. I think it is the SCR.FIQ bit that may be set and then all FIQs ignore the value of CPSR.F and go to monitor mode. Check out the ARM ARM but if I remember correctly if this is happening there is no way for you to know from nonsecure OS code. Then the monitor will reset the Normal world registers and doing an exception return with PC set to the reset exception vector.
The core will take an interrupt to monitor mode, do its thing and return.
Sorry I can't answer you in the comments, I don't have enough reputation, you could always fix that ;), but I hope you see this