[Kernel of Linux] 7. Interrupt (0)
Kernel/Theory

[Kernel of Linux] 7. Interrupt (0)

반응형

1. The Concept of Interrupt

CPU는 instruction을 가져와서 fetch 하고 decode 한 뒤 실행한다. 그 과정은 데이터를 읽고 쓰는 행위가 대부분이다. 32-bit 기준으로 PC는 4-Byte씩 증가하여 다음 instruction을 탐색한다. 이 루틴은 검은색 선으로 된 부분이다. 그런데 여기서 중간에 interrupt가 걸리는 상황을 생각해보자. 이때는 분홍색 선으로 된 루틴을 따라간다. CPU에 interrupt request bit을 보고 interrupt가 가능한지 확인한 뒤에 interrupt가 가능하면 interrupt 루틴을 따라간다. PC에는 평소처럼 4-Byte가 증가하는 것이 아닌 저장되었던 다른(새) 레지스터로 fetch 된다. 즉 해당 address로 jump 한 효과와 같다. 그 address는 요청한 interrupt의 handler 주소를 가리키고 있을 것이다.

interrupt와 exception의 차이는 간단히 말해 CPU 내부에서 일어나냐 외부에서 일어나냐의 차이다. 자세한 건 표를 보길 바란다.

그런데 CPU가 처리할 수 있는 interrupt는 한 CPU에 한 interrupt지만, 한 번에 요청될 수 있는 interrupt의 개수는 devices들이 많을수록 더욱 많아질 것이다. 이를 통제하기 위해서 Interrupt Controller가 필요하다.

 

2. PIC (Programmable Interrupt Controller)

이 interrupt controller를 software로 구현할 수 있게 만들어놓았기 때문에 Progammable Interrupt Controller, 줄여서 PIC라고 한다.

PIC로 여러 device가 interrupt를 request 한다. 이렇게 interrupt를 보내는 line을 IRQ(Interrupt ReQest) Lines라고 한다. devices는 동시에 IRQ 시그널을 보낼 수 있다.
하지만 특정 interrupt는 보내지 못하게 할 수도 있다. 해당 IRQ를 masking 하면 그 interrupt는 막히게 되는 것이다. 이를 표시해주는 register를 IMR(Interrupt Mask Register)이라고 한다. 어떤 interrupt를 masking 할지는 프로그래머가 어떻게 하느냐에 달린 것이다.
그다음은 IRR(Interrupt Request Register)인데 요청된 IRQ를 처리될 때까지 저장하고 있는 레지스터다. 그리고 Priority Register에 의해서 IRR이 여러 IRQ를 hold 하고 있어도 우선순위에 따라 다음에 처리될 IRQ를 가져온다.
이후 해당 interrupt마다 지정된 ISR(Interrupt Service Routine)을 실행하게 된다. 그렇게 INTR(INTerrupt Request)를 처리하게 된다.
device에서 보내는 interrupt마다 vector를 지정해줘서 IRQ line number를 vector number로 encoding 한다. 어떤 device에서 보냈는지를 알려주기 위해서다.
PIC & device controller는 CPU로부터 ACK, 즉 interrupt 처리 완료 시그널이 올 때까지 block 되어 다른 interrupt를 처리할 수 없는 상태에 놓여있게 된다. 이는 곧 interrupt가 재빨리 실행되지 않으면 성능에 영향을 끼칠 수 있다는 것을 의미한다. 그래서 interrupt는 가능한 짧은 시간 내에 처리되어야 한다.

* 강의 자료에 나온 ISR의 Register는 잘못된 것이다. Routine이 맞는 표현이다.

위에서 설명한 것을 도식화하면 다음과 같다. 좀 더 설명하자면 하나의 interrupt line에 여러 device가 물려있을 수 있다. 또 PIC는 CPU에게 INTR과 vector를 전달한다.

 

3. Interrupt Handling in Multiprocessor

