How the processor detects that an exception is occurred? Where is the checkpoint for this? Does processor goes and checks after each F-D-E cycle for exception check or something similar? If it is processor specific, how it happens in arm?
Example: When we assert the IRQ or FIQ line, when system will go and check that line?
Every processor will have flag registers(also known as status register) at the hardware level to represent exceptions. The bits in the registers will be hardwired so as to notify an exception. The next instructions will be executed based on these registers.
Actually there isn't any checkpoint. An exception signal can be triggered at any stage of the pipeline. As a couple of examples, a division by zero on execute stage, an unknown instruction at decode stage, etc... Whenever these exceptions occur, the pipeline is flushed, and the program counter (PC) is updated with the address of the corresponding vector table entry. The bottom line is that the processor doesn't periodically check if there is an exception or not. When an exception is signalled it handles it instantly.
Related
I'm running on a Raspberry Pi Pico (RP2040, Cortex-M0+ core, debugging via VSCode cortex-debug using JLink SWD), and I'm seeing strange behaviour regarding PendSV.
Immediately prior, the SVCall exception handler requested PendSV via the ICSR register. But on exception return, rather than tail-chaining the PendSV, execution instead returns to the calling code and continues non-exception execution.
All the while the ICSR register shows the pending PendSV, even while thread code instructions are repeatedly stepped. System handler priorities are all zero, IRQ priorities are lower.
According to the ARMv6-M reference manual, PendSV cannot be disabled.
So, what am I missing that would cause this behaviour?
Edited to add:
Perhaps it's a debugger interaction? The JLink software (v4.95d) is still in Beta...
I see that the debugger can actually disable PendSV and Systick - C1.5.1 Debug Stepping: "Optionally, the debugger can set DHCSR.C_MASKINTS to 1 to prevent PendSV, SysTick, and external configurable interrupts from occurring. This is described as masking these interrupts. Table C1-7 on page C1-326 summarizes instruction stepping control."
It turns out that the problem is caused by single-stepping the instruction that writes to the PENDSVSET bit in the ICSR: the bit is set, and the VECTPENDING field shows 0xe, but the PendSV never fires.
Free-running over that instruction to a later breakpoint sees the PendSV fire correctly.
So it is indeed a debugger interaction.
Whether that's to do with interrupts being inhibited as #cooperised suggests isn't clear - the DHCSR's C_MASKINTS bit reads as zero throughout, but how that bit is manipulated during the actual step operation isn't visible at this level.
Which makes me wonder whether the way the JLink is performing the step induces unpredictable/indeterminate behaviour - e.g. as per the warning in the C_MASKINTS description. Or perhaps this is simply what happens in an M0+ under these circumstances, and I've never single-stepped this instruction before.
In any case, the workaround is simply to not single-step the instruction that sets PENDSVSET.
Edited to add:
Finally, #cooperised was correct.
On taking more care to distinguish exactly between stepping (including stepping over function calls) and running (including running to the very next instruction), it's clear that stepping disables interrupts including PendSV.
The same thing happened to me but I found that the reason was that I was not closing the previous PensSV interrupt by returning through LR containing 0xFFFFFFF9. Instead I was returning via the PC to a previous routine's return address.
Since I did not return via 0xFFFFFFF9 it was not properly closing the previous PendSV and did not recognize subsequent ones.
It seems as though the difference between a trap and an interrupt is clear: a trap is a software-invoked call to the kernel (such as through an exception) and an interrupt is pertinent to the hardware (the disk, I/O and peripheral devices such as the mouse and the keyboard...) (learn more about the difference here).
Knowing this, under what category should pressing Control + C to end a process be classified? Is it a software-invoked call and thus a trap since it can be executed from the Shell, etc. or is it an interrupt since it's a signal that the CPU receives from the keyboard? Or are interrupts wholly outside users' domain, meaning that it's the hardware interacting with the CPU at a level that the user cannot reach?
Thank you!
It's first and foremost a signal — pressing Control-C causes the kernel to send a signal (of type SIGINT) to the current foreground process. If that process hasn't set up a handler for that signal (using one of the system calls from the signal() family), it causes the process to be killed.
The signal is, I suppose, the "interrupt" signal, but this is unrelated to hardware interrupts. Those are only used internally by the kernel.
The difference between a trap and an interrupt is not as you described in your question (thanks for the reference) but to the asynchronous nature of the events producing it. A trap means an interrupt in the code execution due to a normally incorrect/internal operation (like dividing by zero or a page fault, or as you signaled, a software interrupt), but it ocurrs always at the same place in the code (synchronously with the code execution) and an interrupt occurs because of external hardware, when some device signals the cpu to interrupt what it is doing, as it's ready to send some data. By nature, traps are synchronous and interrupts aren't.
Said this, both are anomalous events that change the normal course of execution of the cpu. Both are hardware produced, but for different reasons: the first occurs synchronously (you know always when, in which instruction, it will be produced, if produced at all) and the second not (you don't know in advance which instruction will be executing when external hardware would assert the interrupt line) Also, there are two kinds of traps (depending on the event that triggered them), one puts the instruction pointer pointing to the next instruction (for example a divide by zero trap) to be executed, and the other puts it pointing to the same instruction that caused the trap (for example a page fault, that has to be reexecuted once the cause of the trap has been corrected) Of course, software interrupts, as by their nature, are always traps (traps that always change the course of execution) as it can be predicted the exact point in the program flow where the cpu will get interrupted.
So, with this explanation, you probably can answer your question yourshelf, a Ctrl-C interrupt is an interrupt as you cannot predice in advance when it will interrupt the cpu execution and you cannot mark that point in your code.
Remember, interrupts ocurr asynchronously, traps not.
The pressing of Ctrl+C on Linux systems is used to kill a process with the signal SIGINT, and can be intercepted by a program so it can clean its self up before exiting, or not exit at all.
Had it been a trap, it'd have got instantaneously died!
Hence,it is a kind of a software interrupt!
Control-C is not an interrupt... at least not on the PC (and now MAC) hardware. In other words, the keyboard controller doesn't generate a specific interrupt for the key combination "control" and "C".
The keyboard uses only one interrupt vector which is triggered on a key down and a key up. The keyboard is an extremely slow hardware device. With the key repeat rate set to the fastest, holding down a key generate 33 interrupt per second.
If the designer of the operating system believe that control-C is extremely important, they may include the test "is this the key down for "C" AND is the "control" key triggered a keyboard interrupt some billions machine cycle ago? Then, while still processing the keyboard interrupt, they would generate a trap using a software interrupt instruction.
A better operating system would reduce the processing time of the keyboard interrupt to the strict minimum. They would just append to a circular buffer (ring buffer) the key code which include the bit pressed/released and immediately terminate the interrupt.
The operating system would then, whenever it has time, notice the change in ring buffer pointer. It would trigger the code which extract the key code from the ring buffer, verify if that code represent the "ctrl-C" combination and set a flag saying "ctrl-C" detected.
Finally, when the scheduler is ready to run a thread that belong to the current process, it check the flag "ctrl-C' detected. If it is the case, the scheduler set PC to point to the SIGINT routine instead of resuming to the previous execution address.
No matter the detail, "ctrl-C" can not be an interrupt. It is either a trap if called from the keyboard interrupt or it is a synchronization object tested asynchronously by the scheduler.
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
How can I estimate the irq latency on ARM processor?
What is the definition for irq latency?
Interrupt Request (irq) latency is the time that takes for interrupt request to travel from source of the interrupt to the point when it will be serviced.
Because there are different interrupts coming from different sources via different paths, obviously their latency is depending on the type of the interrupt. You can find table with very good explanations about latency (both value and causes) for particular interrupts on ARM site
You can find more information about it in ARM9E-S Core Technical Reference Manual:
4.3 Maximum interrupt latency
If the sampled signal is asserted at the same time as a multicycle instruction has started
its second or later cycle of execution, the interrupt exception entry does not start until
the instruction has completed.
The longest LDM instruction is one that loads all of the registers, including the PC.
Counting the first Execute cycle as 1, the LDM takes 16 cycles.
• The last word to be transferred by the LDM is transferred in cycle 17, and the abort
status for the transfer is returned in this cycle.
• If a Data Abort happens, the processor detects this in cycle 18 and prepares for
the Data Abort exception entry in cycle 19.
• Cycles 20 and 21 are the Fetch and Decode stages of the Data Abort entry
respectively.
• During cycle 22, the processor prepares for FIQ entry, issuing Fetch and Decode
cycles in cycles 23 and 24.
• Therefore, the first instruction in the FIQ routine enters the Execute stage of the
pipeline in stage 25, giving a worst-case latency of 24 cycles.
and
Minimum interrupt latency
The minimum latency for FIQ or IRQ is the shortest time the request can be sampled
by the input register (one cycle), plus the exception entry time (three cycles). The first
interrupt instruction enters the Execute pipeline stage four cycles after the interrupt is
asserted
There are three parts to interrupt latency:
The interrupt controller picking up the interrupt itself. Modern processors tend to do this quite quickly, but there is still some time between the device signalling it's pin and the interrupt controller picking it up - even if it's only 1ns, it's time [or whatever the method of signalling interrupts are].
The time until the processor starts executing the interrupt code itself.
The time until the actual code supposed to deal with the interrupt is running - that is, after the processor has figured out which interrupt, and what portion of driver-code or similar should deal with the interrupt.
Normally, the operating system won't have any influence over 1.
The operating system certainly influences 2. For example, an operating system will sometimes disable interrupts [to avoid an interrupt interfering with some critical operation, such as for example modifying something to do with interrupt handling, or when scheduling a new task, or even when executing in an interrupt handler. Some operating systems may disable interrupts for several milliseconds, where a good realtime OS will not have interrupts disabled for more than microseconds at the most.
And of course, the time it takes from the first instruction in the interrupt handler runs, until the actual driver code or similar is running can be quite a few instructions, and the operating system is responsible for all of them.
For real time behaviour, it's often the "worst case" that matters, where in non-real time OS's, the overall execution time is much more important, so if it's quicker to not enable interrupts for a few hundred instructions, because it saves several instructions of "enable interrupts, then disable interrupts", a Linux or Windows type OS may well choose to do so.
Mats and Nemanja give some good information on interrupt latency. There are two is one more issue I would add, to the three given by Mats.
Other simultaneous/near simultaneous interrupts.
OS latency added due to masking interrupts. Edit: This is in Mats answer, just not explained as much.
If a single core is processing interrupts, then when multiple interrupts occur at the same time, usually there is some resolution priority. However, interrupts are often disabled in the interrupt handler unless priority interrupt handling is enabled. So for example, a slow NAND flash IRQ is signaled and running and then an Ethernet interrupt occurs, it may be delayed until the NAND flash IRQ finishes. Of course, if you have priorty interrupts and you are concerned about the NAND flash interrupt, then things can actually be worse, if the Ethernet is given priority.
The second issue is when mainline code clears/sets the interrupt flag. Typically this is done with something like,
mrs r9, cpsr
biceq r9, r9, #PSR_I_BIT
Check arch/arm/include/asm/irqflags.h in the Linux source for many macros used by main line code. A typical sequence is like this,
lock interrupts;
manipulate some flag in struct;
unlock interrupts;
A very large interrupt latency can be introduced if that struct results in a page fault. The interrupts will be masked for the duration of the page fault handler.
The Cortex-A9 has lots of lock free instructions that can prevent this by never masking interrupts; because of better assembler instructions than swp/swpb. This second issue is much like the IRQ latency due to ldm/stm type instructions (these are just the longest instructions to run).
Finally, a lot of the technical discussions will assume zero-wait state RAM. It is likely that the cache will need to be filled and if you know your memory data rate (maybe 2-4 machine cycles), then the worst case code path would multiply by this.
Whether you have SMP interrupt handling, priority interrupts, and lock free main line depends on your kernel configuration and version; these are issues for the OS. Other issues are intrinsic to the CPU/SOC interrupt controller, and to the interrupt code itself.
Can someone please explain to me what happens inside an interrupt service routine (although it depends upon specific routine, a general explanation is enough)? This always used be a black box for me.
There is a good wikipedia page on interrupt handlers.
"An interrupt handler, also known as an interrupt service routine (ISR), is a callback subroutine in an operating system or device driver whose execution is triggered by the reception of an interrupt. Interrupt handlers have a multitude of functions, which vary based on the reason the interrupt was generated and the speed at which the Interrupt Handler completes its task."
Basically when a piece of hardware (a hardware interrupt) or some OS task (software interrupt) needs to run it triggers an interrupt. If these interrupts aren't masked (ignored) the OS will stop what it's doing and call some special code to handle this new event.
One good example is reading from a hard drive. The drive is slow and you don't want your OS to wait for the data to come back; you want the OS to go and do other things. So you set up the system so that when the disk has the data requested, it raises an interrupt. In the interrupt service routine for the disk the CPU will take the data that is now ready and will return it to the requester.
ISRs often need to happen quickly as the hardware can have a limited buffer, which will be overwritten by new data if the older data is not pulled off quickly enough.
It's also important to have your ISR complete quickly as while the CPU is servicing one ISR other interrupts will be masked, which means if the CPU can't get to them quickly enough data can be lost.
Minimal 16-bit example
The best way to understand is to make some minimal examples yourself.
First learn how to create a minimal bootloader OS and run it on QEMU and real hardware as I've explained here: https://stackoverflow.com/a/32483545/895245
Now you can run in 16-bit real mode:
movw $handler0, 0x00
mov %cs, 0x02
movw $handler1, 0x04
mov %cs, 0x06
int $0
int $1
hlt
handler0:
/* Do 0. */
iret
handler1:
/* Do 1. */
iret
This would do in order:
Do 0.
Do 1.
hlt: stop executing
Note how the processor looks for the first handler at address 0, and the second one at 4: that is a table of handlers called the IVT, and each entry has 4 bytes.
Minimal example that does some IO to make handlers visible.
Protected mode
Modern operating systems run in the so called protected mode.
The handling has more options in this mode, so it is more complex, but the spirit is the same.
Minimal example
See also
Related question: What does "int 0x80" mean in assembly code?
While the 8086 is executing a program an interrupt breaks the normal sequence of execution of instruction, divert its execution to some other program called interrupt service Routine (ISR). after executing, control return the back again to the main program.
An interrupt is used to cause a temporary halt in the execution of program. Microprocessor responds to the interrupt service routine, which is short program or subroutine that instruct the microprocessor on how to handle the interrupt.