• 2023. 8. 26.

    by. 도 현

    반응형

    디바이스 드라이버는 주로 외부 하드웨어 장치(키보드, 마우스)와 인터럽트를 통해 통신하는 경우가 많다. 이때 임베디드 리눅스 드라이버 개발자는 인터럽트 핸들러를 등록하고 난 후 관련 인터럽트가 트리거(발생)되면 등록한 인터럽트 핸들러가 호출되는 과정까지 확인한다.

     

    1. 인터럽트 소개

     인터럽트란?

    일상생활에서 인터럽트란 갑자기 생긴 일이나 하던 일을 멈춘다는 의미이다. 일상적으로 하던 일을 멈추게 하는 무엇인가가 갑자기 발생한 상황을 뜻한다. 예를 들면 책을 읽다가 갑자기 전화가 와서 읽던 책을 덮어 놓고 전화를 받는 상황이 그러하다. 하드웨어 관점에서 인터럽트란 하드웨어의 변화를 감지해서 외부 입력으로 전달되는 전기 신호이다. 한 가지 예를 들자면, 손으로 키보드를 치면 하드웨어 적으로 키보드 하드웨어의 변화를 감지하고 신호가 발생한다. 그래서 보통 하드웨어 개발자들은 오실로스코프라는 장비로 인터럽트 신호가 제대로 올라오는지 측정한다. 참고로 인터럽트 신호는 인터럽트 식별하는 구간에 일정하게 5V(Voltage)를 유지하거나 0V에서 5V로 바뀌는 두 가지 종류로 분류된다. 소프트웨어 관점에서는 어떨까? 소프트웨어에서는 인터럽트가 발생하면 프로세스는 하던 일을 멈추고 '이미 정해진 코드'를 실행해서 하드웨어의 변화를 처리한다. 여기서 '이미 정해진 코드'란 인터럽트 벡터와 인터럽트 핸들러를 말한다. 이처럼 인터럽트가 발생하면 소프트웨어적으로 처리하는 과정을 인터럽트 서비스 루틴(Interrupt Service Routine)이라고 한다. 이번에는 CPU 아키텍처 관점에서 보자. 인터럽트는 CPU 아키텍처별로 다르게 처리한다. x86, ARMv7, ARMv8 아키텍처별로 인터럽트를 처리하는 방식이 다른 것이다. 라즈베리 파이는 ARMv7 기반 아키텍처이므로 ARMv7 CPU에서 인터럽트를 처리하는 과정만 알면 된다. ARMv7 프로세서에서 인터럽트는 익셉션(Exception)의 한 종류로 처리되므로 익셉션의 처리 방식에 대해 알 필요가 있다. ARMv7 프로세서는 외부 하드웨어 입력이나 오류 이벤트가 발생하면 익셉션 모드로 진입한다. ARMv7 프로세스는 익셉션이 발생했다고 감지하면 익셉션 종류별로 이미 정해 놓은 주소로 브랜치 한다. 임베디드 시스템이나 운영체제에서 '인터럽트를 처리하는 방식'을 논할 때 흔히 " 인터럽트 핸들러는 빨리 실행해야 한다."라고 한다. 이는 리눅스 드라이버에서도 마찬가지이다. 리눅스 커널에서도 인터럽트 핸들러를 빨리 실행해야 하는 가장 큰 이유는 인터럽트가 발생하면 실행 중인 코드가 멈추기 때문이다. 리눅스 디바이스 드라이버나 커널 코드를 볼 때는 우리가 보고 있고 있거나 실행하는 어떤 커널 코드도 인터럽트가 발생하면 인터럽트 벡터로 실행 흐름이 바뀔 수 있다는 사실을 생각하자. 그런데 인터럽트가 발생하면 실행 중인 코드를 멈추고 익셉션 벡터로 이동한다는 사실은 코드만 봐서 이해하기는 어렵다. 라즈베리 파이 같은 리눅스 시스템에서는 ftrace로 인터럽트의 동작 방식(인터럽트 종류와 인터럽트 발생 빈도)을 확인할 필요가 있다.

     

    2. 리눅스 커널 인터럽트의 주요 개념

    인터럽트 핸들러란?

    인터럽트가 발생하면 이를 핸들링하기 위한 함수가 호출되는데 이를 인터럽트 핸들러라고 한다. 예를 들어, 키보드를 타이핑해서 인터럽트가 발생하면 키보드 인터럽트를 처리하는 키보드 인터럽트 핸들러가 호출된다. 마찬가지로 휴대폰에서 화면을 손으로 만지면 터치 인터럽트가 발생하고 터치 인터럽트를 처리하는 터치 인터럽트 핸들러가 호출된다. 인터럽트 종류별로 인터럽트 핸들러가 있다. 인터럽트 핸들러는 함수 형태로 존재하며, 커널 내부의 IRQ(Interrupt ReQuest) 서브 시스템을 통해 호출된다. 이처럼 인터럽트가 발생해 지정한 인터럽트 핸들러가 동작하려면 request_irq() 함수를 적절한 인자와 함께 호출해서 미리 인터럽트 핸들러를 등록해야한다.

     

    인터럽트 컨텍스트의 활성화

    인터럽트 컨텍스트는 현재 실행 중인 코드가 인터럽트를 처리 중이라는 의미이다. 인터럽트 컨텍스트에 대한 이해를 돕기 위해 먼저 소프트웨어 관점에서 인터럽트의 실행 흐름을 단계별로 살펴보자.

    1. 프로세스 실행 중

    2. 인터럽트 벡터 실행

    3. 커널 인터럽트 내부 함수 호출

    4. 인터럽트 종류별로 인터럽트 핸들러 호출

    5. 인터럽트 핸들러의 서브루틴 실행 시작

    6. 인터럽트 핸들러의 서브루틴 실행 마무리

    복잡한 단계로 인터럽트가 처리되는 것 같아도 처리 과정을 요약하면 다음과 같다.

    - 인터럽트가 발생하면 실행 중인 코드를 멈추고 인터럽트 벡터로 이동해 인터럽트에 대한 처리를 수행한다.

    - 인터럽트 종류별로 지정한 인터럽트 핸들러가 실행된다.

     

    인터럽트 디스크립터란?

    인터럽트 종류별로 다음과 같은 인터럽트의 세부 속성을 관리하는 자료구조를 인터럽트 디스크립터라고 한다.

    - 인터럽트 핸들러

    - 인터럽트 핸들러 매개변수

    - 논리적인 인터럽트 번호

    - 인터럽트 실행 횟수

    프로세스의 세부 속성을 표현하는 자료구조가 태스크 디스크립터이듯 인터럽트에 대한 속성 정보를 저장하는 자료구조가 인터럽트 디스크립터인 것이다. 커널 내부의 IRQ 서브시스템에서 인터럽트 디스크립터를 통해 인터럽트 종류별로 세부적인 처리를 수행한다. 

    반응형