Presentation is loading. Please wait.

Presentation is loading. Please wait.

리눅스 커널과 디바이스드라이버.

Similar presentations


Presentation on theme: "리눅스 커널과 디바이스드라이버."— Presentation transcript:

1 리눅스 커널과 디바이스드라이버

2 커널과 디바이스 드라이버의 관계 디바이스 드라이버
시스템이 지원하는 하드웨어를 응용 프로그램에서 사용할 수 있도록 커널에서 제공하는 라이브러리 응용 프로그램이 하드웨어를 제어하려면 커널에 자원을 요청하고, 커널은 이런 요청에 따라 시스템을 관리 시스템 상에서 실행되는 응용 프로그램은 시스템 콜을 통하여 커널과 통신 일반적으로 응용 프로그램에서는 C 라이브러리 같은 함수를 호출하는데, 라이브러리 내부에서는 커널에게 특정 작업을 지시하기 위해 시스템 콜을 사용하게 된다. 커널로 제어가 넘어가게 되면 커널 모드로 실행되어 커널 서브시스템 또는 디바이스 드라이버를 통해서 하드웨어를 제어

3 커널과 디바이스 드라이버의 관계

4 디바이스 드라이버 디바이스 파일 리눅스는 시스템에 있는 모든 자원을 파일 형식으로 표현
램, 키보드, 보조기억장치인 하드디스크도 파일로 표현 이런 파일들은 /dev/ 디렉터리에 존재하며, 이들을 디바이스 파일이라고 한다. 이 디바이스 파일 하나 하나는 실질적인 하드웨어를 표현 예를들어, 마우스 입력 디바이스는 /dev/mouse라는 디바이스 파일로 표현 일반 파일의 목적이 데이터를 저장하는데 있다면 이들은 하드웨어 정보를 제공하는데 목적이 있다. 이 정보는 세가지로 디바이스 타입정보, 주번호, 부번호이다. 리눅스에서 동작하는 응용 프로그램은 하드웨어를 다루기 위해 해당 디바이스 파일에 저수준 입출력 함수를 사용한다.

5 디바이스 드라이버 디바이스 파일 생성 디바이스 파일은 일반 파일과 달리 create() 함수를 사용하지 않고, mknod 유틸리티에 의해서 생성 디바이스 파일은 주로 “/dev/” 디렉터리에 생성 mknod를 이용하여 디바이스 파일을 만드는 방법은 아래와 같다. 디바이스 파일명은 ttyS4이고, 문자 디바이스 드라이버이고, 주 번호가 4, 부 번호가 68인 디바이스 파일을 생성한다. mknod /dev/ttyS4 c 4 68

6 디바이스 드라이버 주번호와 부번호 주번호 부번호 커널에서 디바이스 드라이버를 구분하고 연결하는데 사용
주번호는 제어하려는 디바이스를 구분하기 위한 디바이스의 ID 부번호 디바이스 드라이버 내에서 장치를 구분하기 위해 사용 같은 종류의 디바이스가 여러 개 있을 때 그 중 하나를 선택하기 위해 사용

7 디바이스 드라이버 주번호와 부번호 시리얼 디바이스 파일을 살펴보면 아래와 같다.
시리얼 COM1 포트를 나타내는 /dev/ttyS0와 COM2 포트를 나타내는 /dev/ttyS1의 주 번호는 ‘4’로 같다. 즉 시리얼 포트라고 하는 같은 종류의 디바이스 파일이다. 하지만 이들 각각을 구분해주는 부번호는 다르다. ~]#ls -al /dev/ttyS* 다음과 같은 메시지가 출력된다 crw root root , 64 Jan /dev/ttyS0 crw root root , 65 Jan /dev/ttyS1 crw root root , 66 Jan /dev/ttyS2 crw root root , 67 Jan /dev/ttyS3

