Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
en:multiasm:paarm:chapter_5_7 [2025/12/04 10:19] – [Conditional Branches] eriks.klavinsen:multiasm:paarm:chapter_5_7 [2025/12/04 12:48] (current) – [Interrupts] eriks.klavins
Line 141: Line 141:
  
 ** Stack Pointer in Exception Levels ** ** Stack Pointer in Exception Levels **
 +
 +AArch64 supports multiple exception levels (EL0 to EL3). Each level can have its own stack pointer. The processor provides two stack pointers for EL1 and above:
 +  * SP_EL0 – stack pointer used when running code at EL0 (user mode)
 +  * SP_ELx – stack pointer used for each higher exception level (EL1, EL2, EL3)
 +When an exception or interrupt occurs, the CPU automatically switches to the appropriate stack pointer for the new level. This prevents user-level code from corrupting kernel or hypervisor data and keeps the stacks for each privilege level separate.
 +It can be manually accessed or configured by using the system registers:\\
 +''<fc #800000>MRS</fc> <fc #008000>X0</fc>, SP_EL0 <fc #6495ed>@ Read user-mode stack pointer</fc>''\\
 +''<fc #800000>MSR</fc> SP_EL0, <fc #008000>X1</fc> <fc #6495ed>@ Write a new value to it</fc>''
 +
 +** Using the Stack for Parameter Passing **
 +
 +In AArch64, the first eight function arguments are passed in registers ''<fc #008000>X0</fc>'' up to''<fc #008000>X7</fc>''. If there are more than eight arguments, the rest are passed on the stack. The caller places these extra arguments at known offsets below ''<fc #008000>SP</fc>'' before executing a ''<fc #800000>BL</fc>'' (branch with link) instruction. The callee can access them either through the frame pointer or via ''<fc #800000>LDR</fc>'' instructions relative to the ''<fc #008000>SP</fc>'' stack pointer. Example:\\
 +''<fc #800000>STR</fc> <fc #008000>X8</fc>, [<fc #008000>SP</fc>, <fc #ffa500>#-16</fc>]**<fc #800080>!</fc>**''\\
 +''<fc #800000>BL</fc> long_function''\\
 +''<fc #800000>ADD</fc> <fc #008000>SP</fc>, <fc #008000>SP</fc>, <fc #ffa500>#16</fc>''\\
 +This pushes the ninth argument onto the stack before calling //long_function//, which can then read it back.
 +
 +===== Interrupts =====
 +
 +An interrupt is a special signal that may cause the processor to temporarily stop normal program execution to handle an event that requires immediate attention. Interrupts are part of the previously described exception system or exception layer.
 +Interrupts on the processors are handled similarly, regardless of the architecture – the processor saves the current program state, program counter and status register. AArch64 then switches to privileged exception levels and finally jumps to the exception vector – a specific address that tells the processor where to find the instructions to handle the current event. The exception vector contains the address of a specific function. In the ARMv8 documentations, the interrupt is treated as a subset of exceptions. The exception is any event that can force the CPU to stop current normal code execution and start with the exception handler. 
 +There are four types of exceptions.
 +
 +Synchronous exception – the exceptions of this type are always caused by the currently executed instruction. For example, the use of the str instruction to store some data at a memory location that does not exist or for which write operations are not available. In this case, a synchronous exception is generated. Synchronous exceptions can also be used to create a “software interrupt”. A software interrupt is a synchronous exception generated by the svc instruction. 
 +
 +IRQ (Interrupt Request) – these are normal interrupts. They are always asynchronous, meaning they have nothing to do with the currently executing instruction. In contrast to synchronous exceptions, asynchronous exceptions are not always generated by the processor itself but by external hardware.
 +
 +FIQ (Fast Interrupt Request) – this type of exception is called “fast interrupts” and exists solely for prioritising exceptions. It is possible to configure some interrupts as “normal” and others as “fast”. Fast interrupts will be signalled first and will be handled by a separate exception handler.
 +
 +SError (System Error) – like IRQ and FIQ, SError exceptions are asynchronous and are generated by external hardware. Unlike IRQ and FIQ, SError always indicates some error condition. 
 +
 +Each exception type needs its own handler, the special function that handles an exact event. Also, separate handlers should be defined for each different exception level at which an exception is generated. If the current code is working on EL1, those states can be defined as follows: the EL1t Exception is taken from EL1, while the stack pointer is shared with EL0. This happens when the SPSel register holds the value 0. EL1h Exception is taken from EL1 at the time when the dedicated stack pointer was allocated for EL1. This means that SPSel holds the value 1. EL0_64 Exception is taken from EL0 executing in 64-bit mode, and EL0_32 Exception is taken from EL0 executing in 32-bit mode.
 +In total, 16 exception handlers must be defined (four exception levels multiplied by four execution states). A special structure that holds addresses of all exception handlers is called the exception vector table, or just the vector table. The [[https://developer.arm.com/documentation/ddi0487/ca/|AArch64 Reference Manual]] has information about the vector table structure. Each exception vector has its own offset:
 +{{:en:multiasm:paarm:ddi0487c_a_armv8_arm.pdf_-_adobe_acrobat_reader_64-bit_.jpg|}}
 +
 +There is no fixed number of interrupts available for the processor. The total number of available interrupts is defined by the Generic Interrupt Controller (GIC) implemented in the system. The Raspberry Pi 5 have a GIC-500 interrupt controller, and according to [[https://documentation-service.arm.com/static/5e9085b8c8052b1608761814?token=|ARM GIC architecture]], the Raspberry Pi 5 can have up to 1020 different interrupt IDs:
 +  * ID0..ID15 is used for Software Generated Interrupts (system calls)
 +  * The next 16 IDs are used for Private Peripheral Interrupts for a single core
 +  * The rest of the IDs are for Shared Peripheral interrupts
 +
 +Practically, the Raspberry Pi 5 may have hundreds of interrupts from different sources in use, because the SoC chip BCM2712 have a lot of internal peripheral interrupts, the RP1 chip (the one that handles I/O lines and other peripherals on board) uses additional interrupts over PCIe bus. The Linux OS creates its own software interrupt, and finally, Linux combines them through the GIC.
 + 
 +The interrupts can be disabled and enabled. For example:\\
 +''<fc #800000>MSR</fc> DAIFCLR, <fc #ffa500>#2</fc><fc #6495ed> @ enable IRQ (interrupt request)</fc>''\\
 +''<fc #800000>MSR</fc> DAIFCLR,<fc #ffa500> #1</fc><fc #6495ed> @ Enable FIQ</fc>''\\
 +''<fc #800000>MSR</fc> DAIFSET, <fc #ffa500>#2</fc><fc #6495ed> @ disable IRQ</fc>'' 
 +
 +
 +** The Stack Pointer and Interrupt Handling **
 +
 +When an interrupt or exception occurs, the processor automatically saves the minimal state. It then switches to the stack pointer associated with the current exception level. The interrupt handler can safely use the stack at that level without overwriting user or kernel data. For example, when an IRQ occurs at EL1, the CPU switches from the user’s stack (SP_EL0) to the kernel’s stack (SP_EL1). This change is invisible to user code and helps isolate privilege levels.
 +Inside an interrupt handler, the code must save and restore any registers it modifies. A minimal handler might look like this:\\
 +''irq_handler: <fc #6495ed>@ the label for the interrupt handler</fc>''\\
 +''<fc #800000>STP</fc> <fc #008000>X0</fc>, <fc #008000>X1</fc>, [<fc #008000>SP</fc>, <fc #ffa500>#-16</fc>]**<fc #6495ed>!</fc>**''\\
 +''<fc #6495ed>@ Handle the interrupt (event)</fc>''\\
 +''<fc #800000>LDP</fc> <fc #008000>X0</fc>, <fc #008000>X1</fc>, [<fc #008000>SP</fc>], <fc #ffa500>#16</fc>''\\
 +''<fc #800000>ERET</fc> <fc #6495ed>@ retorn from innetrupt (exception) handler</fc>''
 +
 +Here, the stack pointer ensures the handler has a private area to store data safely, even if multiple interrupts occur.
 +
 +<codeblock code_label>
 +<caption>Simple examples of interrupt handlers</caption>
 +<code>
 +irq_el1_handler:
 +    @ Save registers
 +    STP X0, X1, [SP, #-16]!
 +    STP X2, X3, [SP, #-16]!
 +
 +    @ Acknowledge interrupt (example for GIC)
 +    MRS X0, ICC_IAR1_EL1       @ Read interrupt ID
 +    CMP X0, #1020              @ Spurious?
 +    BEQ irq_done
 +
 +    @ Handle interrupt (custom code here)
 +    BL handle_device_irq
 +
 +    @ Signal end of interrupt
 +    MSR ICC_EOIR1_EL1, X0
 +
 +irq_done:
 +    @ Restore registers
 +    LDP X2, X3, [SP], #16
 +    LDP X0, X1, [SP], #16
 +    ERET                       @ Return from exception
 +</code>
 +</codeblock>
 +
  
en/multiasm/paarm/chapter_5_7.1764843563.txt.gz · Last modified: 2025/12/04 10:19 by eriks.klavins
CC Attribution-Share Alike 4.0 International
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0