1 / 16

System Call 구현 기초 (since 2004) ( 교재에는 7 th 2006 에 포함 )

System Call 구현 기초 (since 2004) ( 교재에는 7 th 2006 에 포함 ). Linux 커널의 새로운 시스템 호출 구현은 아래 두 가지 작업으로 구성 커널 수정 시스템 호출 번호 할당 시스템 호출 테이블 등록 시스템 호출 처리 함수 구현 커널 컴파일 및 리부팅 새로운 시스템 호출을 이용하는 사용자 수준 응용 시스템 호출을 사용하는 프로그램 작성 라이브러리 작성 ( 꼭 필요한 것은 아님 ) 커널을 수정하기 위해서는 커널 소스 필요

gay-berry
Download Presentation

System Call 구현 기초 (since 2004) ( 교재에는 7 th 2006 에 포함 )

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. System Call 구현 기초 (since2004) (교재에는 7th 2006에 포함) • Linux 커널의새로운 시스템 호출 구현은 아래 두 가지 작업으로 구성 • 커널 수정 • 시스템 호출 번호 할당 • 시스템 호출 테이블 등록 • 시스템 호출 처리 함수 구현 • 커널 컴파일 및 리부팅 • 새로운 시스템 호출을 이용하는 사용자 수준 응용 • 시스템 호출을 사용하는 프로그램 작성 • 라이브러리 작성(꼭 필요한 것은 아님) • 커널을 수정하기 위해서는 커널 소스 필요 • Fedora 13 이상의 경우 커널 개발 패키지를 설치하면 /usr/src/kernels 디렉토리 밑에 설치됨 (커널 버전 2.6.38.6) • 다운로드 http://www.kernel.org $ wget http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.38.6.tar.gz $ ftp ftp.kernel.orgName: anonymous Password: [Enter]cd /pub/linux/kernel • 커널 소스를 구해서 /usr/src/kernels 디렉토리 밑에 설치 $ tar xvfz linux-2.6.38.6.tar.gz 또는 $ tar xvfj linux-2.6.38.6.tar.bz2 • 설치한 소스 디렉토리를 mylinux로 심볼릭 링크 $ ln –s linux-2.6.38.6 mylinux • $ ftp ftp.kernel.org • id: anonymous • password: [Enter] • ftp> binary • ftp> cd pub/linux/kernel/v2.6 • ftp> get linux-2.6.38.6.tar.gz (또는 bz2 파일) ppt reader 설치: $ yum install @libreoffice

  2. 윈도우 환경에서 컴퓨터 네트워크 설정 값을 확인한다 Windows: C:\WINDOWS\system32\ipconfig.exe Linux: $ ifconfig 프로그램과 기타를 클릭한다 네트워크 연결을 클릭한다

  3. 유선 탭에서 자신의 네트워크 장치클릭하고 IPV4 탭 선택 후 편집을 누른다. 네트워크 설정 값들을 입력한 후 저장한다. IP : 10.80.77.84 ~ 131 넷마스크 : 255.255.255.0 게이트웨이: 10.80.77.254 DNS 서버 : 117.16.191.6 ※ 할당된 IP 확인  Windows: ipconfig 또는 Linux: ifconfig

  4. 시스템 호출 과정 ENTRY(system_call) /*arch/x86/kernel/entry_32.S 496*/ SAVE_ALL …. call *sys_call_table(,%eax,4) …. main { … syscall (__NR_newsyscall); } IDT(IVT) divide_error() 0x0 degug() nmi() ENTRY(sys_call_table) /*arch/x86/kernel/syscall_table_32.S*/ … sys_restart_syscall() 0 1 2 3 4 … syscall() { … movl 338, %eax int $0x80 … } … /*real handler*/ asmlinkage int sys_newsyscall() { printk(…); } system_call() 0x80 sys_exit() … sys_fork() sys_read() sys_write() 341 sys_newsyscall() IDT: Interrupt Descriptor Table = IVT: Interrrupt Vector Table /usr/include/asm/unistd_32.h /usr/src/kernels/linux-2.6.38.6/arch/x86/include/asm/unistd_32.h

  5. syscall /usr/include/unistd.h 라인 1078 extern long int syscall (long int __sysno, ...) __THROW; /usr/src/kernels/linux-2.6.38.6/arch/x86/include/asm/unistd_32.h #define _syscall0(type,name) \ type name(void) \ { \ long __res; \vi unistd_32.h __asm__ volatile ("int $0x80" \ : "=a" (__res) \ /* eax register */ : "0" (__NR_##name)); \ __syscall_return(type,__res); \ }

  6. 커널 수정 (1) • 시스템 호출 번호 할당 • Linux 커널이 제공하는 시스템 호출은 각각 고유한 번호를 갖는다 • $ vi /usr/src/kernels/mylinux/arch/x86/include/asm/unistd_32.h 파일 수정 #define __NR_newsyscall 341 (새로운 시스템 호출 번호 341 추가) #define NR_syscalls 342 (시스템 호출 개수를 0~341 즉 342 로수정) /* arch/x86/include/asm/unistd_32.h 파일의 내용 */ #ifndef _ASM_I386_UNISTD_H_ #define _ASM_I386_UNISTD_H_ #define __NR_exit 1 #define __NR_fork 2 #define __NR_read 3 … #define __NR_prlimit64 340 #define __NR_newsyscall 341 #ifdef __KERNEL__ #define NR_syscalls 342 • $ vi /usr/include/asm/unistd_32.h 파일도 똑같이 수정 #define __NR_newsyscall 341 (새로운 시스템 호출 번호 341 추가) #define NR_syscalls 342 (시스템 호출 개수를 0~341 즉 342 로수정)

  7. 커널 수정 (2) • 시스템 호출 테이블 등록 • 시스템 호출처리 함수는 sys_call_table 테이블에 등록 • sys_call_table 정보는 • $ vi /usr/src/kernels/mylinux/arch/x86/kernel/syscall_table_32.S 에 구현 • /* 340 */ 찾은다음 /* 341 */ 라인에 .long sys_newsyscall 라인을 추가 ENTRY(sys_call_table) .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */ .long sys_exit .long sys_fork .long sys_read .long sys_write .long sys_open /* 5 */ … .long sys_prlimit64 /* 340 */ .long sys_newsyscall

  8. 커널 수정 (3) • 시스템 호출 처리 함수 구현 • 일반 적으로 태스크 관리자 관련 함수는 /usr/src/kernels/mylinux/kernel/ 파일 시스템 관련 함수는 /usr/src/kernels/mylinux/fs/ 밑에 구현 • 구현할 함수를 /usr/src/kernels/mylinux/kernel/ 디렉토리 밑에 newsyscall.c 구현 • $ vi /usr/src/kernels/mylinux/kernel/newsyscall.c 코딩 /* /usr/src/mylinux/kernel/newsyscall.c */ #include <linux/linkage.h> #include <linux/unistd.h> #include <linux/errno.h> #include <linux/kernel.h> #include <linux/sched.h> asmlinkage int sys_newsyscall() { printk("Hello Linux, 자기 학번 Sung MeeYoung is in Kernel\n"); return 0; } • $ vi /usr/src/kernels/mylinux/kernel/Makefile 수정 • obj -y = 라인에 newsyscall.o추가

  9. 커널 수정 (4) • 커널 구성 • $ cd /usr/src/kernels/mylinux (커널 소스의 상위 디렉토리로 이동) • $ make mrproper (기존의 커널 설정 제거) • 커널버전 2.6부터 makedep 과 makeclean 불필요 • $ cp ../2.6.38.6-26.rcl.fc15.i686.PAE/.config ./ • $ make oldconfig (실행후 선택문 모두 엔터) • 아래 3 가지 중한 가지만 실행 (재구성할 때는 .config 파일 삭제하고 구성) • $ cp ../2.6.38.6-45.fc14.i686.PAE /.config ./ $ make oldconfig (실행후 선택문 모두 엔터) • 또는 $ make menuconfig (범용적 커널 설정 스크립트 실행) -*- Networking supprot - - - > (Select) WiMax, RF switch subsystem 체크 해제 • 또는 $ make xconfig (그래픽 환경)

  10. 커널 수정 (5) • 커널 컴파일 • 옵션은 아래 사이트 참고 http://doc.kldp.org/KoreanDoc/html/Kernel24_Intro-KLDP/Kernel24_Intro-KLDP-2.html $ make bzImage (컴파일, 새 커널 생성) • 커널 인스톨 • 모듈로 구성된 커널 내부 구성 요소를 알려주고, 이후 구성 요소들이 사용될 때 자동으로 커널에 적재되게 함 $ make modules (모듈 컴파일) $ make modules_install (모듈 인스톨) • 생성된 커널을 /boot 디렉토리에 복사 $ make install (아래 작업 자동 수행) [ $ cp arch/x86/boot/bzImage /boot/vmlinuz-2.6.38.6 ] [ $ cp System.map /boot/System.map-2.6.38.6 (새 System.map으로 대치 ) ] • 부트로더 설정 $ vi /etc/grub.conf default=0 title Fedora (2.6.38.6) mylinux /* title 수정 */ $ reboot 부팅시에 F5로 커널 선택화면 전환 후 부트로드에서 새로 컴파일 한 커널 선택 후 부팅

  11. 실습 0: newsyscall() • 라이브러리 작성(선택사항) • $ gcc –c newsys.c • $ ar –r libnew.a newsys.o • $ ranlib libnew.a • $ vi test.c • $ gcc test.c –L /root(libnew.a 있는 디렉토리) -lnew • $ ./a.out • /* contents of newsys.c */ …독립된 파일 • #include <linux/unistd.h> • #include <errno.h> • call() • { • return syscall(__NR_newsyscall); • } • /* contents of test.c */ …독립된 파일 • main() • { • int i; • i = call(); • } • 사용자수준응용 test.c 작성 #include <linux/unistd.h> #include <errno.h> #include <stdio.h> main() { int i; i=syscall(__NR_newsyscall); printf(“%d\n”, i); } $ gcc –o test test.c 컴파일 $./test 실행 • 결과 확인 방법 • $ dmesg | tail • Control-Alt F5consol 모드 전환 login: root Password: u***l**** Control-Alt F1graphic 모드복귀

  12. 실습 1: sys_gettaskinfo() • sys_gettaskinfo() 라는 커널정보를 출력하는 새로운 시스템 호출(342번) 구현 • current(/usr/src/kernels/mylinux/arch/x86/include/asm/current.h : 17행)라는 전역 변수가 task_struct (/usr/src/mylinux/include/linux/sched.h : 1167행) 자료구조를 포인팅 • $ vi /usr/src/kernels/mylinux/kernel/gettaskinfo.c • #include <linux/linkage.h> • #include <linux/unistd.h> • #include <linux/errno.h> • #include <linux/kernel.h> • #include <linux/sched.h> • asmlinkage int sys_gettaskinfo() • { • int i,cnt =0; • printk("PID: %d\n",current->pid); • printk("PPID: %d\n",current->parent->pid); • if(current->state == -1) printk("Unrunable state\n"); • else if (current->state == 0) printk("Runable state\n"); • else if (current->state == 1) printk("Interruptable state\n"); • else if (current->state == 2) printk("Uninterruptable state\n"); • else if (current->state == 4) printk("Stopped state\n"); • else if (current->state == 8) printk("Zombie state\n"); • else if (current->state == 16) printk("Dead state\n"); • else printk("Unkown sate\n"); • printk("Priority: %lu\n", current->rt_priority); • printk("Scheduling Policy: %lu\n",current->policy); • printk("User CPU time: %lu ticks\n", current->utime); • printk("System CPU time: %lu ticks\n", current->stime); • printk("Start time: %lu \n", current->start_time); • printk("Number of major faults: %lu\n", current->maj_flt); • printk("NUmber of minot faults: %lu\n", current->min_flt); • return(0); • } • 사용자 응용 test1.c 작성 • #include <linux/unistd.h> • #include <errno.h> • #include <sys/syscall.h> • main() • { • int i; • i=syscall(__NR_gettaskinfo); • } /* 커널 구성 하지 않고 시스템 호출만 추가 */ $ make bzImage $ cp arch/x86/boot/bzImage /boot/vmlinuz-2.6.38.6 $ reboot

  13. next_task prev_task next_task prev_task prev_task init_task … task_struct task_struct 태스크 리스트

  14. 실습 2: getstat() • sys_getstat(int id, struct mystat *user_buf) 시스템 호출(342번) 구현 • [참고서적] 리눅스 매니아를 위한 커널 프로그래밍 p70~74 • /* 헤더 파일 mystat.h */ • struct mystat { • int pid; • int ppid; • /* • * pid_t pid; • * pid_t ppid; • */ • int state; • int priority; • int policy; • long utime; • long stime; • long starttime; • unsigned long min_flt; • unsigned long maj_flt; • int open_files;};

  15. 실습 2 • 사용자 응용 test2.c • #include <linux/unistd.h> • #include <stdio.h> • #include <errno.h> • #include "mystat.h" • #include <stdlib.h> • struct mystat *mybuf; • int i; • int main(int argc, char* argv[]) • { • int task_number; • if(argc != 2) • { • printf("USAGE: a.out pid\n"); • exit(1); • } • task_number = atoi(argv[1]); • mybuf = (struct mystat *)malloc(sizeof(struct mystat)); • if(mybuf == NULL) • { • printf("Out of Memory\n"); • exit(1); • } • printf("PID %d\n",task_number); • i = syscall(__NR_getstat, task_number, mybuf); • printf("%d\n", i); • printf("PID = %d\n", mybuf->pid); • printf("PPID = %d\n", mybuf->ppid); • if(mybuf->state == -1) printf("Unrunable state\n"); • else if(mybuf->state == 0) printf("Running state\n"); • else if(mybuf->state == 1) printf("Interruptable state\n"); • else if(mybuf->state == 2) printf("Uninterruptable state\n"); • else if(mybuf->state == 4) printf(" Stopped state\n"); • else if(mybuf->state == 8) printf(" Zombie state\n"); • else if(mybuf->state == 16) printf("Dead state\n"); • else printf("Unknown state\n"); • printf("Priority = %d\n", mybuf->priority); • printf("Policy = %d\n", mybuf->policy); • printf("Task.utime = %lu\n", mybuf->utime); • printf("Task.stime = %lu\n", mybuf->stime); • printf("Task.starttime = %lu\n", mybuf->starttime); • printf("minor fault = %lu\n", mybuf->min_flt); • printf("major fault = %lu\n", mybuf->maj_flt); • printf("opened files = %lu\n", mybuf->open_files); • return 0; • } • 시스템 호출 처리함수 getstat.c • /* getstat.c */ • #include <linux/unistd.h> • #include <linux/errno.h> • #include <linux/sched.h> • #include <../arch/x86/include/asm/uaccess.h> • #include "mystat.h" • #include <linux/slab.h> • #include <linux/file.h> • asmlinkageintsys_getstat(int id, structmystat *user_buf) • { • structmystat *buf; • inti = 0, cnt = 0; • structtask_struct *search; • search = &init_task; • while(search->pid != id) • { • search = list_entry((search)->tasks.next, structtask_struct, tasks); • if(search->pid == init_task.pid) • return(-1); • } • buf = kmalloc(sizeof(structmystat), GFP_KERNEL); • if(buf == NULL) • return(-1); • buf->pid = search->pid; • buf->ppid = search->parent->pid; • buf->state = search->state; • buf->priority = search->rt_priority; • buf->policy = search->policy; • buf->utime = search->utime; • buf->stime = search->stime; • buf->min_flt = search->min_flt; • buf->maj_flt = search->maj_flt; • copy_to_user((void *)user_buf, buf, sizeof(structmystat)); • return 0; • }

  16. 커널 컴파일과 커널 교체 • 기존의 컴파일된 커널을 수정된 커널로 교체할 때 사용한다 • 모듈 컴파일이 완료 된 상태에서 모듈 설정없이 커널만 수정할 경우 모듈 컴파일은 하지 않고 커널 컴파일과 커널 교체 작업만 한다 • $ pwd • /usr/src/kernels/mylinux • $ make mrproper (기존의 커널 설정 제거) • $ cp ../2.6.38.6-26.rcl.fc15.i686.PAE/.config ./ • $ make oldconfig (실행 후 선택문 모두 [Enter]) • $ make bzImage • 생성된 커널을 /boot 디렉토리에 복사 • $ make install (아래 작업 자동 수행하고새 커널 버전 생성) • [ $ cp arch/x86/boot/bzImage /boot/vmlinuz-2.6.35.6 ] • [ $ cp System.map /boot/System.map-2.6.35.6 (새 System.map으로 대치 ) ] • 새 커널 버전 생성 원하지 않으면 커널 이미지만 복사 • $ cp arch/x86/boot/bzImage /boot/vmlinuz-2.6.35.6 • 부트로더 설정 • $ vi /etc/grub.conf • default=0 • title Fedora (2.6.38.6) mylinux • $ reboot (부팅시에 F5로 커널 선택화면 전환 후 부트로드에서 새로 컴파일 한 커널 선택 후 부팅)

More Related