390 likes | 648 Views
리눅스 디바이스 드라이버. 실습 환경 설정 및 준비. 커널 컴파일. 디바이스 파일 (1). 디바이스 파일 (2). mknod 명령 디바이스 파일 생성 mknod [ 디바이스 파일명 ] [ 파일 형 ] [ 주 번호 ] [ 부 번호 ] mknod /dev/devfile c 240 1. 디바이스 드라이버 탐색. 실질적인 디바이스 탐색. 저수준 파일 입출력 함수. 모듈 유틸리티. insmod 모듈을 커널에 적재한다 . rmmod 커널에 등록된 모듈을 제거한다 . lsmod
E N D
리눅스 디바이스 드라이버 실습 환경 설정 및 준비
디바이스 파일(2) • mknod 명령 • 디바이스 파일 생성 • mknod [디바이스 파일명] [파일 형] [주 번호] [부 번호] • mknod /dev/devfile c 240 1 디바이스 드라이버 탐색 실질적인 디바이스 탐색
모듈 유틸리티 • insmod • 모듈을 커널에 적재한다. • rmmod • 커널에 등록된 모듈을 제거한다. • lsmod • 커널에 등록된 모듈의 상태를 보여준다.
모듈 소스 형식(1) • 헤더 파일 선언 • 모듈 초기화 함수, 제거 함수
모듈 컴파일용 Makefile 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 // 두 지운다. rm -rf *.mod.* rm -rf .*.cmd rm -rf *.o
모듈 프로그램 맛보기(1) • test.c #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) • Makefile 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 rm -rf *.mod.* rm -rf .*.cmd rm -rf *.o
kmalloc(), kfree()-1 메모리주소 kmalloc(할당 받을 크기, 옵션); kfree(메모리주소); * 할당 가능한 최대 크기는 32 x PAGE_SIZE (일반적으로 128KB) #include <linux/slab.h> char *buf; buf = kmalloc(1024, GFP_KERNEL); if (buf != NULL) { … kfree(buf); }
vmalloc(), vfree() 메모리주소 vmalloc(할당 받을 크기); vfree(메모리주소); #include <linux/vmalloc.h> char *buf; buf = vmalloc(1024); if (buf != NULL) { … vfree(buf); }
vmalloc(), vfree() 특징 • 가상 주소 공간에서 할당받기 때문에 해당주소의 영역이 • 하드디스크에 있을 수도 있어 실패할 수 있다. • 커다란 연속된 공간을 할당하기 위해 가상메모리 관리 루틴이 • 수행되기 때문에 kmalloc() 보다 속도가 매우 느리다. • 할당 시 프로세스가 잠들지 못하게 할 수 없기 때문에 • 인터럽트 서비스 함수 안에서는 사용할 수 없다.
__get_free_pages(), free_pages() 메모리주소 __get_free_pages(옵션, 차수); free_pages(메모리주소); #include <linux/mm.h> //2.4 #include <linux/gfp.h> //2.6 #include <asm/page.h> //get_order char *buf; buf = __get_free_pages(GFP_KERNEL, order); /* order=0이면 1개의 page, order=3이면 3개의 page /* MAX_ORDER은 11, 그러나 5이하의 값만 사용하는 것이 안전 (32*PAGE_SIZE) */ if (buf != NULL) { … free_pages(buf, order); }
초기화와 종료 처리 • module_init 의 초기화 처리 • 디바이스 드라이버의 등록 • 디바이스 드라이버에 내부 구조체의 메모리 할당 • 여러 프로세스가 하나의 디바이스에 접근하는 경우에 사전처리 • 주 번호에 종속된 부 번호를 관리하기 위한 사전 처리 • 하드웨어 검출 처리 및 에러 처리 • 하드웨어 초기화
초기화와 종료 처리 • module_exit 의종료 처리 • 초기화 시점에 할당된 메모리 모두 반납 (디바이스 드라이버는 커널의 일부이기 때문에 메모리를 자동 반납하지 않는다.) • 디바이스 드라이버의 해제 • 디바이스 드라이버에 할당된 모든 메모리의 해제 • 하드웨어 제거에 따른 처리
초기화와 종료 처리 void xxx_exit(void) { kfree(… // 디바이스 드라이버에 할당된 모든 메모리 해제 unregister_chrdev(… // 디바이스 드라이버의 해제 xxx_shutdown(… //하드웨어 제거에 따른 처리 } module_exit 처리순서
초기화와 종료 처리 int fd; fd = open( DEVICE_FILENAME, O_RDWR|O_NDELAY); //반드시 주번호 정보가 있는 파일 if( fd < 0 ) { printf (“error number %d\n”, error); exit(1); } #include<linux/fs.h> struct file_operations call_fops = { … .open = xxx_open, … } int xxx_open( struct inode *inode, struct file *filp ) { int err = 0; //open() 시 처리내용들…. return err; } *inode – 열린 디바이스 파일에 대한 정보 *filp – 디바이스 드라이버 처리관련 정보 ENODEV : 하드웨어가 존재하지 않는다. ENOMEM : 커널 메모리가 부족하다. EBUSY : 디바이스가 이미 사용중 이다. • 디바이스 드라이버 open( ) 함수[2]
초기화와 종료 처리 • 디바이스 드라이버 release( ) 함수[1] • release( ) 함수 호출 시 종료 처리 • 프로세스별 할당 메모리 해제 • 모듈 사용 횟수 감소(커널 2.4) • 커널 2.6에서는 사용횟수 관리를 커널에서 한다.
초기화와 종료 처리 if( fd ) close( fd ); #include<linux/fs.h> struct file_operations call_fops = { … .release = xxx_release, … } int xxx_release( struct inode *inode, struct file *filp ) { //close( ) 시 처리내용들…. return 0; } • 디바이스 드라이버 release( ) 함수[2]
문자 디바이스 드라이버 동작-3 디바이스 드라이버 하드웨어 인터럽트 insmod xxx_init(); struct file_operations { open : xxx_open write : xxx_write . . . } xxx_exit(); xxx_interupt(); xxx_open(); xxx_write(); 응용 프로그램 open(); write(); rmmod
커널 2.6의 파일 오퍼레이션 구조체 struct file_operations { struct module *owner; int (*open)(struct inode *, struct file *); . . . } * 디바이스 드라이버의 file_operations에서정의되지 않았거나 NULL로 채워진 필드는 커널에 의해서 default 처리를 한다.
#include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/errno.h> #include <linux/types.h> #inlcude <linux/fcntl.h> int xxx_open (struct inode *inode, struct file *filp) { } int xxx_release(struct inode *inode, struct file *filp) { } struct file_operations xxx_fops = { .owner = THIS_MODULE, .open = xxx_open, .release = xxx_release, }; int xxx_init(void) { register_chrdev(240, “char_dev”, &xxx_fops); } void xxx_exit(void) { unreister_chrdev(240, “char_dev”); } module_init(xxx_init); module_exit(xxx_exit);