Arm Linux Kernel Hacks

rousalome.egloos.com

포토로그 Kernel Crash


통계 위젯 (화이트)

94305
1828
210800


[리눅스커널] 인터럽트(Interrupt)란? 5. 인터럽트

인터럽트란 무엇일까요? 인터럽트란 일반적인 상황에서 갑자기 발생하는 비동기적인 통지나 이벤트라고 볼 수 있습니다. 이번 절에서는 인터럽트라는 용어와 그것의 의미를 알아보겠습니다.

일상 생활에서의 인터럽트

인터럽트란 단어가 생소하신가요? 낯설게 들리는 분도 있고 귀에 익은 분도 있을 것입니다. 일상생활에서 인터럽트란 갑자기 생긴 일이나 하던 일을 멈춘다는 의미입니다. 일상적으로 하던 일을 멈추게 하는 무엇인가가 갑자기 발생한 상황을 뜻합니다. 예를 들면, 책을 읽다가 갑자기 전화가 와서 읽던 책을 덮어 놓고 전화를 받는 상황이 그러합니다.

하드웨어 관점에서 인터럽트란?

임베디드 시스템 관점에서 인터럽트는 무엇일까요? 먼저 하드웨어 관점에서 생각해 봅시다. 하드웨어 관점에서 인터럽트란 하드웨어의 변화를 감지해서 외부 입력으로 전달되는 전기 신호입니다.

한 가지 예를 들어보겠습니다. 손으로 키보드를 치면 하드웨어적으로 키보드 하드웨어의 변화를 감지하고 신호가 발생합니다. 그래서 보통 하드웨어 개발자들은 오실로스코프란 장비로 인터럽트 신호가 제대로 올라오는지 측정합니다.

오실로스코프로 인터럽트 신호를 측정하면 다음과 같은 파형을 볼 수 있습니다. 

 
그림 5.1 인터럽트 파형의 예

참고로 인터럽트 신호는 그림 5.1과 같이 인터럽트를 식별하는 구간에 일정하게 5V(Voltage)를 유지하거나 0V에서 5V로 바뀌는 두 가지 종류로 분류합니다.

CPU 입장에서 인터럽트란?

이번에는 소프트웨어 관점에서 인터럽트가 무엇인지 알아봅시다. 인터럽트가 발생하면 프로세스는 하던 일을 멈추고 '이미 정해진 코드'를 실행해서 하드웨어의 변화를 처리합니다. 여기서 '이미 정해진 코드'란 어떤 의미일까요? 인터럽트 벡터와 인터럽트 핸들러를 말합니다.  이처럼 인터럽트가 발생하면 소프트웨어적으로 처리하는 과정을 인터럽트 서비스 루틴(Interrupt Service Routine)이라고 합니다.

이번에는 CPU(ARM) 관점에서 인터럽트를 어떻게 처리하는지 알아봅시다. 인터럽트는 CPU 아키텍처별로 다르게 처리합니다. x86, ARMv7, ARMv8 아키텍처별로 인터럽트를 처리하는 방식이 다른 것입니다. 라즈베리 파이는 ARMv7 기반 아키텍처이므로 ARMv7 CPU에서 인터럽트를 처리하는 과정을 알면 됩니다. 그럼 ARMv7 아키텍처에서는 인터럽트를 어떻게 처리할까요? ARMv7 프로세서에서 인터럽트는 익셉션(Exception)의 한 종류로 처리하므로 익셉션 처리 방식에 대해 알 필요가 있습니다. 

ARMv7 아키텍처에서 익셉션의 동작 원리는 무엇일까요? ARMv7 프로세서는 외부 하드웨어 입력이나 오류 이벤트가 발생하면 익셉션 모드로 진입합니다. ARMv7 프로세스는 익셉션이 발생했다고 감지하면 익셉션 종류별로 이미 정해 놓은 주소로 브랜치합니다. 조금 어려운 개념인데 순간 이동과 비슷한 개념으로 생각해도 좋습니다. 이미 정해진 주소로 브랜치하는 동작은 조금만 생각해보면 그리 낯설지는 않습니다. 어떤 코드에서 함수를 호출할 때 어셈블리 코드로 분석하면 이와 유사한 동작을 합니다.

한 가지 예를 들겠습니다.

