Post

10. Exceptions and Interrupts

10. Exceptions and Interrupts

CPU must prepare for unplanned events!

  • Instruction fail
  • External IO devices
  • Quantum expiration

(1) Check for every possible contingency (Polling)

  • CPU 낭비

(2) 그 문제는 별로 안일어나니까. 생길때만 처리

Interrupt 처리?

이미 들어온 친구들은 다 나갈때까지, 아직 안들어온 애들은 파이프라인에서 다 빼야함.

control transfer to the interrupt handler and back must be transparent to the interrupted thread! → 내 코드는 인터럽트 핸들러가 한 짓을 알면 안됨


Types of Interrupt

Synchronous Interrupts (Exceptions)

  • Tied to a particular instruction
  • illegal OPCODE, illegal operand, virtual memory faults
  • Faulting instruction cannot be finished.

→ No forward-progress unless handled immediately (다음 명령어 실행 불가. 무조건 처리하고 가야함)

Asynchronous Interrupts (Interrupts)

  • External events that not tide to instruction
  • Ctrl+C, IO Events, timer

→ Some delay is allowed, but you cannot postpone forever!

Syscall / Trap Instruction (Planned)

  • Instruction that is purposed to raise an exception
    • printf는… 내 관할이 아니다. OS 형님 카바좀 쳐주십쇼
    • 형님 파일 디스크립터좀 바꿔주셈. 처리되면 얘기해주세요

→ 끊는 시점이 비교적 자유로움


Virtualization and Protection

운영체제만 여러개의 프로세스를 돌리는걸 알고, 유저 레벨에서는 여러개 돌리는지 모름.

architectural state 명확히 보존해주는 것.

Privilege Levels

User - kernel - hypervisor

여기서 상위 레벨의 행동을 하려면 interrupt를 걸어야함

Precise Interrupt

synchronous: 예외 명령어 딱 이전에 멈추고, handling끝나고 다시 해당 예외발생 명령어 처리

asynchronous: 자유긴 한데, 보통 예외 발생 이후는 다 flush함


MIPS Interrupt Architecture

Exception Program Counter (EPC, CR14)

  • EPC(CR14): 문제 생긴 시점의 주소 (어디서 멈춰야 해요?)
  • CR13: 문제가 생긴 이유 레지스터
    • pending interrupt: 내가 뭘 핸들링하고있었는지 적어두는 곳.
  • CR12: enable, disable interrupt 정보
    • 제어용 레지스터. write (인터셉트 등)
1
mfc0 r26, $14  

로 가져온 후, jr로 pc 값을 바꿔서 복귀한다. 한번에 못가져옴


Interrupt의 행동

  • 최대한 레지스터를 안쓰고 나가야한다.
  • function call처럼 r31을 쓸 수 없다.
  • 무조건 callee-saved를 해야한다.
  • 컨벤션: r26 & r27은 커널이 쓰는, 핸들러용 레지스터

Interrupt Servicing

이유를 적은 CR13이 있다.

(1) Interrupt를 핸들하는 코드 자체가 메모리에 저장되어있음

  • flexible, but slow

(2) 하드웨어가 바로 보고 처리한다. (vectored interrupt)

  • fast, but hard-coded

Returning from Interrupt

  • exception은 해당 명령어 재 실행 (EPC에 해당 명령어 주소)
  • interrupt은 해당 명령어 다 보내고 그 다음 명령어 주소 넣기.

(1) MIPS32 : ERET

  • Atomically restore saved CPU states
  • Restore privilege level
  • Jump back to EPC

(2) MIPS2000

  • Assume mfc0 r26 done
  • jr r26 (EPC 복붙한걸로 jump)
  • rfe (restore from exception mode) - branch delay slot에서 실행되어야함

Branch Delay Slot & RFE

1
2
3
4
1000: BEQ  
1004: ADD (branch delay slot)  
  
5000: Handler (kernel)  

여기서 1000에서 BEQ가 만족했지만, branch delay slot으로 1004까지 실행하고 jump한다고 하자. 1004가 page fault 등으로 exception이 났다고 가정하자.

이러면 5000번에서 EPC의 값은 1004이고, ADD를 다시 실행하러 온다. 그런데? 이제 jump해야하는 정보가 사라져서 망해버렸다.

→ 무한 Loop 발생

Solution: Exception은 branch delay slot이면 1000을 걸자.

Harmful in JALR r31

JALR r31이 실행되면 r31의 값으로 점프하면서, 자기의 PC+8을 r31에 넣는다. (이게 기본인데, 하필 가져오는 레지스터도 r31인 것)

우리는 r31을 다시 보면 r31는 PC+8임. 원래 코드 날아감.

→ 원치않는 동작이고, can be looped


Brief Handler code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
_handler_short:  
	# prologue  
	addi sp, sp -0x8 # increast stack size by 8-byte  
	sw r8, 0x0(sp)  
	sw r9, 0x4(sp)  
	  
	// use r26, r27 to resolve   
	  
	# epilogue  
	lw r8, 0x0(sp)  
	lw r9, 0x4(sp)  
	addi sp, sp 0x8 # reduce stack size  
	mfrc0 r26, epc  
	jr r26  
	rfe  

(1) 일단 handler는 exception이 안나도록 해야함

(2) 그래도 나니까 우선순위를 잘 짜라 (CR12)

→ async 인터럽트는 우선순위에 따라 처리되며, 타이밍이 중요한 친구가 우선 처리된다.

서로 다른 우선순위의 인터럽트는 마스킹에 의해 disabled될 수 있다.

→ 오로지 higher-priority만 re-enable하여 처리한다.

만약 낮은 애들도 re-enable해버리면 무한 루프에 돌 수 있다.

Nested Handler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
_handler_short:  
	# prologue  
	addi sp, sp -0x8 # increast stack size by 8-byte  
	mfc0 r26, epc  
	sw r26, 0x0(sp)  
	sw r8, 0x4(sp)  
	  
	addi r26, r0, 0x405 // interrupt enable bit write하여 중간 인터럽트 허용  
	mtc0 r26, status // ??  
	  
	// handler  
	  
	#epilogue  
	  
	addi r8 r0 0x404  
	mtc0 r8, status // ??  
	  
	lw r26, 0x0(sp)  
	lw r8, 0x4(sp)  
	addi sp, sp 0x8 # reduce stack size  
	jr r26  
	rfe  
This post is licensed under CC BY 4.0 by the author.