리눅스 드라이버 #2
TRANSCRIPT
리눅스 드라이버 실습 #22015/Jun/08
박상호
Copyright © 2015 S-Core Co., Ltd. All rights reserved | Con-fidential
실습 내용
Copyright © 2015 S-Core Co., Ltd. All rights reserved | Con-fidential
실습 #1 Wrap-up
- 4 -Copyright © 2015 S-Core Co., Ltd. All rights reserved | Con-fidential
Kernel 의 역할
● 자원 (Resource) 관리○ 자원 : CPU, Memory, Storage, Network,
Graphic Card, etc■ S/W 자원도 포함됨 : 응용 프로그램 ID,
TCP 포트 등○ 자원들을 여러 응용 프로그램이 공유할 수 있도록
제공■ 배분 정책
● 공정성 : Fairness● 시급성 : Time critical
○ 보안■ 다른 프로그램의 정보가 공유되지 않도록 보호
(virus, hack)● Abstracted API 제공
○ H/W 특성에 관계없는 일관된 API(System-call) 을 응용 프로그램에 제공
- 5 -Copyright © 2015 S-Core Co., Ltd. All rights reserved | Con-fidential
코드 흐름
fd = open(argv[1], O_RDONLY);…while ret = read(fd, buf, sizeof(buf)); … ret = write(STDOUT_FILENO, buf, ret)); …close(fd);
readerfd = open(argv[1], O_WRONLY|O_CREAT|O_TRUNC);…while ret = read(STDIN_FILENO, buf, sizeof(buf)); … ret = write(fd, buf + i, len - i)); …close(fd);
writer
● STDIN_FILENO: standard input fd● STDOUT_FILENO: standard output fd● Standard input/output
○ Terminal: keyboard & display → Character device in unix system
● 파일 접근을 위한 system call○ open, read, write, close...
- 6 -Copyright © 2015 S-Core Co., Ltd. All rights reserved | Con-fidential
커널 모듈
- 7 -Copyright © 2015 S-Core Co., Ltd. All rights reserved | Con-fidential
장치 유형
전통적 디바이스 유형
Block: 디스크
특정 offset 의 데이터를 접근할 수 있음
Character: 시리얼 포트 , 터미널
특정 offset 의 개념이 없음
UNIX 는 장치를 특수 유형의 파일로 관리
/dev/sda
/dev/console
Network 디바이스는 예외 : 이단아
$ ls -l /dev
- 8 -Copyright © 2015 S-Core Co., Ltd. All rights reserved | Con-fidential
디바이스 드라이버
● 디바이스 드라이버o 디바이스를 이용하기 위한 커널 S/W 모듈
● UNIX 에서 장치는 파일 (/dev/XXX)o 장치를 이용하기 위해서는 드라이버가 필요o 장치와 드라이버를 어떻게 연결할까 ?
■ 장치별로 Major/Minor 번호 부여
● Major 번호를 담당하는 드라이버 연결
- 9 -Copyright © 2015 S-Core Co., Ltd. All rights reserved | Con-fidential
드라이버 코딩 (4)
$ make$ sudo insmod echo.ko$ dmesg
$ ls -al /dev/echo$ sudo mknod /dev/echo c 250 0$ ls -al /dev/echo
$ sudo ./writer /dev/echo1234^C$ sudo ./reader /dev/echo1234$
- 10 -Copyright © 2015 S-Core Co., Ltd. All rights reserved | Con-fidential
프로그램 실행 Flow
reader/writer
VFS(Virtual File Switch)디바이스 드라이버 , 파일 시스템의 file_operations 호출
echo driver
open(“/dev/echo”, O_RDONLY)
__open(inode, file)
read(fd, buf, sizeof(buf))
__read(file, buf, len, off)
close(fd)
__release_(inode, file)
System Call
User mode
Kernel mode
- 11 -Copyright © 2015 S-Core Co., Ltd. All rights reserved | Con-fidential
실습 자료 및 코드
● 실습 자료● http://
www.slideshare.net/sanghopark1232/1-48809165● 코드● https://
github.com/pasang0000/linux_driver_practice$ git clone https://github.com/pasang0000/linux_driver_practice.git
Copyright © 2015 S-Core Co., Ltd. All rights reserved | Con-fidential
Sleep
- 13 -Copyright © 2015 S-Core Co., Ltd. All rights reserved | Con-fidential
Time sharing
프로그램 A -> 프로그램 B -> 프로그램 C
CPU Execution
Context Switch: schedule() in kernel
Save registers
Load registers
continue to execute
A B C A B CTime
- 14 -Copyright © 2015 S-Core Co., Ltd. All rights reserved | Con-fidential
Simple example
test.c
$ cat test.c#include <stdio.h>
int i = 0;intmain(){ i++; i+=2; i+=3; printf("i=%d\n", i); return 0;}$ gcc –g test.c$ objdump –S a.out…$ objdump –S a.out | less
#include <stdio.h>
int i = 0;intmain(){ 40052d: 55 push %rbp 40052e: 48 89 e5 mov %rsp,%rbp i++; 400531: 8b 05 0d 0b 20 00 mov 0x200b0d(%rip),%eax # 601044 <i> 400537: 83 c0 01 add $0x1,%eax 40053a: 89 05 04 0b 20 00 mov %eax,0x200b04(%rip) # 601044 <i> i+=2; 400540: 8b 05 fe 0a 20 00 mov 0x200afe(%rip),%eax # 601044 <i> 400546: 83 c0 02 add $0x2,%eax 400549: 89 05 f5 0a 20 00 mov %eax,0x200af5(%rip) # 601044 <i> i+=3; 40054f: 8b 05 ef 0a 20 00 mov 0x200aef(%rip),%eax # 601044 <i> 400555: 83 c0 03 add $0x3,%eax 400558: 89 05 e6 0a 20 00 mov %eax,0x200ae6(%rip) # 601044 <i> printf("i=%d\n", i); 40055e: 8b 05 e0 0a 20 00 mov 0x200ae0(%rip),%eax # 601044 <i> 400564: 89 c6 mov %eax,%esi
- 15 -Copyright © 2015 S-Core Co., Ltd. All rights reserved | Con-fidential
Wait & wake
wait_for_completion
complete
void wait_for_completion(struct completion *);void wait_for_completion_interruptible(struct completion *);void wait_for_completion_killable(struct completion *);void wait_for_completion_timeout(struct completion *, unsigned long timeout);void wait_for_completion_interruptible_timeout(struct completion *, unsigned long timeout);void wait_for_completion_killable_timeout(struct completion *, unsigned long timeout);bool try_wait_for_completion(struct completion *x);
void complete(struct completion *);void complete_all(struct completion *);
- 16 -Copyright © 2015 S-Core Co., Ltd. All rights reserved | Con-fidential
Sleep: wait & wake
Wait
sleep_on
interruptible_sleep_on
sleep_on_timeout
interruptible_sleep_on_timeout
wait_event
wait_event_timeout
Wake
wake_up
wake_up_interruptible
void sleep_on(wait_queue_head_t *q)
void interruptible_sleep_on(wait_queue_head_t *q)
long sleep_on_timeout(wait_queue_head_t *q, long timeout)
long interruptible_sleep_on_timeout(wait_queue_head_t *q, long timeout)
#define wait_event(wq, condition) \do { \ if (condition) \ break; \ __wait_event(wq, condition); \} while (0)
#define wake_up(x) __wake_up(x, TASK_NORMAL, 1, NULL)
#define wake_up_interruptible(x) __wake_up(x, TASK_INTERRUPTIBLE, 1, NULL)
void __wake_up(wait_queue_head_t *q, unsigned int mode, int nr_exclusive, void *key)
- 17 -Copyright © 2015 S-Core Co., Ltd. All rights reserved | Con-fidential
Wait(1)
wait
Interruptible?
Signal 을 받을 때 , 깨어남
Uninterruptible (By default)
Signal 을 받아도 깨어나지 않음
$ kill -l 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR111) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+338) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+843) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+1348) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-1253) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-758) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-263) SIGRTMAX-1 64) SIGRTMAX$ man 7 signal
- 18 -Copyright © 2015 S-Core Co., Ltd. All rights reserved | Con-fidential
Wait(2)
wait
Interruptible?
/** * wait_for_completion_interruptible: - waits for completion of a task (w/intr) * @x: holds the state of this particular completion * * This waits for completion of a specific task to be signaled. It is * interruptible. * * Return: -ERESTARTSYS if interrupted, 0 if completed. */int __sched wait_for_completion_interruptible(struct completion *x){ long t = wait_for_common(x, MAX_SCHEDULE_TIMEOUT, TASK_INTERRUPTIBLE); if (t == -ERESTARTSYS) return t; return 0;}EXPORT_SYMBOL(wait_for_completion_interruptible);
- 19 -Copyright © 2015 S-Core Co., Ltd. All rights reserved | Con-fidential
Wait(3)
wait
Timeout
/** * wait_for_completion_interruptible_timeout: - waits for completion (w/(to,intr)) * @x: holds the state of this particular completion * @timeout: timeout value in jiffies * * This waits for either a completion of a specific task to be signaled or for a * specified timeout to expire. It is interruptible. The timeout is in jiffies. * * Return: -ERESTARTSYS if interrupted, 0 if timed out, positive (at least 1, * or number of jiffies left till timeout) if completed. */long __schedwait_for_completion_interruptible_timeout(struct completion *x, unsigned long timeout){ return wait_for_common(x, timeout, TASK_INTERRUPTIBLE);}EXPORT_SYMBOL(wait_for_completion_interruptible_timeout);
- 20 -Copyright © 2015 S-Core Co., Ltd. All rights reserved | Con-fidential
Wait & wake: other primitives
Wait
sleep_on
interruptible_sleep_on
sleep_on_timeout
interruptible_sleep_on_timeout
wait_event
wait_event_timeout
Wake
wake_up
wake_up_interruptible
void sleep_on(wait_queue_head_t *q)
void interruptible_sleep_on(wait_queue_head_t *q)
long sleep_on_timeout(wait_queue_head_t *q, long timeout)
long interruptible_sleep_on_timeout(wait_queue_head_t *q, long timeout)
#define wait_event(wq, condition) \do { \ if (condition) \ break; \ __wait_event(wq, condition); \} while (0)
#define wake_up(x) __wake_up(x, TASK_NORMAL, 1, NULL)
#define wake_up_interruptible(x) __wake_up(x, TASK_INTERRUPTIBLE, 1, NULL)
void __wake_up(wait_queue_head_t *q, unsigned int mode, int nr_exclusive, void *key)
- 21 -Copyright © 2015 S-Core Co., Ltd. All rights reserved | Con-fidential
wait_queue_t
wait_queue_t
struct __wait_queue_head { spinlock_t lock; struct list_head task_list;};typedef struct __wait_queue_head wait_queue_head_t;
- 22 -Copyright © 2015 S-Core Co., Ltd. All rights reserved | Con-fidential
실습
읽을 데이터가 없으면 , 데이터가 있을 때까지 기다리기
https://
github.com/pasang0000/linux_driver_practice/blob/095a1ebbf697fd148c593a8146bfbb1486fea00f/ech
o_driver/echo.c
Copyright © 2015 S-Core Co., Ltd. All rights reserved | Con-fidential
Synchronization
- 24 -Copyright © 2015 S-Core Co., Ltd. All rights reserved | Con-fidential
Simple example
test.c
$ cat test.c#include <stdio.h>
int i = 0;intmain(){ i++; i+=2; i+=3; printf("i=%d\n", i); return 0;}$ gcc –g test.c$ objdump –S a.out…$ objdump –S a.out | less
- 25 -Copyright © 2015 S-Core Co., Ltd. All rights reserved | Con-fidential
Simple example
int i = 0;intmain(){ 40052d: 55 push %rbp 40052e: 48 89 e5 mov %rsp,%rbp i++; 400531: 8b 05 0d 0b 20 00 mov 0x200b0d(%rip),%eax # 601044 <i> 400537: 83 c0 01 add $0x1,%eax 40053a: 89 05 04 0b 20 00 mov %eax,0x200b04(%rip) # 601044 <i> i+=2; 400540: 8b 05 fe 0a 20 00 mov 0x200afe(%rip),%eax # 601044 <i> 400546: 83 c0 02 add $0x2,%eax 400549: 89 05 f5 0a 20 00 mov %eax,0x200af5(%rip) # 601044 <i> i+=3; 40054f: 8b 05 ef 0a 20 00 mov 0x200aef(%rip),%eax # 601044 <i> 400555: 83 c0 03 add $0x3,%eax 400558: 89 05 e6 0a 20 00 mov %eax,0x200ae6(%rip) # 601044 <i> printf("i=%d\n", i); 40055e: 8b 05 e0 0a 20 00 mov 0x200ae0(%rip),%eax # 601044 <i> 400564: 89 c6 mov %eax,%esi 400566: bf 04 06 40 00 mov $0x400604,%edi 40056b: b8 00 00 00 00 mov $0x0,%eax 400570: e8 9b fe ff ff callq 400410 <printf@plt> return 0; 400575: b8 00 00 00 00 mov $0x0,%eax} 40057a: 5d pop %rbp 40057b: c3 retq 40057c: 0f 1f 40 00 nopl 0x0(%rax)
i 에서 eax register로 moveax에 1 덧셈eax에서 i로 mov
- 26 -Copyright © 2015 S-Core Co., Ltd. All rights reserved | Con-fidential
Race condition 예 (1)
가정
main() 을 두개의 thread 에서 동시 실행
예상 결과
A 가 모두 실행된 다음 , B 가 실행될 경우 ,
i = 12
Race 상황
A 가 실행 도중 , 파란 선에서 Context Switching 발생
int i = 0;intmain(){ 40052d: 55 push %rbp 40052e: 48 89 e5 mov %rsp,%rbp i++; 400531: 8b 05 0d 0b 20 00 mov 0x200b0d(%rip),%eax # 601044 <i> 400537: 83 c0 01 add $0x1,%eax 40053a: 89 05 04 0b 20 00 mov %eax,0x200b04(%rip) # 601044 <i> i+=2; 400540: 8b 05 fe 0a 20 00 mov 0x200afe(%rip),%eax # 601044 <i> 400546: 83 c0 02 add $0x2,%eax 400549: 89 05 f5 0a 20 00 mov %eax,0x200af5(%rip) # 601044 <i>
i 에서 eax register로 moveax에 1 덧셈eax에서 i로 mov
- 27 -Copyright © 2015 S-Core Co., Ltd. All rights reserved | Con-fidential
Race condition 예 (2)
A B i
mov 0x200b0d(%rip),%eax #%eax=0
0
i++; 1
i+=2; 3
i+=3; 6
printf(“i=%d\n”, i); 6
add $0x1,%eax 6
mov %eax,0x200b04(%rip) 1
i+=2; 3
i+=3; 6
printf(“i=%d\n”, i); 6
- 28 -Copyright © 2015 S-Core Co., Ltd. All rights reserved | Con-fidential
Critical Section
2 개 이상의 Context 에서 동시에 메모리 접근할 경우 , 보호되어야할 구간
Echo driver 에서도 read/write 이 같은 데이터를 동시에 접근하고 변경하고 있음
$ cat test.c#include <stdio.h>
int i = 0;intmain(){ i++; i+=2; i+=3; printf("i=%d\n", i); return 0;}$ gcc –g test.c$ objdump –S a.out…$ objdump –S a.out | less
- 29 -Copyright © 2015 S-Core Co., Ltd. All rights reserved | Con-fidential
Synchronization
Synchronization: critical section 을 보호하기 위한 방법
Kernel 에서 제공되는 Synchronization primitives
Low-level: Memory barrier, Atomic operations, Synchronize with interrupts, Spin locks
High-level: Completion, Mutex, Semaphore, read-write lock
Spin lock
Spinning: 계속 메모리의 value 를 체크
장점 : lock 을 잡는데 소요되는 시간이 제일 짧음
단점 : CPU 를 계속 사용하게 됨 . Critical section 이 긴 경우 , 사용하면 안됨
Mutex
Sleep-based synchronization
장점 : Lock 을 잡지 못하면 , CPU 를 계속 사용하지 않음
단점 : Lock 을 잡지 못하고 sleep 하게 되는 overhead
- 30 -Copyright © 2015 S-Core Co., Ltd. All rights reserved | Con-fidential
Mutex
/** * mutex_init - initialize the mutex * @lock: the mutex to be initialized * Initialize the mutex to unlocked state. * It is not allowed to initialize an already locked mutex. */void mutex_init(struct mutex *lock);
/* Lock the mutex */void mutex_lock(struct mutex *lock);void mutex_lock_interruptible(struct mutex *lock);void mutex_lock_killable(struct mutex *lock);
/* Unlock the mutex */void mutex_unlock(struct mutex *lock);
- 31 -Copyright © 2015 S-Core Co., Ltd. All rights reserved | Con-fidential
실습
https://
github.com/pasang0000/linux_driver_practice/blob/9897749e82631aabbaa8ffcebe156b6
37ab56ade/echo_driver/echo.c