본 글은 The Linux Kernel 을 정리한 것이며, 출처를 밝히지 않은 모든 이미지는 원글에 속한 것입니다.


인터럽트(Interrupt)

  • 커널은 장치에 요청을 한 뒤 기다리지 않고 다른 작업을 하면서 요청한 작업이 끝나면 장치로부터 인터럽트를 받음
    • 리눅스는 여러 하드웨어 장치를 사용하는데, 동기적으로 구동할 경우 요청을 완료할 때까지 기다려야하는 문제가 있음
  • 인터럽트를 사용할 경우 여러 장치에 동시에 작업을 요청하는 것이 가능
  • 커널이 인터럽트를 처리하는데 일반적인 메커니즘과 인터페이스 표준이 존재하지만 세부 내용은 아키텍처마다 상이함
    • 장치가 인터럽트를 전달하는 것은 하드웨어에서 지원해야 함
  • 보통 CPU의 특정한 핀의 전압이 바뀌면(예를 들어 +5볼트에서 -5볼트), CPU는 하던 일을 멈추고 인터럽트 처리 코드를 실행
    • 어떤 핀은 간격 타이머에 의해 1000분의 1초마다 인터럽트를 받기도 함

https://www.embien.com/blog/interrupt-handling-in-embedded-software/

  • 인터럽트 컨트롤러(Interrupt Controller)
    • 대체로 시스템은 CPU의 인터럽트 핀으로 1:1로 인터럽트를 전달하지 않고, 컨트롤러를 사용하여 장치 인터럽트들을 그룹화
    • 인터럽트 컨트롤러에는 인터럽트를 조정하는 마스크 레지스터와 상태 레지스터가 존재
    • 마스크 레지스터의 비트들을 1 또는 0으로 설정하여 인터럽트를 가능하게 하거나 불가능하게 만들 수 있음
    • 상태 레지스터는 시스템에 현재 발생한 인터럽트를 가짐
    • 시스템의 일부 인터럽트는 하드웨어적으로 연결되어 있는데, 실시간 간격 타이머가 이에 해당되며, 각 시스템은 독자적인 인터럽트 전달 방식을 제공
  • 인터럽트 모드(Interrupt Mode)
    • 인터럽트가 발생하면 CPU는 지금 실행중인 명령어를 잠시 중단하고 인터럽트 처리 코드(Interrupt Handler)가 있거나 해당 코드로 분기하는 명령어의 메모리 주소로 점프(jump)하는데, 여기서 인터럽트 모드에 진입한다고 함
    • 보통 이 모드에서는 다른 인터럽트가 발생할 수 없으며, 예외로 인터럽트에 우선순위를 매기는 CPU의 경우, 높은 인터럽트가 발생하는 것을 허용
    • 인터럽트 처리 코드는 인터럽트 처리하기 전에 CPU의 수행 상태(즉, CPU의 레지스터 등을 포함한 컨텍스트)를 자신의 스택에 저장하고, 인터럽트를 처리하고 나면 CPU의 수행 상태가 인터럽트 처리 전으로 복구되고 인터럽트는 해제됨
    • 이후 CPU는 인터럽트가 발생하기 전에 수행하던 명령어를 재개
  • 프로그램 가능 인터럽트 컨트롤러(Programmable Interrupt Controller, PIC)
    • ISA 주소 공간에 있는 컨트롤러의 레지스터를 이용해 프로그램할 수 있는 컨트롤러
      • 이 레지스터의 위치는 고정되어 이미 알려진 것
    • 인텔에 기반하지 않은 시스템은 위와 같은 구조적 제약에서 자유로우며, 대개 다른 인터럽트 컨트롤러를 사용
    • PIC는 마스크 레지스터와 상태 레지스터를 포함하는데, 마스크 레지스터는 특정 비트를 1 또는 0으로 설정하여 특정 인터럽트(N번 비트면 N번 인터럽트)의 사용 유무를 결정
    •  마스크 레지스터는 쓸 수만 있으며, 써 놓은 값을 읽어오려면 설정 값을 별도로 복사해야 함
    • 인터럽트 허용 상태의 루틴과 인터럽트 금지 상태의 루틴에서, 마스크 레지스터의 복사본을 변경하고 매번 레지스터에 변경된 마스크 값을 씀
    •  인터럽트가 발생하면 인터럽트 처리 코드는 2개의 인터럽트 상태 레지스터(Interrupt Status Register, ISR)를 읽어서 처리

(출처를 못찾겠..) 2개의 PIC 로 장치를 연결

인터럽트 관련 자료구조