8 디바이스 드라이버 저수준 파일 입출력 함수 저수준 파일 입출력 함수는 리눅스 커널에서 제공하는 파일 관련 시스템콜을 라이브러리 함수로 만든 것 이것은 아주 기본적인 파일을 처리하는 함수로서, 디바이스 파일을 실질적으로 다룰 때 사용 저수준 파일을 이용하여 디바이스 파일에 연관된 디바이스 드라이버 함수가 동작하게 된다.

9 디바이스 드라이버 저수준 파일 입출력 함수 저수준 파일 입출력 함수들의 종류와 기능 저수준 파일 입출력 함수 기 능
기 능 open() 파일이나 장치를 연다. 디바이스 노드에 의해 수행되는 첫번째 동작 close() 열린 파일을 닫는다. read() 파일에서 데이터를 읽어온다. write() 파일에 데이터를 쓴다. lseek() 파일의 쓰기나 읽기 위치를 변경한다. ioctl() read(), write()로 다루지 않는 특수한 제어를 한다. fsync() 파일에 쓴 데이터를 실제 하드웨어의 동기를 맞춘다.

10 디바이스 드라이버 디바이스 드라이버의 종류 문자 디바이스 드라이버 블록 디바이스 드라이버 네트워크 디바이스 드라이버
문자 디바이스는 임의의 길이를 갖는 문자열이나 자료의 순차성을 지닌 장치를 다루는 디바이스 드라이버로서 버퍼 캐쉬를 사용하지 않는다. 사용자에게 Raw 데이터를 제공하며 종류로는 Serial, Console, Keyboard, printer, Mouse 등이 있다.  블록 디바이스 드라이버 블록 디바이스 드라이버는 일정 크기의 버퍼를 통해 데이터를 처리하는 디바이스로, 커널 내부의 파일 시스템에서 관리하고 내부적인 버퍼가 있는 디바이스 드라이버이다. 이것의 종류로는 하드 디스크, 램디스크등이 있다. 네트워크 디바이스 드라이버 네트워크 디바이스 드라이버는 네트워크 계층과 연결되어 네트워크 통신을 통해 네트워크 패킷을 송수신할 수 있는 기능을 제공한다. 이것의 종류로는 이더넷, PPP 등이 있다.

11 디바이스 드라이버 커널과 모듈 커널 모듈은 리눅스 커널이 부팅되어 동작중인 상태에서 디바이스 드라이버를 동적으로 추가하거나 제거할 수 있게 하는 개념이다. 이런 모듈 방식은 리눅스에 포함된 디바이스 드라이버를 개발할 때 개발 시간을 단축시킬 뿐만 아니라 필요없는 기능은 커널에 포함시키지 않음으로써 커널 자원을 효율적으로 다루게 한다. 리눅스에서는 다른 운영체제와는 달리 대부분의 기능(파일 시스템, 디바이스 드라이버, 통신 프로토콜 등)을 모듈로 구현할 수 있는데, 특히 하드웨어를 다루는 기능을 구현한 것이 바로 디바이스 드라이버이다.

12 디바이스 드라이버 모듈 프로그래밍 모듈은 커널 프로그램의 특징을 갖고 있으면서 커널에 동적으로 적재되고 제거되므로 일반 프로그램과는 다른 소스 형식을 갖추어야 한다. 디바이스 드라이버 같은 커널 라이브러리를 객체 형태로 만들어서 시스템 콜을 통해서 리눅스 커널에 적재 요청을 하면, 커널은 해당 객체를 커널에 동적으로 링크시킨다. 그러나 그 자체로는 링크처리를 할 수 없기 때문에 커널 심볼테이블 기능을 제공한다. 심볼 테이블은 커널 내부의 함수나 변수 중 외부에서 참조할 수 있는 함수의 심볼과 주소를 담은 테이블이다. 이 심볼 테이블을 이용하면 객체 형태로 작성된 커널 모듈 루틴이 참조할 커널 내부의 함수나 변수에 연결되어 동적으로 링크된다.

