리눅스 커널 모듈 — insmod부터 디바이스 드라이버까지
리눅스는 모놀리식 커널이지만, 커널 모듈 덕분에 런타임에 기능을 추가/제거할 수 있습니다. USB 드라이버를 꽂으면 자동으로 로드되는 것이 이 메커니즘입니다.
커널 모듈이란
LKM(Loadable Kernel Module) 은 커널을 재부팅하지 않고 런타임에 로드/언로드할 수 있는 코드 조각입니다.
리눅스 커널
┌─────────────────────────────┐
│ 핵심 커널 (항상 메모리에) │
│ ┌────┬──────┬────────────┐│
│ │스케줄│메모리 │파일 시스템 ││
│ │러 │관리 │(기본) ││
│ └────┴──────┴────────────┘│
│ │
│ 커널 모듈 (필요할 때 로드) │
│ ┌────┐ ┌─────┐ ┌────────┐│
│ │USB │ │NIC │ │파일시스템││
│ │드라이│ │드라이│ │(ext4) ││
│ │버 │ │버 │ │ ││
│ └────┘ └─────┘ └────────┘│
└─────────────────────────────┘
간단한 커널 모듈 작성
// hello.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("developer");
MODULE_DESCRIPTION("Hello World 커널 모듈");
// 모듈 로드 시 호출
static int __init hello_init(void) {
printk(KERN_INFO "Hello, Kernel Module!\n");
return 0; // 0: 성공, 음수: 에러
}
// 모듈 언로드 시 호출
static void __exit hello_exit(void) {
printk(KERN_INFO "Goodbye, Kernel Module!\n");
}
module_init(hello_init);
module_exit(hello_exit);
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
모듈 관리 명령어
# 모듈 빌드
make
# 모듈 로드
sudo insmod hello.ko
# 모듈 확인
lsmod | grep hello
# 커널 로그 확인
dmesg | tail
# 모듈 언로드
sudo rmmod hello
# 의존성까지 자동 로드
sudo modprobe hello
# 모듈 정보 확인
modinfo hello.ko
디바이스 드라이버
리눅스에서 디바이스는 파일 로 추상화됩니다 (/dev/ 하위).
디바이스 유형
| 유형 | 설명 | 예시 |
|---|---|---|
| 문자 디바이스 | 바이트 스트림 | /dev/tty, /dev/null |
| 블록 디바이스 | 블록 단위 I/O | /dev/sda, /dev/nvme0n1 |
| 네트워크 디바이스 | 네트워크 인터페이스 | eth0, wlan0 |
문자 디바이스 드라이버 구조
#include <linux/fs.h>
#include <linux/cdev.h>
// 파일 연산 구조체
static struct file_operations fops = {
.owner = THIS_MODULE,
.open = device_open, // open() 시스템 콜 처리
.release = device_release, // close() 처리
.read = device_read, // read() 처리
.write = device_write, // write() 처리
};
static int device_open(struct inode *inode, struct file *file) {
printk(KERN_INFO "디바이스가 열렸습니다\n");
return 0;
}
static ssize_t device_read(struct file *file, char __user *buf,
size_t count, loff_t *offset) {
// 커널 → 유저 공간으로 데이터 복사
copy_to_user(buf, kernel_buffer, count);
return count;
}
모듈 매개변수
static int count = 1;
static char *name = "default";
module_param(count, int, 0644); // /sys/module/xxx/parameters/count
module_param(name, charp, 0644);
MODULE_PARM_DESC(count, "반복 횟수");
MODULE_PARM_DESC(name, "모듈 이름");
# 매개변수 전달
sudo insmod hello.ko count=5 name="test"
핵심 포인트
- 커널 모듈 vs 마이크로커널: 모듈은 커널 공간에서 실행되므로 버그 시 커널 크래시 가능 — 진정한 격리가 아님
- insmod vs modprobe: modprobe는 의존성을 자동 해결, insmod은 수동
- printk vs printf: 커널에서는 printf 사용 불가 — printk로 커널 링 버퍼에 출력
정리
커널 모듈은 리눅스가 모놀리식 커널이면서도 유연성을 유지할 수 있게 해주는 핵심 메커니즘입니다. 드라이버 개발의 기본이기도 하며, 커널과 유저 공간의 경계를 이해하는 데 중요한 개념입니다.