인터럽트 처리 커널 자료구조

  • 디바이스 드라이버들이 시스템의 인터럽트에 대한 제어권을 요청하면서 자료구조를 초기화
  • 각 디바이스 드라이버는 인터럽트를 요청해서 켜거나 끄거나 하는 루틴들을 호출해 각자의 인터럽트 처리 루틴의 주소를 커널 자료구조에 저장(등록 과정)
  • PCI 디바이스 드라이버는 장치가 어떤 인터럽트를 사용하는지 알고 있으나, ISA 디바이스 드라이버는 알 방법이 없으므로 커널은 사용할 인터럽트를 탐사(probe)할 기회를 제공
    • 탐사 과정: 디바이스 드라이버는 장치에 인터럽트를 발생하게 한 다음, 다른 장치에 할당되지 않은 모든 인터럽트를 켜서, 처음에 발생시켰던 장치의 인터럽트가 PIC를 통해 커널로 전달되면, 커널은 ISR을 읽어 디바이스 드라이버에게 값을 알려줌. 만약 그 값이 0이 아니라면 탐사 중에 하나 이상의 인터럽트가 발생한 것을 의미. 탐사 종료 후 다른 장치에 할당되지 않은 인터럽트를 모두 끄기
  • ISA 장치가 사용하는 인터럽트 핀은 대개 장치 위에 있는 점퍼를 사용해 설정하고 디바이스 드라이버는 지정된 값을 사용하지만,  PCI 장치가 사용할 인터럽트는 시스템이 부팅 중 PCI 초기화 과정에서 PCI BIOS나 PCI 서브시스템에 의해 할당됨
  • 인텔 칩을 사용하는 PC에서는 시스템 부팅 시 BIOS 에서 셋업 코드를 실행하나, BIOS가 없는 경우 리눅스 커널이 셋업을 수행
    • PCI 셋업 코드는 각 장치별로 인터럽트 컨트롤러의 핀 번호를 PCI 설정 헤더에 쓰고, 장치가 사용하는 PCI 슬롯 번호와 PCI 인터럽트 핀 번호 및 PCI 인터럽트 전달 구조를 이용하여 인터럽트 핀(또는 IRQ)을 결정
    • 디바이스 드라이버는 셋업 코드가 위 정보를 저장한 인터럽트 라인 항목을 읽어서 인터럽트 제어권을 커널에 요청할 때 사용
  • PCI-PCI 브릿지를 사용할 때와 같이 시스템에 PCI 인터럽트를 일으키는 장치가 많은 경우, PCI 장치는 인터럽트를 공유하여 여러 장치의 인터럽트가 하나의 핀에 발생하게 함
    • 공유 인터럽트를 사용하려면 커널에게 인터럽트 제어권을 요청할 때 해당 디바이스 드라이버가 인터럽트 공유 유무를 전달
    • irq_action 배열에 irqaction 구조체를 여러 개 저장하여 인터럽트를 공유
  • 공유 인터럽트가 발생하면 커널은 그 인터럽트 핀을 사용하는 장치의 모든 인터럽트 핸들러를 호출하므로, 모든 PCI 디바이스 드라이버는 서비스할 인터럽트가 없더라도 무시 등의 동작으로 호출을 대비해야함

인터럽트 처리(Interrupt Handling)

https://www.embien.com/blog/interrupt-handling-in-embedded-software/

  • 리눅스에서 인터럽트 처리 서브시스템은 인터럽트를 올바른 핸들러로 전달하기 위해 인터럽트 처리 루틴의 주소를 저장하고 있는 구조체에 대한 포인터를 사용
  • 이 루틴들은 해당 디바이스 드라이버에 있는 것이며, 드라이버가 초기화 될 때 각자 사용할 인터럽트의 제어권을 커널에 요청하면서 루틴의 주소를 알려주게 됨
  • 각 irqaction 구조체는 인터럽트 처리 루틴의 주소를 포함하는데, 핸들러에 필요한 정보도 가짐
    • irq_action 배열의 크기는 인터럽트가 발생하는 장치의 수
  • 인터럽트의 수와 이들이 처리되는 방법은 아키텍처마다 다르기 때문에 리눅스의 인터럽트 핸들러는 아키텍처에 종속적
  • 인터럽트 처리 과정
    • 커널은 시스템에 있는 PIC의 인터럽트 상태 레지스터(ISR)을 읽어 어느 장치가 인터럽트가 발생했는지 파악하고 irq_action 배열의 오프셋을 계산
    • irqaction 구조체에 접근하여 저장된 핸들러가 없다면 커널은 오류를 기록하고, 핸들러가 있다면 이 인터럽트가 발생하는 모든 장치에 대해 irqaction 구조체에 있는 핸들러를 호출
    • 디바이스 드라이버는 인터럽트 원인(오류/요청 작업 완료)을 파악하기 위해 해당 장치의 상태 레지스터를 읽어 인터럽트를 처리
  • 디바이스 드라이버는 인터럽트를 처리할 때 작업량이 많을 수 있는데, 커널에서는 CPU가 오랫동안 인터럽트 모드에 있는 것을 피하기 위해 작업을 인터럽트 처리 후로 미루는 메커니즘을 지원
  • 예를 들어, 터미널에 출력하기 위해 인터럽트가 발생(어셈블리어 명령 int가 인터럽트 처리 루틴을 호출)

https://stackoverflow.com/questions/29656136/is-there-a-system-call-service-routine-in-the-interrupt-vector

 

+ Recent posts