13 디바이스 드라이버 모듈과 일반 프로그램과의 차이점
커널 모듈 프로그램은 커널 영역에서 동작하며 일반 프로그램은 유저 영역에서 동작한다. 모듈은 커널에 로딩 및 제거될 때 호출되는 함수가 따로 존재한다. main() 함수가 존재하지 않으며, 일반적인 라이브러리를 사용하지 못하고 커널이 export 해준 함수만을 사용할 수 있다.

14 디바이스 드라이버 모듈관련 유틸리티 모듈로 만들어진 디바이스 드라이버는 심볼 테이블을 통해 커널에 링크시키도록 도와주는 유틸리티가 필요 이러한 유틸리티는 아래와 같다. insmod : 모듈을 커널에 적재한다. rmmod : 커널에서 모듈을 제거한다. lsmod : 커널에 적재된 모듈 목록을 출력한다. depmod : 모듈간 의존성 정보를 생성한다.

15 디바이스 드라이버 간단한 모듈 프로그램 작성 기초적인 디바이스 드라이버를 모듈 형식으로 작성하고 테스트
작성할 예제는 “Hello world”메시지를 출력해주는 간단한 모듈 드라이버 파일명은 hello.c 모듈 드라이버를 작성할 디렉토리 생성 cd /working mkdir module_driver cd module_driver

16 디바이스 드라이버(hello 모듈 드라이버 작성)
vi hello.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(“Daul BSD/GPL”); 저장 하고 종료한다

17 디바이스 드라이버 간단한 모듈 프로그램 작성 모듈을 컴파일하기 위한 Makefile을 작성
vi Makefile (1) (2) (3) (4) (5) (6) 다음과 같이 수정한다 # Hello Device Driver Makefile CC = arm-linux-gcc obj-m := hello.o KDIR := /working/linux s4210/ PWD := $(shell pwd) default: $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules clean: rm -f *.ko rm -f *.o rm -f *.mod.* rm -f .*.cmd 저장하고 종료한다

18 디바이스 드라이버 간단한 모듈 프로그램 작성 모듈 컴파일 root@ubuntu:/working/module_driver# ls
다음과 같은 메시지가 출력된다 Makefile hello.c make make -C /working/linux s4210/ SUBDIRS=/working/module_driver modules make[1]: Entering directory `/working/linux s4210' CC [M] /working/module_driver/hello.o Building modules, stage 2. MODPOST 1 modules CC /working/module_driver/hello.mod.o LD [M] /working/module_driver/hello.ko make[1]: Leaving directory `/working/linux s4210'

19 디바이스 드라이버 간단한 모듈 프로그램 작성 생성된 파일 리스트를 확인
생성된 파일 중에 커널에 로딩하는 모듈 파일은 hello.ko ls 다음과 같은 메시지가 출력된다 Makefile hello.c hello.mod.c hello.o Module.symvers hello.ko hello.mod.o modules.order

20 디바이스 드라이버 간단한 모듈 프로그램 작성 모듈 실행 hello.ko 파일을 /tftpboot 디렉터리로 복사
cp hello.ko /tftpboot ls /tftpboot/hello.ko 다음과 같은 메시지가 출력된다 /tftpboot/hello.ko ~]# tftp -r hello.ko -g ~]# insmod hello.ko 다음과 같은 메시지가 출력된다 Hello world

21 간단한 모듈 프로그램 작성 모듈 실행 lsmod 를 사용하여 적재된 모듈 목록을 확인
첫번째 열은 등록된 모듈명, 두번째 열은 모듈이 커널에서 차지하고 있는 메모리의 크기, 세번째 열은 사용 여부, 네번째 열은 해당 모듈을 참조하고 있는 모듈명을 나타낸다. ~]# lsmod 다음과 같은 메시지가 출력된다 Module Size Used by Tainted: P hello

22 디바이스 드라이버 간단한 모듈 프로그램 작성 모듈 실행
커널에 등록된 모듈을 제거한다. 이때 디바이스 드라이버 모듈명 만을 지정한다. ~]# rmmod hello ~]# tail /var/log/message 다음과 같은 메시지가 출력된다 Goodbye world

