Overview
리눅스는 2가지 타입의 디바이스 드라이버를 지원합니다.
* 모듈식
* 빌트인 식
모듈 타입의 디바이스 드라이버는 리눅스 시스템이 부팅한 다음 드라이버를 설치하듯 시스템에 동적으로 적재됩니다. 빌트인 타입 디바이스 드라이버는 커널 이미지에 디바이스 드라이버 코드가 포함되는 방식이죠.
사실, 많은 리눅스 시스템에서는 모듈 타입 디바이스 드라이버를 적용합니다. 리눅스 서버와 같이 항상 켜져서 동작해야 하는 경우 동적으로 디바이스 드라이버를 적재할 수 있기 때문입니다.
이번 시간에는 라즈베리 파이에서 모듈 타입 디바이스 드라이버를 설치하는 방법을 소개합니다.
환경 설정
모듈 타입 디바이스 드라이버를 컴파일하려면 리눅스 시스템은 이를 빌드할 수 있는 환경이 구축돼 있어야 합니다.
그런데, 아래 포스팅에서 소개한 바와 같이 리눅스 커널 소스를 내려받아 라즈베리 파이에 빌드해 설치하면 자연스럽게 디바이스 드라이버를 모듈타입으로 빌드할 수 있습니다. 즉, Makefile와 디바이스 드라이버 소스 코드만 있으면 빌드를 할 수 있다는 이야기입니다.
이번에는 라즈베리 파이에서 이 내용을 확인해봅시다.
먼저 '/lib/modules/' 폴더로 이동합시다.
root@raspberrypi:/home/pi/work_0614# cd /lib/modules/
root@raspberrypi:/lib/modules# ls
4.14.98+ 4.14.98-v7+ 4.19.40-v7+
'/lib/modules' 폴더로 이동하니 위와 같이 3가지 폴더가 보이네요.
가장 최근에 내려받은 리눅스 커널 소스 코드의 버전이 4.19.40-v7+이니 4.19.40-v7+ 디렉터리가 보입니다.
4.19.40-v7+ 디렉토리로 이동하겠습니다.
root@raspberrypi:/lib/modules# cd 4.19.40-v7+/
root@raspberrypi:/lib/modules/4.19.40-v7+# ls
build modules.alias.bin modules.dep modules.order modules.symbols.bin
kernel modules.builtin modules.dep.bin modules.softdep source
modules.alias modules.builtin.bin modules.devname modules.symbols
여러가지 파일들이 보이는데 이 중 핵심은 build 디렉터리입니다. 이 디렉터리가 있어야 디바이스 드라이버를 모듈 타입으로 빌드할 수 있습니다.
이제 모듈 타입 디바이스 드라이버를 설치할 수 있는 조건을 점검했으니 가장 간단한 리눅스 드라이버 모듈을 빌드해봅시다.
모듈식 리눅스 디바이스 드라이버 빌드해보기
먼저 디바이스 드라이버 코드를 소개합니다.
소스 코드는 다음과 같습니다.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
MODULE_LICENSE("Dual BSD/GLP");
static int hello_module_init(void)
{
printk("Hello Module! \n");
return 0;
}
static void hello_module_exit(void)
{
printk("Good-bye Module! \n");
}
module_init(hello_module_init);
module_exit(hello_module_exit);
이번 포스팅은 리눅스 디바이스 드라이버를 라즈베리 파이에서 빌드해 설치하는 게 주제니, 소스 코드의 내용은 구지 설명하지 않겠습니다.
소스 코드를 hello_module.c 이름으로 저장합시다.
이어서 hello_module.c 소스 파일을 빌드할 수 있는 메이크 파일을 소개합니다.
코드의 내용은 다음과 같습니다.
obj-m += hello_module.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
위 명령어에서 '$(shell uname -r)' 구문은 현재 리눅스 시스템의 리눅스 커널 버전을 찾아서 치환해주는 기능입니다.
리눅스 시스템의 리눅스 커널 버전이 4.19.40-v7+이니,
'make -C /lib/modules/$(shell uname -r)/build' 은 'make -C /lib/modules/4.19.40-v7+/build' 구문으로 치환됩니다.
hello_module.c 소스 파일과 Makefile를 'root@raspberrypi:/home/pi/work_0614' 디렉터리에 저장한 다음, make 명령어를 입력해 모듈을 빌드합니다.
root@raspberrypi:/home/pi/work_0614# make
make -C /lib/modules/4.19.40-v7+/build M=/home/pi/work_0614 modules
make[1]: Entering directory '/home/pi/kernel_src/out'
CC [M] /home/pi/work_0614/hello_module.o
Building modules, stage 2.
MODPOST 1 modules
CC /home/pi/work_0614/hello_module.mod.o
LD [M] /home/pi/work_0614/hello_module.ko
제대로 빌드가 되서 hello_module.ko 파일이 생성됐음을 알 수 있습니다.
hello_module 드라이버 모듈 설치해보기
hello_module.c 파일을 컴파일 해서 hello_module.ko 파일을 생성했으니 이번에는 설치를 해볼 차례입니다.
터미널에서 'insmod hello_module.ko' 명령어를 입력해 보겠습니다.
root@raspberrypi:/home/pi/work_0614# insmod hello_module.ko
음, 에러 메시지가 보이지는 않으니 제대로 설치를 했는지 잘 모르겠습니다.
라즈베리 파이에 설치된 모듈 타입 디바이스 드라이버의 목록을 출력해주는 'lsmod' 명령어를 입력해봅시다.
01 root@raspberrypi:/home/pi/work_0614# lsmod
02 Module Size Used by
03 hello_module 16384 0
04 fuse 110592 3
05 rfcomm 49152 4
06 bnep 20480 2
07 hci_uart 40960 1
03번째 줄에서 hello_module와 같이 설치된 드라이버의 이름이 보이니 제대로 설치가 된 듯 합니다.
이번에는 커널 로그를 통해 'hello_module'이란 디바이스 드라이버가 제대로 설치됐는지 확인해봅시다.
root@raspberrypi:/home/pi/work_0614# tail -20 /var/log/kern.log
Jun 14 17:03:15 raspberrypi kernel: [ 1668.847624] hello_module: loading out-of-tree module taints kernel.
Jun 14 17:03:15 raspberrypi kernel: [ 1668.847666] hello_module: module license 'Dual BSD/GLP' taints kernel.
Jun 14 17:03:15 raspberrypi kernel: [ 1668.847689] Disabling lock debugging due to kernel taint
Jun 14 17:03:15 raspberrypi kernel: [ 1668.848501] Hello Module!
커널 로그에서 맨 마지막 부분에 'Hello Module!' 메시지가 보이니 hello_module.ko가 설치가 돼서
hello_module_init() 함수가 호출됐음을 확인할 수 있습니다.
다음은 이번 포스팅 앞부분에서 소개한 hello_module_init() 함수의 구현부입니다.
static int hello_module_init(void)
{
printk("Hello Module! \n");
return 0;
}
이번에는 'rmmod hello_module.ko' 명령어를 입력해 hello_module.ko 드라이버를 라즈베리 파이에서 비적재(unload)해봅시다.
root@raspberrypi:/home/pi/work_0614# rmmod hello_module.ko
다시 커널 로그를 확인해 봅시다.
root@raspberrypi:/home/pi/work_0614# tail -20 /var/log/kern.log
Jun 14 17:03:15 raspberrypi kernel: [ 1668.848501] Hello Module!
Jun 14 17:03:36 raspberrypi kernel: [ 1689.798616] Good-bye Module!
커널 로그의 'Good-bye Module!' 메시지가 출력되니 다음과 같이 hello_module_exit() 함수가 제대로 호출됐음을 확인할 수 있습니다.
static void hello_module_exit(void)
{
printk("Good-bye Module! \n");
}
정리
이번 포스팅에서는 라즈베리 파이에서 모듈 타입 디바이스 드라이버를 컴파일하고 로딩하는 방법을 소개했습니다.
키포인트는 모듈 타입 디바이스 드라이버를 컴파일하기 위해서는 라즈비안 커널 소스를 내려받고 빌드를 하면 된다는 점을 기억했으면 합니다.
그렇다며 이런 의문이 생길 것입니다.
* '라즈비안 소스를 내려받지 않고 리눅스 커널 모듈 드라이버를 설치할 수 있도록 어떻게 설정해야 할까?'
의문을 품기 위해서는 다음 링크에 있는 정보를 참고하면 됩니다.
https://stackoverflow.com/questions/20167411/how-to-compile-a-kernel-module-for-raspberry-pi
https://github.com/notro/rpi-source/wiki
위에서 소개한 링크대로 설치를 할 수도 있는데요. 시간이 훨씬 더 오래 걸리고 라즈베리 파이에서 더 많은 용량을 차지할 겁니다. 그 이유는 리눅스 커널 관련 파일과 헤더를 모두 내려받기 때문이죠. 또한 커널 모듈 드라이버 빌드와 상관없는라즈베리 파이와 관련된 유틸리티 파일을 다운로드도 합니다.
차라리 라즈비안 커널 소스를 내려받아 빌드하는게 훨씬 시간을 절약할 것입니다.
이번 시간에는 라즈베리 파이에서 디바이스 드라이버를 설치하는 방법을 소개했습니다. 이 내용 참고해서 많은 분들이 라즈베리 파이에서 디바이스 드라이버를 연습해봤으면 좋겠습니다.
'Core BSP 분석 > Linux Device Driver' 카테고리의 다른 글
[리눅스] 드라이버: module_init 키워드로 지정한 함수가 호출되는 원리 - sys_finit_module() (0) | 2025.02.14 |
---|---|
[리눅스] insmod 명령어로 드라이버 설치 시 커널 내부 동작 디버깅해보기(ftrace) (0) | 2025.02.14 |