Interrupts -1- (Interrupt Controller)

<kernel v5.4>

아키텍처별 인터럽트 컨트롤러 H/W 구성

  • 아키텍처마다 인터럽트 컨트롤러 구성이 다른데 간략히 아래 그림과 같이 다른 처리 방법을 갖는 것을 이해하자
    • x86 with PIC
      • 초기 CPU를 하나만 사용하는 X86 시스템에서는 8259 PIC(Programmable Interrupt Controller)를 하나 이상 사용하여 구성하였다.
    • x86 with APIC
      • x86에서도 SMP 구성을 하면서 APIC(Advanced Programmble Interrupt Controller)를 두 개의 칩에 나누어 하나는 cpu가 있는 코어 프로세서칩에 사용하고 I/O를 담당하는 south 칩셋에 APIC를 구성하였다.
    • ARM SoC
      • ARM은 무척 구성이 다양하다. SoC를 제작하는 회사마다 소유한 인터럽트 컨트롤러 로직을 SoC의 IP 블럭으로 구성하여 사용하는데 점차적으로 ARM사가 디자인한 GIC(Generic Interrupt Controller)를 사용하게 되는 경향이 있다.

 

Single & Hierarchical 구성

다음 그림과 같이 2 개 이상의 인터럽트 컨트롤러들을 연결하여 구성할 수도 있다.

 

ARM에 사용되는 인터럽트 컨트롤러들

arm64 시스템에서 인터럽트 컨트롤러로 GIC v1 ~ GIC v4가 주로 사용되고 있다. 그리고 arm32 시스템에선 각사에서 디자인한 다양한 인터럽트 컨트롤러들이 채택되어 사용되고 있음을 알 수 있다.

  • ARM社 design
    • gic
      • arm,pl390
      • gic-400
      • arm11mp-gic
      • arm1176jzf-devchip-gic
      • cortex-a15-gic
      • cortex-a9-gic
      • cortex-a7-gic
      • qcom,msm-8660-qgic
      • qcom,msm-qgic2
    • gic-v2m
      • arm,gic-v2m-frame
    • gic-v3
      • arm,gic-v3
      • gic-v3-its
        arm,gic-v3-its
    • nvic
      • arm,armv7m-nvic
    • vic
      • arm,pl190-vic
      • arm,pl192-vic
      • arm,versatile-vic
  • Broadcom社 design
    • bcm2835-ic
      • rpi는 ARM의 GIC를 사용하지 않고 broadcom 인터럽트 컨트롤러를 사용한다.
        • 커널 소스 참고: https://github.com/raspberrypi/linux
        • 2가지 구현
          • architecture specific 인터럽트 핸들러로 구현 (머신 디스크립터 정의)
            • arch/arm/mach-bcm2708/bcm2708.c
          • DTB 기반 irq-domain 인터럽트 핸들러로 구현
            • drivers/irqchip/irq-bcm2835.c
    • bcm2836-ic
      • rpi2 역시 broadcom 사의 인터럽트 컨트롤러를 사용하는데 4개의 armv7 코어를 사용하면서 2835에 비해 더 복잡해졌다.
        • 커널 소스 참고: https://github.com/raspberrypi/linux
        • 2가지 구현 (커널 v4.4 이상)
          • architecture specific 인터럽트 핸들러로 구현 (머신 디스크립터 정의)
            • arch/arm/mach-bcm2709/bcm2709.c
          • DTB 기반 per-cpu irq-domain 인터럽트 핸들러로 구현
            • drivers/irqchip/irq-bcm2836.c
  • 그 외 제조사 custom 디자인 IP 블럭
    • exynos-combiner
    • armada-mpic
    • atmel-aic
    • hip04
    • keystone
    • omap-intc
    • xtensa-pic
    • (수십 종류라 생략…)

 


GIC(Generic Interrupt Controller)

GIC 버전별 주요 특징

  • GIC v1
    • 8개까지 PE 지원
    • 1020개 까지 인터럽트 소스 처리 가능
    • Security extension 지원
    • ARM Cortex-A5, A9, R7 등에서 사용
  • GIC v2
    • v1 기능을 모두 포함
    • 가상화(virtualization) 기능 추가
    • ARM Cortex-A7, A15, A53, A57, … 등에서 사용
    • GIC v2m은 MSI(Message based Interrupt) 기능을 추가한 모델
  • GIC v3
    • v2 기능을 모두 포함
    • 클러스터당 8개 PE씩 최대 128개 PE 지원
    • 1020개 초과 인터럽트 소스 처리 가능
    • 시그널(v1 및 v2에서 사용하는 legacy) 방식 뿐만 아니라 MSI 방식 지원
      • MSI는 SPI와 LPI에서 사용할 수 있다.
    • non-secure와 secure 그룹에 따라 인터럽트 처리를 분리하는 진화된 security 기능 추가
    • SPI, PPI & SGI 이외에 LPI(Locality specific Peripheral Interrupt) 지원
    • affinity routing 기능 지원
    • ARM Cortex-A53, A57, A72, … 등에서 사용
  • GICv4
    • v3 기능을 모두 포함
    • 가상 인터럽트의 직접 주입(injection) 기능
    • ARM Cortex-A53, A57, A72, … 등에서 사용

 

GIC 블럭 다이어그램

다음 그림은 GIC v1(390), v2(400), v3(500)에 대한 간단한 내부 블록 다이어그램이다.

 


GIC v2

security extension 지원

GIC v1부터 security extension이 있는 GIC는 인터럽트마다 secure 및 non-secure 지정을 할 수 있다. (칩 구현에 따라 security extension 지원 여부가 결정된다)

  • secure 인터럽트
    • irq 및 fiq를 secure 펌웨어에 전달할 수 있다.
    • irq보다 더 높은 우선 순위인 fiq는 cpu에서 기존 irq를 처리하는 도중에도 preemption되어 fiq를 처리할 수 있다.
  • non-secure 인터럽트
    • irq만 non-secure 커널에 전달할 수 있다.

 

IRQ vs FIQ

ARM 아키텍처는 IRQ와 FIQ 두 가지 인터럽트 소스를 위해 물리적인 각각의 시그널 라인을 사용한다. 인터럽트가 발생되면 ARM 아키텍처는 비동기(Async) Exception에 해당하는 각각의 벡터로 점프된다. FIQ는 IRQ에 비해 더 빠른 처리가 필요할 때 사용되지만 매우 많은 제약을 가지고 있다. 이러한 특징을 조금 더 알아본다.

  • IRQ 보다 더 높은 우선 순위를 FIQ에 부여하기 때문에 cpu가 IRQ 처리 중에도 preemption되어 FIQ에 따른 ISR을 우선 처리할 수 있다.
  • 32비트 ARM 아키텍처
    • FIQ용 벡터 엔트리가 가장 마지막에 위치해서 jump 코드가 아닌 필요한 코드를 곧바로 사용할 수 있어, 수 사이클이라도 줄일 수 있다.
    • IRQ와 다르게 2 개 이상의 워드를 처리하는 긴 명령 사이클 중간에도 인터럽트된다.
    • IRQ 전환 시 저장(Store)하지 않고 즉시 사용 가능한 뱅크된 레지스터는 r13과 r14 두 개를 사용한다. 그러나 FIQ 전환시에는 이보다 더 많은 r8~r14까지 총 7개를 사용할 수 있고 이 중 link register로 돌아가야 할 주소를 담아 사용하는 r14를 제외하면 6개를 사용할 수 있다.
      • 보통 DRAM access를 최소화(캐시된 DRAM access)하고 6개의 레지스터만을 사용하여 FIQ에 대한 ISR을 수행하므로 대단히 빠른 처리를 할 수 있다.
        • 캐시되지 않은 DRAM access를 ISR 내부에서 자주하는 경우 캐시되지 않은 한 번의 DRAM access당 수십~수백 사이클이 소요되므로 FIQ를 사용하는 의미가 거의 없어진다.
      • Exception 레벨 전환에 따른 Store/Restore해야 할 레지스터의 수가 더 적어 빠르게 처리할 수 있다. (context복원)
        • 레벨 전환에 Store/Restore할 레지스터가 더 적어 빠르다 하더라도 보통 FIQ에서는 IRQ에서 ISR 구현하는 것처럼 레지스터들을 백업하고 복구하는 루틴을 사용하지 않는다. 이는 매우 현명하지 않은 사용예일 뿐이다.
  • 64비트 ARM 아키텍처
    • 32비트 ARM과 다르게 뱅크 레지스터를 사용하지 않으므로 사용할 레지스터들은 Store/Release 루틴을 사용하여야 한다.
      • SRAM 등의 처리빠른 전용 메모리 장치를 사용하지 않는 경우 리눅스 커널에선 더욱 사용할 필요가 없다
  • FIQ 루틴은 IRQ보다 수십 나노 세컨드 또는 수십 사이클을 더 빠르게 처리하는 장점을 활용하기 위해 보통 수 개 이하의 입력 소스만 FIQ로 처리하도록 어셈블리 언어를 직접 사용한다.
    • IRQ 같이 여러 인터럽트 소스를 FIQ로 처리하려면 irq domain 등 분기 처리루틴이 추가되면서 많은 소요 시간이 추가되므로 FIQ를 사용하는 장점이 없어진다.
  • 특별한 사용자 변경 없이는 ARM 리눅스 커널은 IRQ를 처리하고, 시큐어 펌웨어에서 FIQ를 처리한다.
    • 리눅스 커널에서는 여러 인터럽트 소스를 사용하므로 대부분 FIQ를 사용하지 않는다.
    • latency 및 ISR의 처리 시간 단축 문제로 IRQ에서 처리하기 힘든 특정 ISR에서만 FIQ를 사용하도록 해야 한다.
  • 빠른 access 성능을 갖춘 전용 SRAM 등이 있는 하드웨어 환경인 경우 FIQ를 사용하면 레지스터들의 백업과 복구를 DRAM이 아닌 이러한 SRAM 등을 사용하여 처리하면 위의 처리 성능을 대폭 줄일 수 있다.
  • 참고: FIQ Handlers in the ARM Linux Kernel | Bootlin

 

인터럽트 전송 타입