23 디바이스 드라이버 디바이스 드라이버의 등록과 해제
디바이스 드라이버는 하드웨어를 다루고 커널 내에서 디바이스 드라이버로서 동작 하기 위한 소프트웨어적인 처리를 수반 이것은 디바이스 드라이버가 동작하기 위한 초기화와 종료에 대한 처리이며, 이것을 처리하기 위한 두가지 시점이 존재

24 디바이스 드라이버 디바이스 드라이버의 등록과 해제 (1) 모듈 초기화와 종료 module_init의 초기화 처리
모듈 초기화 함수에서는 디바이스 드라이버가 처리해야 할 하드웨어 검출 및 검출된 하드웨어를 응용 프로그램에서 사용할 수 있도록 초기화 작업을 한다. 또한 모듈 초기화나 종류 시점에는 응용 프로그램이 디바이스 드라이버를 사용하는 전후의 처리를 구현한다. module_init의 초기화 처리 module_init 매크로가 정의하는 초기화 함수에서는 처리하고자 하는 하드웨어의 검출과 디바이스 드라이버 등록 그리고 디바이스 드라이버가 응용 프로그램에서 사용할 수 있는 환경 등을 처리 디바이스 드라이버의 등록 디바이스 드라이버에 내부 구조체의 메모리 할당 하드웨어 초기화

25 디바이스 드라이버 디바이스 드라이버의 등록과 해제 (1) 모듈 초기화와 종료 module_exit의 종료 처리
디바이스 드라이버의 해제 디바이스 드라이버에 할당된 메모리의 해제 하드웨어 제거에 따른 처리

26 디바이스 드라이버 디바이스 드라이버의 등록과 해제 (2) open()함수와 release() 함수의 초기화와 종료
디바이스 드라이버의 open()과 close()에 대응하는 함수들은 파일이 열리는 시점과 닫히는 시점에 호출되며, 디바이스가 사용되면서 필요한 처리와 디바이스가 더 이상 사용되지 않을 때의 처리를 주로 구현한다.

27 디바이스 드라이버 문자 디바이스 드라이버 문자 디바이스 드라이버는 저수준 파일 입출력 함수를 이용해 디바이스 파일에 데이터를 읽고 쓴다. 그러면 이에 대응하는 디바이스 드라이버 내의 선언 함수가 호출된다. 커널에서는 디바이스 파일에 기록된 디바이스 타입과 주번호를 이용해 커널 내에 등록된 디바이스 드라이버 함수를 연결한다. 문자 디바이스의 경우 chrdevs라는 전역 변수에서 문자 디바이스 드라이버를 관리한다. 이 구조체는 struct file_operations *fops라는 필드를 포함한 문자 디바이스 드라이버를 관리하는 구조체이다. 그리고 이 fops 필드는 file_operations 구조체로, 응용프로그램이 디바이스 파일에 적용한 저수준 파일 입출력 함수에 대응하는 디바이스 드라이버의 함수 주소를 지정하는 필드를 포함한다.

28 디바이스 드라이버 문자 디바이스 드라이버 파일 오퍼레이션 구조체(struct file_operations)
문자 디바이스 드라이버와 응용프로그램을 연결하는 고리는 파일 오퍼레이션 구조체 응용 프로그램이 저수준 파일 입출력 함수를 사용하여 디바이스 파일에 접근하면, 커널은 등록된 문자 디바이스 드라이버의 오퍼레이션 구조체 정보를 참고하여 디바이스 파일에 접근한 함수에 대응하는 함수를 호출

