시스템콜 프로그래밍
Kernel vs Application 수행 방법 Kernel mode vs User mode Application Program: 처음부터 순차적으로 수행 Kernel: 응용프로그램을 위한 system call이나 인터럽트 핸들러를 수행하기 위해 비동기 적으로 수행 Kernel mode vs User mode Kernel Program: 모든 것이 허용된다. Application Program: user mode에서 수행되며 하드웨어에 직접 접근하는 것과 메모리에 대한 허용되지 않은 접근이 제한된다. Application Kernel System call Interrupt
Kernel vs Application Address Space Application Program과 Kernel Program은 서로 다른 메모리 매핑법을 가지고 있으며, 프로그램 코드는 서로 다른 address space를 가지고 있다. Kernel address space User address space 1 G byte 4 G byte 매모리 매핑법이란 주소 영역에서 stack 영역과 heap 영역 code 영역 등을 어떻게 사용할 것인가를 정의하는 방법을 이야기한다. 32bit cpu의 경우 4Gbyte 의 주소를 접근할 수 있는 리눅스에서는 이 4Gbyte 중 1Gbyte를 커널의 코드와 자료구조등을 저장하는데 사용하며 나머지 3Gbyte를 사용자모드 프로세스의 코드와 자료구조를 저장하는데 사용한다. 커널 영역에 해당하는 메모리를 사용하는 방식과 사용자 영역에 해당하는 메모리를 사용하는 방식이 다르기 때문에 두 영역에서 사용하는 가상 주소는 서로 다른 물리주소로 맵핑된다. 3 G byte
시스템콜이란? user mode process와 kernel 간의 interface user mode process는 일반적으로 kernel 영역에 직접적으로 접근할 수 없다. kernel의 자료구조 및 hardware 에 대한 접근 불가 user mode process가 kernel이 가지고 있는 시스템의 상태 정보를 열람하거나 hardware에 접근하여 hardware를 통제하기 위해서는 kernel 과의 communication channel이 필요. User Application API(시스템 라이브러리) 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 일반적으로 프로세스는 커널에 직접적으로 접근할 수 없다. 다시 말해, 프로세스는 커널 메모리에 접근한다거나 커널의 함수를 호출할 수 없다. 보호모드. 시스템 콜은 user program에게 커널 영역에 대한 접근을 허용하는 유일한 chanel이다. user program은 시스템 콜을 사용해서만 hardware 및 커널 자료구조에 접근할 수 있다.
시스템콜 동작과정 (POSIX API) (시스템 콜) 시스템콜 인터페이스 Libc 응용 표준 프로그램 라이브러리 시스템 콜 예> 응용프로그램 open() 호출 … sys_open() 호출 (POSIX API) (시스템 콜) 응용 프로그램 Libc 표준 라이브러리 (포장함수) 시스템 콜 핸들러 시스템 콜 서비스 루틴 시스템콜 인터페이스
System Call 추가 따라하기 목적 단계 기존 kernel에서 제공하지 않는 service를 user application에 제공 새로운 System Call 을 만든다. 단계 커널 수정 System Call 번호 할당 System Call 호출 테이블 등록 System Call 호출 함수 구현 Kernel 컴파일 및 target board에 적재 user application 제작 새로 구현한 System Call을 사용하는 application 제작 library 작성(반드시 필요한 것은 아니다.) target board에 적재
System Call 추가 따라하기 가정 /PXA270/kernel/linux-2.6.11-h270-tku_v1.1/ 에 target system용 kernel source code가 있다. 위 디렉토리를 앞으로의 설명에서 [kernel]로 대치한다.
System Call 추가 따라하기 System Call 번호 할당 Linux 커널이 제공하는 모든 시스템 호출은 각각 고유한 번호를 가지고 있다. [kernel]/include/asm-arm/unistd.h 에 각 시스템 호출의 고유 번호에 정의 되어 있다. 새로 추가할 system call의 고유번호 정의 추가 [kernel]/include/asm-arm/unistd.h 파일을 vi로 연다.
System Call 추가 따라하기 다음과 같이 추가할 System Call에 고유번호를 할당한 후 저장하고 나온다. unistd.h 파일의 위 내용을 보면 현재 system call 은 280 개가 있는 것을 확인할 수 있다. 추가할 system call 은 위 화면과 같이281번으로 할당한다. __NR_은 System Call 고유번호를 나타내는 접두어이며 그 뒤의 hybuscall이 추가할 System Call 처리 함수의 이름이다. (sys_hybuscall 이 아님을 주의 깊게 봐 둔다.) 현재 리눅스에서는 256개까지의 시스템 콜을 지원한다.
System Call 추가 따라하기 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 추가 따라하기 entry-comm.S 에서 다음과 같은 부분을 확인할 수 있다. ENTRY(sys_call_table) 다음에 calls.S를 include하고 있다. vi를 나와서 다시 calls.S를 열어 보자.
System Call 추가 따라하기 calls.S 의 내용은 다음과 같다.
System Call 추가 따라하기 다음과 같이 추가할 System Call 처리함수를 등록한 후 저장 하고 나온다. unistd.h에 정의한 번호와 일치
이 함수가 어셈블리 언어로 구현된 함수에서 호출될 때 사용하는 keyword System Call 추가 따라하기 처리 함수 구현하기 System Call 이 발생했을 때 수행될 함수를 구현한다. [kernel]/kernel/test_syscall.c 를 다음과 같이 만든다. calls.S 에 등록한 이름과 동일한 이름 이 함수가 어셈블리 언어로 구현된 함수에서 호출될 때 사용하는 keyword
System Call 추가 따라하기 Makefile 수정 만들어진 처리함수를 커널이 컴파일 될 때에 함께 컴파일 될 수 있도록 [kernel]/kernel/Makefile에 다음과 같이 추가 한다.
System Call 추가 따라하기 Kernel image를 /tftpboot에 복사 [kernel] 디렉토리에서 커널을 컴파일하고 생성된 커널 이미지를 target에 전송하기 위해 /tftpboot로 복사. # cd [kernel] # make menuconfig; make zImage # cp [kernel]/arch/arm/boot/zImage /tftpboot
System Call 추가 따라하기 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); \ } #else #define __syscall(name) “swi\t” __sys1(__NR_##name)”\n\t” 아래쪽에서 오른쪽 창에 보면 __sys1(__NR_##name) 이라고 된 부분이 있는데 여기서 ##은 두 토큰을 결합한다는 의미이다. 즉 name에 “mysyscall” 을 넘겨준 경우 sys1(__NR_mysyscall) 과 같이 된다. Software interrupt를 발생시키는 assemblier Unistd에서 정의한 symbol로 바꿔준다.
System Call 추가 따라하기 Test 앞서 system call을 추가하여 다시 컴파일한 커널 이미지(현재 /tftpboot에 zImage로 존재) 를 target에 download하고 target 을 리눅스로 부팅한 후 host의 /home/share 마운트 시스템콜을 사용하는 프로그램을 실행 ]# ./hybuscall Welcome to the embedded World!!
Kernel 수정 Application 작성 9.2.3 System Call 추가 따라하기 지금까지의 과정을 정리해 보면 다음과 같다. Kernel 수정 Application 작성 unistd.h 에 system call 번호 정의 calls.S 에 System Call 처리함수 등록 system call을 호출하는 application 작성 Application 을 Target system에 download System Call 처리 함수 구현 Kernel 재 컴파일 Applicatin 실행 Kernel을 Target system에 download
LED 점등을 위한 시스템 콜
LED의 점등을 위한 시스템 호출 및 응용프로그램을 작성해 본다. 타겟 시스템에는 8개의 LED가 있다. 각 LED에 0 혹은 1의 값을 출력함으로써 LED를 점등할 수 있다. LED 점등에 필요한 프로그램 혹은 파일(testLED.c, Makefile, calls.S, unistd.h)을 생성 혹은 수정 실습 LED를 다루기 위한 시스템 호출 프로그램 작성
실습 LED를 다루기 위한 시스템 호출 프로그램 작성 - testLED.c : 소스 작성 01 #include <linux/kernel.h> 02 #include <linux/errno.h> 03 #include <linux/ioport.h> 04 #include <linux/linkage.h> 05 #include <asm/io.h> 06 07 #define ADDRESSOFLED 0x12400000 08 #define LED_CS (*((volatile unsigned char *)(led_base))) 09 10 static void *led_base; 11 unsigned long mem_addr, mem_len; 12 13 asmlinkage int sys_testLED(char x) 14 { 15 int status = 1; 16 17 mem_addr = ADDRESSOFLED; 18 mem_len = 0x1000; 19 led_base = ioremap_nocache(mem_addr, mem_len); 20 if( !led_base) { 21 printk("Error mapping LED memory\n"); 22 release_mem_region(mem_addr, mem_len); 23 return -EBUSY; 24 } 25 26 LED_CS = x; 27 return status; 28 }
실습 LED를 다루기 위한 시스템 호출 프로그램 작성 Makefile 수정 calls.S 수정 unistd.h 수정
<linux>에서 커널 이미지 빌드 실습 LED를 다루기 위한 시스템 호출 프로그램 작성 <linux>에서 커널 이미지 빌드 새로운 커널이미지 <linux>/arch/arm/boot/zImage를 /tftpboot에 복사 미니컴 화면에서 타겟 보드를 수동 부팅 zImage를 타겟 시스템에 전송한 후 플래시에 퓨징
실습 응용 프로그램으로 LED 점등 LED 시스템호출 테스트 프로그램(08/testLED/test-LED.c) 작성 01 #include <stdio.h> 02 #include <stdlib.h> 03 #include <errno.h> 04 #include <linux/unistd.h> 05 06 _syscall1(int, testLED, char, x); 07 08 int main(int argc, char **argv) 09 { 10 int status; char val; 11 12 if(argc <= 1) { 13 printf("please enter : ex)./testLED 0xaa\n"); 14 return -1; 15 } 16 17 if(argv[1][0] == '0' && (argv[1][1] == 'x' || argv[1][1] == 'X')) 18 val = (char)strtol(&argv[1][2],NULL,16); 19 else 20 val = (char)atoi(argv[1]); 21 22 status = testLED(val); 23 return status; 24 }
실습 응용 프로그램으로 LED 점등 Makefile 작성 1 KDIR = /embed/kernel/linux/include 2 CFLAGS := -I$(KDIR) 3 4 test-LED : test-LED.c 5 arm-linux-gcc $(CFLAGS) -o test-LED test-LED.c 6 7 clean: 8 rm -f test-LED
타겟 시스템에서 전송된 응용 프로그램을 실행해 LED가 변화하는 모습을 관찰 테스트 프로그램 컴파일 미니컴을 이용해 타겟 시스템으로 전송 타겟 시스템에서 전송된 응용 프로그램을 실행해 LED가 변화하는 모습을 관찰