https://github.com/raspberrypi/linux/blob/rpi-4.19.y/kernel/sched/core.c
01 asmlinkage __visible void __sched schedule(void)
02 {
...
03 do {
04 preempt_disable();
05 __schedule(false);

05 번째 줄과 같이 __schedule(false) 함수를 호출할 때 어셈블리 코드 관점에서는 어떻게 동작할까요? ARM 코어 프로그램 카운터를 __schedule() 주소로 바꿉니다. 즉, 현재 실행 중인 레지스터 세트를 스택에 푸시합니다.

마찬가지로 ARM 이 익셉션 모드를 감지하면 익셉션 모드별로 정해진 주소로 ARM 코어 프로그램 카운터를 바꿉니다. 이후 실행 중인 코드의 레지스터 세트를 스택에 푸시합니다.

인터럽트나 소프트웨어적인 심각한 오류가 발생하면 ARMv7 프로세스는 ‘이미 정해진 주소’에 있는 코드를 실행합니다. 이미 정해진 주소 코드를 익셉션 벡터(Exception Vector)라 하며, 각 익셉션의 종류에 따라 주소의 위치가 다릅니다. 그런데 ARMv7 프로세서는 인터럽트를 익셉션 벡터 중 하나의 모드로 처리합니다(이 동작은 5.3절에서 상세히 다룹니다).

이제 인터럽트 소개를 마쳤으니 이번에는 인터럽트에 대해 조금 더 자세히 살펴보겠습니다. 임베디드 시스템이나 운영체제에서 '인터럽트를 처리하는 방식'을 논할 때 흔히 “인터럽트 핸들러는 빨리 실행해야 한다.”라는 이야기를 많이 듣습니다. 이는 리눅스 디바이스 드라이버에서도 마찬가지입니다. 그러면 리눅스 커널에서도 인터럽트 핸들러를 빨리 실행해야 하는 이유는 무엇일까요? 가장 큰 이유는 인터럽트가 발생하면 실행되는 코드가 멈추기 때문입니다.

앞으로 여러분이 리눅스 디바이스 드라이버나 커널 코드를 볼 때는 우리가 보고 있고 있거나 실행하는 어떤 커널 코드도 인터럽트가 발생하면 실행이 멈춰서 인터럽트 벡터로 실행 흐름을 이동할 수 있다는 사실을 머릿속으로 그리면서 분석하면 좋겠습니다.

그런데 인터럽트가 발생하면 실행 중인 코드를 멈추고 익셉션 벡터로 이동한다는 사실은 코드만 봐서 이해하기는 어렵습니다. 이를 위해 실습이 필요합니다. 라즈베리 파이 같은 리눅스 시스템에서는 ftrace로 인터럽트의 동작 방식(인터럽트 종류와 인터럽트 발생 빈도)을 확인할 필요가 있습니다. 

* 유튜브 강의 동영상도 있으니 같이 들으시면 좋습니다.



 

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

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

# Reference (인터럽트 처리)

인터럽트 소개  
   * 리눅스 커널에서의 인터럽트 처리 흐름    
인터럽트 컨텍스트  
인터럽트 핸들러는 언제 호출될까?  
인터럽트 핸들러는 어떻게 등록할까?  
인터럽트 디스크립터  
인터럽트 디버깅  

 
# Reference: 리눅스 커널

디버깅을 통해 배우는 리눅스 커널의 구조와 원리. 1

디버깅을 통해 배우는 리눅스 커널의 구조와 원리. 2




핑백

덧글

  • 신입 2019/08/12 15:46 # 삭제 답글

    리눅스 펌웨어 신입사원으로 공부를 위해 인터넷으로 검색하다가 들어왔는데 정말 쉽게 풀어주신거 같습니다 책이 출간되면 꼭 구매해서 사용하고싶습니다. 화이팅!!!
  • AustinKim 2019/08/12 16:04 #

    응원해주셔서 감사합니다.
    블로그에 자주 오셔서 유용한 정보 많이 얻어가셨으면 좋겠습니다.
  • 하민기 2020/12/17 14:48 # 삭제 답글

    안녕하세요. 오늘 책을 주문했습니다. 책에 관련하여 질문이 있는데 답변해주시면 감사하겠습니다.

    질문)
    전에 atmega128에 16MHz 타이머 인터럽트를 셋팅하여 정밀한 타이밍에 GPIO출력을 제어하는 것을 해본적이 있는데,
    라즈베리파이에 라즈비안을 올려서 같은 것을 구현하려고 해보니 자료를 못찾다가 귀하의 책을 발견했는데,
    이 책을 보고 커널단에서 bcm의 타이머 인터럽트를 셋팅하여 atmega처럼 정밀한 타이밍으로 GPIO 출력을 제어 할 수 있을까요?
    구현은 커널 모듈 형태로 하려고 합니다.
  • AustinKim 2020/12/17 15:31 #

    '디버깅을 통해 배우는 리눅스 커널의 구조와 원리'란 책에는 GPIO을 정밀한 타이밍으로 제어하는 내용이 담겨 있지는 않습니다. 대신 라즈베리 파이를 통한 실습으로 리눅스 커널의 기본 동작을 디버깅하는 방법을 다루고 있습니다.

    어느 정도 GPIO를 정밀하게 제어하시는지 모르겠지만, 8장에서 다루는 동적 타이머의 jiffies 정도의 정밀도 수준으로 제어하신다면 리눅스 커널에서 제공하는 softirq와 gpio ftrace 이벤트를 잘 활용하시면 도움이 될 것 같습니다.

    감사합니다.
  • 전자과 공돌이 2020/12/17 15:45 # 삭제

    답변 감사드립니다. gpio 제어 자체는 다른 곳을 통해 정보를 알아보고 있습니다. 다만 타이머의 정밀도가 중요한데.
    0.1마이크로초 단위의 정밀도로 출력 핀을 제어해야합니다. 아트메가로는 16MHz(0.0625마이크로초 주기)로 제어했습니다. jiffies로는 힘들 것으로 보이는데, 목적자체가 마치펌웨어 처럼 타이머 관련 레지스터를 셋팅해서 타이머 인터럽트 핸들링을 하려고하는 것입니다. 개념적으로 커널단에서는 이걸 구현하는게 불가능할까요?
  • AustinKim 2020/12/17 17:40 #

    HR Timer와 관련된 함수를 활용하면 나노초 단위로 코드(타이머 설정 및 처리)를 제어할 수 있는데요.
    라즈비안은 이렇게 정교한 단위로 시간을 처리하는 피쳐(커널 컨피그)가 켜져 있는지 의문입니다.
    (이 부분은 아직 확인하지는 못했습니다.)
  • 전자과공돌이 2020/12/17 19:09 # 삭제

    아 정말감사합니다. 한번 찾아보도록 하겠습니다!!!
  • AustinKim 2020/12/18 08:02 #

    네, 즐거운 하루 되세요.
댓글 입력 영역