29 디바이스 드라이버 문자 디바이스 드라이버 파일 오퍼레이션 구조체(struct file_operations) Operation
설명 struct module *owner 어떤 모듈로 올라간 디바이스 드라이버와 연관을 가지는지를 나타내는 포인터 llseek 현재의 읽기 쓰기 포인터를 옮기고자 할 때 사용 read /write 데이터를 장치에서 읽거나 쓰고자 할 때 사용 readdir 디렉터리에 대해서만 사용되며, 디바이스에 대해서는 NULL값을 가짐 select 디바이스가 읽기나 쓰기, 혹은 예외 상황을 일으켰는지를 확인할 때 사용 ioctl 특정 디바이스에 의존적인 명령을 수행하고자 할 때 사용 mmap 디바이스의 메모리 일부를 현재 프로세스의 메모리 영역으로 매핑하고자 할 때 사용 open / release 디바이스에 대한 열기/닫기를 할 때 사용 fsyn 디바이스에 대한 모든 연산의 결과를 지연하지 않고 즉시 일어나도록 할 때 사용

30 디바이스 드라이버 문자 디바이스 드라이버의 구성
문자 디바이스 드라이버를 제작하려면 최소한 저 수준 파일 입출력에 대응하는 file_operations 구조체에 등록할 함수들과 문자 디바이스 드라이버 등록 및 제거함수 그리고 인터럽트를 사용하는 하드웨어라면 인터럽트 처리 함수가 구현이 되어야 한다. 문자 디바이스 드라이버의 구조에 대해서 알아보기 위해서 아래의 led 문자 디바이스 드라이버 소스 구성을 살펴본다.

31 디바이스 드라이버(LED 문자 디바이스 드라이버 소스)
#include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <asm/uaccess.h> #include <linux/fs.h> #include <asm/io.h> #include <linux/ioport.h> #include <linux/kdev_t.h> #include <linux/miscdevice.h> #include <linux/platform_device.h> #include <asm/ioctl.h> #define DRIVER_AUTHOR "Hanback Electronics" #define DRIVER_DESC "led test program" #define LED_NAME "led" #define LED_MODULE_VERSION "LED V1.0" #define LED_ADDRESS 0x #define LED_ADDRESS_RANGE 0x1000

32 디바이스 드라이버(LED 문자 디바이스 드라이버 소스)
//Global variable static int led_usage = 0; static unsigned long *led_ioremap; // define functions... int led_open(struct inode *minode, struct file *mfile) { if(led_usage != 0) return -EBUSY; led_ioremap= ioremap(LED_ADDRESS,LED_ADDRESS_RANGE); if(!check_mem_region((unsigned long)led_ioremap,LED_ADDRESS_RANGE)){ request_mem_region((unsigned long)led_ioremap,LED_ADDRESS_RANGE,LED_NAME); } else printk(KERN_WARNING"Can't get IO Region 0x%x\n", (unsigned int)led_ioremap); led_usage = 1; return 0; }

33 디바이스 드라이버(LED 문자 디바이스 드라이버 소스)
int led_release(struct inode *minode, struct file *mfile) { iounmap(led_ioremap); release_mem_region((unsigned long)led_ioremap,LED_ADDRESS_RANGE); led_usage = 0; return 0; } ssize_t led_write_byte(struct file *inode, const char *gdata, size_t length, loff_t *off_what) unsigned short *addr; unsigned char c; get_user(c,gdata); addr = (unsigned short*)led_ioremap; *addr = c|0x100; return length;

34 디바이스 드라이버(LED 문자 디바이스 드라이버 소스)
static struct file_operations led_fops = { .owner = THIS_MODULE, .open = led_open, .write = led_write_byte, .release = led_release, }; static struct miscdevice led_driver = { .fops = &led_fops, .name = LED_NAME, .minor = MISC_DYNAMIC_MINOR, int led_init(void) { misc_register(&led_driver); return 0; }

35 디바이스 드라이버(LED 문자 디바이스 드라이버 소스)
void led_exit(void) { misc_deregister(&led_driver); printk(KERN_INFO"driver: %s DRIVER EXIT\n", LED_NAME); } module_init(led_init); module_exit(led_exit); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("Dual BSD/GPL");


Download ppt "리눅스 커널과 디바이스드라이버."

Similar presentations


Ads by Google