커널 프로그래밍 (Kernel Programming)

Slides:



Advertisements
Similar presentations
2 3 t h K o r e a O p e r a t i n g S y s t e m S e m i n a r 8259A 를 아는가 ??? 2 3 t h K o r e a O p e r a t i n g S y s t e m S e m i n a r.
Advertisements

Format String Attack! 포맷 스트링 공격 경일대학교 사이버보안학과 학년 남주호.
컴퓨터와 인터넷.
2장. 프로그램의 기본 구성. 2장. 프로그램의 기본 구성 2-1"Hello, World!" 들여다 보기 /* Hello.c */ #include int main(void) { printf("Hello, World! \n"); return 0;
컴퓨터프로그래밍 1주차실습자료 Visual Studio 2005 사용법 익히기.
인공지능실험실 석사 2학기 이희재 TCP/IP Socket Programming… 제 11장 프로세스간 통신 인공지능실험실 석사 2학기 이희재
9장. C 언어의 핵심! 함수. 9장. C 언어의 핵심! 함수 9-1 함수의 정의와 선언 main 함수 다시 보기 : 함수의 기본 형태 { } 그림 9-1.
Cross Compiler를이용한 커널 컴파일 및 포팅
연결리스트(linked list).
컴퓨터 프로그래밍 기초 [Final] 기말고사
디바이스 드라이버 이해 Hanbat National University Prof. Lee Jaeheung.
제9장 디바이스 드라이버 개요.
System Call Linux Kernel 수업 3번째.
08. 디바이스 드라이버의 읽기와 쓰기 김진홍
Unix Project2 <test character device 생성>
커널 프로그래밍과 시스템 콜을 만들어보고, 디바이스 드라이버에 대한 일반적인 개요를 살펴본다.
Linux System Call.
시스템콜 프로그래밍.
4장. 웹로직 서버상에서의 JDBC와 JTA의 운용
UNIT 07 Memory Map 로봇 SW 교육원 조용수.
제 3장. C보다 나은 C++ II.
07. 디바이스 드라이버의 초기화와 종료 김진홍
CHAPTER 02 OpenCV 개요 PART 01 영상 처리 개요 및 OpenCV 소개.
Root Filesystem Porting
11장. 포인터 01_ 포인터의 기본 02_ 포인터와 Const.
Error Detection and Correction
Root Filesystem Porting
                              데이터베이스 프로그래밍 (소프트웨어 개발 트랙)                               퍼스널 오라클 9i 인스톨.
WinCE Device Driver 실습 #3
WinCE Device Driver 실습 #2
Cross Compiler 설치.
DK-128 실습 EEPROM 제어 아이티즌 기술연구소
Sungkyunkwan University OS Project Dongkun Shin
11장. 1차원 배열.
Cross Compiler를이용한 커널 컴파일 및 포팅
Method & library.
Chap 6.Assembler 유건우.
UNIT 07 Memory Map 로봇 SW 교육원 조용수.
리눅스 시스템 & 커널 기초 P.46 – P.53 이름: nsh009 학번: 112 1/20.
27장. 모듈화 프로그래밍.
Device Driver 임베디드 시스템 I.
영상처리 실습 인공지능연구실.
HTTP 프로토콜의 요청과 응답 동작을 이해한다. 서블릿 및 JSP 를 알아보고 역할을 이해한다.
Lab 1 Guide: 교재 2장 DrawX ( 쪽)
Chapter6 : JVM과 메모리 6.1 JVM의 구조와 메모리 모델 6.2 프로그램 실행과 메모리 6.3 객체생성과 메모리
DK-128 실습 내부 EEPROM 제어 아이티즌 기술연구소 김태성 연구원
School of Electronics and Information. Kyung Hee University.
컴퓨터 프로그래밍 기초 - 10th : 포인터 및 구조체 -
ARM Development Suite v1.2
컴퓨터 프로그래밍 기초 - 8th : 함수와 변수 / 배열 -
Fucntion 요약.
네트워크 환경 구축과 이미지 전송 호스트/타겟 통신 직렬 통신을 이용한 이미지 전송 수퍼 데몬 BOOTP 환경 구축
Canary value 스택 가드(Stack Guard).
Kernel, Ramdisk, JFFS2 Porting
( Windows Service Application Debugging )
OpenCV 설정 2.21 만든이 딩딩.
DK-128 개발환경 설정 아이티즌 기술연구소
3. 모듈 (5장. 모듈).
01. 분산 파일 시스템의 개요 네트워크에 분산된 파일을 사용자가 쉽게 접근하고 관리할 수 있게 해준다.
기초C언어 제2주 실습 프로그래밍의 개념, 프로그램 작성 과정 컴퓨터시뮬레이션학과 2016년 봄학기 담당교수 : 이형원
발표자 : 이지연 Programming Systems Lab.
구조체(struct)와 공용체(union)
Numerical Analysis Programming using NRs
Static과 const 선언 조 병 규 한 국 교 통 대 학 교 SQ Lab..
동적메모리와 연결 리스트 컴퓨터시뮬레이션학과 2016년 봄학기 담당교수 : 이형원 E304호,
06. 디바이스의 등록과 해제 김진홍
1장 C 언어의 개요 C 언어의 역사와 기원 C 언어의 특징 프로그램 과정 C 프로그램 구조 C 프로그램 예제.
1. 지역변수와 전역변수 2. auto, register 3. static,extern 4. 도움말 사용법
29장. 템플릿과 STL 01_ 템플릿 02_ STL.
BoardGame 보드게임 따라가기.
Presentation transcript:

