모듈 vs 디바이스 드라이버: 모듈은 커널 실행 중 동적으로 추가/제거 가능한 커널 라이브러리이고, 디바이스 드라이버는 하드웨어를 다루기 위한 커널 프로그램 라이브러리임. 대부분의 디바이스 드라이버는 모듈 형태로 작성함.
- 동적 링크 기반: 커널에
심볼 테이블이라는 기능 추가. 커널 내부 함수/변수의 심볼과 주소를 담은 테이블. /proc/ksyms: 커널 심볼 테이블을 외부에 제공하는 파일.cat /proc/ksyms # c0134a50 register_chrdev_R1a5f156e # c0134ae0 unregister_chrdev_Rc192d491
- 모듈 적재 시
insmod가 심볼 테이블을 참조하여 객체 내 함수/변수의 실제 주소를 재배치(Relocation)함.
| 커널 2.4 | 커널 2.6 |
|---|---|
#define MODULE |
(불필요) |
#include <linux/module.h> |
#include <linux/init.h> |
#include <linux/kernel.h> |
#include <linux/module.h> |
#include <linux/kernel.h> |
| 커널 2.4 | 커널 2.6 |
|---|---|
int init_module(void) |
static int hello_init(void) |
void cleanup_module(void) |
static void hello_exit(void) |
| (고정 함수명) | module_init(hello_init); |
module_exit(hello_exit); |
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
static int hello_init(void) {
printk("Hello, world\n");
return 0;
}
static void hello_exit(void) {
printk("Goodbye, world\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("Dual BSD/GPL");커널 2.6에서는 필수. 생략하거나 "Proprietary" 지정 시 일부 커널 API 접근 불가.
| 문자열 | 의미 |
|---|---|
"GPL" |
GNU Public License v2 or later |
"GPL v2" |
GNU Public License v2 |
"Dual BSD/GPL" |
GPL v2 or BSD (권장) |
"Proprietary" |
비공개 (비추천) |
obj-m := test.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
clean:
rm -rf *.ko *.mod.* .*.cmd *.o- 컴파일 결과:
test.ko생성. - 여러 소스 파일로 모듈 생성 시:
obj-m := test.o module-objs := test1.o test2.o test3.o
| 명령어 | 기능 |
|---|---|
insmod test.ko |
모듈을 커널에 적재 |
rmmod test |
커널에서 모듈 제거 |
lsmod |
현재 적재된 모듈 목록 출력 (이름, 크기, 사용 횟수, 참조 모듈 표시) |
depmod |
모듈 간 의존성 정보 생성 |
modprobe |
의존성을 고려하여 모듈 적재/제거 (modules.dep 참조) |
- insmod 주요 옵션:
-f: 커널 버전이 달라도 강제 적재 (커널 안정성 보장 안 됨).-p: 커널에 성공적으로 적재될 수 있는지 사전 검사.
insmod 적재 시 외부에서 드라이버 내부 변수 초기값을 주입하는 기능.
insmod ./test.ko onevalue=0x27 twostring="Oh my god"#include <linux/moduleparam.h>
static int onevalue = 1;
static char *twostring = NULL;
module_param(onevalue, int, 0); // 정수형
module_param(twostring, charp, 0); // 문자열module_param(변수명, 변수타입, 접근속성) - 접근 속성은 특별한 경우 아니면 0 사용.
| 변수 타입 | C 타입 |
|---|---|
short, ushort |
short, unsigned short |
int, uint |
int, unsigned int |
long, ulong |
long, unsigned long |
charp |
char * |
bool, invbool |
int |
MODULE_PARM(onevalue, "i"); // i: int, h: short, l: long, s: string
MODULE_PARM(twostring, "s");MODULE_AUTHOR("홍길동 hong@example.com");
MODULE_DESCRIPTION("My Device Driver Module");printf()의 커널 버전. 메시지를 즉시 콘솔로 출력하지 않고, 원형 큐 형식의 로그 버퍼에 저장.- 로그 버퍼 크기:
CONFIG_LOG_BUF_SHIFT값 기반, 기본값 16,384 바이트. - 반드시
\n포함해야 출력이 시작됨. - 실행 시간이 길어 시간에 민감한 루틴에서 과도한 사용 자제.
| 상수 | 레벨 | 의미 |
|---|---|---|
KERN_EMERG |
<0> |
시스템 동작 불가 |
KERN_ALERT |
<1> |
항상 출력 |
KERN_CRIT |
<2> |
치명적 정보 |
KERN_ERR |
<3> |
오류 정보 |
KERN_WARNING |
<4> |
경고 정보 (레벨 미지정 시 기본값) |
KERN_NOTICE |
<5> |
정상적 정보 |
KERN_INFO |
<6> |
시스템 정보 |
KERN_DEBUG |
<7> |
디버깅 정보 |
printk(KERN_INFO "system ok\n"); // == printk("<6>system ok\n");dmesg: 로그 버퍼에 저장된 최근 커널 메시지 출력 (1회성).sudo dmesg -w: 실시간 모니터링.cat /proc/kmsg: 실시간 스트리밍. 새 메시지 발생 시까지 블로킹 대기.Ctrl+C로 종료./proc/kmsg는 독점 읽기 파일이므로 다른 로깅 데몬이 점유 중이면 영구 대기 가능.
- 커널 메시지 관리 데몬:
klogd,syslogd→/var/log/messages에 기록.
커널 소스는 50M 이상의 방대한 코드로, 함수/변수명 충돌 방지 필수.
static int checkout = 0;
static int dev_app_check(void) { ... }static사용 시 해당 파일 소스에서만 참조 가능 → 심볼 테이블에 유지되지 않음.- 주의: 지역 변수에
static사용 시 전역 변수처럼 함수 종료 후에도 값 유지.
[새로운내용]