디바이스에서 발생한 인터럽트를 아래 두 가지 형태로 신호 또는 메시지로 GIC에 전달한다. GIC는 관련 cpu에 irq 또는 fiq 형태로 시그널을 전달한다.

  • Legacy Interrupt
    • 시그널 기반 전송 인터럽트는 디바이스가 인터럽트를 위한 별도의 인터럽트 시그널 라인을 통해 직접 GIC에 시그널(1과 0의 표현)로 전달한다.
  • MSI(Message based Interrupt)
    • 메시지 기반 전송 인터럽트는 디바이스가  인터럽트를 위한 별도의 회로를 사용하지 않고 데이터 통신을 수행하는 interconnect 버스(arm 및 arm64에서는 AXI 버스)를 통해 메시지 형태로 GIC에 전달한다.
    • 장점
      • Legacy 인터럽트에 비해 별도의 라인을 사용하지 않아 인터럽트에 사용하는 많은 라인들을 줄일 수 있다.
      • Legacy  인터럽트는 1~4개의 인터럽트를 사용하지만 MSI 방식에서는 디바이스마다 더 많은 인터럽트를 정의하여 사용할 수 있다.
    • 단점
      • interconnect에 직접 연결되는 디바이스만 가능한다. 대표적으로 PCIe 컨트롤러가 있다.
        • PCIe 버스에 연결된 PCIe 디바이스의 경우 PCIe 버스를 경유하고 AXI 버스를 통해 GIC에 인터럽트가 전달된다.
      • interconnect 버스를 통해야 하므로 추가적인 지연(latency)이 발생한다.
        • ITS를 사용하는 경우 DRAM 테이블을 사용하므로 더 큰 지연이 발생하지만, 높은 우선 순위 및 빈도 높은 인터럽트등은 캐시되어 사용되므로 지연을 최대한 줄일 수 있다.

 

다음 그림은 Signal 기반과 Message 기반의 인터럽트 전송 방법을 비교하여 보여준다.

 

다음 그림은 Signal 기반과 Message 기반이 실제 PCIe 디바이스에 구현된 사례를 보여준다.

  • 현재 PCIe 규격은 legacy 인터럽트와 MSI 둘 다 지원한다.

 

GIC 인터럽트 상태

SGI, PPI, SPI 들은 각각의 인터럽트에 대해 아래와 같이 4개의 상태(state)로 구분할 수 있다. 단 LPI는 inactive와 pending 상태로만 구분된다.

  • Inactive
    • 인터럽트가 발생하지 않은 상태
  • Pending
    • 하드웨어 또는 소프트웨어에서 인터럽트가 발생하였으나 타깃 프로세스에게 전달되지 않음
    • level sensitive 트리거 모드에서는 인터럽트가 발생하는 동안 pending 상태가 지속된다.
  • Active
    • 인터럽트가 발생하여 프로세스에게 전달되었고 프로세스가 ack하여 인터럽트를 처리 중이며 완료되지 않은 상태
  • Active & Pending
    • 인터럽트가 발생하여 프로세스에게 전달되었고, 동일한 인터럽트가 발생하여 보류중인 상태

 

GIC 인터럽트 타입

인터럽트 타입은 다음과 같다. (INTID(인터럽트 ID) 1020~1022번은 특수 목적으로 예약되었다. 예: 1023=no pending interrupt)

    • SGIs(Software Generated Interrupts)
      • 각 core에 전용으로 사용되며, 외부 인터럽트가 아니라 소프트웨어에서 발생시킬 수 있는 내부 IRQ 들로 0 ~ 15 까지의 id를 사용한다.
      • INTID0~7번은 non-secure, INTID8~15번은 secure로 사용하도록 arm사가 적극 권장한다.
    • PPIs(Private Peripherals Interrupts)
      • 각 core에 전용으로 사용될 수 있는 IRQ 들로 INTID16 ~ 31 까지 사용한다.
      • GIC에서 사용하는 클럭과 연동된다.
    • SPIs(Shared Peripherals Interrupts)
      • core에 공용으로 사용될 수 있는 IRQ 들로 INTID32 ~ 1019까지 사용한다.
      • GIC에서 사용하는 클럭과 연동된다.
    • LPI(Locality-specific Peripheral Interrupt)
      • GICv3 이상에서 새롭게 지원하는 타입의 인터럽트로 legacy 시그널 형태는 지원하지 않고 메시지 방식인 MSI 형태만 지원하며 INTID8192 이상을 사용한다.
      • non-secure group 1 인터럽트로만 사용되며 edge trigger 방식으로 동작한다.
      • 지정된 PE에 연동된 redistributtor로 전달되지만, 옵션 장치인 ITS(Interrupt Translation Service)를 사용하면, 특정 PE의 redistributor로 변환하여 라우팅 서비스를 사용할 수 있다.

 

ARM 권장 PPI의 INTIDs

다음은 ARM사에서 권장하는 PPI의 INTID들이다. 그럼에도 불구하고 일부 arm64 SoC 제작사에서는 아래와 다른 번호를 가진 시스템도 있다.

  • 30 : EL1 physical timer
  • 29 : EL3 physical timer
  • 28: Non-Secure EL2 virtual timer (ARMv8.1)
  • 27: EL1 Virtual timer
  • 26: Non-Secure EL2 physical timer
  • 25: Virtual CPU Interface Maintenence interrupt
  • 24: Cross Trigger Interface interrupt
  • 23: Performance Monitor Counter Overflow interrupt
  • 22: Debug Communcations Channel interrupt
  • 20: Secure EL2 Physical Timer (ARMv8.4)
  • 19: Secure EL2 Virtual Timer (ARMv8.4)

 

인터럽트 트리거

인터럽트 트리거 모드는 다음과 같이 두가지 타입이 있고, high 또는 low 신호 방향 중 하나를 가진다.

  • Level Sensitive
  • Edge Trigger

 

다음 그림은 high activate 시그널로 동작하는 두 가지 인터럽트 트리거 모드에 대한 인터럽트 상태 변화를 보여준다.

 

우선 순위 (Priority)

인터럽트별로 0~255까지 우선 순위를 줄 수 있다.

  • 0=가장 높은 우선 순위
  • 255=가장 낮은 우선 순위

 

우선 순위 Filter

  • 설정된 우선 순위 filter 값보다 높은 우선 순위의 인터럽트를 전달하고, 그 외는 block 한다.
    • 설정된 우선 순위 값보다 작은 숫자만 인터럽트를 전달한다.
    • 예) priority filter = 0xf0인 경우
      • 우선 순위 값이 0x00 ~ 0xef 범위인 인터럽트만 허용하고, 나머지는 허용하지 않는다.

 

Prioritization

Preemption Interrupt

  • Binary Point
    • 3개의 비트를 사용한 0~7의 값으로 각 하드웨어 인터럽트에 설정된 priority 값을 두 그룹으로 분리한다.
    • 분리한 두 개의 그룹
      • Group Priority
        • irq preemption: fast interrupt 처리가 가능하도록 현재 처리하고 있는 인터럽트가 있다하더라도 더 높은 우선 순위의 인터럽트 발생 시  먼저 처리하도록 한다.
      • Sub Priority
        • 현재 처리하고 있는 인터럽트의 우선 순위보다 더 높은 우선 순위의 인터럽트 발생 시 먼저 처리하지 않는다.
    • 리눅스 커널은 GIC v3 드라이버에서 Binary Point 값으로 0을 기록하여 리셋시켜 사용한다. (리셋 후 값은 칩 구현에 따라 다르다)

 

다음 그림은 인터럽트 그루핑을 보여준다.

 

Priority Leveling

GIC는 칩 구현에 따라 security extension을 사용하는 경우 최소 32~256 레벨을 사용할 수 있다. (GIC v3 이상에서  two security states에서는 32~256단계를 사용하고, single security states에서는 16~256단계를 사용한다.)

  • GICD_IPRIORITYRn 레지스터는 인터럽트 n번의 우선순위를 기록하는데 사용한다.
    • GICD_IPRIORITYRn에 설정된 우선 순위는 GIC가 사용하는 단계에 맞춰 mask되어 사용된다.
    • 예) 칩이 32단계로 구현된 경우 0xff를 기록하더라도 mask 값 0xf8과 and하여 뒤의 3 비트는 무시되어 0으로 기록된다.
  • GIC v3를 사용하는 경우 칩이 사용중인 레벨은 ICC_CTLR_EL1.pribits 값을 읽어 알아올 수 있다. (Read Only)
    • 수식 = 2^(N+1) 단계(레벨)
    • 3=16 단계
    • 4=32 단계
    • 5=64 단계
    • 6=128 단계
    • 7=256 단계
  • 리눅스 커널은 모든 irq에 대해 한 가지 우선 순위를 사용하여 preemption이 발생하지 않는다. 단 최근 추가된 Pesudo-NMI 기능을 지원하는 경우 nmi를 사용하는 인터럽트는 더 높은 우선 순위로 설정한다.

 

Secure/Non-Secure에서 priority 값 변환

GIC v1~v2에서 security extension을 사용하는 경우 group 1 인터럽트는 non-secure로 사용되고, group 0 인터럽트는 secure로 사용된다.(참고로 GIC v3부터는 group 1 인터럽트도 non-secure와 secure로 분리할 수 있다) 그리고 group 1 인터럽트가 group 0 인터럽트를 선점하지 않도록 ARM 제작사는 다음 내용을 강력히 권장하고 있다.

  • group 1 인터럽트는 0x80 ~ 0xff 범위를 사용한다.
  • group 0 인터럽트는 0x00 ~ 0x7f 범위를 사용한다.
  • group 0 인터럽트는 group 1의 모든 인터럽트들보다 항상 우선 순위를 더 높게 강제한다.
    • 이는 priority 비트들 중 최상위 bit7에 따라 group 0와 group 1이 나뉘는 것을 의미한다.
      • bit7=0 -> group 0
      • bit7=1 -> group 1

 

secure states에 따라 다음과 같은 규칙을 갖는다.

  • secure states
    • group 0에 해당하는 0x00~0x7f 우선 순위와 group 1에 해당하는 0x80~0xff 우선 순위 모두 설정할 수 있고 그 값을 그대로 읽을 수 있다.
  • non-secure states
    • group 1에 해당하는 우선 순위만 기록하고 읽을 수 있다. (group 0에 해당하는 우선 순위는 접근할 수 없다.)
    • non-secure states에서는 secure states에서 사용하는 우선 순위 값과 다르게 표현된다. secure states에서 사용하는 값을 좌측으로 1 시프트한 값을 사용한다.
    • 반대로 non-secure states에서 기록한 값은 secure states 또는 distributor 입장에서 우측으로 1 시프트하고 bit7을 1로 설정한 값을 사용한다.

 

다음 그림과 같이 non-secure에서 사용하는 priority 값과 secure states(distributor와 동일)에서 priority 값은 변환되는 관계를 보여준다.

  • non-secure로 동작하는 리눅스 커널에서 특정 인터럽트의 우선 순위 값을 0x02로 설정하는 경우, GIC의 distributor는 이를 0x81 우선 순위로 인식하여 사용하는 것을 알 수 있다.

 

Virtualization 지원

다음 그림은 하이퍼바이저가 수신한 인터럽트를 Guest OS에 가상 인터럽트로 전달하는 과정을 보여준다.

 

