Block Device Driver in Linux

Slides:



Advertisements
Similar presentations
제10장 디바이스 드라이버.
Advertisements

컴퓨터와 인터넷.
KEY 디바이스 드라이버 Lecture #12. 2 차례 GPIO 및 Control Registers KEY 하드웨어 구성 KEY Driver 프로그램 key-driver.c 시험 응용 프로그램 key-app.c.
패러럴 포트를 이용한 Text LCD 제어 6월 17일 허정수 나선웅.
Linux/UNIX Programming
5장. Enhanced Char Driver Operations 과제
김태원 심재일 김상래 강신택. 김태원 심재일 김상래 강신택 인터넷 통신망의 정보를 제공하는 서비스 인터넷의 자원 및 정보는 NIC가 관리 IP주소 또는 도메인으로 정보 검색 이용자 및 통신망 관한 정보를 제공.
제14장 동적 메모리.
인공지능실험실 석사 2학기 이희재 TCP/IP Socket Programming… 제 11장 프로세스간 통신 인공지능실험실 석사 2학기 이희재
공유메모리 int shmget(key_t key, size_t size, int permflags);
1. Windows Server 2003의 역사 개인용 Windows의 발전 과정
Network Lab. Young-Chul Hwang
디바이스 드라이버에 대한 일반적인 개요를 살펴본다
컴퓨터 프로그래밍 기초 [Final] 기말고사
디바이스 드라이버 이해 Hanbat National University Prof. Lee Jaeheung.
08. 디바이스 드라이버의 읽기와 쓰기 김진홍
디바이스 드라이버 (Device Driver)
디바이스 드라이버 기초 디바이스 드라이버의 개요 파일 연산 디바이스 드라이버 등록 디바이스 드라이버 구성
디바이스 드라이버.
이식성과 데이터형 서로 다른 프로세서 상에서의 이식성을 위해 가급적 리눅스 커널이 제공하는 데이터형을 사용하는 것이 좋다.
디바이스 드라이버 개요 가상 디바이스드라이버 실습
Module Programming Linux Kernel 수업 4번째.
제15장 파일 입출력 문자열을 출력하는 여러가지 방법 (15-2쪽) 문자열만 처리하는 입출력 함수
Unix Project2 <test character device 생성>
쉽게 풀어쓴 C언어 Express 제17장 동적메모리와 연결리스트 C Express Slide 1 (of 13)
4장. 웹로직 서버상에서의 JDBC와 JTA의 운용
UNIT 07 Memory Map 로봇 SW 교육원 조용수.
FND (Flexible Numeric Display)
Embedded System Porting (2)
한남대학교 컴퓨터공학과 컴퓨터 네트워크 실험실
Step Motor Device Driver
양방향 파이프의 활용 양방향 통신 파이프는 기본적으로 단방향이므로 양방향 통신을 위해서는 파이프를 2개 생성한다.
리눅스 커널과 디바이스드라이버.
07. 디바이스 드라이버의 초기화와 종료 김진홍
CHAPTER 02 OpenCV 개요 PART 01 영상 처리 개요 및 OpenCV 소개.
Embedded Linux와 device driver
11장. 포인터 01_ 포인터의 기본 02_ 포인터와 Const.
WinCE Device Driver 실습 #2
커널 모듈 프로그래밍 (Kernel Module Programming)
DK-128 실습 EEPROM 제어 아이티즌 기술연구소
HBE-SMIII-SV210 리눅스 커널과 디바이스 드라이버
TCP/IP Socket Programming…
망고100 보드로 놀아보자 -13 리눅스 디바이스 드라이버 개요
문자 디바이스 드라이버 임베디드 시스템.
디 지 털 공 학 한국폴리텍V대학.
Cache Manager Yonghyun Kim Microsoft MVP Dev 5 team leader, ESTsoft
UNIT 07 Memory Map 로봇 SW 교육원 조용수.
Linux/UNIX Programming
리눅스 시스템 & 커널 기초 P.46 – P.53 이름: nsh009 학번: 112 1/20.
27장. 모듈화 프로그래밍.
컴퓨터의 기초 제 2강 - 변수와 자료형 , 연산자 2006년 3월 27일.
Device Driver 임베디드 시스템 I.
Chapter6 : JVM과 메모리 6.1 JVM의 구조와 메모리 모델 6.2 프로그램 실행과 메모리 6.3 객체생성과 메모리
리눅스 디바이스 드라이버 (Linux Device Driver)
DK-128 실습 내부 EEPROM 제어 아이티즌 기술연구소 김태성 연구원
컴퓨터 프로그래밍 기초 - 10th : 포인터 및 구조체 -
패러럴 포트를 이용한 Text LCD 제어 6월 17일 허정수 나선웅.
Stepper Motor 디바이스 드라이버
컴퓨터 프로그래밍 기초 - 8th : 함수와 변수 / 배열 -
Linux/UNIX Programming
컴퓨터 계측 및 실습 디지털 출력 영남대학교 기계공학부.
네트워크 환경 구축과 이미지 전송 호스트/타겟 통신 직렬 통신을 이용한 이미지 전송 수퍼 데몬 BOOTP 환경 구축
8. 리눅스의 내부 군자삼락 [君子三樂] 청출어람이청어람 [ 靑出於藍而靑於藍 ] Why Linux ?
DK-128 직렬통신 실습 아이티즌 기술연구소
3. 모듈 (5장. 모듈).
구조체(struct)와 공용체(union)
06. 디바이스의 등록과 해제 김진홍
1. 지역변수와 전역변수 2. auto, register 3. static,extern 4. 도움말 사용법
08. 블록 디바이스 드라이버 김진홍
22. 블록 디바이스 드라이버 김진홍
Presentation transcript:

