Lab3: ARM Exception and Interrupt

Exception and Interrupt

Reference: Exception types

造成程式暫停並切換 context 的事件稱為 exception (其他處理器架構可能將其描述為 interrupt),可分為:

  • synchronous exception
  • asynchronous exception

Synchronous Exception

由指令所引起,或與指令有關。原因如下:

  • invalid instruction:在不適當的 exception level 執行的指令或該指令被禁用
  • 由 memory access 引起:misaligned address 或 MMU 檢查失敗
  • 特殊指令: svc, hvc, smc 所引起,用來實作 system call

System call

Fundamentals of ARMv8Privilege and Exception levels

In AArch64, the Exception level determines the level of privilege, in a similar way to the privilege levels defined in ARMv7. The Exception level determines the privilege level, so execution at ELn corresponds to privilege PLn.

The name of the System register indicates the lowest Exception level from which that register can be accessed. For instance, TTBR0_EL1 is the register that holds the base address of the translation table used by EL0 and EL1. This register cannot be accessed from EL0, and any attempt to do so will cause an exception to be generated.

操作 system register 一定要在至少 EL1 層級進行操作,作法是在 EL0 會透過 svc 實作的 System calls 切換到 EL1 進行操作。

svc 指令的 imm16 會傳遞給 esr 的 ISS 欄位,因此可以傳遞不同參數來實現各種 system call。

Asynchronous Exception

與指令無關,由外部所引起,無法確定何時處理,只要求在有限時間內發生。exception 可以處在 pending state 等待被處理。Asynchronous exception又被稱為 interrupt。

In the Armv8-A and Armv9-A architecture, interrupts are a type of externally generated exception.

asynchronous exception 有幾種類型:

  • Physical interrupts
    • SError (System error)
    • IRQ
    • FIQ
  • Virtual Interrupts
    • vSError (Virtual System Error)
    • vIRQ (Virtual IRQ)
    • vFIQ (Virtual FIQ)

Interrupt (Asynchronous Exception)

Ref: QA7_rev3.4

ARM interrupt 分兩種

  • Core related interrupts
  • Core un-related interrupts

Core related interrupt 是與 core 綁在一起的 interrupt,大多數的 interrupt 來自 core 自身,且每個 core 分配到 4 個 mailbox。core related interrupts 有

  • Four timer interrupt (64-bit timer)
  • One performance monitor interrupts
  • Four mailbox interrupts

每個 interrupt 可以選擇送到該 core 的 IRQ 或是 FIQ pin。除了 mailbox 只有全部 enable/disable 的選擇,另外初始化時所有 bit 設置為 0,所以沒有 interrupt 是 enabled。

  • Mailbox

    mailbox 由兩個 32bit register 組成

    • write-bits-high-to-set register (write only)
    • write-bits-high-to-clear register (write/read)

    mailbox 0-3 分配給 core 0,mailbox 4-7 分配到 4-7,剩下兩個 core 以此類推。

Core un-related interrupt 可送到 4 個 core 的任一個、interrupt 或是 fast-interrupt。core un-related interrupt 有:

  • GPU IRQ (As generated by the ARM Control logic)
  • GPU FIQ (As generated by the ARM Control logic)
  • Local timer interrupt
  • AXI error
  • (unused: Fifteen local peripheral interrupts)

重置後所有 bit 為 0,因此所有 interrupt 往 core 0 送。注意到這些 interrupt 沒有所謂的 ‘disable’ code,而是在產生中斷的來源處有 enable/disable bit。

ARM Peripheral Interrupt

Ref: page 109, BCM2835

UART, system timer 被歸集並送到 arm controller,並被視為 GPU IRQ。

ARM peripherals interrupts table

實際上有 4 個 timer,timer 0 & timer 2 被 GPU 所使用,所以表上剩下 timer 1 和 timer 3。

Basic pending register

對於每個 interrupt 來源,都會有一個 interrupt enable bit 和 interrupt pending bit。

Basic pending register 會包含 ARM specific interrupts、一些特別的 GPU IRQs 、代表 GPU IRQ 32-63 和 VC IRQs 0-31 的 GPU pend 1 和 GPU pend 0

Registers

IRQ pending 1 和 IRQ pending 2 應該稱為 GPU pending 1 register 和 GPU pending 2 register,掌管從 GPU 方面的 interrupt。

在 basic pending register 內的 8,9 bit 只有在 GPU 0~63 interrupt 一些沒有連接到 basic pending register 的 interrupt 發生時才會設置為 1。

而只有在 enable bit 設置的情況下,pending bit 才會被設置。

來看看 Basic pending register 長什麼樣子,再上去是連接部份 GPU IRQ。

Interrupt handler

Reference: 3.1: Interrupts

下方為一個 interrupt handler 的雛型,用來處理 timer interrupt。事實上多個中斷可能同時發生,因此,在 OS 內通常以迴圈將其包覆起來。

1
2
3
4
5
6
7
8
9
10
11
void handle_irq(void)
{
unsigned int irq = get32(IRQ_PENDING_1);
switch (irq) {
case (SYSTEM_TIMER_IRQ_1):
handle_timer_irq();
break;
default:
printf("Unknown pending irq: %x\r\n", irq);
}
}

Masking/unmasking interrupts

masking 代表禁用中斷,unmasking 代表啟用。

在 PSTATE 內的欄位 D, A, I, F 分別代表以下意義

  • D Masks debug exceptions. These are a special type of synchronous exceptions. For obvious reasons, it is not possible to mask all synchronous exceptions, but it is convenient to have a separate flag that can mask debug exceptions.
  • A Masks SErrors. It is called A because SErrors sometimes are called asynchronous aborts.
  • I Masks IRQs
  • F Masks FIQs

我們希望進入 IRQ handler 前的 kernel_entry 保存完狀態後馬上啟用中斷,防止 IRQ handler 耗時太久。透過 daifclrdaifset 指令達成:

1
2
3
4
5
6
7
8
9
.globl enable_irq
enable_irq:
msr daifclr, #2
ret

.globl disable_irq
disable_irq:
msr daifset, #2
ret

或以 extended asm 實作,i 表示 immediate integer

asm statements that have no output operands and asm goto statements, are implicitly volatile.

1
2
3
#define DAIF_IRQ_BIT (1<<1) /* IRQ mask bit */

__asm__ ("msr DAIFSet, %0" : : "i" (DAIF_IRQ_BIT) : "memory");

Reference

  1. 3.1: Interrupts
  2. 第三十二期-ARM Linux内核的中断(2)
  3. armv8-bare-metal/aarch64.c
  4. 6.47.3.1 Simple Constraints