Adding a New Dev file - 김성영, 이재혁, 김남현 - 발표자 : 김남현
목차 01 Progress 02 Device file 03 How create dev file 04 Example
Progress 4 월 1 일 프로젝트방향설정 4 월 8 일 device file 추가방법조사 mem.c 파일분석 4 월 10 일 알고리즘제시필요한함수분석 4 월 16 일 발표자료조사및만들기
진행중어려운점 Google 예제의부족 디바이스드라이버를 built-in 형태로구현 Linux 버전에따른코드의수정 2.x 버젼의 nopage 가없어지고 3.x 버젼의 fault 로통합 Unmap 의방법
해야하는일 Fault handling PTE에서 physical page에접근하는것을막는방법 Fault가일어나는이유를구분
Device File System
디바이스드라이버 시스템이지원하는하드웨어를응용프로그램에서사용할수있도록커널에서제공하는라이브러리 하드웨어는디바이스드라이버를통해접근 응용프로그램이하드웨어를제어하려면커널에자원을요청하고, 커널은이런요청에따라시스템을관리
디바이스드라이버
디바이스파일 유닉스의철학 : Everything is a file 리눅스는시스템에있는모든자원을파일형식으로표현 램, 키보드, 보조기억장치인하드디스크도파일로표현 일반파일의목적이데이터를저장하는데있다면이들은하드웨어정보를제공하는데목적이있다. /dev/ 디렉터리에존재하며, 이파일하나하나는실질적인하드웨어를표현
디바이스드라이버의종류 문자디바이스드라이버 임의의길이를갖는문자열이나자료의순차성을지닌장치를다루는디바이스드라이버 버퍼캐쉬를사용하지않는다. Ex) Serial, Console, Keyboard, Printer, Mouse. 블록디바이스드라이버 일정크기의버퍼를통해데이터를처리하는디바이스드라이버 Ex) Hard disk, RAM. 네트워크디바이스드라이버 네트워크계층과연결되어네트워크통신을통해패킷을송수신할수있는기능을제공한다. Ex) 이더넷, PPP.
디바이스파일 주번호와부번호 주번호 커널에서디바이스드라이버를구분하고연결하는데사용 주번호는제어하려는디바이스를구분하기위한디바이스의 ID 부번호 디바이스드라이버내에서장치를구분하기위해사용 같은종류의디바이스가여러개있을때그중하나를선택하기위해사용
디바이스파일 주번호와부번호 시리얼디바이스파일을살펴보면아래와같다. root@ubunt:~$ ls al /dev/ttys* crw-rw---- 1 root dialout 4, 64 Apr 17 02:31 /dev/ttys0 crw-rw---- 1 root dialout 4, 65 Apr 17 02:31 /dev/ttys1 crw-rw---- 1 root dialout 4, 74 Apr 17 02:31 /dev/ttys10 crw-rw---- 1 root dialout 4, 75 Apr 17 02:31 /dev/ttys11 crw-rw---- 1 root dialout 4, 76 Apr 17 02:31 /dev/ttys12. 시리얼 COM1 포트를나타내는 /dev/ttys0 와 COM2 포트를나타내는 /dev/ttys1 의주번호는 4 로같다. 즉시리얼포트라고하는같은종류의디바이스파일이다. 하지만이들을각각을구분해부번호는다르다.
Create Dev File
디바이스파일생성 mknod ( 쉘에서 ) 디바이스파일은일반파일과달리 create() 함수를사용하지않고, mknod 유틸리티에의해서생성 디바이스파일은주로 /dev/ 디렉터리에생성 mknod 를이용하여디바이스파일을만드는방법은아래와같다 root@ubuntu:# mknod /dev/ttys4 c 4 68 디바이스파일명은 ttys4 이고, 문자디바이스드라이버이고, 주번호가 4, 부번호가 68 인디바이스파일을생성한다.
디바이스파일생성 mknod ( 소스코드에서 ) 응용프로그램에서디바이스파일을만들어야할경우 int mknod(const char *pathnmae, mode_t mode, dev_t dev) Const char *pathname 작성할디바이스파일명 mode_t mode 접근허가및디바이스타입 (OR 연산으로설정 ) dev_t dev 디바이스주번호및부번호 ( 시프트연산으로같이입력 )
디바이스등록 register_chrdev 커널내부에등록된 device driver 를관리하는 chrdev[] 배열구조체에하나의배열을할당받는다. 배열안의필드에파일의이름과파일오퍼레이션을연결한다. int register_chrdev(unsigned int major, const char *name, struct file_operations *fops) unsigned int major 할당하고자하는주번호 const char *name 디바이스파일의이름 strtuct file_oprations *fops 드라이버의엔트리포인트를실행하는데사용되는함수구조체포인터
2 가지형태의구현방법 External Module 사용자에의해 modprobe 혹은 insmod 의명령어로동적으로모듈에적재된다. Built-in 부팅되는과정에서커널에적재된다.
/kernel/include/linux/init.h
External Module 방식 /* Each module must use one module_init(). */ #define module_init(initfn) \ static inline initcall_t inittest(void) \ { return initfn; } \ int init_module(void) attribute ((alias(#initfn))); /* This is only required if you want to be unloadable. */ #define module_exit(exitfn) \ static inline exitcall_t exittest(void) \ { return exitfn; } \ void cleanup_module(void) attribute ((alias(#exitfn)));
Built-in 방식 #define device_initcall(fn) define_initcall(fn,6)... #define initcall(fn) device_initcall(fn)... /** * module_init() - driver initialization entry point * @x: function to be run at kernel boot time or module insertion * * module_init() will either be called during do_initcalls() (if * builtin) or at module insertion time (if a module). There can only * be one per module. */ #define module_init(x) initcall(x);
#define define_initcall(level,fn,id) \ static initcall_t initcall_##fn##id used \ attribute (( section (".initcall" level ".init"))) = fn... #define device_initcall(fn) define_initcall(fn,6)
start_kernel(void) rest_init(void) kernel_init(void* unused) do_basic_setup(void) do_initcalls(void)
do_initcalls(void) extern initcall_t initcall_start[], initcall_end[], early_initcall_end[]; static void init do_initcalls(void) { initcall_t *call; for (call = early_initcall_end; call < initcall_end; call++) do_one_initcall(*call); /* Make sure there is no pending stuff from the initcall sequence */ flush_scheduled_work(); }
do_one_initcalls(initcall_f fn) int do_one_initcall(initcall_t fn) { int count = preempt_count(); ktime_t t0, t1, delta; char msgbuf[64]; int result; if (initcall_debug) { printk("calling %pf\n", fn); t0 = ktime_get(); } result = fn(); }...
Built-in Device Driver 소스코드작성 Kconfig 수정 Make file 수정 make menuconfig 수정
예제 /drivers/char my_driver.c 파일생성 static int my_dev_init(void) { int res; printk("initializer has been called\n"); res = register_chrdev(my_dev_major,my_dev_name,&mem_fops); if(res<0) return res; } return 0; module_init (my_dev_init);
/driver/char Kconfig 수정 menu "Character devices source "drivers/tty/kconfig config MYDEVDRIVER bool "my_dev_driver" default y... y 는선택되었다는것을의미한다. Make menuconfig 입력시, 메뉴화면은 Kconfig의내용을파싱한것임.
/driver/char Makefile 수정 obj-$(config_mydevdriver) obj-y obj-$(config_tty_printk) += my_driver.o += mem.o random.o += ttyprintk.o...
Make menuconfig Device Drivers -> Character devices
결과
Example
Google Example Code #include <linux/init.h> static char ker_buf[100]; //driver local buffer static int dev_open(struct inode *inod, struct file *fil); static ssize_t dev_read(struct file *filep,char *buf,size_t len,loff_t *off); static ssize_t dev_write(struct file *flip,const char *buff,size_t len,loff_t *off); static int dev_release(struct inode *inod,struct file *fil); //structure containing device operation static struct file_operations fops= {.read=dev_read,.write=dev_write,.open=dev_open,.release=dev_release, };
Google Example Code static int dev_open(struct inode *inod, struct file *fil) { printk("kern_alert device opened"); return 0; } static ssize_t dev_read(struct file *filep,char *buf,size_t len,loff_t *off) { copy_to_user(buf,ker_buf,len); return len; } static ssize_t dev_write(struct file *flip,const char *buf,size_t len,loff_t *off) { copy_from_user(ker_buf,buf,len); ker_buf[len]=0; return len; }
Google Example Code static int dev_release(struct inode *inod,struct file *fil) { printk("kern_alert device closed\n"); return 0; } static int hello_init(void) { int t=register_chrdev(90,"mydev",&fops); if(t<0) printk(kern_alert "device registration failed."); else printk(kern_alert "device registred\n"); return 0; } static void hello_exit(void) { unregister_chrdev(90,"mydev"); printk(kern_alert "exit"); } module_init(hello_init); module_exit(hello_exit);
감사합니다 - 김성영, 이재혁, 김남현