multiprocessor에서는 다음과 같은 모습을 가질 수 있다. 하나의 bus에 2개의 CPU가 Timer만을 가지는 Local APIC(Advanced PIC)을 가지고 붙어있고 다른 쪽에서는 나머지 모든 I/O devices가 multi-APIC에 물려있다.

  • Local APIC
    - SMP에서 각 CPU마다 하나씩 존재
    - Timer interrupt를 발생시킴
    - 모든 local APIC은 외부 APIC과 연결되어 있음
  • multi-APIC
    - multiprocessor를 위한 APIC
    - IRQ가 요청되면 요청할 CPU를 선택하고 그 local APIC에 인터럽트 시그널을 보냄

좀 더 구체적으로 살펴보기 전에 먼저 bus와 I/O interface의 동작이 어떻게 이루어지는지 보고 넘어가자. CPU에서 어떤 주소를 통해 access를 하려 할 때 MMU(Memory Management Unit)이 그 주소의 범위를 보고 가야 할 곳을 지정해준다. 예를 들어 0x0000000~0x7777XXX 까지는 Memory bus로 보내고 0x7777XXX~0x7777777 까지는 I/O bus로 가게 한다. I/O bus로 가면 거기에는 standard에 맞게 설계된 I/O interface가 존재한다. disk address, 쓰거나 읽을 data, 그리고 보조 레지스터로 control, status 레지스터 등등이 존재한다. control 레지스터는 CPU가 컨트롤하고 싶은 정보를 담고 있고 status 레지스터는 말 그대로 상태를 표시해주고 있다. 그리고 device 내에 있는 ROM에는 vendor id, device id, interrupt line 같은 정보들이 담겨있다. 이런 I/O interface들은 I/O bus에 직접 꼽힐 수도 있지만 PIC을 통해 꼽힐 수도 있다.

어떤 한 device에서 IRQ를 발생시키고 APIC에게 전달된다. APIC은 어떤 CPU에게 전달해야 하는지 고민이 생긴다. SMP(Symmetric MultiProcessing)이기 때문에 모든 CPU는 동일한 가치를 지니고 있는 상황이다.

이를 해결하기 위한 방법은 architecture마다 차이가 존재하지만 기본적으로 사용되는 알고리즘은 2개 존재한다.

  1. Static distribution
    - static table을 사용해서 정해진 경로를 통해 전달
  2. Dynamic distribution
    - process priority를 사용
    - 같은 priority면 중재

Dynamic IRQ distribution 알고리즘의 flow를 좀 더 살펴보자. priority에 따라 처리하는데 만약 같은 priority를 가지고 있는 process들이 IRQ를 보내면 Tie 상황이 발생한다. 이때 Arbitration(중재) 알고리즘으로 해결한다. CPU는 counter 변수를 가지고 있는데 APIC에게 선택받은 CPU는 counter가 0으로 초기화되고 선택받지 못한 나머지 CPU들은 counter가 증가한다. APIC은 가장 높은 counter를 가진 CPU에게 IRQ를 전달하여 CPU 간 중재하는 방식이 바로 중재 알고리즘이다. 이렇게 하면 골고루 IRQ를 처리할 수 있다. 리눅스가 선택한 방식이기도 하다.

SMP와는 반대의 성격을 가지는 Asymmetric Multiprocessing도 있다. Slave CPU들은 각자의 PC를 가지고 Shared Memory에 접근한다. 반면에 Master CPU는 자기만의 Local Memory를 가지고 거기에 kernel까지 있다. 이는 Master CPU만이 I/O instruction을 가질 수 있다는 것을 의미한다. Slave CPU들은 I/O를 하고 싶으면 Master CPU에게 요청해야만 가능하다.

이 방식이 가지는 장점은 mutual exclusion이 생기지 않는다는 것이다. 모든 I/O instruction들이 한 줄로 전달되기 때문이다. 이 장점 덕분에 디자인하기 쉬워서 옛날에는 모두 이 방식을 사용했다. 단점으로는 Master CPU만이 system call을 처리하기 때문에 많은 양의 system call을 한 번에 처리하는 데 과부하가 걸리기 쉽고, Master가 망가지면 모든 system이 다운되는 현상이 발생할 수 있다. 이런 단점들 때문에 현재에는 볼 수 없는 multiprocessing 방식이다.

반응형