Skip to content

Latest commit

 

History

History
180 lines (142 loc) · 5.95 KB

File metadata and controls

180 lines (142 loc) · 5.95 KB

커널 모듈 기본 (4장)

모듈 vs 디바이스 드라이버: 모듈은 커널 실행 중 동적으로 추가/제거 가능한 커널 라이브러리이고, 디바이스 드라이버는 하드웨어를 다루기 위한 커널 프로그램 라이브러리임. 대부분의 디바이스 드라이버는 모듈 형태로 작성함.

1. 모듈의 구현 원리

  • 동적 링크 기반: 커널에 심볼 테이블이라는 기능 추가. 커널 내부 함수/변수의 심볼과 주소를 담은 테이블.
  • /proc/ksyms: 커널 심볼 테이블을 외부에 제공하는 파일.
    cat /proc/ksyms
    # c0134a50 register_chrdev_R1a5f156e
    # c0134ae0 unregister_chrdev_Rc192d491
  • 모듈 적재 시 insmod가 심볼 테이블을 참조하여 객체 내 함수/변수의 실제 주소를 재배치(Relocation)함.

2. 모듈 소스 형식 (커널 버전별 비교)

헤더 파일

커널 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);

Hello World 예제 (커널 2.6)

#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");

라이선스 등록 (MODULE_LICENSE)

커널 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" 비공개 (비추천)

3. Makefile (커널 2.6)

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

4. 모듈 유틸리티

명령어 기능
insmod test.ko 모듈을 커널에 적재
rmmod test 커널에서 모듈 제거
lsmod 현재 적재된 모듈 목록 출력 (이름, 크기, 사용 횟수, 참조 모듈 표시)
depmod 모듈 간 의존성 정보 생성
modprobe 의존성을 고려하여 모듈 적재/제거 (modules.dep 참조)
  • insmod 주요 옵션:
    • -f: 커널 버전이 달라도 강제 적재 (커널 안정성 보장 안 됨).
    • -p: 커널에 성공적으로 적재될 수 있는지 사전 검사.

5. 모듈 매개변수

insmod 적재 시 외부에서 드라이버 내부 변수 초기값을 주입하는 기능.

insmod ./test.ko onevalue=0x27 twostring="Oh my god"

커널 2.6: module_param 매크로

#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

커널 2.4: MODULE_PARM 매크로 (구버전)

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");

6. printk() - 커널 메시지 출력

  • 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에 기록.

7. static 키워드 사용 권장

커널 소스는 50M 이상의 방대한 코드로, 함수/변수명 충돌 방지 필수.

static int checkout = 0;
static int dev_app_check(void) { ... }
  • static 사용 시 해당 파일 소스에서만 참조 가능 → 심볼 테이블에 유지되지 않음.
  • 주의: 지역 변수에 static 사용 시 전역 변수처럼 함수 종료 후에도 값 유지.

[새로운내용]