커널 프로그래밍 (Kernel Programming) Lecture #9

목 차 (1) System call이란? 1. Kernel Programming 이란? 2. System call 추가하기 (2) Kernel vs Application (3) Kernel programming 주의 사항 (4) Kernel Interface 함수 2. System call 추가하기 (1) System call이란? (2) POSIX API와 System calls (3) System call 원리 이해 (4) System call 추가하기 (5) System call 확장

1. 커널 프로그래밍

Kernel Programming 이란? Linux kernel core 기능 추가 Linux kernel 알고리즘 개선

Kernel vs Application (1) 수행 방법 Application Program: 처음부터 순차적으로 수행 Kernel: 응용프로그램을 위한 system call이나 인터럽트 핸들러를 수행하기 위해 비동기적으로 수행 Application Kernel System call Interrupt

Kernel vs Application (2) Library Application Program: 모든 library를 link 하고 사용할 수 있다. Kernel: kernel에서 export 하는 것들만 사용할 수 있다. Kernel mode vs User mode Application Program: user mode에서 수행되며 하드웨어에 직접 접근하는 것과 메모리에 대한 허용되지 않은 접근이 제한된다. Kernel Program: 모든 것이 허용된다.

Kernel vs Application (3) Address Space Application Program과 Kernel Program은 서로 다른 메모리 매핑법을 가지고 있으며, 프로그램 코드는 서로 다른 address space를 가지고 있다. Kernel address space User address space 1 G byte 매모리 매핑법이란 주소 영역에서 stack 영역과 heap 영역 code 영역 등을 어떻게 사용할 것인가를 정의하는 방법을 이야기한다. 32bit cpu의 경우 4Gbyte 의 주소를 접근할 수 있는 리눅스에서는 이 4Gbyte 중 1Gbyte를 커널의 코드와 자료구조등을 저장하는데 사용하며 나머지 3Gbyte를 사용자모드 프로세스의 코드와 자료구조를 저장하는데 사용한다. 커널 영역에 해당하는 메모리를 사용하는 방식과 사용자 영역에 해당하는 메모리를 사용하는 방식이 다르기 때문에 두 영역에서 사용하는 가상 주소는 서로 다른 물리주소로 맵핑된다. 4 G byte 3 G byte

Kernel vs Application (4) Namespace pollution Application Program: 현재 개발하는 프로그램에서만 각 함수와 변수의 이름을 구별하여 주면 된다. Kernel Program: 현재 개발하는 모듈 외에도 커널 전반적으로 함수와 변수의 이름이 충돌하지 않도록 하여야 한다.

