디바이스 드라이버를 위한 커널 서비스
2. 인터럽트 처리
2.1 예외 처리
address |
Exception |
Mode on Entry |
Priorities |
0x00000000 |
Reset |
Supervisor |
1 |
0x00000004 |
Undefined instruction |
Undefined |
6 |
0x00000008 |
Software interrupt |
Supervisor |
6 |
0x0000000C |
Abort (prefetch) |
Abort |
5 |
0x00000010 |
Abort (data) |
Abort |
2 |
0x00000014 |
Reserved |
Reserved |
Reserved |
0x00000018 |
IRQ |
IRQ |
4 |
0x0000001C |
FIQ |
FIQ |
3 |
2.2 인터럽트
디바이스는 프로세서와는 다른 시간 간격, 정확하게는 훨씬 느린 시간으로 수행된다.
프로세서가 무작정 외부 이벤트를 기다리는 것은 바람직하지 못하므로 프로세서에게 뭔가가 발생했다고 알릴 방법이 있어야 한다.
2.3 인터럽트 컨트롤러
이름 |
용도 |
SRCPND |
인터럽트가 발생 여부가 체크 되는 레지스터, 여러개의 인터럽트 소스가 체크될 수 있음. |
INTMSK |
인터럽트의 사용 여부를 결정 |
INTPND |
SRCPND 레지스터와 달리 여러개의 인터럽트 소스가 발생하면 우선 순위 로직을 거쳐 하나의 인터럽트 소스만 체크되는 레지스터 |
SUBSRCPND |
SRCPND 레지스터와 동일한 기능이며, Sub 개념을 좀 더 많은 인터럽트 소스를 처리하기 위해 사용 |
INTSUBMSK |
INTMSK 레지스터와 동일한 기능이며, SUBSRCPND의 인터럽트 사용 여부를 결정 |
INTMOD |
인터럽트 소스를 IRQ/FIQ로 사용할지를 결정 |
2.4 인터럽트 처리
- 인터럽트 핸들러 (인터럽트 서비스 루틴 - ISR)
- 인터럽트 처리를 두 단계로 분리
- 인터럽트 서비스 처리 흐름
- 인터럽트 서비스 함수의 형식
int irq |
인터럽트 번호 (irqs.h에 정의) |
void *dev_id |
인터럽트 ID 또는 인터럽트 함수가 사용 가능한 메모리 주소. 인터럽트 서비스 공유에 사용되거나 인터럽트 서비스 함수를 수행할 때 필요한 정보가 저장된 메모리의 주소를 저장 |
struct pt_regs *regs | 인터럽트가 발생했을 당시의 레지스터 값 대부분 사용하지 않음 (디버깅 목적) |
- 인터럽트 서비스 함수의 등록 - request_irq()
int irq |
인터럽트 번호 |
irqreturn_t (*handler) (int, void* struct pt_regs *regs) |
인터럽트가 발생했을 때 처리되는 인터럽트 서비스 함수 포인터 |
unsigned long flags |
인터럽트 공유나 바른 인터럽트 같은 처리 속성을 지정 SA_INTERRUPT: 다른 인터럽트를 허가하지 않음 SA_SHIRQ: 동일한 인터럽트 번호를 공유 SA_SAMPLE_RANDOM: 랜덤 값 처리에 영향을 줌 (/dev/random) |
const char *device |
인터럽트에 대한 소유자를 표현하는 문자열을 지정 |
void* dev_id |
인터럽트가 공유되었을 때 인터럽트에 대한 구분 인자로 사용 인터럽트 서비스 함수가 참조하는 데이터에 대한 주소를 지정 |
- 정상적으로 수행되면 0을 리턴
- 비정상적일 때는 에러 상황에 맞는 음수 값을 반환
- 인터럽트 서비스 함수의 해체 - free_irq()
int irq |
제거하고자 하는 인터럽트 서비스 함수의 인터럽트 번호 |
dev_id |
request_irq() 함수에서 사용한 dev_id와 동일 |
- 인터럽트 서비스 등록 시점과 해제 시점
- 하나의 응용 프로그램만이 디바이스 파일을 사용하는 경우
모듈 초기화, open() 함수 모두 ISR 등록 가능
응용 프로그램이 종료되고 난 후 close() 함수에서 ISR 제거
- 두 개 이상의 응용 프로그램이 디바이스 파일을 사용하는 경우
모듈 초기화에서 ISR 등록
-> open() 에서 등록할 경우 동일한 인터럽트 서비스 루틴이 두 번 이상 등록할 수 있음
-> open() 에서 등록할 경우 먼저 해제를 시도한 쪽에서 인터럽트 서비스 함수를 제거하는 경우,
다른 쪽 응용 프로그램에서 인터럽트 서비스 함수가 동작하지 않음.
- PC 같은 범용 시스템에 사용되는 디바이스 드라이버
-> open()과 close() 함수에서 처리
- 임베디드와 같은 특정 목적의 시스템에서는 모듈의 등록과 해제 시에 처리하는 것이 좋음
2.5 인터럽트 함수와 디바이스 드라이버 간의 데이터 공유
2.6 인터럽트 공유
2.7 인터럽트 금지와 해제
- 인터럽트 서비스 함수가 동작 중에 다른 인터럽트가 발생하지 못하게 금지하는 방법
- 일반적인 함수 수행 중에 데이터 처리를 보호하기 위해 인터럽트를 강제로 막는 방법
#include <asm/irq.h> |
|
void disable_irq(int irq) |
인터럽트 금지 |
void enable_irq(int irq) |
인터럽트 허가 |
void disable_irq_nosync(int irq) |
현재 핸들러가 종료할 때까지 기다리지 않음 |
synchronize_irq(unsigned int irq) |
특정 인터럽트 핸들러가 실행 중일 경우 기다렸다가 실행이 끝나면 리턴 |
- 프로세서 전체의 인터럽트를 금지하고 해제하는 방법
#include <asm/system.h> |
|
local_irq_disable(void) |
프로세서의 인터럽트 처리를 금지 |
local_irq_enable(void) |
프로세서의 인터럽트 처리를 허가 |
local_save_flags(ulong flags) |
현재의 프로세스의 상태를 저장 |
local_restore_flags(ulong flags) |
저장된 프로세스의 상태를 복구 |
local_irq_save(unsigned long flags) |
프로세서의 인터럽트 처리를 금지시키면서 동시에 현재 프로세서의 상태를 저장 |
local_irq_restore(unsigned long flags) |
프로세서의 인터럽트 처리를 허가시키면서 동시에 현재 프로세서의 상태를 복구 |
- 보편적인 인터럽트 방지법
unsigned long flags; local_save_flags(flags); local_irq_disable(); local_restore_flags(flags); |
* local_irq_enable() 함수를 사용하지 않는 이유
local_save_flags() 함수에 의해 저장된 flags 변수에 이미 인터럽트 허가 상태가 포함되어 있기 때문에 local_restore_flags() 함수에 의해 local_irq_enable() 함수를 호출한 효과가 발생
'Linux Driver' 카테고리의 다른 글
캐릭터 디바이스 드라이버 (Character Device Driver) (0) | 2018.08.30 |
---|---|
디바이스 드라이버 (Device Driver) - 1. 개요 (1) | 2018.08.29 |
커널 모듈 (Kernel Module) (0) | 2018.08.29 |
디바이스 드라이버를 위한 커널 서비스 (Kernel Service for Device Driver) - 1. 변수와 메모리 할당 (0) | 2018.08.29 |
리눅스 커널 (linux kernel) (2) | 2018.08.29 |