인터럽트는 어떻게 처리하나요?

CPU가 인터럽트를 감지하면 현재 상태 저장 → IDT 조회 → 커널 모드 전환 → ISR 실행 → 상태 복원 → 복귀의 과정으로 처리합니다.

전체 처리 흐름 요약

① 인터럽트 발생 (하드웨어 신호 또는 소프트웨어 명령어)
② CPU가 현재 명령어 실행 완료
③ 인터럽트 수락 여부 확인 (IF 플래그)
④ 현재 상태 저장 (PC, 레지스터, 플래그 → 스택)
⑤ IDT에서 벡터 번호로 핸들러 주소 조회
⑥ 커널 모드 전환 (모드 비트 1 → 0)
⑦ ISR(Interrupt Service Routine) 실행
⑧ EOI 전송 (하드웨어 인터럽트의 경우)
⑨ 저장된 상태 복원
⑩ iret 명령어로 원래 프로그램 복귀

단계별 상세 설명

1단계: 인터럽트 발생

인터럽트 종류에 따라 발생 경로가 다릅니다.

[하드웨어 인터럽트]
장치 → IRQ 신호 → 인터럽트 컨트롤러(PIC/APIC)
    → 우선순위 판단 → CPU INTR 핀에 신호 + 벡터 번호 전달

[소프트웨어 인터럽트 — 트랩]
프로그램 → syscall 명령어 실행 → CPU가 직접 감지

[소프트웨어 인터럽트 — 예외]
프로그램 실행 중 오류 → CPU가 직접 감지 → 벡터 번호 결정

2단계: CPU가 현재 명령어 실행 완료

CPU는 명령어 실행 도중에 인터럽트를 처리하지 않음
현재 실행 중인 명령어를 완료한 뒤 인터럽트를 확인

명령어1 실행 → 명령어2 실행 → [인터럽트 확인 시점] → 인터럽트 처리
                                    ↑
                            매 명령어 완료 후 확인

3단계: 인터럽트 수락 여부 확인

CPU: RFLAGS 레지스터의 IF(Interrupt Flag) 확인
    │
    ├── IF = 1 (활성화) → 인터럽트 수락, 처리 진행
    │
    └── IF = 0 (비활성화) → 마스커블 인터럽트 무시
                            (NMI는 IF와 무관하게 항상 수락)
인터럽트 종류IF = 0 일 때
마스커블 (키보드, 디스크 등)무시됨 (나중에 처리)
논마스커블 NMI (전원 이상 등)무시 불가, 즉시 처리
소프트웨어 인터럽트 (트랩, 예외)IF와 무관하게 처리

4단계: 현재 상태 저장

CPU가 자동으로 커널 스택에 저장하는 값:

커널 스택
┌───────────────────┐ ← 높은 주소
│  SS (사용자 스택 세그먼트)  │
│  RSP (사용자 스택 포인터)   │
│  RFLAGS (플래그 레지스터)   │
│  CS (사용자 코드 세그먼트)   │
│  RIP (복귀할 명령어 주소)    │
│  Error Code (예외 시)       │
└───────────────────┘ ← 낮은 주소 (현재 RSP)

이후 ISR이 추가 레지스터를 수동으로 저장:
  push 범용 레지스터 (RAX, RBX, RCX, RDX, RSI, RDI, R8~R15 등)

5단계: IDT에서 핸들러 조회

CPU: 벡터 번호 확정
    │
    ▼
IDTR 레지스터 → IDT 시작 주소
    │
    ▼
IDT[벡터 번호] → 디스크립터 읽기
    │
    ├── Selector → 코드 세그먼트 확인
    ├── Offset   → ISR 시작 주소
    ├── DPL      → 접근 권한 검사
    └── Type     → Interrupt Gate / Trap Gate
    │
    ▼
ISR 주소로 점프 준비 완료
예시: 키보드 입력 (IRQ1 → 벡터 33)

IDTR → IDT 시작 주소: 0xFFFF8000
IDT[33] 조회:
  ┌─────────────────────────────────┐
  │ Offset: 0xFFFF8000_001A3400    │ → ISR 주소
  │ Selector: 0x10 (커널 코드 세그먼트) │
  │ Type: Interrupt Gate            │ → IF 자동 클리어
  │ DPL: 0 (커널 권한)              │
  └─────────────────────────────────┘

6단계: 커널 모드 전환 + ISR 실행

모드 비트: 1 → 0 (사용자 → 커널)
스택 전환: 사용자 스택 → 커널 스택 (TSS에서 커널 RSP 로드)

