340 likes | 489 Views
디바이스드라이버. 모듈프로그래밍 디바이스드라이버 프로그래밍. 모듈프로그래밍. 초기 리눅스 : 커널 변경시 커널 전체를 다시 컴파일 모듈 프로그램으로 개발하면 해당 모듈만 컴파일하고 필요할 때만 동적으로 링크시켜 커널의 일부로 사용할 수 있어 효율적 자주 사용하지 않는 커널 기능은 메모리에 상주시키지 않아도 됨 확장성과 재사용성을 높일 수 있음. 모듈 프로그래밍의 특징 사건 구동형 (event-driven program) 방식으로 작성 내부에 main() 이 없음
E N D
디바이스드라이버 모듈프로그래밍 디바이스드라이버 프로그래밍
모듈프로그래밍 • 초기 리눅스: 커널 변경시 커널 전체를 다시 컴파일 • 모듈 프로그램으로 개발하면 해당 모듈만 컴파일하고 필요할 때만 동적으로 링크시켜 커널의 일부로 사용할 수 있어 효율적 • 자주 사용하지 않는 커널 기능은 메모리에 상주시키지 않아도 됨 • 확장성과 재사용성을 높일 수 있음.
모듈 프로그래밍의 특징 • 사건 구동형(event-driven program) 방식으로 작성 • 내부에 main()이 없음 • 커널에 적재/제거하기 위한 규칙과 유틸리티가 필요 • 외부로 공개할 전역변수 사용에 주의 • 커널에 적재된 모듈 프로그램은 무제한의 특권을 가지므로 신중하게 작성해야 함
심볼 및 관련 매크로 • 전역변수와 전역 함수 이름을 심볼 테이블에 등록 • 커널 심볼 테이블의 내용은 /proc/kallsyms라는 텍스트 파일로 외부에 제공 • EXPORT_NO_SYMBOLS: 공개하지 않음 • EXPORT_SYMBOL(), EXPORT_SYMBOL_GPL(): 공개
호스트 시스템에서 모듈 생성을 위한 Makefile 기본 형태 • 타겟 시스템에서 모듈 생성을 위한 Makefile 기본 형태
실습 호스트 시스템의 커널 공개 심볼 살펴보기 • head /proc/kallsyms, tail /proc/kallsyms를 입력해 커널 심볼 테이블의 내용을 확인
insmod: 모듈을 커널로 적재하는 명령 • rmmod: 제거하는 명령 • lsmod: 정상적으로 적재되었는지 확인하는 명령
실습 Hello 모듈 프로그램 작성 및 실행 • 모듈 프로그램 hello.c 작성 01 #include <linux/kernel.h> 02 #include<linux/module.h> 03 #include<linux/init.h> 04 05 static int module_begin(void) // 모듈 초기화 함수 06 { 07 printk("Hello, Module!\n"); 08 return 0; 09 } 10 11 static void module_end(void) // 모듈 마무리 함수 12 { 13 printk("Good bye!\n"); 14 } 15 16 module_init(module_begin); 17 module_exit(module_end);
① ② ③ ④ ⑤ 실습 9-2 Hello 모듈 프로그램 작성 및 실행 • Makefile을 작성 앞의 호스트시스템용 makefile에서 test.o→hello.o • make로 hello.ko 모듈 프로그램을 생성하고 테스트
실습 9-2 Hello 모듈 프로그램 작성 및 실행 • cat /proc/kallsyms 명령으로 커널 심볼 테이블에 있는 hello.c의 심볼들을 확인
디바이스드라이버 개요 • 디바이스: 컴퓨터시스템의 주변 하드웨어 • 디바이스 드라이버는 디바이스 구동 프로그램 • 디바이스의 종류 • 문자 디바이스(character device) • 블록 디바이스(block device) • 네트워크 디바이스(network device) • 주번호(major number)와 부번호(minor number)로 구분 • 동일한 디바이스는 동일한 주번호를 가지며 서로 구분하기 위해 부번호를 사용
디바이스드라이버 개요 • 문자 디바이스 • 파일시스템에서 하나의 노드 형태로 존재 • 자료의 순차성을 지닌 하드웨어 • 데이터를 문자 단위 또는 연속적 바이트 흐름으로 전달하고 읽음. • 터미널, 콘솔, 키보드, 사운드카드, 스캐너, 프린터, 직렬/병렬 포트, 마우스, 조이스틱 등 • 블록 디바이스 • 파일시스템에서 하나의 노드 형태로 존재 • 데이터를 블록 단위로 입출력 • 하드디스크, 플로피 디스크, 램디스크, 테이프, CD-ROM, DVD 등
디바이스 파일 • 리눅스 시스템은 디바이스를 /dev 디렉토리에 있는 일종의 파일로 취급. 즉, 디바이스를 파일로 추상화 • 디바이스 파일은 사용자에게 보이는 디바이스 드라이버의 인터페이스 부분 • 응용 프로그램은 디바이스에 접근하기 위하여 열기, 읽기, 쓰기 등과 같은 파일 연산을 이용 • 디바이스 파일은 파일시스템에서 고유한 번호와 이름을 할당받음 • 디바이스 파일은 파일시스템의 데이터 영역을 차지하지 않고 단지 디바이스 드라이버를 접근할 수 있는 관문 역할을 수행
① ② 실습 호스트 시스템의 디바이스 파일 관찰 • 호스트 시스템의 디바이스 파일이 있는 /dev 디렉토리 내용관찰
디바이스 파일의 생성 • 디바이스 파일은 /dev 에서 관리 • 디바이스 파일 형식: 문자형 c , 블록형 b • 리눅스에서 사용되는 디바이스 파일의 주번호
① ② 실습 mknod 명령으로 디바이스 파일 생성 • 디바이스 파일을 생성하고 세부 내용 관찰
디바이스 드라이버 • 디바이스와 시스템 사이에 데이터를 주고받기 위한 인터페이스 • 표준적으로 동일한 서비스 제공을 목적 • 커널의 일부분으로 내장 • 서브루틴과 데이터의 집합체 • 디바이스의 고유한 특성을 내포
file 구조체 • 파일 연산을 위한 인자 전달 방법으로 사용 • 디바이스에 필요한 자료 구조를 정의
파일 연산 구조체 • 커널은 등록된 디바이스 드라이버의 파일 연산 구조체를 참고해 응용프로그램의 요청에 대응하는 함수 호출
문자 디바이스 드라이버의 파일 연산 구조체 사용 • 전형적인 파일 연산 구조체의 선언내용 (xxx는 일반적으로 디바이스의 이름) struct file_operations xxx_fops = { .owner = THIS_MODULE, .open = xxx_open, .release = xxx_release, .read = xxx_read, .write = xxx_write, .ioctl = xxx_ioctl, };
문자 디바이스의 등록과 해제 • major : 주번호로, 0이면 사용하지 않는 주번호 중에서 동적으로 할당 • name : 디바이스의 이름으로 /proc/devices에 나타나 있음 • 반환값 : 오류 코드. 반환값이 0이거나 양수이면 성공적인 수행. 음수이면 오류 발생.
블록 디바이스의 등록과 해제 • major : 주번호로, 0이면 사용하지 않는 주번호 중에서 동적으로 할당 • name : 블록 디바이스 장치 이름 • 반환값 : 오류 코드. 0이나 양수이면 성공적인 수행. 음수이면 오류 발생
실습 가상 디바이스 드라이버 구현 • 가상 문자 디바이스 드라이버 프로그램 작성(10/chr_dev.c) 01 #include <linux/module.h> 02 #include <linux/kernel.h> 03 #include <linux/fs.h> 04 #include <linux/init.h> 05 06 #define CHR_DEV_NAME "chr_dev" // 디바이스 파일 이름 07 #define CHR_DEV_MAJOR 240 // 디바이스 파일의 주번호 08 09 int chr_open(struct inode *inode, struct file *filp) 10 { 11 int number = MINOR(inode->i_rdev); // 부번호를 number에 저장 12 printk("Virtual Character Device Open: Minor Number is %d\n", number); 13 return 0; 14 } 15 16 ssize_t chr_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos) 17 { 18 printk("write data: %s\n", buf); // 응용프로그램 write() 19 // 함수의 buf 값을 커널 메시지에 출력 20 return count; 21 } 22
실습 가상 디바이스 드라이버 구현 23 ssize_t chr_read(struct file *filp, const char *buf, size_t count, loff_t *f_pos) 24 { 25 printk("read data: %s\n", buf); // 응용프로그램 read() 26 // 함수의 buf 값을 커널 메시지에 출력 27 return count; 28 } 29 30 int chr_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) 31 { 32 switch(cmd) { // ioctl 함수로 전달된 cmd 값을 출력 33 case 0: printk("cmd value is %d\n", cmd); break; ………… 37 case 4: printk("cmd value is %d\n", cmd); break; 38 } 39 return 0; 40 } 41 42 int chr_release(struct inode *inode, struct file *filp) 43 { 44 printk("Virtual Character Device Release\n"); 45 return 0; 46 } 47 48 struct file_operations chr_fops = 49 { 50 .owner = THIS_MODULE, 51 .ioctl = chr_ioctl, 52 .write = chr_write, 53 .read = chr_read, 54 .open = chr_open, 55 .release = chr_release, 56 }; 57
실습 가상 디바이스 드라이버 구현 58 int sample_init(void)// 디바이스를 커널에 모듈로 적재시 수행되는 함수 59 { 60 int registration; // registration에 주번호나 반환값을 저장 61 printk("Registration Character Device to Kernel\n"); 62 registration = register_chrdev(CHR_DEV_MAJOR,CHR_DEV_NAME, &chr_fops); 63 if(registration < 0) 64 return registration; 65 printk("Major Number:%d\n", registration); 66 return 0; 67 } 68 69 void sample_cleanup(void) // 커널에서 디바이스를 제거할 때 수행되는 함수 70 { 71 printk("Unregistration Character Device to Kernel\n"); 72 unregister_chrdev(CHR_DEV_MAJOR, CHR_DEV_NAME); 73 } 74 75 MODULE_LICENSE("GPL"); 76 module_init(sample_init); 77 module_exit(sample_cleanup);
실습 가상 디바이스 드라이버 구현 • Make 유틸리티를 실행해 모듈 생성
실습 10-3 가상 디바이스 드라이버 구현 • 가상 문자 디바이스를 사용하는 응용프로그램 작성 01 #include <stdio.h> 02 #include <sys/types.h> 03 #include <sys/stat.h> 04 #include <fcntl.h> 05 #include <sys/ioctl.h> 06 #include <unistd.h> 07 08 #define DEVICE_FILE_NAME "/dev/chr_dev" // 디바이스 파일 09 10 int main(int argc, char *argv[]) // argv 값을 받아 디바이스 11 { // 파일의 IOCTL cmd 값으로 사용 12 int device; 13 char wbuf[128] = "Write buffer data"; 14 char rbuf[128] = "Read buffer data"; 15 int n = atoi(argv[1]); 16 17 device = open(DEVICE_FILE_NAME, O_RDWR|O_NDELAY); 18 if( device >= 0 ) { 19 printf("Device file Open\n"); 20 ioctl(device, n); // argv 값을 디바이스 파일에 cmd 값으로 전달 21 write(device, wbuf, 10); // wbuf 값을 디바이스 파일에 전달 22 printf("Write value is %s\n", wbuf); 23 read(device, rbuf, 10); 24 printf("read value is %s\n", rbuf); 25 } 26 else 27 perror("Device file open fail"); 28 29 return 0; 30 }
① ② 실습 10-3 가상 디바이스 드라이버 구현 • 응용프로그램을 타겟 시스템용으로 교차 컴파일 • 디바이스 드라이버 모듈 chr_dev.ko 파일과 컴파일한 응용 프로그램 chr_appl을 타겟 시스템으로 전송 • 디바이스 드라이버 모듈을 적재하고 적재 여부 확인
① ② 실습 10-3 가상 디바이스 드라이버 구현 • 디바이스 파일을 만들고 확인 • 명령행 인자를 사용해 응용 프로그램을 실행→디바이스 드라이버 모듈 제거