본문 바로가기
linux

Hello 커널 모듈 작성 예제

by 상레알 2010. 6. 2.
출처 : 리눅스 커널 프로그래밍  저 한동훈,원일용, 하홍준  / 한빛 미디어


2.4 커널 모듈   hello.c  
-----------------------------------------------------------------------------------------------------------
#include <linux/ kernel.h>
#include <linux/module.h>

// 초기화 루틴
int __init init_module(void)
{
printk( KERN_ALERT "[Module Message] Hello, Module.\n");
return 0;
}

// 종료 루틴
void __exit cleanup_module(void)
{
printk( KERN_ALERT "[Module Message] Do you really want to break up with me?\n");
}

MODULE_LICESE ("GPL");

2.4 커널에서 사용할 모듈을 모두 작성했으면 다음과 같이 컴파일을 합니다.

gcc -D__KERNEL__ -DMODULE -I/usr/src/linux-2.4.32/include -c

hello.c -o hello.o

설명
         (커널 관련 코드로 정의합니다.)             (참조할 헤더파일의 경로를 지정합니다.)
" gcc -D__KERNEL__ -DMODULE -I/usr/src/linux-2.4.32/include -c
                               (모듈 컴파일로 정의합니다.)                        (컴파일만 수행하고 오브젝트(.o)파일을생성합니다.)
hello.c -o hello.o (컴파일 결과를 hello.o로 생성합니다.)

2.4 커널에서만 __KERNEL__ 과 MODULE 정의를 사용합니다. -D은 C언어의 #define  문과 같기 떄문에 다음과 같이 코드 안에 직접 선언할 수 있습니다.
#define __KERNEL__
#define MODULE

gcc에서 소스 코드를 컴파일 할 때 헤더 파일은 /usr/include 에서 참조하게 되어 있고, 리눅스와 어셈블리 관련 헤더파일은 /usr/include/linux 와 /usr/include/asm 에서 참조하게 되어 있습니다. 이들 경로는 리눅스를 설치할 때 사용된 커널 버전에 맞는 헤더파일이 위치하게 됩니다. 따라서 새로운 커널을 설치하는 경우에는 맞지 않게 됩니다. 하지만 시스템의 다른 파일들은 이 헤더파일을 사용해서 빌드되기 때문에 이 경로를 수정하지 않는 것이 좋습니다. 따라서 기본 경로 대신 직접 참조할 경로를 지정하기 위해 -I 옵션을 사용합니다 . /usr/include의 헤더파일 경로를 삭제하거나 링크를 생성하는 것도 하나의 해결방법이 될 수 있지만 다양한 커널 버전을 빌드하고, 테스트하는 경우에는 적절한 해결책이 될 수 없습니다. -I/usr/src/linux-2.4.32/include 대신에 -I/lib/modules/2.4.32/build 옵션을 사용할 수 있습니다. 이 경로는 커널 빌드 과정에서 [make modules_install]을 실행했을때 , 커널 소스의 헤더 파일들이 복사된 경로이기 떄문에 실제로 이 둘은 동일합니다.

리눅스에서 [uname -r]을 실행하면 현재 커널의 버전 번호가 "2.4.32" 와 같이 출력됩니다. 그러므로 -I/usr/src/linu-'uname -r' /include 와 같이 사용하면 커널 버전에 관계없이 항상 현재 사용중인 커널 버전에 맞는 헤더파일을 사용하게 할 수 있습니다.

gcc를 사용한 커널 모듈 빌드는 2.4 커널에만 해당됩니다.
-----------------------------------------------------------------------------------------------------------
2.4 Makefile

2.4 커널 모듈을 편하게 컴파일을 할 수 있는 Makefile은 다음과 같습니다. 2.4 커널에서 Makefile의 사용은 선택이지만, 편한게 좋겟죠?

KERNELDIR = /lib/modules/$(shell uname -)/build

CFLAGS = -D__KERNEL__ -DMODULE -I$(KERNELDIR) /include -02 -fomit-frame-pointer

TARGETS =

MOD_TARGETS = hello.o

all := ${TARGETS}    $(MOD_TARGETS}

%.c%:
            ${CC} -o $@ $^

%.c%.o:
            ${CC} -o $@ $^

clean:
            rm -rf ${TARGETS} ${MOD_TARGETS}

           이부분은 탭으로 띄워야 한다.

TARGETS에는 컴파일 할 응용프로그램 목록을 적을 수 있고, MOD_TARGETS에는 컴파일 할 모듈의 목록을 적을 수 있도록 작성한 Makefile입니다.

커널에서 모듈 로드

$ insmod hello.o

[Module Message] Hello, Module.

-----------------------------------------------------------------------------------------------------------

2.6 커널 모듈 hello.c

#include <linux/init.h>   //-> init.h를 추가합니다.
#include <linux/kernel.h>
#include <linux/module.h>

//초기화 루틴
int __init init_hello(void)  // init_hello 초기화 루틴 위치
{
printk(KERN_ALERT "[Module Message] Hello, Modue.\n");
return 0;
}
//종료 루틴
void __exit exit_hello(void)     // exit_hello : 종료 루틴 위치
{
printk( KERN_ALERT "[Module Message] Do you really want to break up with me? \n");
}
module_init(init_hello);                         // init_hello : 초기화 루틴 위치입니다.
module_exit(exit_hello);                       // exit_hello : 종료 루틴 위치입니다.
MODULE_LICENSE("GPL");

