디바이스 드라이버와 응용 사이 데이터 교환
- 커널과 응용 프로그램 사이 데이터 교환
1. 응용 프로그램은 직접 커널 메모리 영역에 접근할 수 없음.
* 메모리 접근 예외 발생.
2. 커널은 응용 프로그램이 전달한 자신의 메모리 주소를 이용해 데이터 교환.
* 읽기/쓰기를 하기 전에 메모리 주소가 변경되면 문제 발생.
* 프로세스는 상황에 따라 sleep 상태로 전이될 수 있음.
* sleep 상태에서 깨어나면 할당된 메모리 주소가 유효하지 않을 수 있음.
3. 메모리 복사 전에 주소가 유효한지 검사하는 특별한 함수 지원.
- 디바이스 드라이버와 응용 사이 데이터 교환 함수.
- 커널 공간 데이터를 사용자 공간으로 전달.
1 2 3 4 5 | #include <asm/uaccess.h> unsigned long clear_user(void __user *to, unsigned long n); unsigned long copy_to_user(void __user *to, const void *from, unsigned long n); put_user(x, ptr); | cs |
* to, x : 사용자 공간 데이터 포인터
* n : 크기
* from, ptr : 커널 공간 데이터 포인터
- 안전하게 커널 데이터를 사용자 공간으로 복사.
1. 복사전에 필요에 따라 clear_user()를 호출해 사용자 데이터 공간을 0으로 초기화.
2. copy_to_user()를 호출해 n만큼 복사. 정상적으로 복사되면 반환 값은 0.
3. put_user()는 copy_to_user()대신 구조체나 배열을 제외한 기본형에 간편하게 적용.
* 1byte, 2byte, 4byte 복사 시에 사용.
* 컴파일러가 형 검사후 pu_user1(), put_user2(), put_user4()로 변환함
- 사용자 공간 데이터를 커널 공간으로 전달
1 2 3 4 | #include <asm/uaccess.h> unsigned long copy_from_user(void *to, const void __user *from, unsigned long n); get_user(x, ptr); | cs |
* to, x : 커널 공간 데이터 포인터
* n : 크기
* from, ptr : 사용자 공간 데이터 포인터
- 안전하게 사용자 데이터를 커널 공간으로 복사.
1. copy_from_user()를 호출해 n만큼 복사. 정상적으로 복사되면 반환 값은 0.
2. get_user() 는 copy_from_user() 대신 구조체나 배열을 제외한 기본형에 간편하게 적용.
1 2 3 4 5 | #include <asm/uaccess.h> long strnlen_user(const char __user *s, long n); strlen_user(str); long strncpy_from_user(char *dst, const char __user *src, long count); | cs |
* s, str, src : 사용자 공간 데이터 포인터.
* n, count : 크기
* dst : 커널 공간 데이터 포인터
- NULL로 끝나는 사용자 공간의 문자열을 안전하게 커널 공간으로 복사.
1. strlen_user()를 호출해 복사할 문자열 크기 파악. 반환 값은 NULL을 포함한 크기.
2. strnlen_user()는 strlen_user()와 동일하며 최대 버퍼 크기 이내에서 파악.
3. strncpy_from_user()를 호출해 count 만큼 복사. 정상적으로 복사되면 반환 값은 NULL을 제외한 크기. 실패하면 -EFAULT
- 데이터 교환 드라이버 구현 예제
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/miscdevice.h> #include <linux/mutex.h> #include <asm/uaccess.h> #include <linux/slab.h> void * memory_buffer; // 커널에서 동작 할당된 메모리 주소 저장. ssize_t cur_len; // 현재 버퍼에 저장된 데이터 크기 #define BUF_SIZE 16 // 동적으로 할당할 메모리 크기 static ssize_t drv_simple_buffer_read(struct file * file, char * buf, size_t length, loff_t * ofs) { ssize_t retval; if(*ofs > 0){ retval = 0; goto out; } retval = cur_len; // 버퍼 내용을 사용자에게 전달 if(copy_to_user(buf, memory_buffer, retval)){ retval = -EFAULT; goto out; } printk("drv_buffer_read: [%dbyte -> %dbyte]\n", length, retval); *ofs += retval; out: return retval; } static ssize_t drv_simple_buffer_write(struct file * file, const char * buf, size_t length, loff_t * ofs) { ssize_t retval; if(length > BUF_SIZE){ retval = -ENOMEM; goto out; } cur_len = retval = length; // 사용자가 전달한 데이터를 버퍼에 저장. if(copy_from_user(memory_buffer, buf, retval)){ retval = -EFAULT; goto out; } printk("drv_buffer_write: [%dbyte -> %dbyte]\n", length, retval); out: return retval; } static struct file_operations drv_simple_buffer_fops = { .owner = THIS_MODULE, .read = drv_simple_buffer_read, .write = drv_simple_buffer_write, }; static struct miscdevice drv_simple_buffer_driver = { .minor = MISC_DYNAMIC_MINOR, .name = "drv_simple_buffer", .fops = &drv_simple_buffer_fops, .mode = 0777, }; static int drv_simple_buffer_init(void) { // memory_buffer에 도적으로 BUF_SIZE만큼 메모리 할당. memory_buffer = kmalloc(BUF_SIZE, GFP_KERNEL); if(!memory_buffer){ printk("error: allocating memory for the buffer\n"); return -ENOMEM; } // 메모리 초기화 memset(memory_buffer, 0, BUF_SIZE); return misc_register(&drv_simple_buffer_driver); } static void drv_simple_buffer_exit(void) { if(memory_buffer){ //동적으로 할당 다은 메모리 제거. kfree(memory_buffer); } misc_deregister(&drv_simple_buffer_driver); } module_init(drv_simple_buffer_init); module_exit(drv_simple_buffer_exit); MODULE_AUTHOR("PlanX Studio"); MODULE_DESCRIPTION("drv_simple_buffer"); MODULE_LICENSE("Dual BSD/GPL"); | cs |
출처 : 인지소프트웨어 기술포럼 ( 전유진 강사님 수업자료)
'임베디드 > 디바이스 드라이버' 카테고리의 다른 글
디바이스 드라이버 GPIO 모션 센서 예제 (0) | 2017.12.28 |
---|---|
디바이스 드라이버 GPIO 조이스틱 예제 (0) | 2017.12.28 |
Misc 디바이스 드라이버1 (0) | 2017.12.26 |
디바이스 드라이버 구조 (0) | 2017.12.26 |
SYSFS (1) | 2017.12.26 |