Block Device Driver in Linux 경희대학교 컴퓨터공학과 조 진 성

주요 내용 주요내용 리눅스에서 디바이스 드라이버 개념이해 블록 디바이스 이해 램디스크 구현

디바이스 드라이버 제작 과정 Define objective of applications using device Study Hardware manual 장치 인터페이스 이해 (Registers) 인터럽트 발생의 원인 인지(vector number) 입출력 경로를 알아야 함 Understand interface to related utilities Device setup Device 등록 및 해제 ioctl command Design to adapt to future changes Module

리눅스 디바이스 드라이버 리눅스에서의 디바이스 Device Driver의 종류 Linux에서 Device는 특별한 하나의 파일처럼 취급되고, access가 가능함. 사용자는 File operation을 적용할 수 있음 각 디바이스는 Major number와 Minor number를 가짐 Device Driver의 종류 문자 디바이스 드라이버 블록 디바이스 드라이버 네트워크 디바이스 드라이버

디바이스 드라이버 구조 리눅스 시스템 구조 상의 블록 디바이스 드라이버 Application System Call Interface VFS Network Subsystem Buffer Cache Network D/D Block D/D Char Device Driver Device Interface Hardware Application area Kernel area

Block Device(블록 디바이스) Block device 특징 리눅스에서의 Block device random access 가능 블록 단위의 입출력이 가능한 장치 버퍼캐쉬에 의한 내부 장치 표현 파일 시스템에 의해 mount 되어 관리되는 장치 디스크, Ram Disk, CD-ROM 등 리눅스에서의 Block device brw------- 1 root floppy 2, 0 May 6 1998 fd0 brw-rw---- 1 root disk 3, 0 May 6 1998 hda brw-rw---- 1 root disk 3, 1 May 6 1998 hda1 brw-rw---- 1 root disk 8, 0 May 6 1998 sda brw-rw---- 1 root disk 8, 1 May 6 1998 sda1 fd* : Floppy disk Hd* : Hard disk sda : SCSI disk 파일 관련 정보 중 첫 문자인 b는 block device를 의미

블록 디바이스 드라이버의 데이터 구조 Block device의 커널 데이터 구조 Block Device Driver의 데이터 구조 Major number - include/linux/major.h 최대 255로 정의 : MAX_BLKDEV로 정의 blkdevs[ ] – fs/block_dev.c 커널은 해당 구조체 내의 index 값으로 block device driver의 major number를 사용 해당 driver가 제공하는 함수들도 찾음 ~/include/linux/fs.h static struct { const char *name; struct block_device_operations *bdops; } blkdevs[MAX_BLKDEV]; /*MAX_BLKDEV = 255*/

