Linux Kernel(4.19) Hacks

rousalome.egloos.com

포토로그 Kernel Crash


통계 위젯 (화이트)

132199
1107
135860


[리눅스커널][인터럽트] 인터럽트 컨택스트란 - in_interrupt() 5. 인터럽트

인터럽트 컨텍스트와 관련된 코드를 분석함으로써 인터럽트 컨텍스트의 세부 동작 방식을 알아보기에 앞서 인터럽트 컨텍스트의 개념을 알아보겠습니다. 먼저 인터럽트 컨텍스트를 간단히 정의하자면 "현재 실행 중인 프로세스가 현재 인터럽트를 처리 중"이라는 것을 의미합니다. 즉, 현재 실행 중인 함수가 인터럽트 핸들러이거나 인터럽트 핸들러에서 호출된 함수라는 것입니다.

이어서 인터럽트 컨텍스트의 의미을 조금 더 깊이 알아보겠습니다. 인터럽트 컨텍스트라는 용어는 인터럽트와 컨텍스트라는 단어를 합친 것입니다. 인터럽트의 컨텍스트라고도 볼 수 있습니다. 

리눅스 커널에서 컨텍스트란?

인터럽트 컨텍스트의 의미를 파악하기 위해 먼저 '컨텍스트'가 무엇인지 알아볼 필요가 있습니다. 컨텍스트란 '프로세스 실행 그 자체'를 의미하며 현재 실행 중인 프로세스 정보를 담고 있는 레지스터 세트로 표현할 수 있습니다.

이해를 돕기 위해 간단한 질문을 하나 해보겠습니다. 커널이 schedule() 함수를 실행하고 있는데 이 함수의 주소가 0xC000D000입니다. 그렇다면 프로그램 카운터는 어떤 값을 저장하고 있을까요? 이 질문에 다음과 같이 대답할 수 있습니다. 

   * 프로그램 카운터 레지스터는 0xC000D000이다.

이처럼 PC 레지스터를 포함한 레지스터 세트로 현재 실행 중인 프로그램 상태를 표현할 수 있습니다.


프로세스가 스케줄링으로 휴면할 때는 현재 실행 중인 레지스터 세트를 특정 공간(스택의 최상단 주소)에 저장합니다. 스케줄링으로 의해 다시 깨어나면 이전에 동작했던 지점의 코드부터 실행해야 하기 때문입니다. 그럼 프로세스는 다시 실행하기 전에 어떤 동작을 할까요? 프로세스는 휴면할 때 저장했던 레지스터 세트를 로딩합니다. 그 이유는 휴면할 때 저장했던 레지스터에 프로세스 실행 정보가 담겨 있기 때문입니다. 


이처럼 프로세스 실행은 레지스터 세트로 표현할 수 있습니다. 그렇다면 여기서 말하는 레지스터 세트는 어떤 자료구조일까요? 정답은 cpu_context_save 구조체입니다. cpu_context_save 구조체를 함께 확인해 봅시다.

https://github.com/raspberrypi/linux/blob/rpi-4.19.y/arch/arm/include/asm/thread_info.h
struct cpu_context_save {
__u32 r4;
__u32 r5;
__u32 r6;
__u32 r7;
__u32 r8;
__u32 r9;
__u32 sl;
__u32 fp;
__u32 sp;
__u32 pc;
__u32 extra[2]; /* Xscale 'acc' register, etc */
};

cpu_context_save 구조체 필드는 프로세스가 실행 중인 레지스터 값을 나타내며, 이 필드에 현재 동작 중인 프로세스의 레지스터가 저장됩니다.

그럼 cpu_context_save 구조체는 어디에 저장될까요? 프로세스 스택의 최상단 주소를 나타내는 thread_info 구조체의 cpu_context 필드에 저장됩니다. 

https://github.com/raspberrypi/linux/blob/rpi-4.19.y/arch/arm/include/asm/thread_info.h
01 struct thread_info {
02 unsigned long flags; /* low level flags */
03 struct cpu_context_save cpu_context; /* cpu context */

thread_info 구조체의 03번째 줄을 눈여겨봅시다. 필드명도 cpu_context입니다.

쉽게 설명하면 컨텍스트란 “프로세스가 실행 중인” 상태라고 할 수 있습니다. 위에서 알아봤듯이 레지스터 세트로 현재 실행 중인 상태를 저장하기 때문입니다.

이제 처음으로 돌아가서 인터럽트 컨텍스트의 의미를 짚어 보겠습니다. 

인터럽트 컨텍스트란 무엇인가?

이제 결론을 내리겠습니다. 인터럽트 컨텍스트란 용어는 무슨 뜻일까요? 바로 “인터럽트를 처리 중”이란 뜻입니다.

인터럽트가 발생하면 인터럽트 벡터 주소부터 인터럽트 핸들러까지 함수 흐름으로 인터럽트를 처리합니다. 인터럽트 컨텍스트란 이 흐름 중 하나라고 볼 수 있습니다. 인터럽트 컨텍스트를 처음 접하는 분은 이 같은 의미를 파악하기 어려우니 조금 더 풀어서 정리하면 현재 인터럽트 핸들러를 실행 중이면 인터럽트 컨텍스트입니다. 인터럽트를 핸들링하는 중이기 때문입니다. 

그럼 인터럽트 핸들러에서 호출된 서브 함수 중 하나가 실행될 때도 인터럽트 컨텍스트라고 볼 수 있을까요? 맞습니다. 현재 인터럽트가 발생한 다음 인터럽트를 핸들링하는 도중이기 때문입니다. 

그렇다면 리눅스 커널에서 인터럽트 컨텍스트를 정의한 이유는 무엇일까요? 그 이유는 인터럽트가 발생하면 이를 핸들링하는 코드를 빨리 실행해야 하기 때문입니다. 리눅스 커널 및 디바이스 드라이버에서 실행되는 함수는 인터럽트 핸들러에서 실행될 수도 있고 아닌 경우도 있습니다.

그래도 인터럽트 컨텍스트의 의미를 이해하기 어렵습니다. 커널은 이론으로 아무리 자세하게 읽어도 이해가 안 되고 머릿속에 잘 남지 않는 것 같습니다. 그렇다고 실망할 필요는 없습니다. 우리에겐 커널 코드와 ftrace라는 강력한 도구가 있습니다. ftrace 로그를 열어서 실제로 어느 로그가 인터럽트 컨텍스트인지 확인하는 실습을 해보면 인터럽트 컨텍스트가 무엇인지 조금 더 쉽게 파악할 수 있습니다.

인터럽트 컨텍스트란 용어는 왜 배워야 할까?
인터럽트 컨텍스트란 용어를 알아야 하는 이유는 간단합니다. 리눅스 커널 전반에 이 용어가 사용되고, 이 개념을 적용한 커널 코드가 많기 때문입니다. 인터럽트 컨텍스트에 대한 공학적 의미를 이해하지 못하면 다른 코드를 이해하기 어렵습니다.

이어지는 절에서는 인터럽트 컨텍스트를 ftrace와 커널 로그로 조금 더 알아보겠습니다.

 

"이 포스팅이 유익하다고 생각되시면 댓글로 응원해주시면 감사하겠습니다.  
"혹시 궁금한 점이 있으면 댓글로 질문 남겨주세요. 아는 한 성실히 답변 올려드리겠습니다!" 

Thanks,
Austin Kim(austindh.kim@gmail.com)

# Reference (인터럽트 처리)


핑백

덧글

댓글 입력 영역