임베디드/[ Linux Kernel ]

[ Linux Kernel ] 21. 모듈 프로그래밍

kim.svadoz 2020. 10. 28. 17:12
반응형

21. 모듈 프로그래밍


커널 모듈(Kernel Module)

  • 시스템 부팅후에 동적으로 loading할 수 있는 커널 구성요소를 말한다.
  • 커널을 다시 컴파일하거나 시스템 재부팅 할 필요없이 커널의 일부분을 교체하는 것이 가능하다
  • 디바이스 드라이버, 파일 시스템, 네트워크 프로토콜 등이 모듈로 제공된다.

일반 응용프로그램과 뭐가 다른거죠??

커널 모듈은 일반 응용 프로그램과 달리 main함수가 없다.

대신에 커널에 로딩 및 제거될 때 불러지는 함수가 존재하는데, 이는 아래와 같다.

  • Loading 시 : module_init()로 지정된 함수 호출
  • Unloading 시 : module_exit()로 지정된 함수 호출

25.1 리눅스 디바이스 드라이버의 특성

  1. 커널 코드
    • 디바이스 드라이버는 커널의 한 부분이므로, 커널의 다른 코드와 마찬가지로 잘못되면 시스템에 치명적인 피해를 줄 수 있다.
  2. 커널 인터페이스
    • 디바이스 드라이버는 리눅스 커널이나 자신이 속한 서브시스템에 표준 인터페이스를 제공해야 한다.
  3. 커널 매커니즘과 서비스
    • 디바이스 드라이버는 메모리 할당, 인터럽트 전달, wait queue와 같은 표준 커널 서비스를 사용할 수 있다.
  4. Loadable
    • 대부분의 리눅스 드라이버는 커널 모듈로서, 필요할 때 Load하고 더이상 필요하지 않을 때 Unload할 수 있다.
  5. 설정 가능(Configurable)
    • 리눅스 디바이스 드라이버를 커널에 포함하여 컴파일할 수 있다. 어떤 장치를 넣을 것인지는 커널을 컴파일 할 때 설정할 수 있다.

25.2 간단한 커널모듈 작성해보기

1. hello.c

//hello.c
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("BUTTER SHOWER");
MODULE_DESCRIPTION("module programming - hello module");

static int __init module_begin(void) {
    printk("Hello, linux kernel module. \n");
    return 0;
}

static void __exit module_end(void) {
    printk("Good Bye!\n");
}
module_init(module_begin);
module_exit(module_end);
  1. 필요한 include 파일들 include 시켜주기
  2. module license 지정
    • 종류 : GPL, GPL v2, Dual BSD/GPL, Proprietary
    • 커널 2.6부터 반드시 지정해야 함
  3. module_init 함수 작성 및 등록 : module_init(init_func);
  4. module_exit 함수 작성 및 등록 : module_exit(exit_func);

2. 커널 모듈 프로그램을 위한 Makefile

obj-m += hello.o
all :
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean :
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

Makefile이라는 이름으로 위의 코드를 붙여 만들어 준후, make 명령어를 하면 아래와 같이 실행된다.

image-20201028141518368

컴파일 과정

  1. hello.o 파일 먼저 생성
  2. modpost를 C 소스파일에 적용해 .ko에서 요구되는 추가 정보를 부착하여 hello.mod.c를 생성한 후 컴파일 -> hello.mod.o 생성
  3. 두개의 .o파일을 링크하여 .ko(kernel object)파일을 생성

3. 모듈 적재(loading) 그리고 제거(unloading)

  1. 생성된 모듈(hello.ko)을 로딩

    insmod hello.ko
  2. 커널에 적재된 모듈 목록보기

    lsmod
  3. 모듈 제거

    rmmod hello # (.ko가 붙지 않는다)
  4. hello 모듈 동작 확인

    # 모듈 적재와 제거 시에 메시지들이 출력되는지 확인
    #dmesg 또는
    #tail -f /var/log/kern.log (-f 옵션 : 계속적인 변화 출력)

25.3 디바이스 드라이버 작성 방법

1. 디바이스 드라이버 함수 작성

  • struct file_operations 정의
  • open, release, read, write, ioctl 함수 구현
  • init, exit 함수 구현

2. 커널에 디바이스 드라이버 등록

Init 함수에서 수행

int res;

res = register_chardev();    // char driver
res = register_blkdev();    // block driver
res = register_netdev();    // network driver

(사실 register_xxxdev() 함수 파라미터에 필요한 값들이 있지만 일단 생략.. 추후 포스팅 예시를 보면 알 것이다)

3. 컴파일/로딩

# make        ... Makefile 작성 후 실행
# insmod    ... 생성된 .ko 파일 load

4. 디바이스 파일 생성

# mknode [디바이스 파일 이름] [드라이버타입] [주번호] [부번호]

(예시)
#mknod /dev/LED c 239 0

필요하면 속성을 변경해주면 된다.

# chmod ug+w /dev/LED

5. 디바이스 파일에 입출력하는 응용프로그램 작성 및 테스트

디바이스 파일에 입출력하는 응용프로그램을 작성하고, 테스트한다.

커널 영역을 침범하는 파일이기 때문에 작성에 유의해야 한다.

25.4 디바이스 드라이버 골격

디바이스 드라이버의 골격은 아래와 같다.

image-20201028142247092

반응형