GIC v2 주요 레지스터들

  • GIC는 CPU Interface 레지스터들과 Distributor 레지스트들을 통해 제어한다.
  • CPU Interface 레지스터
    • core로 전달된 group 1 irq들 전체를 한꺼번에 통제한다.
    • core로 전달될 irq들에 대해 설정한 priority mask 값을 사용하여 통과시킨다.
      • priority 레벨링 (16 ~ 256 단계)
  • Distributor 레지스터
    • secure 상태에 따라 group 0/1의 방향을 선택하게 한다. (irq/fiq)
      • non-secure extension 사용시 group은 항상 fiq로 forward된다.
      • secure extension 사용시 group-0은 fiq, group-1은 irq로 forward 된다.
    • IRQ 별로 forward를 설정(Set-enable) 및 클리어(Set-Clear) 요청할 수 있다.
    • IRQ 별로 priority를 설정할 수 있다.
    • IRQ 별로 개별 cpu interface로의 전달여부를 비트마스크로 설정할 수 있다. (1=forward, 0=drop)
    • PPI & SPI에 해당하는 하드웨어 IRQ 별로 인터럽트 트리거 타입을 설정할 수 있다.
      • 0=level sensitive (전압의 레벨이 지속되는 동안)
      • 1=edge trigger (high나 low로 바뀌는 순간만)
        • SGI는 edge 트리거를 사용한다.

 

GIC v2의 AArch64 시스템용 레지스터들은 다음과 같은 그룹으로 나눌 수 있다. (AArch32는 생략)

  • 메모리 맵드 레지스터들
    • GICC, CPU Interface Registers
    • GICD, Distributor Registers
    • GICH, Virtual CPU Interface Control Registers
      • 생략
    • GICV, Virtual CPU Interface Registers
      • 생략

 

1) GICC, CPU Interface Registers

  • GICC_CTLR (CPU Interface Control Register)
    • secure mode 별로 레지스터가 bank 되어 사용된다.
    • Enable
      • group 1 인터럽트의 forward 여부 (0=disable, 1=enable)
    • EnableGrp1
      • group 1 인터럽트의 forward 여부 (0=disable, 1=enable)
    • FIQBypDisGrp1 & IRQBypDisGrp1
      • cpu 인터페이스 비활성화시 PE에 인터럽트 바이패스 Disable 여부 (0=bypass, 1=bypass disable)
    • EOImodeNS
      • EOI 모드 운영 방법 선택
        • 0=GICC_EOIR & GICC_AEOIR을 사용하여 priority drop 기능과 비활성화 기능 지원
        • 1=GICC_EOIR & GICC_AEOIR을 사용하여 priority drop 기능만 지원, 인터럽트 비활성화 기능은 별도로 GICC_DIR 사용해야 한다.
  • GICC_PMR (Interrupt Priority Mask Register)
    • core로 전달될 irq들에 대해 설정한 priority 마스크 미만만 통과시킨다.
        • 리눅스 커널의 GIC v1~v4 드라이버는 디폴트 값으로 0xf0을 사용한다.
    • 0 값을 기록하는 경우 모든 인터럽트가 전달되지 않는다.
  • GICC_BPR (Binary Point Register)
    • priority 값을 group/sub와 같이 두 그룹으로 나누어 그 중 group에 해당하는 priority를 가진 인터럽트에 대해 preemption interrupt로 분류한다.
      • 리눅스 커널의 경우 GIC v3 부터 이 필드에 0 값을 기록하여 리셋시킨다. 설정되는 값은 구현에 따라 다르다.
  • GICC_IAR  (Interrupt Acknowledge Register)
    • 인터럽트 수신 시 이 레지스터를 읽어 인터럽트 id를 읽어오는 것으로 인터럽트 처리 루틴이 ack 처리되었음을 gic에 알린다.
  • GICC_EOIR  (End of Interrupt Register)
    • ISR(Interrupt Service Routine)에서 인터럽트 처리 완료 시 해당 인터럽트 id를 기록하여 eoi 처리하였음을 gic에 알린다.
  • GICC_RPR (Running Priority Register)
    • 읽기 전용으로 현재 동작하고 있는 인터럽트의 priority 값을 알아온다. idle 상태인 경우는 0xff
    • non-secure에서 읽은 경우 0x80을 mask 하여사용한다.
  • GICC_HPPIR (Highest Priority Pending Interrupt Register)
    • 읽기 전용으로 현재 하드웨어 인터럽트 (PPI&SPI)들 중 pending되고 있는 가장 높은 priority irq 번호와 cpu를 읽어온다.
    • 소프트 인터럽트(SGI)의 경우 cpu 값만 읽어올 수 있다.
  • GICC_IIDR (CPU Interface Identification Register)
    • 읽기 전용으로 GIC 제품 ID, 아키텍처 버전, 리비전, 구현회사 등의 정보를 읽어올 수 있다.
  • GICC_ABPR (Aliased Binary Point Register)
  • GICC_APRn (Active Priorities Register)
  • GICC_AEOIR (Aliased End of Interrupt Register)
  • GICC_AIAR (Aliased Interrupt Acknowledge Register)
  • GICC_AHPPIR (Aliased Highest Priority Pending Interrupt Register)
  • GICC_DIR (Deactivate Interrupt Register)
  • GICC_NSAPRn (Non-Secure Active Priorities Register)

 

2) GICD, Distributor Registers

  • GICD_CTRL (Distributor Control Register)
    • Pending 인터럽트에 대해 CPU interface로 올려보낼지 여부를 통제한다.
    • secure extension을 사용할 때 non-secure 모드에서는 group1에 대해서만 통제할 수 있다.
      • 1=forward enable
    • security extension 사용 시 bank 된다.
  • GICD_TYPER (Interrupt Controller Type Register)
    • 읽기 전용으로 Security Extension을 사용 시 최대 지원 cpu 수와 인터럽트 수 등을 알아내기 위해 사용한다.
      • Lockable SPI
        • 최대 지원 lockable SPI 수
      • SecurityExtn (bit:10)
        • 1=security extension 사용
        • 0=security extension 사용하지 않음
      • CPU Number
        • 최대 지원 CPU 수
      • ITLinesNumber
        • 최대 지원 인터럽트 수
  • GICD_IIDR (Distributor Implementer Identification Register)
    • 읽기 전용으로 GIC implementor 정보를 알아온다.
  • GICD_IGROUPRn (Interrupt Group Registers)
    • secure extension을 사용하는 경우 인터럽트별로 secure group 0와 non-secure group 1을 지정한다.
      • 0=group 0, 1=group 1
    • secure extension을 사용하는 경우 리셋시 0으로(RAS) 읽히며, 모든 인터럽트가 재설정되기 전엔 모두 group 0 상태가된다.
      • SMP 시스템에서 secure extension을 지원하고, non-secure 프로세서들에 대해서는 뱅크된 GICD_IGROUPR0은 group 1 상태로 리셋한다.
    • IRQ #0~31을 위해 첫 레지스트가 cpu별로 bank 되어 사용된다.
  • GICD_ISENABLERn (Interrupt Set-Enable Registers)
    • IRQ 별로 통과(Set-Enable) 여부를 설정할 수 있다.
      • 1=set 요청
    • IRQ #0~31을 위해 첫 레지스트가 cpu별로 bank 되어 사용된다.
  • GICD_ICENABLERn (Interrupt Clear-Enable Registers)
    • IRQ 별로 통제(Clear-Enable) 여부를 설정할 수 있다.
      • 1=clear 요청
    • IRQ #0~31을 위해 첫 레지스트가 cpu별로 bank 되어 사용된다.
  • GICD_ISPENDRn (Interrupt Set PENDing Registers)
    • IRQ 별로 pending 상태를 설정할 수 있다.
      • 1=set 요청
    • IRQ #0~31을 위해 첫 레지스트가 cpu별로 bank 되어 사용된다.
  • GICD_ICPENDRn (Interrupt Clear PENDing Registers)
    • IRQ 별로 pending 상태 해제를 요청할 수 있다.
      • 1=clear 요청
    • IRQ #0~31을 위해 첫 레지스트가 cpu별로 bank 되어 사용된다.
  • GICD_IPRIORITYRn (Interrupt PRIORITY Registers)
    • IRQ 별로 priority를 설정할 수 있다.
      • 0~255 priority 설정
    • IRQ #0~31을 위해 첫 8개의 레지스트가 cpu별로 bank 되어 사용된다.
  • GICD_ITARGETRn (Interrupt processor TARGET Registers)
    • IRQ 별로 개별 cpu interface로의 전달여부를 비트로 마스크 설정할 수 있다.
    • bit0=cpu#0 제어, bit1=cpu#1 제어…
      • 0=disable forward, 1=enable forward
    • IRQ #0~31을 위해 첫 8개의 레지스트가 cpu별로 bank 되어 사용된다.
  • GICD_ICFGRn (Interrupt ConFiGuration Registers)
    • IRQ 별로 인터럽트 트리거 방향을 설정할 수 있다.
      • 0=상향 시 트리거, 1=하향 시 트리거
    • IRQ #160~31을 위해 두 번째 레지스트가 cpu별로 bank 되어 사용된다.
  • GICD_SGIR (Software Generated Interrupt Register)
    • TLF (Target List Filter)
      • 0=white list 제어 방식, CPU Target List에 설정된 cpu로만 forward
      • 1=black list 제어 방식, CPU Target List에 설정된 cpu만 drop
      • 2=위의 ACL 방식 제어를 사용하지 않는다.
      • 3=reserved
    • CPU Target List
      • 0~7개의 cpu bit
    • NSATT (Non-Secure
      • 0=SGI#에 대해 group-0으로 설정된 경우 CPU Target List로 forward
      • 1=SGI#에 대해 group-1로 설정된 경우 CPU Target List로 forward

 

다음 그림은 GICv2 주요 레지스터들에 대해 GICv1 명칭과 비교하여 보여준다.

 


GIC v3

Security States

GIC v2까지 적용되었던 Security Extension 용어를 사용하지 않고, GIC v3 부터는 다음과 같이 두 가지 security states를 가지고 운영한다.

  • Single Security States
    • GIC에서 Secure와 Non-Secure를 나누어 사용하지 않는다.
    • EL0~3 Exception 레벨에 Secure와 Non-Secure 구분하지 않고 인터럽트를 전달한다.
  • Two Security States
    • GIC에서 Secure와 Non-Secure로 나누어 사용된다.
    • EL0~2 Exception 레벨에 Secure와 Non-Secure로 나누어 인터럽트를 전달한다. EL3의 경우는 Secure 상태만 사용한다.
    • 특정 레지스터는 Secure와 Non-Secure에 따라 뱅크되어 운영된다. (같은 이름을 사용하지만 각각 운영된다)

 

인터럽트 라이프 사이클

다음 그림과 같이 각 인터럽트의 발생과 종료에 대한 라이프 사이클을 보여준다.

 

ACK(Acknowledge) 처리 방법

ack 처리는 다음 읽기 전용 레지스터를 읽는 것만으로 완료된다.

  • ICC_IAR0_EL1
  • ICC_IAR1_EL1
  • GICC_IAR
  • GICC_AIAR

 

EOI(End Of Interrupt) 처리 방법

eoi 처리는 다음 쓰기 전용 레지스터를 기록하는 것만으로 완료된다.

  • ICC_EOIR0_EL1
  • ICC_EOIR1_EL1
  • GICC_EOIR
  • GICC_AEOIR

 

deactivation 처리는 다음 쓰기 전용 레지스터를 기록하는 것만으로 완료된다.

  • ICC_DIR_EL1
  • GICC_DIR

 

GIC v3 이상부터 eoi 처리 방법이 다음과 같이 두 개로 나뉜다.

  • priority drop & deactivation 통합 처리
    • GICD_CTLR.EOImode=0 설정 사용
    • eoi 명령 사용 시 priority drop과 deactivation이 자동으로 처리된다.
    • GIC v1 & v2의 경우 eoi 처리 시 priority drop과 deactivation을 둘 다 처리하였다.
  • priority drop & deactivation 분리 처리
    • GICD_CTLR.EOImode=1 설정 사용
    • eoi 명령 사용 시 priority drop만 처리한다.
      • 이 때 running priority에는 idle priority(0xff)가 설정되어 다른 우선 순위를 가진 인터럽트가 preempt되는 것을 허용한다.
      • 단 deactivation 명령 처리 전까지 현재 완료되지 않은 인터럽트 번호는 진입을 허용하지 않는다.
    • 이 모드는 virtualization을 지원하기 위해 채용되었다.
      • 리눅스 커널이 EL2에서 부팅한 경우에만 Host OS 역할로 동작할 때 이렇게 분리된 모드를 사용한다.
      • 리눅스 커널은 v4.3-rc1부터 EOImode=1을 지원한다.

 

인터럽트 수신 Exception 레벨

arm64 시스템에서 커널과 secure firmware를 동작시켜 인터럽트를 수신하는 경우 커널에서는 non-secure group 1에 대해 irq를 수신받고, secure firmware에서는 secure group 0에 대해 irq 보다 더 높은 우선 순위인 fiq를 수신받아 처리하였다. 최근 곧 출시할 ARMv8.4 아키텍처와 GIC v3 등의 최신 아키텍처로 무장한 시스템을 사용하여 linaro 측에서는 secure 처리에 대해 하나의 secure firmware로만 관리하지 않고 secure application과 secure OS를 각 Exception 레벨에서 분리하여 운영할 계획을 가지고 있다. 추가로 Hypervisor도 Secure와 Non-Secure를 분리하여 처리할 계획이 있다.

 

다음 그림은 각 Exception 레벨에서 운영할 Application과 OS등을 보여준다.

  • 각 Exception 레벨에서 인터럽트를 각각 할당하여 처리하여야한다.
  • 상위 EL2나 EL3 Exception 레벨에서는 하위 Exception 레벨을 대신 emulation 하기도 한다. (해당 OS가 직접받아 처리하는 것이 가장 빠르다)
  • ARMv8.4 아키텍처부터 Secure EL2가 동작 가능하다.

 

인터럽트별 group 및 secure 상태 분류

각 Exception 레벨의 Secure 및 Non-Secure 에 인터럽트를 전달하기 위한 경로를 3개로 나누어 처리하는 것을 보여준다.

  • 기존 GIC v2 까지는 single security states 처럼 처리하였다.
    • 인터럽트별로 group을 지정한다.
  • GIC v3부터는 single security states도 지원하지만, two security states를 사용하는 경우 인터럽트별로 group을 지정하고 이어서 group modifier 레지스터를 적용하여 다음과 같이 3가지 상태로 변환하여 처리할 수 있다.
    • G1NS(non-secure group 1)
    • G1S(secure group 1)
    • G0(secure group 0) 또는 G0S

 

IRQ 및 FIQ 분리

GIC v3 이전에는 인터럽트별로 설정된 group 0은 secure 상태로 FIQ로 전달되고, group 1은 non-secure 상태로 IRQ로 전달되었다. 따라서 non-secure 상태로 동작하는 리눅스 커널은 IRQ를 수신하여 처리하고, Secure Firmware는 FIQ를 수신하여 처리하는 것으로 간단히 분리하였다. 그러나 GIC v3 부터는 group modifier 레지스터를 통해 group + secure 상태로 변환되어 조금 더 복잡하게 처리한다.

  • 설정에 의해 각 secure/non-secure Exceptin 레벨로 IRQ 및 FIQ를 보낼 수 있게 하였다.

 

다음 그림은 리눅스 커널이 secure 펌웨어 등과 같이 동작할 때 single 및 two security state에 대해 동작하는 일반적인 사례를 보여준다.

 

다음 그림은 휴대폰으로 전화가 온 경우 secure에서 받은 fiq 인터럽트를 리눅스 커널까지 라우팅하는 두 가지 사례를 보여준다.

  • 1)번 그림의 경우 (1) cpu가 L1 secure state에 있을 때 non-secure group 1으로 지정된 인터럽트가 발생하였다. 이 인터럽트는 non-secure용이기 대문에 Rich OS에 전달해야 하는데 이 인터럽트는 fiq로 변환되어 일단 trust OS 또는 Secure Monitor로 보내게 된다. 왜냐면 SCR_EL3.FIQ=1로 설정되어 있으므로 fiq 인터럽트는 EL3 Secure Monitor로 향하게 된다. Secure Monitor에서는 특수 용도의 인터럽트 번호인 1021번으로 진입하여 fiq 벡터로 수신되는데, 이는 “non-secure로 전환하여 인터럽트를 보내라는 의미“이다. (2) 따라서 non-secure에서 동작하는 Rich OS로 인터럽트를 보내기 위해 non-secure EL1으로 context switching을 하면 (3) 자동으로 non-secure 인터럽트가 non-secure EL1에서 발생하여 Rich OS의 irq 벡터에서 수신할 수 있게 된다.
  • 2)번 그림의 경우는 1)번 그림과 유사하지만 (1) secure EL1에서 동작하는 Trusted OS로 fiq가 전달된다. 왜냐면 SCR_EL3.FIQ가 0으로 설정되었기 때문이다. 그런후 (2) smc 명령을 사용하여 EL3로 context switching을 수행한다. 그 이후 흐름은 1)번 그림과 같다.

 