Kernel programming 주의 사항 (1) Library stdio.h 와 같은 일반 프로그램에서 사용하는 헤더 파일을 include해서는 안된다. 오직 /usr/include/linux 와 /usr/include/asm 아래에 선언된 헤더파일 만을 include 한다. Namespace pollution 외부 파일과 link하지 않을 모든 심볼을 static으로 선언 또는 외부 파일과 link할 symbol을 symbol table 등록 EXPORT_NO_SYMBOLS; EXPORT_SYMBOL(name); 전역 변수는 잘 정의된 prefix를 붙여 준다. Ex: sys_open() symbol(함수나 변수등의 identifier)을 static 으로 선언하면 link 시에 다른 object에서 참조 되지 않는다. static으로 선언하지 않는 경우 대부분 다른 object에서 참조할 수 있게 된다. 심볼을 심볼 테이블에 등록해주는 아래의 두 매크로를 사용할 경우에는 static으로 선언하지 않아도 외부에서 symbol을 참조할 수 없고 명시적으로 export해준 symbol만을 외부에서 참조할 수 있게된다. symbol table은 전역 커널 항목 -- 함수와 변수 – 을 담고 있다. /proc/ksyms에 text 형태로 저장되어 있으므로 사용자가 읽어 볼 수도 있다. Kernel 에 모듈을 추가할 경우 insmod 프로그램은 이 symbol table을 검사하여 추가하려는 모듈에서 아직 연결 되지 않은 (unresolved) symbol 을 연결 시켜 준다. EXPORT_NO_SYMBOLS;  링크할때 어떤 심볼도 다른 오브젝트에서 참조하지 못하도록 한다. EXPORT_SYMBOL(name)  name에 해당하는 심볼을 다른 오브젝트에서 참조 할 수 있도록 한다.

Kernel programming 주의 사항 (2) Fault handling Kernel은 하드웨어 접근에 대해 어떠한 제한도 없기 때문에 커널에서의 에러는 시스템에 치명적인 결과를 발생시킨다. 함수 호출 등의 작업 시 모든 에러 코드를 검사하고 처리해야 한다. Address space 커널이 사용하는 stack의 크기는 제한되어 있고, 인터럽트 핸들러도 동일한 스택을 사용하므로 큰 배열을 사용하거나, recursion이 많이 일어나지 않도록 주의해야 한다. Application과 data를 주고 받기 위해(call by reference) 특별한 함수를 사용 하여야 한다. 커널과 application은 서로 다른 주소 공간을 사용한다. 때문에 call by reference를 사용할 수 없고 이를 위해 특별한 함수를 사용하여 커널과 application에서 data를 주고 받는다. 뒷 장에서 이러한 함수들을 소개한다. MMX[엠엠엑스]는 멀티미디어 응용프로그램들의 실행을 좀더 빠르게 할 수 있도록 설계된 인텔 펜티엄 프로세서이다. 인텔에 따르면, MMX 기능이 부가된 마이크로프로세서는 동일한 클록속도의 MMX 기능이 없는 프로세서에 비해, 멀티미디어 응용프로그램을 최고 60%까지 빠르게 실행할 수 있다고 한다. 그 외에도, MMX 마이크로프로세서는 일반적으로 다른 프로그램들도 약 10% 정도 더 빠르게 수행한다

Kernel programming 주의 사항 (3) 기타 실수연산 이나 MMX 연산을 사용할 수 없다. 커널과 application은 서로 다른 주소 공간을 사용한다. 때문에 call by reference를 사용할 수 없고 이를 위해 특별한 함수를 사용하여 커널과 application에서 data를 주고 받는다. 뒷 장에서 이러한 함수들을 소개한다. MMX[엠엠엑스]는 멀티미디어 응용프로그램들의 실행을 좀더 빠르게 할 수 있도록 설계된 인텔 펜티엄 프로세서이다. 인텔에 따르면, MMX 기능이 부가된 마이크로프로세서는 동일한 클록속도의 MMX 기능이 없는 프로세서에 비해, 멀티미디어 응용프로그램을 최고 60%까지 빠르게 실행할 수 있다고 한다. 그 외에도, MMX 마이크로프로세서는 일반적으로 다른 프로그램들도 약 10% 정도 더 빠르게 수행한다

