μT-Kernel for Raspberry Pi おぼえがき(3)
IRQ ハンドラ
ARM の割込み(昔からの TRON の分類で言う「EIT の I」)は、コアでは外部の割込み要因の識別などをおこなったりせず、単一のハンドラを呼ぶようになっている。
AT91 では外部の割込みコントローラを使用しているのでハンドラのコードは簡単だが、Raspberry Pi はソフトウェアで処理しなければならないため、コードが多くなっている。
やはり kernel/sysdepend/device/app_raspib/icrt0.S の、最後に部分にコードがある。
.global knl_irq_handler knl_irq_handler: sub lr, lr, #4 stmfd sp!, {lr} /* sp-> lr_xxx */ stmfd sp!, {ip} /* sp-> ip, lr_xxx */ mrs ip, spsr stmfd sp!, {ip} /* sp-> spsr_xxx, ip, lr_xxx */ stmfd sp!, {r3} /* sp-> r3, spsr_xxx, ip, lr_xxx */ /* * based on Broadcom BCM2835 Peripherals datasheet p. 111 */ #define BCM2708_PERI_BASE 0x20000000 #define BCM2708_ARM_BASE (BCM2708_PERI_BASE + 0xB000) #define BCM2708_ARMCTRL_IC_BASE (BCM2708_ARM_BASE + 0x200) #define BCM2708_ARM_IRQ_PEND0 (BCM2708_ARMCTRL_IC_BASE + 0x0) #define BCM2708_ARM_IRQ_PEND1 (BCM2708_ARMCTRL_IC_BASE + 0x4) #define BCM2708_ARM_IRQ_PEND2 (BCM2708_ARMCTRL_IC_BASE + 0x8) #define BCM2708_ARM_IRQ0_BASE 64 #define BCM2708_ARM_IRQ1_BASE 0 #define BCM2708_ARM_IRQ2_BASE 32 .macro get_irqnr_preamble base, tmp ldr \base, =ARMCTRL_IC_BASE .endm .macro get_irqnr_and_base irqnr, irqstat, base, tmp ldr \irqstat, [\base, #(ARM_IRQ_PEND0 - ARMCTRL_IC_BASE)] @ get masked status mov \irqnr, #(ARM_IRQ0_BASE + 31) and \tmp, \irqstat, #0x300 @ save bits 8 and 9 bics \irqstat, \irqstat, #0x300 @ clear bits 8 and 9, and test bne 1010f tst \tmp, #0x100 ldrne \irqstat, [\base, #(ARM_IRQ_PEND1 - ARMCTRL_IC_BASE)] movne \irqnr, #(ARM_IRQ1_BASE + 31) @ Mask out the interrupts also present in PEND0 - see SW-5809 bicne \irqstat, #((1<<7) | (1<<9) | (1<<10)) bicne \irqstat, #((1<<18) | (1<<19)) bne 1010f tst \tmp, #0x200 ldrne \irqstat, [\base, #(ARM_IRQ_PEND2 - ARMCTRL_IC_BASE)] movne \irqnr, #(ARM_IRQ2_BASE + 31) @ Mask out the interrupts also present in PEND0 - see SW-5809 bicne \irqstat, #((1<<21) | (1<<22) | (1<<23) | (1<<24) | (1<<25)) bicne \irqstat, #((1<<30)) beq 1020f 1010: @ For non-zero x, LSB(x) = 31 - CLZ(x^(x-1)) @ N.B. CLZ is an ARM5 instruction. sub \tmp, \irqstat, #1 eor \irqstat, \irqstat, \tmp clz \tmp, \irqstat sub \irqnr, \tmp 1020: @ EQ will be set if no irqs pending .endm stmfd sp!, {r0-r1} get_irqnr_preamble r0, r1 get_irqnr_and_base lr, r3, r0, r1 ldmfd sp!, {r0-r1} ldr ip, =Csym(knl_intvec) /* exception vector table */ add ip, ip, lr, LSL #2 /* ip := &vector[IRQ No.] */ ldr r3, [ip] /* r3 := vector[IRQ No.] */ mov lr, pc bx r3
一旦マクロを定義してから使っているが、コメントにもある通りデータシートに示されているコードである。knl_intvec は機種共通部の kernel/sysdepend/device/app_raspib/devinit.c に実体がある。定数の定義については Raspberry Pi 用 Linux のソースコードの linux/arch/arm/mach-bcm2708/include/mach/platform.h も参考にした。