Pseudo-NMI 구현

arm 및 arm64 시스템에는 NMI 기능이 지원되지 않는다. 그러나 최근 arm64 시스템에서 인터럽트 컨트롤러로 GIC v3 이상을 사용하는 경우 ICC_PMR(Prioirty  Mask Register) 기능으로 irq preemption 기법을 적용하여, x86 시스템의 NMI와 유사한 동작을 수행하도록 구현하였다.

  • local_irq_disable() 루틴의 동작
    • 기존 방법은 “msr daifset, #2” 명령으로 PSTATE.I를 설정하는 것으로 local irq를 disable하였다.
    • 새로운 방법은 PMR을 사용하여 IRQOFF를 위해 0x60 미만의 우선 순위만을 허용하게 설정하여 디폴트 우선 순위 값 0xa0을 사용하는 irq를 차단하지만, NMI용 우선 순위 값 0x20을 사용하는 irq는 허용한다.
  • local_irq_enable() 루틴의 동작
    • 기존 방법은 “msr daifclr, #2” 명령으로 PSTATE.I를 클리어하는 것으로 local irq를 enable하였다.
    • 새로운 방법은 PMR을 사용하여 IRQON을 위해 0xe0 미만의 우선 순위만을 허용하게 설정하여 디폴트 우선 순위 값 0xa0을 사용하는 irq 및 NMI용 우선 순위 값 0x20을 사용하는 irq 둘 다 허용한다.
  • PMR 관련 priority mask 상수 값
    • GIC_PRIO_IRQON (0xe0)
    • GIC_PRIO_IRQOFF (0x60) <- 위의 값 중 bit7 클리어
  • irq 라인별 우선 순위 상수 값
    • GICD_INT_DEF_PRI (0xa0)
    • GICD_INT_NMI_PRI (0x20) <- 위의 값 중 bit7 클리어
  • 사용 방법
    • CONFIG_ARM64_PSEUDO_NMI=y로 설정해야 한다.
    • 커널 파라미터 “irqchip_gicv3_pseudo_nmi=1” 설정
    • APIs
      • request_nmi() & free_nmi()
      • request_percpu_nmi() & free_percpu_nmi()
  • 제약 조건

 

다음은 irq를 disable 방법에 대해 일반적인 방법과 priority mask를 사용하는 방법을 비교하여 보여준다.

 

저전력 지원

절전 기능을 사용하는 경우 priority mask에 의한 인터럽트 마스킹이 아니라 일반 마스킹을 사용한 절전 방법을 보여준다.

  • core를 정지하는 wfi 명령을 사용한 후 수신된 인터럽트로 인해 깨어나서 해당 인터럽트를 처리하는 과정을 보여준다.

 

Affinity 라우팅 지원

SMP로 동작하는 ARM 아키텍처에는 core마다 각 레벨의 affinity 정보가 기록되어 있다. (각 레벨의 affinity 값은 최대 8비트를 사용한다)

  • AArch32에서는 3 레벨로 운영이된다. (MPIDR에 기록되어 있다.)
  • AArch64에서는 3 또는 4 레벨로 운영이된다. (MPIDR_EL1에 기록되어 있다.)

GIC v3의 Affinity 라우팅은 다음과 같이 운영된다.

  • Affnity 라우팅 사용 여부는 다음 레지스터를 사용한다.
    • GICD_CTLR.ARE_NS
    • GICD_CTLR.ARE_S
  • 칩에 설정된 Affinity 라우팅 레벨은 다음 레지스터에서 확인할 수 있다.
    • ICC_CTLR_EL3.A3V
    • ICC_CTLR_EL1.A3V
    • GICD_TYPER.A3V
  • AArch32에서는 3 레벨로 운영이된다.
  • AArch64에서는 3 레벨 또는 4 레벨로 운영된다.
    • 0.b.c.d (3 레벨 운영)
    • a.b.c.d (4 레벨 운영)

 

Affinity 라우팅 for SPI

각 SPI에 대한 Affinity 라우팅 설정은GICD_IROUTERn을 사용하여 기록한다.

  • 리눅스 커널의 GIC v3에서 모든 SPI 인터럽트들은 디폴트로 boot cpu에 라우팅되도록 boot cpu의 AFFx 값들을 읽어 이 레지스터에 기록하여 사용한다.
  • 예) 어떤 SPI 인터럽트를 1번 cpu의 2번 core로 라우팅하려면 aff3=0, aff2=0, aff1=1, aff0=2로 설정한다.

 

Affinity 라우팅 for SGI

각 SGI에 대한 인터럽트를 만들어 발생할 때 Affinity 라우팅은 다음과 같이 동작한다.

  • 관련 레지스터는 다음과 같다.
    • ICC_SGI0R_EL1
    • ICC_SGI1R_EL1
    • ICC_ASGI1R_EL1. 설정은 GICD_IROUTERn을 사용하여 기록한다.
  • SGI에서는 1개의 Aff3~Aff1까지를 지정하고 Aff0의 경우 16비트로 구성된 TargetList를 사용하여 최대 16개 까지 cpu들에 복수 라우팅이 가능하다.
  • 예) 어떤 SGI 인터럽트를 1번 cpu의 0~3번 core에 동시에 라우팅하려면 aff3=0, aff2=0, aff1=1, TargetList=0x000f로 설정한다.

 