Kernel Interface 함수 (1) 주의 사항 Kernel interface 함수 분류 Kernel program은 일반적인 library를 사용하지 못하고 kernel에서 export 해준 함수들 만을 사용할 수 있다. Kernel interface 함수 분류 Kernel 에서 제공하는 함수 중 kernel programming에 자주 사용되는 함수는 다음과 같이 분류할 수 있다. Port I/O Interrupt Memory Synchronization Kernel message 출력 Device Driver registration

Kernel Interface 함수 (2) I/O device 와 data를 주고 받기 위한 함수: unsigned inb(unsigned port): Port에서 1byte를 읽는다. unsigned inw(unsigned port) Port에서 2byte를 읽는다. unsigned inl(unsigned port) Port에서 4byte를 읽는다. unsigned outb(char value, unsigned port) Port에 1byte value를 쓴다. unsigned outw(short int value, unsigned port) Port에 2byte value를 쓴다. unsigned outl(long int value, unsigned port) Port에 4byte value를 쓴다. 주변 장치에는 cpu 의 I/O 주소 영역에 mapping 되어 사용되는 장치가 있고 Memory 영역에 mapping 되어 사용되는 장치가 있다. 위 함수들은 I/O 주소 영역에 mapping 된 장치를 위한 것이고, Memory 영역에 mapping 된 장치는 일반적으로 memory를 사용하는 방식으로 접근할 수 있다.

Kernel Interface 함수 (3) I/O device 와 data를 주고 받기 위한 함수: void insb(unsigned port, void *addr, unsigned long count) Port에서 count bytes를 읽어서 메모리의 addr 주소부터 저장 void insw(unsigned port, void *addr, unsigned long count) Port에서 16bit * count 만큼 읽어서 메모리의 addr 주소부터 저장 void insl(unsigned port, void *addr, unsigned long count) Port에서 32bit * count 만큼 읽어서 메모리의 addr 주소부터 저장

Kernel Interface 함수 (4) I/O device 와 data를 주고 받기 위한 함수: void outsb(unsigned port, void *addr, unsigned long count) Memory의 addr번지 에서부터 count bytes를 읽어서 port에 쓴다. void outsw(unsigned port, void *addr, unsigned long count) Memory의 addr번지 에서부터 count * 16bit를 읽어서 port에 쓴다. void outsl(unsigned port, void *addr, unsigned long count) Memory의 addr번지 에서부터 count * 32bit를 읽어서 port에 쓴다.

Kernel Interface 함수 (5) I/O device 와 data를 주고 받기 위한 함수: Pausing I/O 예) inb() 함수의 경우 inb_p()

Kernel Interface 함수 (6) 인터럽트의 설정 및 처리에 관한 함수(or 매크로) : cli()/sti() clear/set interrupt enable save_flags(unsigned long flag), restore_flags(unsigned long flag) status register의 내용을 저장하고 복원하는 매크로 두 매크로는 같은 함수 안에서 호출 되어야 한다. flag를 다른 함수로 pass해서는 안된다. int requst_irq(unsigned int irq, void (*handler)(int), unsigned long flags, const char *device) 커널로부터 IRQ를 요청하고, 이 IRQ에 대한 interrupt handler를 install cli()/sti() 는 전체 인터럽트를 금지하거나 가능하게 해주는 매크로이다. Status register는 system의 각 상태를 가지고 있는 레지스터이다. Processor 마다 차이가 있지만 일반적으로Interrupt 가 enable 상태 인지, 직전의 연산에서 carry가 발생하였는 가 등의 정보를 가지고 있다. requst_irq 는 사용자가 인터럽트를 추가하고자 할 때 사용한다. 인터럽트가 발생할 수 있는 source 를, 현재 사용하고 있지 않은 irq 에 등록하고, 이러한 인터럽트가 발생했을 때 수행될 interrupt handler 함수를 등록한다.