┌──────────────────────────────────────┐
│ ISR 실행 내용 (인터럽트 종류에 따라 다름)  │
├──────────────────────────────────────┤
│                                      │
│ [하드웨어 인터럽트 — 키보드 예시]        │
│  ① in 명령으로 키보드 컨트롤러에서       │
│     스캔 코드 읽기                     │
│  ② 입력 버퍼에 저장                    │
│  ③ Bottom Half 등록                  │
│                                      │
│ [소프트웨어 인터럽트 — 시스템 콜 예시]    │
│  ① RAX에서 시스템 콜 번호 추출          │
│  ② sys_call_table[RAX] 조회           │
│  ③ 커널 함수 실행 (sys_read 등)        │
│  ④ 결과를 RAX에 저장                   │
│                                      │
│ [예외 — 페이지 폴트 예시]               │
│  ① CR2 레지스터에서 폴트 주소 확인       │
│  ② 유효한 접근인지 판단                 │
│  ③ 디스크에서 페이지 로드               │
│  ④ 페이지 테이블 갱신                   │
│                                      │
└──────────────────────────────────────┘

7단계: EOI 전송 (하드웨어 인터럽트만)

ISR 처리 완료
    │
    ▼
인터럽트 컨트롤러에 EOI(End of Interrupt) 전송
    │
    ▼
인터럽트 컨트롤러가 해당 IRQ 라인을 다시 수신 가능 상태로 전환

※ EOI를 보내지 않으면:
   해당 IRQ 이하 우선순위의 인터럽트가 영원히 차단됨

8단계: 상태 복원 및 복귀

ISR 완료
    │
    ├── ① 수동 저장한 범용 레지스터 복원 (pop)
    │
    ├── ② iret 명령어 실행
    │    ├── RIP 복원 (복귀할 명령어 주소)
    │    ├── CS 복원 (코드 세그먼트)
    │    ├── RFLAGS 복원 (플래그 레지스터, IF 포함)
    │    ├── RSP 복원 (사용자 스택 포인터)
    │    └── SS 복원 (사용자 스택 세그먼트)
    │
    └── ③ 모드 비트: 0 → 1 (커널 → 사용자)
    │
    ▼
원래 프로그램이 중단된 지점부터 계속 실행

키보드 입력 처리 전체 예시

사용자가 'A' 키를 누름
    │
    ▼ ──────────── 1단계: 인터럽트 발생 ────────────
키보드 컨트롤러 → IRQ1 → APIC → CPU INTR 핀 (벡터 33)
    │
    ▼ ──────────── 2단계: 명령어 완료 ──────────────
CPU: 현재 명령어 실행 완료
    │
    ▼ ──────────── 3단계: IF 확인 ─────────────────
RFLAGS.IF = 1 → 인터럽트 수락
    │
    ▼ ──────────── 4단계: 상태 저장 ────────────────
SS, RSP, RFLAGS, CS, RIP → 커널 스택에 push
    │
    ▼ ──────────── 5단계: IDT 조회 ────────────────
IDTR → IDT[33] → 키보드 ISR 주소 획득
    │
    ▼ ──────────── 6단계: ISR 실행 ────────────────
[Top Half]
  - 스캔 코드(0x1E) 읽기
  - 입력 버퍼에 저장
  - Tasklet 등록
    │
    ▼ ──────────── 7단계: EOI 전송 ────────────────
APIC에 EOI → IRQ1 다시 수신 가능
    │
    ▼ ──────────── 8단계: 상태 복원 + 복귀 ──────────
iret → RIP, CS, RFLAGS, RSP, SS 복원 → 사용자 모드 복귀
    │
    ▼ ──────────── Bottom Half (나중에) ────────────
[Tasklet]
  - 스캔 코드 → 'A' 문자 변환
  - read()로 대기 중인 프로세스 깨우기

인터럽트 종류별 처리 차이

단계하드웨어 인터럽트시스템 콜 (트랩)예외
발생장치 → APIC → CPUsyscall 명령어CPU가 오류 감지
벡터 결정APIC가 전달0x80 또는 MSR 기반CPU가 자동 결정
상태 저장동일동일 (RCX, R11 사용)동일 + Error Code
ISR 내용장치 데이터 처리sys_call_table 조회오류 복구 또는 종료
EOI필요불필요불필요
복귀iretsysretiret (Fault: 같은 명령어, Trap: 다음)

Java에서의 인터럽트 처리 체감

// 파일 읽기 한 줄에서 발생하는 인터럽트 처리 과정
byte[] data = Files.readAllBytes(Path.of("data.txt"));

// 1. [트랩] open() 시스템 콜
//    → 상태 저장 → IDT → sys_open() → 복귀

// 2. [트랩] read() 시스템 콜
//    → 상태 저장 → IDT → sys_read()
//      → 디스크 I/O 요청 → 프로세스 Sleep

// 3. [하드웨어 인터럽트] 디스크 I/O 완료
//    → 상태 저장 → IDT → 디스크 ISR
//      → Top Half: DMA 완료 확인
//      → Bottom Half: 프로세스 깨우기
//    → EOI → 복귀

// 4. 프로세스 재개 → 데이터를 Java 배열에 복사

// 5. [트랩] close() 시스템 콜
//    → 상태 저장 → IDT → sys_close() → 복귀

CSLOG에서 보기