Affinity 라우팅 Legacy 지원 옵션

GIC v3가 legacy (GIC v2로 작성된 드라이버 소프트웨어)를 지원하기 위해 GICD_CTRL 레지스터의 Affinity Routing Enable (ARE) 비트를 사용하여 결정한다.

  • 0: affinity 라우팅 비활성화 (legacy operation).
  • 1: affinity 라우팅 활성화

 

다음 그림은 two security states를 사용하면서 각 states에서 legacy 지원 여부를 각각 결정하는 모습을 보여준다.

 

Redistributor

Redistributor는 다음과 같이 프로그래밍 인터페이스를 제공한다.

  • SGI 및 PPI 활성화 또는 비활성화
  • SGI 및 PPI의 우선 순위 설정
  • 각 PPI를 레벨 감지 또는 에지 트리거로 설정
  • 각 SGI 및 PPI를 인터럽트 그룹에 할당
  • SGI 및 PPI의 보류(Pending) 상태 제어
  • SGI 및 PPI의 활성(Active) 상태 제어
  • 연결된 PE에 대한 전원 관리 지원
  • LPI가 지원되는 경우 관련 인터럽트 속성 및 보류 상태를 지원하는 메모리의 데이터 구조에 대한 기본 주소 제어
  • GICv4가 지원되는 경우 관련 가상 인터럽트 속성 및 보류 상태를 지원하는 메모리의 데이터 구조에 대한 기본 주소 제어

 

 

GIC v3 레지스터들

GIC v3에는 기존 GIC v2에는 없었던 3 가지 시스템 레지스터 그룹(ICC, ICV, ICH)들과 2 개의 메모리 맵드 레지스터 그룹(GICR, GITS)들이 추가되었다. GIC v3의 AArch64 시스템용 레지스터들은 다음과 같은 그룹으로 나눌 수 있다. (AArch32는 생략)

  • 시스템 레지스터들
    • ICC, Physical GIC CPU interface Systerm Registers (GICC를 대체)
    • ICV, Virtual GIC CPU interface Systerm Registers (GICV를 대체)
    • ICH, Virtual Interface Control System Registers (GICH를 대체)
  • 메모리 맵드 레지스터들
    • GICC, CPU Interface Registers
    • GICD, Distributor Registers
    • GICH, Virtual CPU Interface Control Registers
    • GICR, Redistributor Registers
    • GICV, Virtual CPU Interface Registers
    • GITS, ITS Registers

 

시스템 레지스터들과 메모리 맵드 레지스터간의 관계

GIC 아키텍처는 동일한 레지스터를 메모리 맵드 레지스터와 동등한 시스템 레지스터간에 공유 할 수 있도록 허용하지만 필수는 아니다. 다음과 같은 조건으로 하나를 선택하여 사용한다.

  • a) Legacy 미지원
    • 리눅스 커널의 GIC v3 드라이버가 사용한다. 이 경우 GIC v2와 호환하지 않는다.
    • ICC_SRE_ELx.SRE==1
    • 시스템 레지스터를 사용하여 메모리 맵드 레지스터보다 빠르다.
  • b) Legacy 지원
    • GIC v2와 호환 코드를 사용하기 위해 메모리 맵드 레지스터를 사용한다.
    • ICC_SRE_ELx.SRE==0
    • 메모리 맵드 레지스터에 액세스 한 경우 시스템 레지스터가 수정 될 수 있음을 의미한다

 

다음 그림은 레지스터 인터페이스의 Legacy의 호환 여부에 따른 비교를 보여준다.

 

1-1) ICC, Physical GIC CPU interface System Registers

  • ICC_CTLR_EL1 (Interrupt Controller Control Register EL1)
  • ICC_CTLR_EL3 (Interrupt Controller Control Register EL3)
    • CBPR (Common Binary Point Register)
      • 0=preemption 그룹으로 group 0만 사용
      • 1=preemption 그룹으로 group 0과 group 1 모두 사용
    • EOImode (End Of Interrupt Mode)
      • 0=ICC_EOIR_EL1 & ICC_AEOIR_EL1을 사용하여 priority drop 기능과 비활성화 기능 지원
      • 1=ICC_EOIR_EL1 & ICC_AEOIR_EL1을 사용하여 priority drop 기능만 지원, 인터럽트 비활성화 기능은 별도로 ICC_DIR_EL1 사용
    • PMHE (Priority Mask Hint Enable)
      • ICC_PMR_EL1을 힌트로 사용하는 것의 유무
      • 0=disable, 1=enable
    • PRIbists (Priority bits)
      • 몇 개의 priority 비트를 지원하는지를 알아온다. (Read Only)
        • 2개의 security state를 지원하는 시스템의 경우 최소 32단계(5 priority bits) 이상이어야 한다.
        • 1개의 security state를 지원하는 시스템의 경우 최소 16단계(4 priority bits) 이상이어야 한다.
    • IDbits (Identifier bits)
      • 인터럽트 id로 몇 비트를 사용하는지 알아온다. (Read Only)
        • 000=16bits, 001=24bits
    • SEIS (SEI Support)
      • CPU 인터페이스가 local SEI들의 generation을 지원하는지 여부 (Read Only)
        • 0=not support, 1=support
    • A3V (Affinity 3 Valid)
      • CPU 인터페이스가 SGI generation시 affinity 3의 사용을 지원하는지 여부(Read Only)
        • 0=zero values, 1=non-zero values
    • RSS (Range Select Support)
      • SGI 사용 시 Targeted Affinity 레벨 0 값으로 허용하는 범위
        • 0=0~15까지 허용한다. (0~15 cpu)
        • 1=0~255까지 허용한다. (0~255 cpu)
    • ExtRange
      • 확장 SPI 지원 여부
        • 0=INTID 1024 to 8191까지 사용하지 않는다.
        • 1=INTID 1024 to 8191까지 사용 가능하다.

 

  • ICC_PMR_EL1 (Interrupt Controller Interrupt Priority Mask Register EL1)
    • Priority Mask
      • priority mask 값으로 이 값보다 작은 값(수치가 작을 수록 가장 높은 우선 순위이다)의 priority를 가진 인터럽트를 PE(Processing Element)에 전달하고, 그 외의 인터럽트는 block 한다.
      • 참고로 BIT(8 – IIC_CTRL.pribits) 값을 이 필드에 저장하고 다시 읽었을 때 0인 값이 읽히면 group 0를 사용하지 못하는 상태를 알 수 있다.
      • Pesudo-NMI 구현 시 이 값으로 GIC_PRIO_IRQON(0xe0)과 GIC_PRIO_IRQOFF(0x60)을 기록하여 사용한다.
      • 0 값을 기록하는 경우 모든 인터럽트가 전달되지 않는다.
  • ICC_BPR0_EL1 (Interrupt Controller Interrupt Binary Point Register 0 EL1)
  • ICC_BPR1_EL1 (Interrupt Controller Interrupt Binary Point Register 1 EL1)
    • Binary Point
      • priority 값을 group priority(g) 필드와 subpriority(s) 필드로  나누는 기준 값을 설정한다.  group priority 필드는 인터럽트 preemption을 의미한다.
        • 0=ggggggg.s
        • 1=gggggg.ss
        • 2=ggggg.sss
        • 3=gggg.ssss
        • 4=ggg.sssss
        • 5=gg.ssssss
        • 6=g.sssssss
        • 7=ssssssss (no preemption)
      • 이 필드에 0 값을 기록하여 리셋시킬 수 있다. 리셋된 후의 값은 구현에 따라 다르다.
    • security 사용 여부에 따라 다음과 같이 처리한다.
      • Security Extension을 사용하지 않는 경우 다음과 같이 처리한다.
        • group 0 인터럽트 또는 GICC_CTLR.CBPR==1인 경우 GICC_BPR을 사용한다.
        • group 1 인터럽트 또는 GICC_CTLR.CBPR==0인 경우 GICC_ABPR을 사용한다.
      • Security Extension을 사용하는 경우 secure/non-secure별 뱅크된 GICC_BPR을 사용한다.
  • ICC_IAR0_EL1 (Interrupt Controller Interrupt Acknowledge Register 0 EL1)
  • ICC_IAR1_EL1 (Interrupt Controller Interrupt Acknowledge Register 1 EL1)
    • 인터럽트 수신 시 이 레지스터를 읽어 인터럽트 id를 읽어오는 것으로 인터럽트 처리 루틴이 ack 처리되었음을 gic에 알린다. (읽기 전용)
  • ICC_EOIR0_EL1 (Interrupt Controller Interrupt End Of Interrupt Register 0 EL1)
  • ICC_EOIR1_EL1 (Interrupt Controller Interrupt End Of Interrupt Register 1 EL1)
    • ISR(Interrupt Service Routine)에서 인터럽트 처리 완료 시 해당 인터럽트 id를 기록하여 eoi 처리하였음을 gic에 알린다. (쓰기 전용)
  • ICC_RPR_EL1 (Interrupt Controller Interrupt Running Priority Register EL1)
    • 읽기 전용으로 현재 동작하고 있는 인터럽트의 priority 값을 알아온다.
    • idle 상태인 경우는 0xff
  • ICC_HPPIR0_EL1 (Interrupt Controller Interrupt Highest Priority Pending Interrupt Register 0 EL1)
  • ICC_HPPIR1_EL1 (Interrupt Controller Interrupt Highest Priority Pending Interrupt Register 1 EL1)
    • 현재 하드웨어 인터럽트들 중 pending되고 있는 가장 높은 priority irq 번호를 읽어온다. (읽기 전용)
  • ICC_SRE_EL1 (Interrupt Controller Interrupt System Register Enable Register EL1)
  • ICC_SRE_EL2 (Interrupt Controller Interrupt System Register Enable Register EL2)
  • ICC_SRE_EL3 (Interrupt Controller Interrupt System Register Enable Register EL3)
    • SRE (System Register Enable)
      • 0=반드시 메모리 맵드 인터페이스가 사용되야 한다.
      • 1=현재 security state의 시스템 레지스터 인터페이스를 enable 한다.
        • 리눅스 커널의 GIC v3 드라이버는 시스템 레지스터를 사용한다.
    • DFB (Disable FIQ Bypass)
      • 0=FIQ bypass enable
      • 1=FIQ bypass disable
    • DIB (Disable IRQ Bypass)
      • 0=IRQ bypass enable
      • 1=IRQ bypass disable
  • ICC_DIR_EL1 (Interrupt Controller Interrupt Deactivate Interrupt Register EL1)
    • INTID에 해당하는 인터럽트를 비활성화시킨다. (쓰기 전용)
  • ICC_IGRPEN0_EL1 (Interrupt Controller Interrupt Group 0 Enable Register EL1)
  • ICC_IGRPEN1_EL1 (Interrupt Controller Interrupt Group 1 Enable Register EL1)
  • ICC_IGRPEN1_EL3 (Interrupt Controller Interrupt Group 1 Enable Register EL3)
    • Group 0(1) 인터럽트의 활성화를 결정한다.
      • 0=disable
      • 1=enable
  • ICC_AP0Rn_EL1 (Interrupt Controller Interrupt Active Priorities Group 0 Registers EL1)
  • ICC_AP1Rn_EL1 (Interrupt Controller Interrupt Active Priorities Group 1 Registers EL1)
    • group 0(1)의 active priorities 정보를 제공한다. (칩 구현에 따라 다르다.)

 

  • ICC_SGI0R_EL1 (Interrupt Contorller Software Generated Interrupt Group 0 Register EL1)
  • ICC_SGI1R_EL1 (Interrupt Contorller Software Generated Interrupt Group 1 Register EL1)
  • ICC_ASGI1R_EL1 (Interrupt Contorller Alias Software Generated Interrupt Group 1 Register EL1)
    • SGI를 발생시킨다. (쓰기 전용)
    • 리눅스 커널에서는 IPI(Inter Process Interrupt)라고 불린다.
    • TargetList
      • SGI를 발생시킬 aff0 레벨의 cpu들(최대 16개)
    • INTID
      • 발생시킬 SGI 번호
    • Aff1~3
      • SGI 인터럽트가 전달될 cpu affinity를 지정한다.

 