Kernel Interface 함수 (7) 인터럽트의 설정 및 처리에 관한 함수(or 매크로) : void free_irq(unsigned int irq) request_irq()에서 획득한 irq를 반납함

Kernel Interface 함수 (8) Kernel에서의 동적 메모리 할당 함수: void * kmalloc(unsigned int len, int priority) 커널 메모리 할당. 128~131056byte까지 가능 priority:GFP_BUFFER, GFP_ATOMIC, GFP_USER, GFP_KERNEL 물리적으로 연속적인 메모리를 할당한다. void kfree(void *obj) kmalloc()에서 할당 받은 커널 메모리를 반납 GFP_KERNEL : 일반적인 커널 메모리 할당. 할당 가능한 Memory가 부족할 경우 sleep할 수도 있다. GFP_BUFFER : 버퍼 캐쉬를 관리할때 사용되므로 할당자가 sleep상태로 갈수 있다. I/O 서브 시스템이 스스로 메모리를 필요로 할때 데드락과을 피하도록 하기 위해 디스크에 dirty page를 disk에 플러쉬함으로서 메모리를 free한다는 점에서 GFP_KERNEL과 다르다. GFP_ATOMIC : 인터럽트 핸들러 등 프로세스 컨텍스트 외부 코드에서 메모리를 할당할때 사용한다. 결코 sleep상태가 되지 않는다. GFP_USER : 사용자들이 메모리 할당할때 사용. 낮은 우선순위를 가진다. GFP_HIGHUSER High memory에서 할당할때 사용한다.

Kernel Interface 함수 (9) Kernel에서의 동적 메모리 할당 함수 : void * vmalloc(unsigned int len) 커널 메모리 할당 크기 제한 없음 가상 주소 공간에서 연속적인 메모리 영역을 할당 void vmfree(void *addr) vmalloc()에서 할당 받은 커널 메모리를 반납

Kernel Interface 함수 (10) 사용자 공간과 커널 공간 사이에 데이터를 공유하기 위한 함수 : unsigned long copy_from_user(void *to, const void *from, unsigned long n) 사용자 주소공간에서 n byte만큼 data 복사. unsigned long copy_to_user(void *to, const void *from, unsigned long n) 사용자 주소 공간에 n byte만큼 data 복사 void * memset(void *s, char c, sizt_t count) 메모리 s에 c를 count만큼 복사 put_user(datum,ptr) / get_user(ptr) 사용자 공간에 datum을 전달하거나 가져오기 위한 매크로

Kernel Interface 함수 (11) 동기화 함수 : void sleep_on(struct wait_queue **q) q의 번지를 event로 sleep하며, uninterruptible void sleep_in_interruptible(struct wait_queue **q) q의 번지를 event로 sleep하며, interruptible void wake_up(struct wait_queue **q) sleep_on(q)에 의해 sleep한 task를 wakeup void wake_up_interruptible(struct wait_queuq **q) sleep_on_interruptible(q)에 의해 sleep한 task를 wakeup uninterruptible 이란 말은 wake_up 함수의 호출 외에 다른 signul 에 의해서 깨어날 수 없음을 의미하는 것이다. Interruptible 은 wake_up 함수가 호출되지 않아도 임의로 process에 signul을 주어 깨어나게 할 수 있다는 의미이다.

Kernel Interface 함수 (12) stdout으로 메시지를 출력하기 위한 함수 : printk(const char *fmt,… .) printf의 커널 버전 printk(LOG_LEVEL_ message) LOG_LEVEL:KERN_EMERG, KERN_ALERT, KERN_ERR,KERN_WARNING, KER_INFO, KERN_DEBUG 예 printk(“<1>Hello, World”); printk(KERN_WARNING”warning… \n”); LOG_LEVEL은 메시지의 우선 순위를 정의하는 것이다. LOG_LEVEL에 기초하여 커널을 메시지를 현재의 문자 콘솔에 출력하게 되는데 만약 console_loglevel 의 값 보다 우선 순위가 낮다면 console에 출력되지 않는다. console_loglevel은 sys_syslog 시스템 콜로 값을 바꿀 수 있다. LOG_LEVEL 은 <linux/kernel.h> 헤더에 정의 되어 있다.

