0
votes

I know many questions are asked in relation to this but I still haven't quite found my answer. I'm thinking from the perspective of a C/C++ programmer who is not fully aware of what happens at machine level.

When a function is called, I understand that the return address of the calling function is pushed onto the stack (or link register gets return address automatically) along with all the registers in use by the calling function and the Program counter gets the address of the entry point to the function.

My main question is, is all this saving of context done automatically in hardware or is it done in software , hence the compiler generates assembly code for this? How are the local variables of the callee function also saved on the stack?

When an interrupt occurs, I believe the procedure is quite similar in order to go to the Interrupt Service Routine except that the ISR doesn't take arguments or return anything, but what is the main difference? Are interrupts disabled automatically or is it up to the compiler to generate code to disable interrupts on entering an ISR?

Many thanks in advance.

4
Saving of registers for a function call is in software, and according to the calling convention. You can have a look at the compiler generated code. For interrupts, ARM has banked registers, so if a mode switch occurs some registers are preserved by hardware.Jester
You need a tutorial or book. Also there are different ARM cores with very different interrupt handling.too honest for this site
My question got a -1. It seems we can't ask anything here these days without some criticism. How are people supposed to learn?Engineer999

4 Answers

2
votes

ARM has pre-emptive context switch.

For cortex arch

Internally has two stack pointers, the main stack pointer (MSP) and the process stack pointer (PSP).

When you do a context switch, ARM hardware pushes by hardware some (but not all registries and the PC) then pops by hardware the other context. Typically R4-R12 and LR and the PC will be pushed to the stack

This featured is used by KERNEL / userspace models, and isn't that useful on interrupts. Here is why:

By hardware, interrupts are jumps (C gotos), to a fixed address on an interruption vector. This address may then call a function (your interrupt handler)

As you may have multiple interruption levels, when doing this function call you can't rely on the context switch and you need to save your registers on the stack (as with any other frame, but this time at the main stack).


For Classic ARM

You have multiple modes, each mode with it's own stack, and different interrupts are mapped to different modes.

You don't have multiple interrupt levels, so you may rely purely on hardware pushing XPSR, PC,R0,R1,R2,R3,R12 and LR on context switching.


Source: http://www.design-reuse.com/articles/25768/cortex-m-and-classical-series-arm-architecture-comparisons.html

0
votes

In asm terms, a process doesn't have "local variables". It just has the fixed number of architectural registers. If there were more variables than regs, the code implementing the function already had to spill some variables to the stack.

In a multitasking OS with privilege separation and memory protection, ISRs don't use the user-space stack at all. They use the kernel stack, otherwise other threads of the user-space process could interfere with the kernel's ISRs!

I assume ARM is similar to other architectures, like x86, where hardware saves the interrupt return address, but preserving the rest of the architectural state (including registers) is up to software. A tiny ISR that doesn't need all the registers wouldn't even need to save them all.

Oh, actually Jester's comment reminded me that ARM has a separate set of regs that are active for ISRs, so yes, the hardware does take care of preserving most regs. (This is only a partial answer to this part of the question. I mainly posted to point out that it's just registers that need saving, i.e. a fixed-size amount of stuff.)

0
votes

It depends on which arm architecture you are talking about and which instructions. The branch link (BL) and branch link exchange (BLX) instructions have the link register r14 hardcoded such that the pc of the return address is written there.

The return instructions bx lr, mov pc,lr, the software chooses lr as the return it is not hardwired like other instruction sets.

A programmer or compiler is free to not use the bl instruction and can use the stack, but it makes more sense to just use these instructions as intended.

As far as interrupts and local variables and saving state on a function call. the software has to save state on a function, call the hardware does not do that for you. Saving state on an interrupt, that depends on the architecture. for the traditional 32 bit arm you had/have banked regitsters, and when you switched modes some or many of your registers swtiched to another bank, for example there were a number of r13 registers, one for user mode, one for irq, and so on, such that you didnt have to use different instructions the registers you were using switched out from under you, so in that respect when you went from user or service mode to irq mode, that basically protected or saved state by switching yo away from that bank of registers, any more state you wanted to save you needed to do yourself.

Now the cortex-m microcontrollers are a little different, when an interrupt occurs, the hardware saves state for you, all the registers, there is no banking of registers, it simply pushes them on the stack and uses a bit pattern for the return address to indicate this was an interrupt and to restore the registers/state.

All of these things are documented either in the Architectural Reference Manual for an arm architecture or in the Technical Reference Manual for the specific core. both sets of documents are found at infocenter.arm.com

The arm cores vary as to how interrupts are handled, traditionally you had individual irq and fiq lines coming in. ARM makes cores not chips, so it was up to the chip vendor to implement the rest of the interrupt design, and it varies widely. In general though you (software) have some responsibility to go to the peripheral and tell it to deassert the interrupt from its end. How it is latched between the peripheral and the core is part of the stuff that can vary. Basically you want to have the signal deasserted before leaving the service routine. the cortex-ms and newer full sized cores can have dozens to hundreds of individual interrupts supported making softwares job easier and performance better you dont have to spend time in one universal isr figuring out who caused it then branching off to various handlers, they take it to the other extreme of each peripheral or even finer grained than that can have its own isr.

Some cores more of the interrupt management is in the core and you see the arm docs for that, the rest of the interrupt management is specific to that chip and you need the docs from the chip vendor for that information, there is in no way a universal answer for how interrupts work.

-2
votes

In ARM this is done by hardware. It's automatic and you don't have to worry about. In the case of ISR, the core doesn't prevent you from other nested IRQ, but I think in some target you can have high priority IRQ that can't be further interrupted