개요
인터럽트는 프로세서가 실행하는 명령어의 순서를 바꾸는 사건으로 정의한다. 이런 사건은 CPU의 내·외부에서 하드웨어적인 회로가 발생하는 전기적인 신호에 해당하다.
흔히 동기적 인터럽트와 비동기적 인터럽트로 나눈다.
- 동기적인 인터럽트는 CPU의 제어 유닛이 명령어를 실행하는 과정에서 발생하는데, 제어 유닛은 명령어 실행을 마친 후에만 이를 발생시키기 때문에 동기적이라고 한다.
- 비동기적 인터럽트는 다른 하드웨어 장치가 CPU 클럭의 신호와 관계없이 아무 때나 발생한다.
인텔 마이크로프로세서 매뉴얼에서는 동기적인 인터럽트를 예외(Exception), 비동기적인 인터럽트를 인터럽트라고 명한다.
인터럽트는 간격 타이머와 입출력장치에 의해 발생한다. 입출력장치인 키보드의 키를 누르면 인터럽트가 발생한다.
반면, 예외는 프로그래밍 에러나 커널이 처리해야 하는 비정상적인 상황에 의해 발생한다. 프로그래밍 에러인 경우 커널은 현재 프로세스에게 신호를 보내 예외를 처리한다. 비정상적인 상황인 경우에는 페이지 폴트(Page Fault)나 커널 서비스 요청(int 또는 systenter) 같은 비정상적인 상황을 복구하는데 필요한 모든 단계를 수행한다.
인터럽트 신호와 역할
인터럽트 신호는 프로세서가 정상적인 제어 흐름 밖의 코드로 방향을 바꾸는 방법을 제공한다. 인터럽트 신호가 도착하면 CPU는 EIP와 CS 레지스터를 커널 모드 스택에 저장하고, 발생한 인터럽트 종류와 연계된 주소를 프로그램 카운터에 넣어 수행한다.
이 전환 과정은 프로세스 전환 과정의 컨텍스트 전환과 큰 차이가 있다. 인터럽트·예외 핸들러가 실행하는 코드는 프로세스가 아니다. 인터럽트가 발생한 시점에 CPU를 점유하고 있던 프로세스가 수행되던 과정에서 실행되는 커널 제어 경로라고 할 수 있다. 인터럽트 핸들러는 커널 제어 경로 이므로 프로세스보다 가볍다.
인터럽트는 다음의 조건을 만족해야 한다.
- 가능한 빨리 인터럽트에서 벗어나고 되도록 많은 작업을 나중으로 미뤄야 한다.
- 중첩 인터럽트를 가능한한 많이 허용해야 한다.
- 인터럽트를 받을 수 없는 임계 영역은 가능한 제한해야 한다.
인터럽트와 예외
인터럽트
마스크 가능한 인터럽트 : 입출력 장치가 발생시키는 모든 인터럽트 요청(IRQ)는 마스크 가능한 인터럽트를 발생시킨다. 마스크 가능한 인터럽트는 마스크 되거나 되지않은 상태 중 하나에 있을 수 있다. 제어 유닛은 마스크 된 인터럽트는 마스크 되어 있는 동안 계속 무시한다.
마스크 불가능한 인터럽트 : 몇몇 심각한 사건(하드웨어 고장)만이 마스크 불가능한 인터럽트를 발생시킨다. CPU를 마스크 불가능한 인터럽트가 발생하면 항상 감지한다.
예외
프로세서가 감지하는 예외 : CPU가 명령어를 실행하다가 비정상적인 상황을 감지할 때 발생한다. CPU 제어 유닛이 예외를 발생시킬 때 커널 모드 스택에 저장하는 EIP 레지스터의 값에 따라 세 그룹으로 분류할 수 있다.
- 폴트 : 일반적으로 고칠 수 있으며, 일단 바로 잡으면 프로그램은 재시작하여 이어서 실행할 수 있다. 저장된 eip 값은 폴트를 일으킨 명령어의 주소이기 때문에 예외 핸들러를 끝마치면 해당 명령어로 복귀할 수 있다.
- 트랩 : 트랩을 발생시키는 명령어를 실행하자마자 발생한다. 프로그램은 커널로부터 제어를 돌려 받은 후에 이어서 실행할 수 있다. 저장된 eip 값은 트랩을 발생시킨 명령어 다음에 실행해야 하는 명령어의 주소이다. 트랩은 종요한 명령어를 다시 실행할 필요가 없을 때만 일어난다. 트랩의 주 용도는 디버깅이다. 디버거에 특정 명령어가 실행되었음을 알려주는 역할을 한다. 사용자는 디버거가 제공하는 데이터를 검사한 후 디버깅하고 있는 프로그램이 다음 명령어부터 실행을 재개하도록 할 수 있다.
- 중단 : 심각한 오류가 생겼을 때 발생한다. 제어 유닛이 어려운 상황에 빠져 있고, eip 레지스터에 예외를 일으킨 정확한 위치를 저장하지 못할 수도 있다. 이는 하드웨어 고장이나 시스템 테이블에 잘못된 값이 들어 있을 때 발생한다. 제어 유닛이 보낸 인터럽트 신호는 제어권을 해당 중단 예외 핸들러에 넘기려는 긴급 신호이다. 이 핸들러는 문제가 발생한 프로세스를 강제로 종료하는 것 외에 다른 선택권이 없다.
- 프로그래밍에 의한 예외 : 프로그래머의 요청이나 int, int3 명령어에 의해 발생한다. into와 bound 명령어도 검사하는 조건이 맞지 않은 경우 프로그래밍에 의한 예외를 발생시킨다. 제어 유닛은 이 예외를 트랩으로 처리한다. 소프트웨어 인터럽트라고도 불린다. 시스템 콜을 구현하는 것과 디버거에 신호를 주는 용도로 사용된다.
각 인터럽트나 예외는 0~255 까지의 숫자로 구별한다. 인텔은 8비트로 0 이상의 숫자를 벡터라고 부른다. 마스크 불가능한 인터럽트와 예외 벡터 번호는 고정되어 있다. 반면에 마스크 가능한 인터럽트의 벡터 번호는 인터럽트 컨트롤러를 프로그램하여 바꿀 수 있다.
IRQ와 인터럽트
인터럽트 요청을 제기할 수 있는 모든 하드웨어 장치 컨트롤러를 IRQ 출력 선 하나를 갖는다. 시스템에 존재하는 모든 IRQ 선은 인터럽트 컨트롤러라는 하드웨어 회로의 입력 핀으로 연결된다. 인터럽트 컨트롤러는 다음과 같이 동작한다.
- IRQ 선을 감시하고, 신호가 발생하는 이를 검사한다. 여러 개의 선에서 발생한느 경우 핀 번호가 낮은 것을 먼저 처리한다.
- IRQ 선에서 발생한 신호는
- 수신한 신호를 벡터로 변환한다.
- 인터럽트 컨트롤러의 입출력 포트에 벡터를 저장하여 CPU가 데이터 버스를 통해서 이를 읽을 수 있도록 한다.
- 발생한 신호를 프로세서의 INTR 핀으로 보낸다. 즉 인터럽트를 발생시킨다.
- CPU가 프로그램 가능한 인터럽트 컨트롤러의 입출력 포트 중 하나에 값을 써 넣어 CPU가 인터럽트 신호를 받았음을 알려줄 때 까지 기다린다. 확인하면 INTR 선을 0으로 만든다
- 1단계로 돌아간다.
IRQ 선은 0부터 시작해서 순차적으로 번호가 붙어 있으며, 첫 번째 IRQ 선을 보통 IRQ0으로 표시한다. 인텔에서 IRQn에 부여하는 기본 벡터는 n+32이다. IRQ와 베거 사이의 매핑은 인터럽트 컨트롤러 포트에 적절한 입출력 명령어를 보내서 수정할 수 있다.
각 IRQ 선을 선택적으로 금지할 수 있으며, 여러 IRQ를 금지하도록 PIC를 프로그램 할 수도 있다. 즉 어떤 특정 IRQ 선에서 오는 인터럽트를 더는 발생시키지 않도록 PIC에 요청할 수도 있고 허용할 수도 있다. 금지된 인터럽트는 없어지는 것이 아니며, PIC가 해당 인터럽트를 허용하자마자 인터럽트는 CPU에 전달된다. 이런 특성은 종류가 동일한 IRQ를 연속적으로 처리할 수 있게 하기 때문에 대부분의 인터럽트 핸들러에서 이용한다.
선택적으로 IRQ를 허용하거나 금지하는 것과 별도로 마스크 가능한 모든 인터럽트를 마스크하거나 언마스크 할 수도 있다. eflags 레지스터의 IF 플래그를 0으로 만들면, CPU는 일시적으로 PIC가 발생시키는 어떠한 마스크 가능한 인터럽트도 무시한다. cli와 sti 어셈블리어를 통해 IF 플래그를 설정하거나 지울 수 있다.
전통적으로 PIC는 8259A 종류의 외부 칩 2개를 중첩 방식으로 연결하여 구현한다. 각 칩은 8개까지 서로 다른 인터럽트 선을 처리할 수 있다. 슬레이브 PIC의 INT 출련 선은 마스터 PIC의 IRQ2로 연결되어 있기 때문에 사용할 수 있는 IRQ의 개수는 15개로 제한된다.