Kernel Interface 함수 (13) 디바이스 드라이브 등록 함수 : int register_xxxdev(unsigned int major, const char *name,struct file_operations *fops) character/block driver를 xxxdev[major]에 등록 xxx:blk/chr int unregister_xxxdev(unsigned int major, const char *name) xxxdevs[major]에 등록되 있는 device driver를 제거 int register_netdev(const char *name) int unregister_netdev(const char *name) MAJOR(kdev_t dev)/MINOR(kdev_t dev) 장치번호dev로부터 major/minor 번호를 구함

2. System Call

System Call (1) User Application API(시스템 라이브러리) User Level System Call Interface User Level Kernel Level File System Buffer Cache Charater Device Driver Block Process Management (IPC-interprocess Communication, scheduling, Memory Management Process Acounting, etc) Hardware Interface

System Calls (2) user mode process와 kernel 간의 interface  kernel의 자료구조 및 hardware 에 대한 접근 불가 user mode process가 kernel이 가지고 있는 시스템의 상태 정보를 열람하거나 hardware에 접근하여 hardware를 통제하기 위해서는 kernel 과의 communication channel이 필요. 일반적으로 프로세스는 커널에 직접적으로 접근할 수 없다. 다시 말해, 프로세스는 커널 메모리에 접근한다거나 커널의 함수를 호출할 수 없다.  보호모드. 시스템 콜은 user program에게 커널 영역에 대한 접근을 허용하는 유일한 chanel이다. user program은 시스템 콜을 사용해서만 hardware 및 커널 자료구조에 접근할 수 있다.

POSIX API & System calls (1) POSIX API (Application Programming Interface) 유닉스 운영체계에 기반을 두고 있는 일련의 표준 운영체계 인터페이스. application이 시스템에 각 서비스를 요청할 때에 어떠한 함수를 사용해야 하는지 지정한 것. 표준을 두어 각각 다른 시스템에 응용 프로그램을 porting 하는 것이 용이 하게 하기 위한 목적. open(), close(), read(), write() 등 System Call 소프트웨어 인터럽트를 통해 커널에 서비스를 요청하는 것 Linux에서는 POSIX API를 준수하는 library 함수 안에서 system call 함수를 호출함으로써 system call을 사용한다.

POSIX API & System calls (2) 예> 응용프로그램  open() 호출  …  sys_open() 호출 (POSIX API) (시스템 콜) 응용 프로그램 Libc 표준 라이브러리 (포장함수) 시스템 콜 핸들러 시스템 콜 서비스 루틴 시스템콜 인터페이스

System Call 원리 이해 (1) Linux 에서의 system call 처리 Interrupt 주변 장치와 커널이 통신하는 방식 중 하나로 주변 장치가 자신에게 발생한 비동기적 사건을 kerenl에게 알리는 메커니즘. PIC disk tty network cdrom RTC CPU Kernel IDT(IVT) Interrupt handlers el3_interrupt() tty_interrupt() hd_interrupt() timer_interrupt() 1 2 3 4 … 인터럽트를 발생시킬 수 있는 주변 장치들은 하드웨어 적으로 PIC(Programmable Interrupt Controller)라는 칩의 각 핀에 연결되어 있다. PIC는 CPU의 한 PIN에 연결되어 있다. KERNEL은 부팅 과정에서 PIC를 초기화 시킨다. 주변장치에서 인터럽트를 발생시키면 PIC는 CPU에게 인터럽트가 발생되었음을 알리고 CPU는 PIC에게 몇번 인터럽트가 발생되었는가를 문의하여 해당 장치의 IRQ를 알려 준다. 3번 인터럽트가 발생했다고 가정하면 CPU는 KERNEL에게 3번 장치에서 인터럽트가 발생했음을 알린다. KERNEL은 IDT(Interrupt Descriptor Table) 에서 index 3 의 entry에 등록되어 있는 handler 함수를 호출하게 되며 위 그림에서는 el3_interrupt() 를 호출하게 된다. IDT: Interrupt Vector Tale(IVT)라고도 하는 entry table로 각 인터럽트가 발생했을 때 이를 처리해 주기위한 루틴의 시작 주소를 가지고 있다.

