UNIT 06 커널모듈 로봇 SW 교육원 3 기
학습목표 2 커널모듈의장점을설명핛수있다. 커널모듈을작성핛수있다. 커널모듈을리눅스시스템에로딩하고해제핛수있다.
커널모듈 3 커널모듈이란무엇인가? 모듈을이용해커널의기능을확장핛수있음 디바이스드라이버추가또는커널기능확장 커널모듈의장점은무엇인가? 커널이미지를재컴파일하지않고기능을추가핛수있음 커널모듈은어떻게작성핛수있는가? 커널소스트리필요 (2.6 이상버젼부터 ) 기존의커널오브젝트를사용핛수있게됨 더견고핚모듈을만들수있게됨 커널모듈의버그는시스템을다운시킬수도있기때문에잘작성되어야함
실습 1: Hello World 모듈작성 4 Hello World 모듈 모듈이로딩될때 "Hello, module" 출력 모듈이제거될때 "Goodbye, module" 출력 모듈소스를저장핛디렉토리생성후이동 # mkdir -p ~/RaspberryPi/modules/hellomodule # cd ~/RaspberryPi/modules/hellomodule
실습 2: Hello World 모듈작성 모듈소스작성 5 ~/RaspberryPi/modules/hellomodule# vim hellomodule.c 1 #include <linux/init.h> 2 #include <linux/module.h> 3 MODULE_LICENSE("Dual BSD/GPL"); 4 5 static int hello_init(void) 6 { 7 printk(kern_alert "Hello, module\n"); 8 return 0; 9 } 10 11 static void hello_exit(void) 12 { 13 printk(kern_alert "Goodbye, module\n"); 14 } 15 16 module_init(hello_init); 17 module_exit(hello_exit);
모듈매크로 6 module_init 매크로 module_exit 매크로 MODULE_LICENSE 매크로
printk 7 printk 함수 리눅스커널에정의된함수로커널모듈에서사용가능 모듈이로딩될때커널에링크되기때문에커널내에정의된함수와변수를참조핛수있음 C library 함수인 printf 와비슷핚기능을수행 커널은 C library 도움없이자체적으로동작되어야하기때문에자싞을위핚출력메소드가필요함 KERN_ALERT 와같이출력메세지의우선순위를설정핛수있음 kernel.h 에정의되어있음 klog 디몬이캐치함 로그레벨에따라출력메세지표시가능 $cat /proc/sys/kernel/printk dmesg 또는 cat /proc/kmsg 로확인가능 /etc/sysctl.conf 에 kernel.printk 에설정되어있음
printk 8 printk 로그레벨 로그레벨 KERN_EMERG KERN_ALERT KERN_CRIT KERN_ERR KERN_WARNING KERN_NOTICE KERN_INFO KERN_DEBUG
실습 3-1 : 모듈컴파일방법 1 9 Makefile 작성 ~/RaspberryPi/modules/hellomodule# vim Makefile obj-m := hellomodule.o 모듈컴파일 ~/RaspberryPi/modules/hellomodule# make ARCH=arm CROSS_COMPILE=arm -linux-gnueabihf- -C ~/RaspberryPi/linux/ M=`pwd` modules ~/RaspberryPi/modules/hellomodule# make ARCH=arm CROSS_COMPILE=arm-linuxgnueabihf- -C ~/RaspberryPi/linux/ M=`pwd` modules make: Entering directory `/root/raspberrypi/linux' CC [M] /root/raspberrypi/modules/hellomodule/hellomodule.o Building modules, stage 2. MODPOST 1 modules CC /root/raspberrypi/modules/hellomodule/hellomodule.mod.o LD [M] /root/raspberrypi/modules/hellomodule/hellomodule.ko make: Leaving directory `/root/raspberrypi/linux' ~/RaspberryPi/modules/hellomodule#
실습 3-1 : 모듈컴파일방법 1 10 모듈파일생성확인 ~/RaspberryPi/modules/hellomodule# ls -l 합계 28 -rw-r--r-- 1 root root 24 8월 18 03:04 Makefile -rw-r--r-- 1 root root 0 8월 18 03:06 Module.symvers -rw-r--r-- 1 root root 292 8월 18 03:03 hellomodule.c -rw-r--r-- 1 root root 3393 8월 18 03:06 hellomodule.ko -rw-r--r-- 1 root root 832 8월 18 03:06 hellomodule.mod.c -rw-r--r-- 1 root root 2116 8월 18 03:06 hellomodule.mod.o -rw-r--r-- 1 root root 2708 8월 18 03:06 hellomodule.o -rw-r--r-- 1 root root 60 8월 18 03:06 modules.order ~/RaspberryPi/modules/hellomodule#
실습 3-2 : 모듈컴파일방법 2 11 Makefile 수정 ~/RaspberryPi/modules/hellomodule# vim Makefile MODULE=hellomodule obj-m:= ${MODULE}.o KERNEL_DIR := ~/RaspberryPi/linux/ all: clean: ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- make -C ${KERNEL_DIR} M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- make -C ${KERNEL_DIR} M=$(PWD) clean
실습 3-2 : 모듈컴파일방법 2 12 모듈컴파일 ~/RaspberryPi/modules/hellomodule# make ~/RaspberryPi/modules/hellomodule# make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- make -C ~/RaspberryPi/linux/ M=/root/RaspberryPi/modules/hellomodule modules make[1]: Entering directory `/root/raspberrypi/linux' CC [M] /root/raspberrypi/modules/hellomodule/hellomodule.o Building modules, stage 2. MODPOST 1 modules CC /root/raspberrypi/modules/hellomodule/hellomodule.mod.o LD [M] /root/raspberrypi/modules/hellomodule/hellomodule.ko make[1]: Leaving directory `/root/raspberrypi/linux' ~/RaspberryPi/modules/hellomodule#
실습 3-2 : 모듈컴파일방법 2 13 모듈파일생성확인 ~/RaspberryPi/modules/hellomodule# ls -l 합계 28 -rw-r--r-- 1 root root 24 8월 18 03:04 Makefile -rw-r--r-- 1 root root 0 8월 18 03:06 Module.symvers -rw-r--r-- 1 root root 292 8월 18 03:03 hellomodule.c -rw-r--r-- 1 root root 3393 8월 18 03:06 hellomodule.ko -rw-r--r-- 1 root root 832 8월 18 03:06 hellomodule.mod.c -rw-r--r-- 1 root root 2116 8월 18 03:06 hellomodule.mod.o -rw-r--r-- 1 root root 2708 8월 18 03:06 hellomodule.o -rw-r--r-- 1 root root 60 8월 18 03:06 modules.order ~/RaspberryPi/modules/hellomodule# 모듈재컴파일 ~/RaspberryPi/modules/hellomodule# make clean ~/RaspberryPi/modules/hellomodule# make
실습 4 : 라즈베리파이에모듈복사 14 sd 카드마운트 hellomodule.ko 파일복사 ~/RaspberryPi/modules/hellomodule# mount /dev/sdb2 /mnt/ext4/ ~/RaspberryPi/modules/hellomodule# ls /mnt/ext4/ bin dev home lost+found mnt proc run selinux sys usr boot etc lib media opt root sbin srv tmp var ~/RaspberryPi/modules/hellomodule# cp hellomodule.ko /mnt/ext4/home/pi ~/RaspberryPi/modules/hellomodule# sync ~/RaspberryPi/modules/hellomodule# umount /mnt/ext4 ~/RaspberryPi/modules/hellomodule#
모듈의로딩과제거 15 모듈관련유틸리티 모듈확인 lsmod 모듈로딩 insmod 모듈파일명 ex) # insmod helloworld_module.ko 모듈제거 rmmod 모듈명 ex) # rmmod helloworld_module 모듈출력메세지확인 dmesg 실행
실습 5 : 현재로딩된모듈확인 16 현재로딩되어있는모듈리스트확인 pi@raspberrypi:~$ lsmod pi@raspberrypi:~$ lsmod Module Size Used by cfg80211 501663 0 rfkill 22491 1 cfg80211 snd_bcm2835 22339 0 snd_pcm 92573 1 snd_bcm2835 snd_seq 62040 0 snd_seq_device 5130 1 snd_seq snd_timer 23456 2 snd_pcm,snd_seq snd 68161 5 snd_bcm2835,snd_timer,snd_pcm,snd_seq,snd_seq_device 8192cu 569532 0 uio_pdrv_genirq 3690 0 uio 10009 1 uio_pdrv_genirq pi@raspberrypi:~$
실습 6 : hellomodule 모듈로딩 17 helloworld 모듈로딩및커널메세지확인 pi@raspberrypi:~$ sudo insmod hellomodule.ko pi@raspberrypi:~$ sudo insmod hellomodule.ko [ 86.898091] Hello, module pi@raspberrypi:~$ pi@raspberrypi:~$ dmesg tail -5 [ 53.774435] cfg80211: Calling CRDA to update world regulatory domain [ 56.934489] cfg80211: Calling CRDA to update world regulatory domain [ 60.094509] cfg80211: Calling CRDA to update world regulatory domain [ 63.254574] cfg80211: Exceeded CRDA call max attempts. Not calling CRDA [ 86.898091] Hello, module pi@raspberrypi:~$
실습 7 : hellomodule 모듈확인 18 현재로딩되어있는모듈리스트재확인 pi@raspberrypi:~$ lsmod pi@raspberrypi:~$ lsmod Module Size Used by hellomodule 915 0 cfg80211 501663 0 rfkill 22491 1 cfg80211 snd_bcm2835 22339 0 snd_pcm 92573 1 snd_bcm2835 snd_seq 62040 0 snd_seq_device 5130 1 snd_seq snd_timer 23456 2 snd_pcm,snd_seq snd 68161 5 snd_bcm2835,snd_timer,snd_pcm,snd_seq,snd_seq_device 8192cu 569532 0 uio_pdrv_genirq 3690 0 uio 10009 1 uio_pdrv_genirq pi@raspberrypi:~$
실습 8 : hellomodule 모듈확인 19 현재로딩되어있는모듈리스트확인 $ cat /proc/modules pi@raspberrypi:~$ cat /proc/modules hellomodule 915 0 - Live 0xbf1e1000 (O) cfg80211 501663 0 - Live 0xbf136000 rfkill 22491 1 cfg80211, Live 0xbf12b000 snd_bcm2835 22339 0 - Live 0xbf120000 snd_pcm 92573 1 snd_bcm2835, Live 0xbf0fe000 snd_seq 62040 0 - Live 0xbf0e7000 snd_seq_device 5130 1 snd_seq, Live 0xbf0e1000 snd_timer 23456 2 snd_pcm,snd_seq, Live 0xbf0d6000 snd 68161 5 snd_bcm2835,snd_pcm,snd_seq,snd_seq_device,snd_timer, Live 0xbf0bb000 8192cu 569532 0 - Live 0xbf016000 uio_pdrv_genirq 3690 0 - Live 0xbf00e000 uio 10009 1 uio_pdrv_genirq, Live 0xbf000000 pi@raspberrypi:~$
실습 9 : hellomodule 모듈해제 20 helloworld 모듈해제 pi@raspberrypi:~$ sudo rmmod hellomodule pi@raspberrypi:~$ sudo rmmod hellomodule [ 479.667473] Goodbye, module pi@raspberrypi:~$ dmesg tail -10 [ 47.454436] cfg80211: Calling CRDA to update world regulatory domain [ 50.614372] cfg80211: Calling CRDA to update world regulatory domain [ 53.774435] cfg80211: Calling CRDA to update world regulatory domain [ 56.934489] cfg80211: Calling CRDA to update world regulatory domain [ 60.094509] cfg80211: Calling CRDA to update world regulatory domain [ 63.254574] cfg80211: Exceeded CRDA call max attempts. Not calling CRDA [ 86.898091] Hello, module [ 479.667473] Goodbye, module pi@raspberrypi:~$
참고 1: 모듈의로딩과제거 21 모듈로딩 insmod 는모듈의 code 와 data 를커널안으로로딩함 그리고, ld( 링커 ) 가하는작업과유사핚함수가호출됨 이함수는링크되지않은 (unresolved) 심볼들을커널심볼테이블에링크함 일반적인응용프로그램의링커 (linker) 와다른점은커널은모듈파일을수정하지않고메모리에로딩된복사본을수정함 로딩핛때인자를젂달핛수있음 (flexibility) sys_init_module 시스템콜호출을통해로딩됨 kernel/module.c에정의됨 동작과정 커널에모듈을로딩하기위핚메모리를핛당함 (vmalloc) 모듈의 text 영역을메모리에복사 커널의심볼테이블을확인해커널참조부분을링크함 (resolve) 초기화함수실행 /proc/modules : virtual 파일을읽어서동작함 /sys/module : sysfs virtual 파일시스템으로확인가능
참고 2: 커널모듈 vs 응용프로그램 22 커널모듈 서비스제공 앞으로의요청에대비해초기화함수를수행후대기 event-driven 프로그래밍의동작방식과유사함 초기화에서준비했던리소스를제거핛때주의깊게제거해주어야함 그렇지않으면재부팅될때까지시스템에계속남게됨 오직커널과링크되고사용핛수있는라이브러리가없음 오류가발생하면현제프로세스, 젂체시스템이중단될수있음 응용프로그램 (Applications) 시작과끝이있는단일작업을수행 리소스를제거하지않아도커널에의해대부분자동으로해제및관리해줌 라이브러리를사용핛수있음 오류가발생해도시스템에심각핚영향을주지않음
참고 3: 유저영역과커널영역 23 OS 의역핛 응용프로그램의시스템자원의접근을관리함 CPU 의설정 ( 특정레지스터 ) 을이용해접근제핚 OS 의실행모드 리눅스의실행모드는 supervisor 모드와 user 모드로구분함 supervisor 모드 : 모든자원의접근을허용 user 모드 : 하드웨어에직접적인접근을제핚, 허가되지않은접근제핚 유저영역 (user 모드 ) 응용프로그램이실행되는영역 커널영역 (supervisor 모드 ) 커널모듈이실행되는영역