블록 디바이스 드라이버의 등록 Block device의 등록 ~/include/linux/fs.h int register_blkdev(unsigned int major, const char *name, struct block_device_operations *bdops); { if (major == 0){ for (major = MAX_BLKDEV-1; major > 0; major--) { if (blkdevs[major].bdops == NULL) { blkdevs[major].name = name; blkdevs[major].bdops = bdops; return major; } } return –EBUSY; if (major >= MAX_BLKDEV) return –EINVAL; if (blkdevs[major].bdops && blkdevs[major].bdops != bdops) return –EBUSY; return 0;

블록 디바이스 드라이버의 해제 Block device의 해제 int unregister_blkdev(unsigned int major, const char *name); { if (major >= MAX_BLKDEV) return –EINVAL; if (!blkdevs[major].bdops) if ( strcmp(blkdevs[major].name, name)) blkdevs[major].name = NULL; blkdevs[major].bdops = NULL; return 0; }

블록 디바이스 드라이버 연산(1) Block device의 연산 struct block_device_operations = { int (*open) (struct inode*, struct file*);/*open*/ int (*release) (struct inode*, struct file*, unsigned, unsigned long);/*close*/ int (*ioctl) (struct inode*, struct file*, unsigned, unsigned long);/*I/O control*/ int (*check_media_change) (kdev_t);/*제거 가능 미디어의 물리적 변화 판별*/ int (*revalidate) (kdev_t); /*버퍼와 캐쉬의 관리*/ };

블록 디바이스 드라이버 연산(2) 기본 블록 디바이스 연산 블록 디바이스 드라이버를 설정 하지 않았을 때 기본 연산으로 사용 struct file_operations def_blk_fops= { open : blkdev_open, /*장치 열기*/ release : blkdev_close, /*장치 해제*/ llseek : block_llseek, /*읽기와 쓰기 위치 변경*/ read : block_read, /*블록 디바이스 읽기*/ write : block_write, /*블록 디바이스 쓰기 */ fsync : block_fsync, /*메모리 내용을 디바이스에 쓰기*/ ioctl : blkdev_ioctl, /*디바이스에 제어 연산*/ };

모듈의 적재/제거 Init_module() request() ceanup_module() register_blkdev() block_read() unregister_blkdev() blk_dev[] blkdevs[] fops insmod rmmod Driver Module Core Kernel One function Other function Data Function call Data pointer Function pointer Assignment to data

IDE 구동기 작성 예(1) 하드디스크 드라이버 주요 기능 파일시스템에서 논리적인 블록에 대한 읽기/쓰기 요청이 발생했을 때 이 논리적인 블록을 물리적인 주소(헤더, 트랙, 섹터 및 요구되는 섹터의 수)로 변환시키는 것 물리적인 주소에서 실제 데이터를 주 메모리(실제로는 커널의 버퍼캐쉬공간)로 읽는 것 혹은 주메모리에 있는 데이터를 물리적인 주소에 쓰는 것 디스크에서 사건의 발생(인터럽트 발생)을 알렸을 때 그 사건을 처리하는 것

IDE 구동기 작성 예(2) 인터페이스 함수 중심의 IDE 방식 하드디스크 드라이브의 구조 hd_init() struct file_operations hd_ops /* driver/block/hd.c */ NULL, block_read, block_write NULL, NULL, hd_ioctl, hd_open, NULL hd_release, block_fsync hd_init() Buffer Cache hd_open( ) hd_release( ) hd_request( ) hd_ioctl( ) hd_interrupt( ) hd_out( ) check_status( ) 파일시스템과의 인터페이스 함수 하드웨어와의 인터페이스 함수 드라이버 초기화 함수

IDE 구동기 작성 예(3) 디스크 드라이버 초기화 struct file_operations hd_ops NULL, block_read, block_write NULL, NULL, hd_ioctl, hd_open, NULL hd_release, block_fsync struct file_operations hd_ops /* driver/block/hd.c */ register_blkdev() /* fs/devices.c */ hd_init() - register_blkdev(HD_MAJOR, “hd”, &hd_fops); - blkdevs[major].name = device name - blkdevs[major].fops = fops /* include/linux/major.h */ init_module init_process 디스크 드라이버 초기화

IDE 구동기 작성 예(4) 디스크 드라이버 open - get_unused_fd( ) - fd_install(fd, f) filp_open( ) /* fs/open.c */ sys_open( ) open_namei( ) /* fs/namei.c */ - get_unused_fd( ) - fd_install(fd, f) - struct file initialize - f->f_op->open( ) blkdev_open( ) /* fs/device.c */ - filp->f_op = get_blkfops(MAJOR(inode->i_rdev)); /* filp->f_op = blkdevs[major].fops */ - filp->f_op->open; /* hd_open */

IDE 구동기 작성 예(5) 문자 디바이스 드라이버와의 차이점 등록할 때 register_chrdev() 대신 register_blkdev() 사용 blkdevs 테이블에 드라이버 이름, 파일 연산 등 등록 읽기/쓰기 연산을 위한 별도의 함수가 존재하는 것이 아니라 hd_request() 함수에서 모두 지원 디스크에서 읽은 데이터를 직접 사용자 공간에 쓰는 것이 아니라 커널이 관리하는 공간인 버퍼캐쉬(buffer cache)라는 공간에 씀 파일 연산 자료구조에 읽기/쓰기 함수가 등록되어야 하는 위치에 block_read(), block_write() 라는 이름의 함수가 등록되어 있는데, 이것은 드라이버에서 구현하는 함수가 아니라 Linux 커널이 제공하는 함수임. 블록 디바이스는 블록 단위로 데이터를 입출력하는 방식을 사용

IDE 구동기 작성 예(6) 디스크 드라이버 read System call handling layer VFS layer generic_file_read() /* mm/filemap.c */ sys_read() /* fs/read_write.c */ - f->f_op->read - try to find page in cache, if (hit) OK. - inode->i_op->readpage() System call handling layer VFS layer sock_read() hd_read() tty_read() pipe_read() Specific File layer Specific FS layer

파일시스템이 드라이버에게 요청한 request IDE 구동기 작성 예(7) struct blk_dev_struct { request_fn; queue; request; ... } blk_dev[]; /* include/linux/blkdev.h */ struct request { rq_status rq_dev cmd /* R/W */ error sector, nr_sector buffer, bh sem next } block device driver queue req buffer cache bread block_read ll_rw_block make_request hd_request hd_out request_fn 파일시스템이 드라이버에게 요청한 request 디스크 드라이버와 데이터 전송

블럭 디바이스 드라이버 구현 블럭 디바이스 제작방법 문자 디바이스 드라이버와 마찬가지로 외부와는 파일 인터페이스로 연결, 파일 연산들을 제공 문자 디바이스 드라이버와는 별개로 관리되며, 문자 디바이스 드라이버와 major number가 겹쳐도 상관 없다 일반 read/write와는 달리 버퍼캐시를 통한 read/write을 하기 때문에 read/write을 하기 위한 별도의 인터페이스가 필요(request) Request 함수를 구현해야 하고, 이 함수에서 실질적인 read/write 작업을 한다. 또한 블럭, 섹터, 전체 크기 등을 따로 블럭 장치를 관리하는 전역 변수에 설정 해야 한다

블록 디바이스 드라이버 구현(2) 장치의 등록과 해제 파일 연산 등록 해제 문자 장치에서와 마찬가지로 major번호 0은 동적할당 해제 파일 연산 read/write/fsync함수는 따로 구현할 필요가 없음, block_read(), block_write(), block_fsync()를 그대로 사용 open, release는 문자 디바이스 드라이버와 동일하게 구현 ioctl함수는 블록 디바이스 드라이버에는 공통적으로 사용하는 여러 가지의 ioctl 명령이 있으며, 이들의 대부분은 반드시 지원해 주어야 한다 extern int devfs_register_blkdev(unsigned int major, const char name, struct block device operation *bdops) extern int devfs_unregister_blkdev(unsigned int major, const char *name)

블럭 디바이스 드라이버 예제 Mini RAMDISK RAM 상의 일부 메모리를 디스크처럼 사용하는 간단한 블록 디바이스 구축 구현 파일 연산을 정의하고 등록 Read/write는 일반적인 블록 read/write 함수를 이용 블록 디바이스 구현에 필요한 request함수와 블록 크기, 섹터 크기, 장치 크기 등을 지정 모듈을 load할 때 RAK Disk를 위해 필요한 메모리를 할당 Request 함수는 버퍼 캐시의 버퍼와 할당받은 메모리 사이에 read/write를 수행한다. 참조자료 리눅스 커널 프로그래밍 자료 - 이호 Site : http://www.linuxkernel.net/moduleprog/lkp/

블럭 디바이스 드라이버(1) RAM상에서 일부 메모리를 디스크처럼 활용 블럭 디바이스 드라이버 프로그램 소스 예제(minird.c) #include <linux/kernel.h> #include <linux/module.h> #ifdef CONFIG_MODVERSIONS #define MODVERSIONS #include <linux/modversions.h> #endif #include <linux/fs.h> #include <linux/vmalloc.h> #include <asm/uaccess.h> #include <linux/devfs_fs_kernel.h> #define MINIRD_MAJOR 0 /* major number : dynamic allocation */ #define DEVICE_NAME "MiniRD“ /* device name */ #define DEVICE_FILENAME "minird" #define DEVICE_NUM 2 /* minor device number */ #define MINIRD_DEF_SIZE 1024 /* default device size in KB */ #define MINIRD_BLOCKSIZE 1024 /* sizeof block */ #define MINIRD_SECTSIZE 512 /* sizeof sector */

블럭 디바이스 드라이버(2) extern int s_nMajor; #define MAJOR_NR (s_nMajor) #define DEVICE_NR(device) (MINOR(device)) #define DEVICE_ON(device) /* do nothing */ #define DEVICE_OFF(device) /* do nothing */ #define DEVICE_NO_RANDOM #include <linux/blk.h> #include <linux/blkpg.h> /* Globak Variables */ static int s_nMajor = 0; static int minird_size = MINIRD_DEF_SIZE; static int s_kbsize[DEVICE_NUM]; /* size in blocks of 1024 bytes */ static int s_blocksize[DEVICE_NUM]; /* size of 1024 byte block */ static int s_hardsect[DEVICE_NUM]; /* sizeof real block in bytes */ static int s_length[DEVICE_NUM]; /* size of disks in bytes */ static char *s_data[DEVICE_NUM]; static devfs_handle_t devfs_handle; MODULE_PARM(minird_size, "i"); MODULE_PARM_DESC(minird_size, "RAM Disk size in KB");

블럭 디바이스 드라이버(3) 파일 연산을 등록 /* Function Prototypes */ static int minird_open(struct inode *inodep, struct file *filp); static int minird_release(struct inode *inodep, struct file *filp); static int minird_ioctl(struct inode *inodep, struct file *filp, unsigned int cmd, unsigned long arg); static int minird_make_request(request_queue_t *q, int rw, struct buffer_head *sbh); /* Device Operations */ static struct block_device_operations minird_fops = { open : minird_open, release : minird_release, ioctl : minird_ioctl, }; /* Module startup/cleanup */ int init_module(void) { int i, j; printk("Loading Mini RAM Disk Module\n"); for (i = 0; i < DEVICE_NUM; ++i) { s_kbsize[i] = minird_size; 파일 연산을 등록

블럭 디바이스 드라이버(4) 요구되는 메모리 할당 블럭 디바이스 등록 s_blocksize[i] = MINIRD_BLOCKSIZE; s_hardsect[i] = MINIRD_SECTSIZE; s_length[i] = (minird_size << BLOCK_SIZE_BITS); if ((s_data[i] = vmalloc(s_length[i])) == NULL) { for (j = 0; j < i; ++j) vfree(s_data[j]); return -ENOMEM; } if ((s_nMajor = devfs_register_blkdev(MINIRD_MAJOR, DEVICE_NAME, &minird_fops)) < 0) { printk(DEVICE_NAME " : Device registration failed (%d)\n", s_nMajor); return s_nMajor; printk(DEVICE_NAME " : Device registered with Major Number = %d\n", MAJOR_NR); devfs_handle = devfs_mk_dir(NULL, DEVICE_FILENAME, NULL); devfs_register_series(devfs_handle, "%u", DEVICE_NUM, DEVFS_FL_DEFAULT, s_nMajor, 0, S_IFBLK | S_IRUGO | S_IWUGO, &minird_fops, NULL); blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), &minird_make_request); 요구되는 메모리 할당 블럭 디바이스 등록

블럭 디바이스 드라이버(5) 블럭 디바이스 해제 blk_size[MAJOR_NR] = s_kbsize; blksize_size[MAJOR_NR] = s_blocksize; hardsect_size[MAJOR_NR] = s_hardsect; return 0; } void cleanup_module(void) { int i; printk("Unloading Mini RAM Disk Module\n"); for (i = 0; i < DEVICE_NUM; ++i) destroy_buffers(MKDEV(MAJOR_NR, i)); /* flush the devices */ vfree(s_data[i]); devfs_unregister(devfs_handle); devfs_unregister_blkdev(MAJOR_NR, DEVICE_NAME); blk_size[MAJOR_NR] = NULL; blksize_size[MAJOR_NR] = NULL; hardsect_size[MAJOR_NR] = NULL; 블럭 디바이스 해제

블럭 디바이스 드라이버(6) /* Device Operations */ int minird_open(struct inode *inodep, struct file *filp) { if (DEVICE_NR(inodep->i_rdev) >= DEVICE_NUM) return -ENXIO; MOD_INC_USE_COUNT; return 0; } int minird_release(struct inode *inodep, struct file *filp) MOD_DEC_USE_COUNT; int minird_ioctl(struct inode *inodep, struct file *filp, unsigned int cmd, unsigned long arg) int minor = DEVICE_NR(inodep->i_rdev); long devsize; switch (cmd) { case BLKGETSIZE : /* return device size */ devsize = s_length[minor] / s_hardsect[minor]; return put_user(devsize, (long *) arg);

블럭 디바이스 드라이버(7) case BLKSSZGET : /* block size of media */ return put_user(s_blocksize[minor], (int *) arg); case BLKFLSBUF : /* flush */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; destroy_buffers(inodep->i_rdev); break; case BLKROSET : case BLKROGET : return blk_ioctl(inodep->i_rdev, cmd, arg); default : return -EINVAL; } return 0; /* Request Processing */ int minird_make_request(request_queue_t *q, int rw, struct buffer_head *sbh) { char *ptr, *bdata; int size, minor;

블럭 디바이스 드라이버(8) if ((minor = DEVICE_NR(sbh->b_rdev)) > DEVICE_NUM) { printk(DEVICE_NAME " : Unknown Minor Device\n"); goto fail; } ptr = s_data[minor] + sbh->b_rsector * s_hardsect[minor]; size = sbh->b_size; if (ptr + size > s_data[minor] + s_length[minor]) { printk(DEVICE_NAME " : Request past end of device\n"); bdata = bh_kmap(sbh); switch (rw) { case READ : case READA : memcpy(bdata, ptr, size); break; case WRITE : memcpy(ptr, bdata, size); default :

블럭 디바이스 드라이버(9) sbh->b_end_io(sbh, 1); return 0; fail: }

Makefile 작성 예 /* Makefile */ CC = arm-linux-gcc LD = arm-linux-ld KERNELDIR = /usr/src/linux-2.4.19 INCLUDEDIR = -I$(KERNELDIR)/include CFLAGS = -D__KERNEL__ -DMODULE -O2 -Wall $(INCLUDEDIR) OBJS = minird.o SRCS = minird.c $(OBJS): $(SRCS) $(CC) $(CFLAGS) -c $(SRCS) clean : rm -f *.o *~

블럭 디바이스 드라이버 실행 블럭 디바이스 드라이버 컴파일 방법 LED 디바이스 드라이버 실행 방법 블럭 디바이스 테스트 $ make LED 디바이스 드라이버 실행 방법 생성된 minird.o파일을 타겟 보드로 전송 $ insmod minird.o $ mknod /dev/minird0 b [major] 0 $ dd if=/dev/zero of=/dev/minird0 bs=1024 count=1024 $ mke2fs /dev/minird0 1024 $ mkdir /mnt/other 블럭 디바이스 테스트 $ mount /dev/minird0 /mnt/other $ cp /bin/ls /mnt/other $ ls /mnt/other $ umount /mnt/other $ mount /dev/minird0 /mnt/other

블럭 디바이스 드라이버 실행 예 디바이스 드라이버 컴파일

블럭 디바이스 드라이버 실행 예(2) 디바이스 드라이버 테스트

블럭 디바이스 드라이버 실행 예(3)