ICC_IAR1_EL1는 'Interrupt Controller Interrupt Acknowledge Register 1'의 약자로 인터럽트에 대한 Acknowledge를 수행하는 레지스터입니다.
MRS 명령어를 통해 ICC_IAR1_EL1 레지스터의 값을 읽기만 하면 CPU Interface에 ACK를 보냅니다. 이를 통해 "CPI Interface에게 인터럽트를 확인했다"라고 알립니다. ICC_IAR1_EL1 레지스터를 읽으면 ‘Group 1’에서 관리하는 인터럽트 아이디(Interrupt ID)를 반환합니다.
인터럽트 아이디(Interrupt ID)는 인터럽트를 나타내는 식별자이며 이 값을 저장한 다음에 ICC_EOIR1_EL1 레지스터에게 다시 써줍니다.
ICC_IAR1_EL1 레지스터에 대한 비트 맵은 다음 그림에서 확인할 수 있습니다.
그림 16.16 ICC_IAR1_EL1 레지스터의 비트 맵
그림과 같이 ICC_IAR1_EL1 레지스터의 비트 맵은 InterruptID 비트로 구성돼 있습니다.
InterruptID, bits [23:0]
InterruptID는 ‘Group 1’ 인터럽트에 대한 인터럽트 아이디를 뜻합니다. 이 값을 읽기만 하면 "CPU Interface'에게 인터럽트를 확인했다"는 ACK를 보냅니다.
나머지 Bits [31:24]은 Reserved된 영역으로 사용되지는 않습니다.
InterruptID 비트, ICC_IAR1_EL1 레지스터는 언제 접근할까?
Arm 코어는 IRQ 인터럽트가 유발되면 이를 익셉션의 한 종류로 처리합니다. 그래서 어떤 명령어를 실행다가 인터럽트를 감지하면 ‘IRQ 인터럽트’ 익셉션으로 정의된 익셉션 벡터 주소로 프로그램 카운터를 브랜치합니다. 특정 주소에 존재하는 명령어를 익셉션 핸들러라고 하는데 익셉션 핸들러에서 먼저 인터럽트 서비스 루틴으로 분기합니다.
인터럽트 서비스 루틴에서 가장 먼저 어떤 처리를 할까요? 바로 ICC_IAR1_EL1 레지스터를 읽습니다.
이어서 리눅스 커널에서 ICC_IAR1_EL1 레지스터를 읽어 처리하는 코드를 분석하면서 더 자세히 알아 봅시다.
https://elixir.bootlin.com/linux/v5.4.61/source/drivers/irqchip/irq-gic-v3.c
01 static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
02 {
03 u32 irqnr;
04
05 irqnr = gic_read_iar();
05번째 줄을 보면 gic_read_iar() 함수를 호출한 결과를 irqnr 지역 변수에 저장합니다. 여기서 irqnr는 ‘Group 1’ 인터럽트 그룹에서 관리되는 인터럽트 아이디 정보(정수 값)를 담고 있습니다.
이 내용은 gic_read_iar() 함수 구현부를 보면 더 자세히 알 수 있습니다.
https://elixir.bootlin.com/linux/v5.4.61/source/arch/arm/include/asm/arch_gicv3.h
01 static inline u32 gic_read_iar(void)
02 {
03 u32 irqstat = read_sysreg(ICC_IAR1);
04
05 dsb(sy);
06
07 return irqstat;
08 }
03번째 줄을 보면 ICC_IAR1_EL1 시스템 레지스터를 읽어 로컬 변수인 irqstat에 저장합니다. 그 다음 07번째 줄에서 ICC_IAR1_EL1 시스템 레지스터의 값을 담고 있는 irqstat을 반환합니다.



최근 덧글