2.6 커널에서는 linux/init.h 헤더파일이 추가되었습니다. 그리고 init_module()과 cleanup_module() 이라는함수 이름 규약을 더이상 따르지 않아도 됩니다. 초기화 함수와 종료 함수는 자신이 원하는 이름으로 작성하면 되고, module_init()과 module_exit()매크로에서 초기화 함수와 종료 함수의 이름만 지정해주면 됩니다. 물론 2.4 커널의 init_module(), cleanup_module()을 사용해도 되지만, 현재 커널 해커들은 이들 함수를 전혀 사용하고 있지 않습니다. 2.4.20 이후 버전의 커널에서는 위와 같은 2.6 형식의 코드를 사용하고, gcc를 사용해서 모듈로 빌드할 수 있습니다. 2.4.20 이후 버전과 2.6 커널의 모듈은 동일한 코드를 사용할 수 있으며, 빌드 과정만 다릅니다.

2.6 커널부터는 커널 빌드에 대해서 kbuild 시스템을 사용합니다. 따라서 모듈을 빌드하기 위해서 gcc를 사용할 수 없고, Makefile을 정의하고, kbuild 시스템으로 모듈을 빌드해야 합니다.


커널 2.6 모듈 빌드용 Makefile
------------------------------------------------------------------------------------------------------
KERNELDIR = /lib/modules/$(shell uname -)/build

obj-m = hello.o

KDIR  :=  /lib/modules/$ (shell uname -r)/build
PWD := $(shell pwd)

default :
            $ (MAKE) -C $ (KDIR) SUBDIRS=$ (PWD) modules
clean :
          rm -rf *.ko
          rm -rf *.mod.*
          rm -rf .*.cmd
          rm -rf *.o
------------------------------------------------------------------------------------------------------
           이부분은 탭으로 띄워야 한다.

Makefile을 모두 작성했으면 make를 실행합니다.
 $ make
make -C /lib/modules/ .....
.
.
CC[M] /root/works/cahrp....
Build modules, stage 2.
MODPOST
CC      /root/works/chap04/2.6/hello.mod.o
LD[M] /root/works/chap04/2.6/hello.ko   // hello.ko : 2.6 커널의 hello 모듈

커널에서 모듈 로드

$ insmod hello.ko

[Module Message] hello, Module
------------------------------------------------------------------------------------------------------


Error !!!!

insmod 명령을 실행했을 때 다음과 같은 오류 메시지가 나타날 수 있습니다.

       QM_MODULE: Function not implemented

이 메시지는 모듈 기능을 지원하지 않게 커널이 빌드되어 있기 때문에 발생합니다. 또는 2.6커널에서 사용하는 모듈 포맷인 .ko을 지원하는 모듈 유틸리티 프로그램이 설치되어 있지 않았기 떄문에 발생합니다. 2.6 커널을 위한 모듈 유틸리티는 데비안에서 [apt-get install module-init-tools]로 설치할 수 있습니다 커널에서 모듈 기능 설정은 2.4커널에서는 기본 설정에서 사용가능으로 되어 있고, 2.6커널에서는 사용하지 않음으로 되어 있습니다.

2.6 커널 모듈 지원 설정

Loadable modul support --->
[*] Enable loadalbe module support
[*] Module unloading
[*]      Forced module unloading
[ ] Module versioning support (EXPERIMENTAL)
[ ] Source checksum for all modules
[*] Automatic kernel module loading
위와 같이 커널을 설정하고, [make]를 실행해서 커널을 재빌드하고, 커널 이미지를 다시 복사하고, 재부팅한 후에 [insmod]를 실행하면 모듈이 제대로 로드 되는것을 확인할 수 있다.

모듈이 로드된것을 확인하기 위해 [lsmod] 명령을 실행한다.

$ lsmod

Module     size    used by
hello           1312      0


Module은 모듈의 이름을 나타내고, Size는 모듈이 차지하는 ㅔㅁ모리 크기를 나타냅니다. Used by는 다른 모듈에서 참조할 경우 올라가는 카운터 입니다.

이제 [rmmod]명령으로 모듈을 제거합니다. 커널 버전에 관계없이 동일하며 제거할 모듈 이름만 지정합니다. 모듈이름은 [lsmod]의 Module 항목에 나열된 이름입니다.

$ rmmod hello
[Module Message] Do you really want to break up with me?

이것으로 간단한 Hello 모듈의 모든것을 살펴보았습니다. 모듈 프로그래밍 자체는 간단하지만 그 이면에서 동작하는 내용들은 꽤 복잡합니다 . 하지만 그런것들을 살펴보아야 맛이 아닐까요?

'linux' 카테고리의 다른 글

프로세스 일정 관리  (0) 2010.08.14
프로세스와 신호  (0) 2010.08.13
vim 설정  (0) 2010.06.30
모듈의 상호참조  (0) 2010.06.03
모듈에 대해 알아야 할것들  (0) 2010.06.03
모듈 개발.  (0) 2010.06.01
운영체제 커널 분류에대해...  (0) 2010.06.01
커널 소스 컴파일  (0) 2010.06.01
/usr/lib/python2.4/site-packages/_sqlitecache.so: undefined symbol: g_assert_warning  (0) 2010.04.22
Git 1.6.1 설치  (0) 2010.04.22