System Call 원리 이해 (2) System Call User task Kernel main () { …. mysyscall() } swi __NR_##name User task sys_mysyscall() … … … sys_write() sys_read() sys_fork() sys_exit() System_call_table 1 2 3 4 226 Name  mysyscall __NR_myscall  226 Kernel printk(“…”); /* [kernel]/arch/arm/kernel/entry-common.S*/ ENTRY(vector_swi) get_scno … adr tbl, sys_call_table ldrcc pc, [tbl,scno, lsl #2] swi 는 software 인터럽트를 발생키셔주는 어셈블리 인스트럭션이다. .macro get_scno #ifdef CONFIG_ARM_THUMB tst r8, #T_BIT @ this is SPSR from save_user_regs addne scno, r7, #OS_NUMBER << 20 @ put OS number in ldreq scno, [lr, #-4] #else mask_pc lr, lr ldr scno, [lr, #-4] @ get SWI instruction #endif .endm

System Call 추가하기 (1) 목적 단계 기존 kernel에서 제공하지 않는 service를 user application에 제공  새로운 System Call 을 만든다. 단계 커널 수정 System Call 번호 할당 System Call 호출 테이블 등록 System Call 호출 함수 구현 Kernel 컴파일 및 target board에 적재 user application 제작 새로 구현한 System Call을 사용하는 application 제작 library 작성(반드시 필요한 것은 아니다.) Ramdisk에 포함시켜서 target board에 적재

System Call 추가하기 (2) 가정 /usr/local/pxa255/linux-2.4.19-cd 에 target system용 kernel source code가 있다. 위 디렉토리를 앞으로의 설명에서 [kernel]로 대치한다.

System Call 추가하기 (3) System Call 번호 할당 Linux 커널이 제공하는 모든 시스템 호출은 각각 고유한 번호를 가지고 있다. [kernel]/include/asm-arm/unistd.h 에 각 시스템 호출의 고유 번호에 정의 되어 있다.  새로 추가할 system call의 고유번호 정의 추가 [kernel]/include/asm-arm/unistd.h 파일을 vi로 연다.

System Call 추가하기 (4) System Call 번호 할당 (계속) unistd.h 파일의 위 내용을 보면 현재 system call 은 225 개가 있는 것을 확인할 수 있다. 추가할 system call 은 위 화면과 같이226번으로 할당한다. __NR_은 System Call 고유번호를 나타내는 접두어이며, 그 뒤의 mysyscall이 추가할 System Call 처리 함수의 이름이다. (sys_mysyscall 이 아님을 주의 깊게 봐 둔다.) 현재 리눅스에서는 256개까지의 시스템 콜을 지원한다.

System Call 추가하기 (5) System Call 테이블에 System Call 처리 함수 등록 [kernel]/arch/arm/kernel/entry-comm.S 에 sys_call_table이라는 entry로 구현되어 있다. sys_call_table에는 system call 처리함수의 시작 주소들이 들어있고 각 함수들은 unistd.h에 정의 되어있는 system call 번호를 인덱스로 하여 접근된다.  sys_call_table에 추가할 System Call 처리함수 등록 entry-comm.S 파일을 vi로 연다.

System Call 추가하기 (6) System Call 테이블에 System Call 처리 함수 등록 (계속) entry-comm.S 에서 다음과 같은 부분을 확인할 수 있다. ENTRY(sys_call_table) 다음에 calls.S를 include하고 있다. vi를 나와서 다시 calls.S를 열어 보자.

