리눅스 드라이버 #2

31
리리리 리리리리 리리 #2 2015/Jun/08 리리리

Upload: sangho-park

Post on 28-Jul-2015

174 views

Category:

Software


8 download

TRANSCRIPT

Page 1: 리눅스 드라이버 #2

리눅스 드라이버 실습 #22015/Jun/08

박상호

Page 2: 리눅스 드라이버 #2

Copyright © 2015 S-Core Co., Ltd. All rights reserved | Con-fidential

실습 내용

Page 3: 리눅스 드라이버 #2

Copyright © 2015 S-Core Co., Ltd. All rights reserved | Con-fidential

실습 #1 Wrap-up

Page 4: 리눅스 드라이버 #2

- 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) 을 응용 프로그램에 제공

Page 5: 리눅스 드라이버 #2

- 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...

Page 6: 리눅스 드라이버 #2

- 6 -Copyright © 2015 S-Core Co., Ltd. All rights reserved | Con-fidential

커널 모듈

Page 7: 리눅스 드라이버 #2

- 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

Page 8: 리눅스 드라이버 #2

- 8 -Copyright © 2015 S-Core Co., Ltd. All rights reserved | Con-fidential

디바이스 드라이버

● 디바이스 드라이버o 디바이스를 이용하기 위한 커널 S/W 모듈

● UNIX 에서 장치는 파일 (/dev/XXX)o 장치를 이용하기 위해서는 드라이버가 필요o 장치와 드라이버를 어떻게 연결할까 ?

■ 장치별로 Major/Minor 번호 부여

● Major 번호를 담당하는 드라이버 연결

Page 9: 리눅스 드라이버 #2

- 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$

Page 10: 리눅스 드라이버 #2

- 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

Page 11: 리눅스 드라이버 #2

- 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

Page 12: 리눅스 드라이버 #2

Copyright © 2015 S-Core Co., Ltd. All rights reserved | Con-fidential

Sleep

Page 13: 리눅스 드라이버 #2

- 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

Page 14: 리눅스 드라이버 #2

- 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

Page 15: 리눅스 드라이버 #2

- 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 *);

Page 16: 리눅스 드라이버 #2

- 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)

Page 17: 리눅스 드라이버 #2

- 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

Page 18: 리눅스 드라이버 #2

- 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);

Page 19: 리눅스 드라이버 #2

- 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);

Page 20: 리눅스 드라이버 #2

- 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)

Page 21: 리눅스 드라이버 #2

- 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;

Page 22: 리눅스 드라이버 #2

- 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

Page 23: 리눅스 드라이버 #2

Copyright © 2015 S-Core Co., Ltd. All rights reserved | Con-fidential

Synchronization

Page 24: 리눅스 드라이버 #2

- 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

Page 25: 리눅스 드라이버 #2

- 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

Page 26: 리눅스 드라이버 #2

- 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

Page 27: 리눅스 드라이버 #2

- 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

Page 28: 리눅스 드라이버 #2

- 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

Page 29: 리눅스 드라이버 #2

- 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

Page 30: 리눅스 드라이버 #2

- 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);