1-2) ICV, Virtual GIC CPU interface Systerm Registers

  • ICV_AP0Rn_EL1 (Interrupt Controller Virtual Active Priorities Group 0 Registers EL1)
  • ICV_AP1Rn_EL1 (Interrupt Controller Virtual Active Priorities Group 1 Registers EL1)
  • ICV_BPR0_EL1 (Interrupt Controller Virtual Binary Point Register 0 EL1)
  • ICV_BPR1_EL1 (Interrupt Controller Virtual Binary Point Register 1 EL1)
  • ICV_CTLR_EL1 (Interrupt Controller Virtual Control Register EL1)
  • ICV_DIR_EL1 (Interrupt Controller Deactivate Virtual Interrupt Register EL1)
  • ICV_EOIR0_EL1 (Interrupt Controller Virtual End Of Interrupt Register 0 EL1)
  • ICV_EOIR1_EL1 (Interrupt Controller Virtual End Of Interrupt Register 1 EL1)
  • ICV_HPPIR0_EL1 (Interrupt Controller Virtual Highest Priority Pending Interrupt Register 0 EL1)
  • ICV_HPPIR1_EL1 (Interrupt Controller Virtual Highest Priority Pending Interrupt Register 1 EL1)
  • ICV_IAR0_EL1 (Interrupt Controller Virtual Interrupt Acknowledge Register 0 EL1)
  • ICV_IAR1_EL1 (Interrupt Controller Virtual Interrupt Acknowledge Register 1 EL1)
  • ICV_IGRPEN0_EL1 (Interrupt Controller Virtual Interrupt Group 0 Enable register EL1)
  • ICV_IGRPEN1_EL1 (Interrupt Controller Virtual Interrupt Group 1 Enable register EL1)
  • ICV_PMR_EL1 (Interrupt Controller Virtual Interrupt Priority Mask Register EL1)
  • ICV_RPR_EL1 (Interrupt Controller Virtual Running Priority Register EL1)

 

1-3) ICH, Virtualization Control System Registers

  • ICH_AP0Rn_EL2 (Interrupt Controller Hyp Active Priorities Group 0 Registers EL2)
  • ICH_AP1Rn_EL2 (Interrupt Controller Hyp Active Priorities Group 1 Registers EL2)
  • ICH_HCR_EL2 (Interrupt Controller Hyp Control Register EL2)
  • ICH_VTR_EL2 (Interrupt Controller VGIC Type Register EL2)
  • ICH_MISR_EL2 (Interrupt Controller Maintenance Interrupt State Register EL2)
  • ICH_EISR_EL2 (Interrupt Controller End of Interrupt Status Register EL2)
  • ICH_ELRSR_EL2 (Interrupt Controller Empty List Register Status Register EL2)
  • ICH_VMCR_EL2 (Interrupt Controller Virtual Machine Control Register EL2)
  • ICH_LRn_EL2 (Interrupt Controller List Registers EL2)

 

2-1) GICC, CPU interface Registers

  • GICC_CTRL (CPU Interface Control Register)
    • GIC v2와 다르게 3가지 모드에서 사용방법이 다르고, 더 많은 제어 비트를 가진다.
      • 1) GICD_CTRL.DS=0 & Non-Secure
        • 리눅스 커널에서 GIC v3  드라이버가 이 모드를 사용하여 설정한다.
      • 2) GICD_CTRL.DS=0 & Secure
        • 시큐어 OS가 사용하는 모드이다.
      • 3) GICD_CTRL.DS=1
    • EnableGrp0~1
      • Group 0와 Group 1에 대한 인터럽트 시그널의 enable 설정이다. (0=disable, 1=enable)
    • FIQEn
      • group 0 인터럽트의 FIQ 시그널 처리 여부
        • 0=disable(IRQ로 처리), 1=enable(FIQ로 처리)
    • CBPR
      • 인터럽트 preemption 지원 방법
        • 0=GICC_BPR을 사용하여 group 0 인터럽트들의 preemption을 지원하고, group 1 인터럽트는 GICC_ABPR 레지스터를 사용하여 지원
        • 1=GICC_BPR을 사용하여 group 0 및 group 1 인터럽트들의 preemption을 지원한다.
    • FIQBypDisGrp0~1 & IRQBypDisGrp0~1
      • cpu 인터페이스 비활성화시 PE에 인터럽트 바이패스 Disable 여부 (0=bypass, 1=bypass disable)
    • EOImode (EOImodeS & EOImodeNS)
      • 0=GICC_EOIR & GICC_AEOIR을 사용하여 priority drop 기능과 비활성화 기능 지원
      • 1=GICC_EOIR & GICC_AEOIR을 사용하여 priority drop 기능만 지원, 인터럽트 비활성화 기능은 별도로 GICC_DIR 사용

 

  • GICC_PMR (Interrupt Priority Mask Register)
    • core로 전달될 irq들에 대해 설정한 priority 마스크 값보다 작은 priority 값(값이 작을 수록 우선 순위가 높다)을 cpu로 전달한다.
      • 리눅스 커널의 GIC v1~v4 드라이버는 0xf0을 설정하여 사용한다.
    • 0 값을 기록하는 경우 모든 인터럽트가 전달되지 않는다.
  • GICC_BPR (Binary Point Register)
    • priority 값을 group/sub와 같이 두 그룹으로 나누어 그 중 group에 해당하는 priority를 가진 인터럽트에 대해 preemption interrupt로 분류한다.
      • 0=ggggggg.s
      • 1=gggggg.ss
      • 2=ggggg.sss
      • 3=gggg.ssss
      • 4=ggg.sssss
      • 5=gg.ssssss
      • 6=g.sssssss
      • 7=ssssssss (no preemption)
    • 리눅스 커널의 경우 GIC v3 부터 이 필드에 0 값을 기록하여 리셋시킨 후 사용한다. 리셋 후의 값은 칩 구현에 따라 다르다.
    • two security state를 사용하는 경우 secure/non-secure별 뱅크된 GICC_BPR을 사용한다.
    • single security state를 사용하는 경우 group 0만 인터럽트 preemption을 지원한다.
  • GICC_IAR  (Interrupt Acknowledge Register)
    • 인터럽트 수신 시 이 레지스터를 읽어 인터럽트 id를 읽어오는 것으로 인터럽트 처리 루틴이 ack 처리되었음을 gic에 알린다.
  • GICC_EOIR  (End of Interrupt Register)
    • ISR(Interrupt Service Routine)에서 인터럽트 처리 완료 시 해당 인터럽트 id를 기록하여 eoi 처리하였음을 gic에 알린다.
  • GICC_RPR (Running Priority Register)
    • 읽기 전용으로 현재 동작하고 있는 인터럽트의 priority 값을 알아온다. idle 상태인 경우는 0xff
    • non-secure에서 읽은 경우 0x80을 mask 하여사용한다.
  • GICC_HPPIR (Highest Priority Pending Interrupt Register)
    • 읽기 전용으로 현재 하드웨어 인터럽트들 중 pending되고 있는 가장 높은 priority irq 번호를 읽어온다.
  • GICC_IIDR (CPU Interface Identification Register)
    • 읽기 전용으로 GIC 제품 ID, 아키텍처 버전, 리비전, 구현회사 등의 정보를 읽어올 수 있다.
  • GICC_ABPR (Aliased Binary Point Register)
  • GICC_APRn (Active Priorities Register)
  • GICC_NSAPRn (Non-Secure Active Priorities Register)
    • active priorities 정보를 제공한다. (칩 구현에 따라 다르다)
  • GICC_AEOIR (Aliased End of Interrupt Register)
  • GICC_AIAR (Aliased Interrupt Acknowledge Register)
  • GICC_AHPPIR (Aliased Highest Priority Pending Interrupt Register)
  • GICC_DIR (Deactivate Interrupt Register)
    • INTID에 해당하는 인터럽트를 비활성화시킨다. (쓰기 전용)

 