System Call 추가하기 (7) System Call 테이블에 System Call 처리 함수 등록 (계속) calls.S 의 내용은 다음과 같다. 다음과 같이 추가할 System Call 처리함수를 등록한 후 저장 하고 나온다. unistd.h에 정의한 번호와 일치

이 함수가 어셈블리 언어로 구현된 함수에서 호출될 때 사용하는 keyword System Call 추가하기 (8) 처리 함수 구현하기 System Call 이 발생했을 때 수행될 함수를 구현한다. [kernel]/kernel/test_syscall.c 를 다음과 같이 만든다. calls.S 에 등록한 이름과 동일한 이름 이 함수가 어셈블리 언어로 구현된 함수에서 호출될 때 사용하는 keyword

System Call 추가하기 (9) Makefile 수정 만들어진 처리함수를 커널이 컴파일 될 때에 함께 컴파일 될 수 있도록 [kernel]/kernel/Makefile에 다음과 같이 추가 한다.

System Call 추가하기 (10) Kernel image를 /tftpboot에 복사 [kernel] 디렉토리에서 커널을 컴파일하고 생성된 커널 이미지를 target에 전송하기 위해 /tftpboot로 복사. % cd [kernel] % make clean; make dep; make zImage % cp [kernel]/arch/arm/boot/zImage /tftpboot

System Call 추가하기 (11) System Call을 호출하는 user application 작성 library를 만들지 않고 user application을 만드는 경우 unistd.h 에 정의된 매크로로 System Call 처리함수의 타입과 이름을 인자로 넘겨준다. *sys 접두어를 붙이지 않는다. /* linux/unistd.h */ #define _syscall0(type,name) type name(void){ \ register long __res __asm__(“r0”); \ __asm__ __volatile__{ \ __syscall(name) \ : “=r” (__res) \ : “ \ : “lr”); \ __syscall_return(type,__res); \ } 아래쪽에서 오른쪽 창에 보면 __sys1(__NR_##name) 이라고 된 부분이 있는데 여기서 ##은 두 토큰을 결합한다는 의미이다. 즉 name에 “mysyscall” 을 넘겨준 경우 sys1(__NR_mysyscall) 과 같이 된다. #else #define __syscall(name) “swi\t” __sys1(__NR_##name)”\n\t” Software interrupt를 발생시키는 assemblier Unistd에서 정의한 symbol로 바꿘준다.

System Call 추가하기 (12) System Call을 호출하는 user application 작성(계속) Library를 만들고 user application을 만드는 경우 newsys.c 파일을 다음과 같이 만든다. (임의의 directory에)

System Call 추가하기 (13) System Call을 호출하는 user application 작성(계속) 앞에서 만든 newsys.c를 컴파일하고 라이브러리로 만들어 준다. (example에서는 /root/mylib 에 newsys.c를 만들었다.) target board 에 올라갈 kernel의 header file을 사용해야 한다. 검색할 Inclued 디렉토리 지정 Library로 만들기 위해 link 하지 않고object code 까지만 만든다.

System Call 추가하기 (14) System Call을 호출하는 user application 작성(계속) 만들어진 library를 사용하는 application을 만든다.

System Call 추가하기 (15) System Call을 호출하는 user application 작성(계속) 위에서 만든 application을 compile한다. 만들어진 user application을 /home/share에 복사 Library 검색 위치를 알려준다. ‘new’ 라는 이름의 library를 link

System Call 추가하기 (16) Test 앞서 system call을 추가하여 다시 컴파일한 커널이미지(현재 /tftpboot에 zImage로 존재) 를 target에 download하고 target 을 리눅스로 부팅한 후 host의 /home/share 마운트

System Call 추가하기 (17) 지금까지의 과정을 정리해 보면 다음과 같다. Kernel 수정 Application 작성 unistd.h 에 system call 번호 정의 calls.S 에 System Call 처리함수 등록 System Call 처리 함수 구현 Kernel 재 컴파일 Kernel을 Target system에 download Library 작성 Library 와 link 하여 system call을 호출하는 application 작성 Application 을 ramdisk에 추가 Ramdisk를 target system에 dwonload