2-2) GICD, Distributor Registers

  • GICD_CTRL (Distributor Control Register)
    • EnableGrp0~1
      • Group 0(1) 인터럽트의 활성화 여부 (EnableGrp1NS=non-secure에서, EnableGrp1S=secure에서)
        • 0=disable, 1=enable
      • Pending 인터럽트에 대해 CPU interface로 올려보낼지 여부를 통제한다.
        • secure extension을 사용할 때 non-secure 모드에서는 group1에 대해서만 통제할 수 있다.
        • security extension 사용 시 bank 된다.
    • ARE (Affinity Routing Enable)
      • affinitiny routing의 활성화 여부 (ARE_NS=non-secure에서, ARE_S=secure에서)
        • 0=disable, 1=enable
    • DS (Disable Security)
      • non-secure 에서 group 0 인터럽트들에 대한 레지스터들에 access를 허용 여부
        • 0=access 금지, 1=access 허용
    • E1NWF (Enable 1 of N Wakeup Functionality)
      • N 개 중 하나의 인터럽트를 선택하여 PE를 깨어나게 하는 기능
        • 0=disable, 1=enabel
    • RWP (Register Write Pending)
      • 이 레지스터의 기록이 진행중인지 여부. 진행 중에는 기록하지 못한다. (Read Only)
        • 0=Write 가능
        • 1=Write 진행중

 

  • GICD_TYPER (Interrupt Controller Type Register)
    • 읽기 전용으로 Security Extension 사용 시 최대 지원 cpu 수와 인터럽트 수 등을 알아내기 위해 사용한다.
    • ESPI_range
      • GICD_TYPER.ESPI==1로 설정된 경우 최대 확장 SPI INTID 수로 다음 식과 같다.
        • = (32 * (ESPI_range + 1) + 4095)
    • RSS (Range Select Support)
      • affinity level 0에서 IRI 지원 SGI 대상 범위 선택
        • 0=0~15
        • 1=0~255
    • No1N (No support 1 Of N)
      • 1 of N SPI 인트럽트 비지원 여부
        • 0=supported, 1=not supported
    • A3V
      • Affinity 3 valid 여부
        • 0=not support (all zero values), 1=support
    • IDBits
      • 지원하는 인터럽트 수에 대한 비트 표현-1
      • 수식 = 2^(N+1)
        • 예) 0b01001 -> 1024 인터럽트
    • DVIS (Direct Virtual LPI Injection Support)
      • Direct Virtual LPI 인젝션의 지원 여부
        • 0=not support, 1=support
    • LPIS (LPI Support)
      • LPI 지원 여부
        • 0=not support, 1=support
    • MBIS (Message Based Interrupts Support)
      • 메시지 기반 인터럽트의 지원 여부
        • 0=not support, 1=support
    • num_LPIs
      • 지원 가능한 LPI 수 (GICD_TYPER.IDbits를 초과할 수 없다)
        • =2^(num_LPIs+1) .
          • LPI용 INITID 범위: 8192 ~ (8192 + 2^(num_LPIs+1) – 1)
        • 0인 경우 GICD_TYPER.IDbits 로 산출된 수와 동일
        • ◦ This field cannot indicate a maximum LPI INTID greater than that indicated byWhen the supported INTID width is less than 14 bits, this field is RES0 and no LPIs are supported.
    • SecurityExtn
      • Two Security 지원 여부
        • 0=not support (single security states), 1=support (two security states)
    • ESPI (Extended SPI range)
      • Extended SPI range 지원 여부
        • 0=미지원 1=지원
    • CPU Number
      • Affinity Routing 사용 시 최대 지원 CPU 수에 대한 비트 표현-1(0=ARE 미지원)
        • 수식 = 2^(N+1)
        • 예) 0b001 -> 4개 cpu
    • ITLinesNumber
      • 지원 SPI 인터럽트 수(최대 수=1020)
      • 수식 = 32 * (N+1)
        • 예) 0b00011 -> 32 * (3 + 1) = 128
        • 예) 0b11111 -> 32 * (31 + 1) = 1024이나 최대 수인 1020개 제한
  • GICD_IIDR (Distributor Implementer Identification Register)
    • 읽기 전용으로 GIC implementor 정보를 알아온다.

 

  • GICD_IGROUPRn (Interrupt Group Registers)
    • secure extension을 사용하는 경우 인터럽트별로 secure group 0와 non-secure group 1을 지정한다.
      • 0=secure group 0, 1=non-secure group 1
    • secure extension을 사용하는 경우 리셋시 0으로(RAS) 읽히며, 모든 인터럽트가 재설정되기 전엔 모두 secure group 0 상태가된다.
      • SMP 시스템에서 secure extension을 지원하고, non-secure 프로세서들에 대해서는 뱅크된 GICD_IGROUPR0은 non-secure group 1 상태로 리셋한다.
    • IRQ #0~31을 위해 첫 레지스트가 cpu별로 bank 되어 사용된다.
    • 최종 secure 상태를 결정하기 위해 GICD_IGRPMODRn 과 같이 사용된다.
    • two security states를 사용할 때에는 반드시 secure에서 설정을 해야 유효하다. non-secure에서 동작하는 리눅스 커널에서의 설정은 의미가 없다.
    • 리눅스 커널의 GIC v3 드라이버에서는 single security state를 위해 모든 SPI 인터럽트들을 G1NS(non-secure group 1)으로 설정한다.
  • GICD_IGRPMODRn (Interrupt Group Modifier Registers)
    • two security 모드로 동작 시 GICD_IGROUPRn와 같이 사용하여 최종 그룹과 secure 상태를 결정한다.
      • 0=secure group 0 -> G0S(secure group 0), non-secure group 1 -> G1NS(non-secure group 1)
      • 1=secure group 0 -> G1S(secure group 1), non-secure group 1 -> G1NS(non-secure group 1, reserved)
    • two security states를 사용할 때에는 반드시 secure에서 설정을 해야 유효하다. non-secure에서 동작하는 리눅스 커널에서의 설정은 의미가 없다.
  • GICD_ISENABLERn (Interrupt Set-Enable Registers)
    • IRQ 별로 통과(Set-Enable) 여부를 설정할 수 있다.
      • 1=set 요청
    • IRQ #0~31을 위해 첫 레지스트가 cpu별로 bank 되어 사용된다.
  • GICD_ICENABLERn (Interrupt Clear-Enable Registers)
    • IRQ 별로 통제(Clear-Enable) 여부를 설정할 수 있다.
      • 1=clear 요청
    • IRQ #0~31을 위해 첫 레지스트가 cpu별로 bank 되어 사용된다.
  • GICD_ISPENDRn (Interrupt Set PENDing Registers)
    • IRQ 별로 pending 상태를 설정할 수 있다.
      • 1=set 요청
    • IRQ #0~31을 위해 첫 레지스트가 cpu별로 bank 되어 사용된다.
  • GICD_ICPENDRn (Interrupt Clear PENDing Registers)
    • IRQ 별로 pending 상태 해제를 요청할 수 있다.
      • 1=clear 요청
    • IRQ #0~31을 위해 첫 레지스트가 cpu별로 bank 되어 사용된다.
  • GICD_IPRIORITYRn (Interrupt PRIORITY Registers)
    • IRQ 별로 priority를 설정할 수 있다.
      • 0~255 priority 설정
    • IRQ #0~31을 위해 첫 8개의 레지스트가 cpu별로 bank 되어 사용된다.
    • 리눅스 커널의 GIC v3 드라이버는 디폴트 값으로 0xa0 값을 사용한다.  단 최근 커널에서 pesudo-nmi를 지원하는 경우 nmi 모드를 위해서는 0x20 값을 사용한다.
      • non-secure에서 설정한 값이므로 우선순위 값은 다음과 같이 변환되어 사용된다.
        • (0xa0 >> 1 | 0x80) = 0xd0
        • (0x20 >> 1 | 0x80) = 0x90
  • GICD_ITARGETRn (Interrupt processor TARGET Registers)
    • IRQ 별로 개별 cpu interface로의 전달여부를 비트로 마스크 설정할 수 있다.
    • bit0=cpu#0 제어, bit1=cpu#1 제어…
      • 0=disable forward, 1=enable forward
    • IRQ #0~31을 위해 첫 8개의 레지스트가 cpu별로 bank 되어 사용된다.
  • GICD_ICFGRn (Interrupt ConFiGuration Registers)
    • IRQ 별로 인터럽트 트리거 방향을 설정할 수 있다.
      • 0=상향 시 트리거, 1=하향 시 트리거
    • IRQ #160~31을 위해 두 번째 레지스트가 cpu별로 bank 되어 사용된다.
  • GICD_ISACTIVERn (Interrupt Set-Active Registers)
    • IRQ 별로 활성화 요청한다.
      • 1=활성화 요청
  • GICD_ICACTIVERn (Interrupt Clear-Active Registers)
    • IRQ 별로 비활성화 요청한다.
      • 1=비활성화 요청
  • GICD_NSACRn (Non-secure Access Control Registers)
    • non-secure 소프트웨어만 설정할 수 있다.
    • 특정 PE의 non-secure 그룹 0 인터럽트에 대한 제어 활성화 여부
      • 00=not permit
      • 01=set-pending 허용, secure SGI 생성 허용, clear-pending 허용 가능(구현에 따라)
      • 10=01에 추가하여 clear-pending 허용, set-active 및 clear-active 허용
      • 11=10에 추가하여 target cpu 지정 및 affinity 라우팅 정보 사용 가능

 

  • GICD_SGIR (Software Generated Interrupt Register)
    • TLF (Target List Filter)
      • 0=white list 제어 방식, CPU Target List에 설정된 cpu로만 forward
      • 1=black list 제어 방식, CPU Target List에 설정된 cpu만 drop
      • 2=위의 ACL 방식 제어를 사용하지 않는다.
      • 3=reserved
    • CPU Target List
      • 0~7개의 cpu bit
    • NSATT (Non-Secure
      • 0=SGI#에 대해 group-0으로 설정된 경우 CPU Target List로 forward
      • 1=SGI#에 대해 group-1로 설정된 경우 CPU Target List로 forward
  • GICD_CPENDSGIRn (SGI Clear-Pending Registers)
    • Pending SGI 인터럽트 상태 클리어 (1=clear 요청)
  • GICD_SPENDSGIRn (SGI Set-Pending Registers)
    • Pending SGI 인터럽트 상태 설정 (1=set 요청)
  • GICD_IROUTERn (Interrupt Routing Registers)
    • affinity 라우팅(ARE)이 활성화된 경우 SPI에 대한 라우팅 정보를 제공한다.
    • Aff0~3
      • affinity 레벨별 cpu 마스크 정보
        • 리눅스 커널의 GIC v3 드라이버는 boot cpu의 aff3.aff2.aff1.aff0 정보를 기록하여 boot cpu로 라우팅하도록 디폴트로 설정하여 운영한다.
    • IRM (Interrupt Routing Mode)
      • 0=인터럽트가 aff3,aff2.aff1.aff0으로 라우팅 (정보를 사용하여 Affinity Routing)
        • 리눅스 커널의 GIC v3 드라이버가 이 모드를 디폴트 설정하여 운영한다.
      • 1=인터럽트가 협력하는 노드의 모든 PE로 라우팅 (정보를 사용하지 않고 노드내 모든 PR로 Affinity Routing)

 

2-3) GICH, Virtual CPU Interface Control Registers

  • GICH_APR (Active Priorities Register)
  • GICH_EISRn (End of Interrupt Status Registers)
  • GICH_ELRSRn (Empty List Register Status Registers)
  • GICH_HCR (Hypervisor Control Register)
  • GICH_LRn (List Registers)
  • GICH_MISR (Maintenance Interrupt Status Register)
  • GICH_VMCR (Virtual Machine Control Register)
  • GICH_VTR (VGIC Type Register)

 

2-4) GICR, Redistributor Registers

  • GICR_CLRLPIR (Clear LPI Pending Register)
  • GICR_CTLR (Redistributor Control Register)
  • GICR_ICACTIVER0 (Interrupt Clear-Active Register 0)
  • GICR_ICENABLER0 (Interrupt Clear-Enable Register 0)
  • GICR_ICFGR0 (Interrupt Configuration Register 0)
  • GICR_ICFGR1 (Interrupt Configuration Register 1)
  • GICR_ICPENDR0 (Interrupt Clear-Pending Register 0)
  • GICR_IGROUPR0 (Interrupt Group Register 0)
  • GICR_IGRPMODR0 (Interrupt Group Modifier Register 0)
  • GICR_IIDR (Redistributor Implementer Identification Register)
  • GICR_INVALLR (Redistributor Invalidate All Register)
  • GICR_INVLPIR (Redistributor Invalidate LPI Register)
  • GICR_IPRIORITYRn (Interrupt Priority Registers)
  • GICR_ISACTIVER0 (Interrupt Set-Active Register 0)
  • GICR_ISENABLER0 (Interrupt Set-Enable Register 0)
  • GICR_ISPENDR0 (Interrupt Set-Pending Register 0)
  • GICR_NSACR (Non-secure Access Control Register)
  • GICR_PENDBASER (Redistributor LPI Pending Table Base Address Register)
  • GICR_PROPBASER (Redistributor Properties Base Address Register)
  • GICR_SETLPIR (Set LPI Pending Register)
  • GICR_STATUSR (Error Reporting Status Register)
  • GICR_SYNCR (Redistributor Synchronize Register)
  • GICR_TYPER (Redistributor Type Register)
  • GICR_VPENDBASER (Virtual Redistributor LPI Pending Table Base Address Register)
  • GICR_VPROPBASER (Virtual Redistributor Properties Base Address Register)
  • GICR_WAKER (Redistributor Wake Register)

 

2-5) GICV, Virtual CPU Interface Registers

  • GICV_ABPR (VM Aliased Binary Point Register)
  • GICV_AEOIR (VM Aliased End of Interrupt Register)
  • GICV_AHPPIR (VM Aliased Highest Priority Pending Interrupt Register)
  • GICV_AIAR (VM Aliased Interrupt Acknowledge Register)
  • GICV_APRn (VM Active Priorities Registers)
  • GICV_BPR (VM Binary Point Register)
  • GICV_CTLR (Virtual Machine Control Register)
  • GICV_EOIR (VM End of Interrupt Register)
  • GICV_HPPIR (VM Highest Priority Pending Interrupt Register)
  • GICV_IAR (VM Interrupt Acknowledge Register)
  • GICV_PMR (VM Priority Mask Register)
  • GICV_RPR (VM Running Priority Register)
  • GICV_IIDR (VM CPU Interface Identification Register)
  • GICV_DIR (VM Deactivate Interrupt Register)

 

2-6) GITS, ITS Registers

  • GITS_BASERn (ITS Translation Table Descriptors)
  • GITS_CBASER (ITS Command Queue Descriptor)
  • GITS_CREADR (ITS Read Register)
  • GITS_CTLR (ITS Control Register)
  • GITS_CWRITER (ITS Write Register)
  • GITS_IIDR (ITS Identification Register)
  • GITS_TRANSLATER (ITS Translation Register)
  • GITS_TYPER (ITS Type Register)

 


BCM2708(RPI) 인터럽트 컨트롤러

BCM2708 인터럽트 컨트롤러

arm irq에 해당하는 박스에 색상이 있는 항목들은 실제 ARM 커널 드라이버에서 처리된다.

 

인터럽트 소스 구분

RPI에서 처리하는 인터럽트 소스는 다음과 같다.

  • Pending IRQ1:
    • GPU peripherals 인터럽트
    • irqnr = #0~31
      • 7, 9, 10, 18, 19번은 ARM과 share
  • Pending IRQ2:
    • GPU peripherals 인터럽트
    • irqnr = #32~63
      • 53~57, 62번은 ARM과 share
  • Pending Base IRQ0:
    • ARM peripherals 인터럽트
    • irqnr = #64~95
      • 64~71번은 timer, doorbell #0~1, mailbox, …
      • 72-73번은 pending #1-#2 레지스터 소스
      • 74~85번은 VideoCore와 share

 

 

관련 레지스터

  • 0x7E00_0000으로 시작하는 주소는 GPU(VC)에 연결된 I/O peripherals 기본 물리 주소이다. 따라서 ARM 리눅스에서 사용하는 물리주소와 가상주소로 변환하여 사용한다.
    • rpi (ARM 기본 주소):
      • GPU 물리 주소: 0x7e00_0000 (DTB에 구성된 주소로 ARM 관점에서 BUS 주소로 본다.)
      • ARM 물리 주소: 0x2000_0000
      • ARM 가상 주소: 0xf200_0000
    • rpi2 (ARM 기본 주소):
      • GPU 물리 주소: 0x7e00_0000 (DTB에 구성된 주소로 ARM 관점에서 BUS 주소로 본다.)
      • ARM 물리 주소: 0x3f00_0000
      • ARM 가상 주소: 0xf300_0000

 


BCM2709(RPI2) 인터럽트 컨트롤러

BCM2709 인터럽트 컨트롤러

arm irq에 해당하는 박스에 색상이 있는 항목들은 실제 ARM 커널 드라이버에서 처리된다.

인터럽트 소스 구분

RPI2에서 처리하는 인터럽트 소스는 다음과 같다. Machine Specific 함수에서 초기화한 경우와 Device Tree로 초기화할 때의 구성이 다르다.

  • HARD IRQs
    • GPU Pending IRQ1:
      • GPU peripherals 인터럽트
      • Machine Specific irqnr = #0~31
        • 7, 9, 10, 18, 19번은 ARM과 share
      • Device Tree virq=30~61, hwirq=32~63
    • GPU Pending IRQ2:
      • GPU peripherals 인터럽트
      • Machine Specific irqnr = #32~63
        • 53~57, 62번은 ARM과 share
      • Device Tree virq=62~93, hwirq=64~95
    • ARM Pending Base IRQ0:
      • ARM peripherals 인터럽트
      • irqnr = #64~95
        • 64~71번은 timer, doorbell #0~1, mailbox, …
        • 72-73번은 pending #1-#2 레지스터 소스
        • 74~85번은 VideoCore와 share
      • Device Tree virq=22~29, hwirq=0~7
    • LOCAL:
      • 인터럽트 소스로 해당 비트가 설정되는 경우 각각의 레지스터를 통해 해당 IRQ를 얻어낸다.
      • irqnr = #96~127
        • 100~103번은 mailbox0~3 interrupt controller 레지스터 소스
        • 104 번은 pending #0 레지스터 소스
        • 105번은 PMU 레지스터 소스
      • Device Tree virq=16~21, hwirq=0~9
  • Soft IRQs:
    • IPI (mailbox #0)
      • ipinr = #0~31
        • 8~31번은 리눅스에서 사용하지 않는다.
    • mailbox #1~3, doorbell, timer, …

 

BCM2709 인터럽트 컨트롤러 레지스터 (Machine Specific)

관련 레지스터

BCM2708의 10개의 (IRQ basic pending ~ ) 기본 레지스터들과 동일하고 BCM2709는 ARM 전용으로 다음과 같이 추가되었다.

이 레지스터들은 GPU(VC)에서 사용하지 않고 ARM 전용으로 사용된다.

  • rpi2 (ARM LOCAL 기본 주소):
    • ARM 물리 주소: 0x4000_0000
    • ARM 가상 주소: 0xf400_0000

 

RPI2 인터럽트 확인 (Machine-Specific)

rpi2를 machine specific 코드 기반으로 초기화된 인터럽트 정보이다.

  • 보여주는 정보 순서
    • irq 번호
    • cpu별 인터럽트 통계
    • irq_chip.name
    • irq_domain.hwirq
      • irq_domain이 설정되지 않아 출력되지 않음
    • 트리거 레벨
      • CONFIG_GENERIC_IRQ_SHOW_LEVEL이 설정되지 않아 출력되지 않음
    • irq name
      • 이름이 설정되지 않아 아무것도 출력되지 않음
    • action list
      • 1개 이상은 컴마로 분리됨
$ cat /proc/interrupts
           CPU0       CPU1       CPU2       CPU3
 16:          0          0          0          0   ARMCTRL  bcm2708_fb dma
 24:      12845          0          0          0   ARMCTRL  DMA IRQ
 25:       2980          0          0          0   ARMCTRL  DMA IRQ
 32:  128848277          0          0          0   ARMCTRL  dwc_otg, dwc_otg_pcd, dwc_otg_hcd:usb1
 52:          0          0          0          0   ARMCTRL  BCM2708 GPIO catchall handler
 65:         11          0          0          0   ARMCTRL  bcm2708_vcio
 66:          2          0          0          0   ARMCTRL  VCHIQ doorbell
 75:          1          0          0          0   ARMCTRL
 83:          2          0          0          0   ARMCTRL  uart-pl011
 84:     497931          0          0          0   ARMCTRL  mmc0
 99:    4675934    2099819     568663      90331   ARMCTRL  arch_timer
FIQ:              usb_fiq
IPI0:          0          0          0          0  CPU wakeup interrupts
IPI1:          0          0          0          0  Timer broadcast interrupts
IPI2:     137529      40597      36229      25588  Rescheduling interrupts
IPI3:         14         17         11         15  Function call interrupts
IPI4:          1          5          1          3  Single function call interrupts
IPI5:          0          0          0          0  CPU stop interrupts
IPI6:          0          0          0          0  IRQ work interrupts
IPI7:          0          0          0          0  completion interrupts
Err:

 

RPI2 인터럽트 확인 (Device Tree)

Device Tree로 구성한 인터럽트 정보이다..

  • 보여주는 정보 순서
    • irq 번호
    • cpu별 인터럽트 통계
    • irq_chip.name
    • irq_domain.hwirq
    • 트리거 레벨
    • irq name
      • 이름이 설정되지 않아 아무것도 출력되지 않음
    • action list
      • 1개 이상은 컴마로 분리됨
$ cat /proc/interrupts
           CPU0       CPU1       CPU2       CPU3
 16:          0          0          0          0  bcm2836-timer   0 Edge      arch_timer
 17:   37228140   22280702  154598435   50544784  bcm2836-timer   1 Edge      arch_timer
 23:      24375          0          0          0  ARMCTRL-level   1 Edge      3f00b880.mailbox
 24:        216          0          0          0  ARMCTRL-level   2 Edge      VCHIQ doorbell
 39:          1          0          0          0  ARMCTRL-level  41 Edge
 46:          0          0          0          0  ARMCTRL-level  48 Edge      bcm2708_fb dma
 48:     545428          0          0          0  ARMCTRL-level  50 Edge      DMA IRQ
 50:          0          0          0          0  ARMCTRL-level  52 Edge      DMA IRQ
 62:  925102072          0          0          0  ARMCTRL-level  64 Edge      dwc_otg, dwc_otg_pcd, dwc_otg_hcd:usb1
 79:          0          0          0          0  ARMCTRL-level  81 Edge      3f200000.gpio:bank0
 80:          0          0          0          0  ARMCTRL-level  82 Edge      3f200000.gpio:bank1
 86:     540806          0          0          0  ARMCTRL-level  88 Edge      mmc0
 87:       5053          0          0          0  ARMCTRL-level  89 Edge      uart-pl011
 92:    9308589          0          0          0  ARMCTRL-level  94 Edge      mmc1
FIQ:              usb_fiq
IPI0:          0          0          0          0  CPU wakeup interrupts
IPI1:          0          0          0          0  Timer broadcast interrupts
IPI2:    1160150    6582642    1541946    1893722  Rescheduling interrupts
IPI3:          3          5          8          8  Function call interrupts
IPI4:        114         91         79         97  Single function call interrupts
IPI5:          0          0          0          0  CPU stop interrupts
IPI6:          0          0          0          0  IRQ work interrupts
IPI7:          0          0          0          0  completion interrupts
Err:          0

 

참고

 

 

댓글 남기기