본문 바로가기

L I N U X

Step By Step 커널 프로그래밍 강좌 ① 커널프로그래밍의환


커널프로그래밍의환경구축

 

 

 강좌는 커널 프로그래밍에 관심을 가지고 있는 입문자들을 위한 것이다하지만 아무리 입문자라고 해도 리눅스에 대해 전혀 모르고 있다면  강좌를 이해하기 쉽지 않을 것이다따라서  글을 보고 있는 독자라면 리눅스에서 Application 프로그래밍을   이상 해봤다는 가정 아래 강좌를 진행하고자 한다구체적으로 말하자면 gcc vi 정도는 사용할  있으며

기본적인 리눅스 명령어들을 알고 있는 분들을 말한다커널 프로그래밍  회에서는 커널 프로그래밍을하기 위한 환경구축및 커널 패치하기커널 프로그래밍의 특징 등에 대해 살펴보도록 한다.

 

 _ 민찬 KLDP 멤버전문 프로그래머

 

 

앞으로의 연재 순서

① 커널 프로그래밍의 환경 구축

② 모듈 구현하기

③ 커널의 동기화에 관하여

④ 커널의 시간관리  지연 함수에 대하여

⑤ 파일시스템과 proc file system 사용하기

⑥ 디버깅 기술에 관하여

 

 

커널 프로그래밍 개발환경 구축

 5~6 전만 해도 리눅스 커널을 적절하게 다시 빌드하는 것은 그리 만만한 작업이 아니었다하지만 요즘의 리눅스 배포판들은 굉장히 쉬운 방법으로 리눅스 커널을 빌드할  있게 했다심지어는 그것을 패키지 형태로 만들어 다른 컴퓨터에 복사함으로써 단순한 설치명령어를 실행하는 것만으로도 리눅스 커널을설치할  있도록 하고 있다.

여기서 필자는 커널 프로그래밍의 환경 구축을 위해 현재 리눅스 데스크탑용으로 가장 인기를 끌고 있는우분투(ubuntuedgy) 6.10 desktop 용을 사용할 것이다우분투는 iso 이미지 형태로 다음의 URL 페이지에서 다운로드할  있다 (http://releases.ubuntu.com/6.10/

 ftp://ftp.kaist.ac.kr/ubuntu-cd/edgy/). 우분투를 설치하는 것은 윈도우를 설치하는 것만큼이나 쉽다. 심지어는 윈도우와 멀티 부팅 환경도 스스로 만들어 준다.

우리가 해야  것은 ISO image CD 만들어서 설치하면 그만이다또는 필자와 같이 vmware 같은툴을 활용하면 ISO파일을 그대로 이용해 윈도우에서 설치할 수도 있다우분투에 관한 내용들은 다음의 URL 많은 정보들이 있다. ( http://www.ubuntu.or.kr/wiki.php/FrontPage)

우분투의 설치가 끝났다면 기본적으로 일반 사용자로 로그인이 되어 있을 것이다커널 컴파일을 위해서는 root 사용자의 권한이 필요하다. sudo 명령을 사용하여 커널을 빌드할 수도 있지만 쉽게 하기 위해 root 로그인을 다시 하도록 한다. root로의 login 다음의 명령을 통해   있다.

 

 

sudo i

 

우분투 6.10에는 기본적으로 /bin/sh /bin/dash 심볼릭링크로 되어 있다이것으로 인하여 소스를 컴파일 하는데 간혹 문제가 생기는  같다다음의 명령을 통해 /bin/bash를 사용할  있게 바꾼다

 

rm f /bin/sh

ln s /bin/bash /bin/sh

 

 

다음으로 apt-get 이용하여 현재 시스템의 모든 패키지들 최신으로 update한다.

 

apt-get update

 

이번에는 자신이 현재 사용하고 있는 커널의 버전을 확인해 보자커널 버전은 다음의 명령을 통해 확인해   있다.

 

 

uname -r

 

 

아마도 우분투 6.10이나  이하의 버전을 사용하고 있는 자중 직접 커널을 업데이트하지 않은 독자라면 현재 2.6.17-10 버전 이하의 리눅스 커널을 사용하고 있을 것이다.

 

 

리눅스 커널 버전 관리

2.6.18 = major.minor.release

 

 

2.6.18이라하면 major번호가 2이고 minor 6, 그리고 18번째라는 것이다, 2.6 18번째 릴리즈된 버전이라는 또한 리눅 의 minor 버전은 커널이 안정된 버전인지 개발 중  버전인지를 나타낸다안정된 버전은 짝수를 가지며 개발중인 버전은 홀수를 갖게 된다일반적으로 짝수와 홀수 버전은 커널 아카이브 트리에 공존한다.

예를 들어 2.4 짝수 minor 버전을 가진 새로운 커널이 릴리즈되면 2.5 홀수 버전을 가진 개발버전이2.6 준비하며작업에 들어간다. 2.5에서 개발 중인 개발 버전들이 많은  추가와 테스트를 통해 안정화되면 2.4 릴리즈 버전들이 점차 올라가며 2.5 기능들이 추가되고 버그들이 수정되어 나간다 2.4.1, 2.4.2, 2.4.3 이런 식으로 올라가게 되는 것 이다현재는 우리가 사용하고 있는 커널의 minor 번호는 6 이니 안정된 버전이라고   있다.

하지만 2.6으로 오면서 변화가 생겼다. 2.6대의 커널이 릴리즈되면 2.7 2.8 준비해야 하는 커널 아카이브 트리가 생겨야 하지만 현재 그렇지가 않다. 2004 Linux Kernel Developer Summit에서  이상 그런 개발방법으로 진행하지 않기로 결정했기 때문이다. 2.6커널은 충분히 안정화되어 있고 홀수 버전을 만들어야  만큼  기능변화가 없을 것이 라는 판단에서이다. 지금부터 우리는 현재 커널을 2.6.18 버전으로 업그레이드 할 것이다먼저 시스템에 커널을 빌드하고빌드된 커널을 데비안 패키지로 만들기 위한 툴들을 설치해야 한다콘솔에서 다음 명령을 통해 그러한 툴들을 설치할  있다.

 

 

apt-get install kernel-package

libncurses5-dev fakeroot

wget bzip2

 

 

이번엔 우리가 빌드하게  2.6.18버젼의 커널 소스를 다운로드 하도록 하자우리는 wget 사용할 것이다하지만 wget install되어 있지 않은 분들은 웹브라우저를 통해서도 아래  URL에서 다운로드할  있다.

 

 

cd /usr/src

wgethttp://www.kernel.org/pub/linux/kernel/v2.6/

linux 2.6.18.tar.bz2

 

 

이것으로 커널의 빌드를 위한 환경구축은 끝마쳤다.

 

 

 

커널 빌드

이번에는 다운로드 받은 새로운 커널을 빌드하기 위해 /usr/src 디렉토리에 압축을 해지한  linux 이름으로 심볼

 링크를 만든  새로운 커널의 소스 디렉토리로 이동한다.

 

 

tar xjf linux-2.6.18.tar.bz2

ln -s linux-2.6.18 linux

cd /usr/src/linux

 

지금부터는 커널 컴파일에 앞서 자신의 시스템 환경에 맞게 커널을 설정하는 과정이다사실 커널 빌드를위해 설정하는 과정이 커널 빌드에 있어 제일 복잡하고 어려운 과정이다왜 냐하면 자신의 시스템의 모든 하드웨어와  하드웨어 연결관계를 모두 알고 있어야 하기 때문이다또한 하드웨어와 관련된 커널 설정들도 일일이 설정해줘야 자신의 시스템에 맞  가장 알맞은 형태의 커널을 구성할  있다.

하지만 이러한 모든 지식을 갖기 위해서는 많이 시간을 투자해야 한다대부분의 배포판에는 위와 같은 설정을 가지고 있는 파일이 이미 있다물론 자신의 시스템에 최적화된 config 파일은 아니다단지 일반적으로 사용할  있는 config 파일일 뿐이다그러므로 불필요한 설정을 포함하고 있는 경우도 많이 있다하지만 강좌를 쉽게 만들기 위해 우리는 배포판에

이미 있는 config 파일을 사용하도록  것이다 config파일을 자신의 환경에 최적화할  있게 불필요한 것은  빼서 날씬하게 만드는 일은 여러분들의 몫이다. ( 오래되긴 했지  다음의 글을 보면 많은 도움이  것이다.

http://kldp.org/KoreanDoc/html/Kernel-KLDP/)

 

 

 

커널을 빌드할  사용되는 kbuild config파일을 통해 커널설정을 하게 된다. config 파일을 만드는 방법은 크게 3가지가 있다.

 

 

 

● make config : 텍스트를 기반으로 사용자가  질문에 대하여 대답하는 방식

● make menuconfig : 텍스트 기반 curses 라이브러리 사용하는 방식

● make xconfig : X윈도우 기반의 방식

 

 

우리는  방식  make menuconfig 사용할 것이다. 먼저 아래의 명령을 통해 현재 디렉토리/usr/src/linux 배포판의 config 파일을 .config라는 이름으로 복사하도록 하자.

(다른 배포판들도 이와 유사한 config 파일을 /boot 디렉토리나 커널 소스에 설치했다면 /usr/src/config등에 들어 있을 것이다.)

 

 

cp /boot/config-`uname r` ./.config

 

 

이번에는 복사된 .config 파일을 커널 설정에 반영할 차례이다. make menuconfig 통해 .config 파일을읽어 들인다. 먼저 Load an Alternate Configuration File 항목으로 들어 간다.

 

 

 

이번에는 .config 파일을 입력하여 .config파일을 읽어 들인다.

 

 

마지막으로 설정을 저장하고 빠져나온다.

 

이제 커널을 빌드할 차례이다우분투에서는 컴파일을  때 다음과 같은 방법을 통해 우분투 패키지로 커널 이미지와 커널 헤더파일을 만들어 내는 것을 권장한다현재는 계속 /usr/src/linux 디렉토리다.

 

make-kpkg clean

make-kpkg --initrd --append-to-version=

-barrios kernel_image kernel_headers

 

 

make-kpkg clean 과정은 처음으로 커널 소스의 압축을 풀어 새롭게 빌드를 시작하는 경우에는 필요하지않은 과정이  다 명령을 수행하게 되면 커널 소스 디렉토리에 있는 이전  빌드했던 오브젝트 파일들을 제거한다. 다음으로 append-to-version 들어갈 내용은 항상 -(하이픈부호) 시작해야하며 어떤 공백도 들어가선  된다 이름은 커널을 구분짓기 위한 이름이니 자신이생각해서 알맞은 이름으로 넣으면 된다커널의 빌드과정이 끝나게 되면 /usr/src 디렉토리에는 다음과 같은 2개의 .deb 패키지 형태의 결과물이 나오게 된다.

 

 

● linux-image-2.6.18-barrios_2.6.18-barrios-

10.00.Custom_i386.deb

● linux-headers-2.6.18-barrios_2.6.18-barrios-

10.00.Custom_i386.deb

 

 

 번째 파일은 실제 커널 이미지를 포함하고 있는 파일로서 이 파일을 설치하면 커널이 시스템에 설치되는 것이다.  번째 파일은 나중에 모듈만 새로 추가할  필요한 커널  파일을 설치하는 것이다.  파일을 아래와 같은 명령으로 설치할  있다.

dpkg i linux-image-2.6.18-barrios_2.6.18-

barrios-10.00.Custom_i386.deb

dpkg i linux-headers-2.6.18-barrios_2.6.18-

barrios-10.00.Custom_i386.deb

 

 이제 새로운 커널의 설치가 끝났다정말 간단하지 않은 가재부팅을   커널 버전을 확인해보자.

 

커널 설치 후의 변화들

우리는 위에서 만든 커널의 설치로 인해 우리의 시스템에는 어떤 변화가 있어났는지를 알아야  필요가 있다그래야만

우분투가 아닌 다른 시스템에서도 커널 업그레이드를 진행할  있을 것이다사실  패키지 형태로 커널을 설치할 때는 

 빌드에 필요한 다음과 같은 과정을 건너   있다일반적 으로 커널을 빌드할 때는 다음의 명령어 순으로 진행하기 

련이다.

 

 

일반적인 커널 빌드 절차

make clean

make

make modules_install

cp arch/i386/boot/bzImage /boot/vmlinuz-2.6.18-barrios

cp System.map /boot/System.map-2.6.18-barrios

cd /boot

mkinitramfs 2.6.18-barrioso /boot/initrd.img-2.6.18-barrios

 

 

/boot 디렉토리를 살펴보면다음과 같은 파일들이 생긴 것을 알  있다.

 

● config-2.6.18-barrios : 새로운 커널의 config 파일

● initrd.img-2.6.18-barrios : 새로운 커널이 사용하게 될 initramfs 파일

● System.map-2.6.18-barrios : 새로운 커널의 커널 함수들의 주소가 저장되어 있는 파일(나중에 디버깅을 위해 사용됨)

● vmlinuz-2.6.18-barrios : 새로운 커널의 압축 이미지가 들어있는 바이너리

 

 

또한 /lib/modeuls 디렉토리에는 다음과 같은 디렉토리가 생겨  것을   있다일반적인 컴파일 방법으로 는 make modules_install 실행하면 생성되는 디렉토리이다.

● 2.6.18-barrios : 새로운 커널의 모듈들이 들어있는 디렉토리

 

 

마지막으로 /boot/grub/menu.lst에는 다음과 같은 항목이 추가된 것을   있다.

 

 

title Ubuntu, kernel 2.6.18-barrios

root (hd0,0)

kernel /boot/vmlinuz-2.6.18-barrios

root=/dev/sda1 ro quiet splash

initrd /boot/initrd.img-2.6.18-barrios

quiet

savedefault

boot

title Ubuntu, kernel 2.6.18-barrios

(recovery mode)

root (hd0,0)

kernel /boot/vmlinuz-2.6.18-

barrios root=/dev/sda1 ro single

initrd /boot/initrd.img-2.6.18-barriosboot

 

 

이들은 새로운 커널로 부팅할  있도록 grub(부트로더)에게 알리는 역할을 한다.

 

 

커널 패치하기

다음으로 우리는 커널 패치(Patch) 대해서 알아보도록 한다커널 개발자들은 커널의 새로운 기능이나버그들을 패치파일의 형태로 만들어서 전달한다. 그렇기 때문에 자신의 커널을 업그레이드(새로운 기능을 추가기존의 버그 해결)하기 위해서는 커널을 패치하는 방법에 대해 알고 있어야 한다. 패치를 하기위해서는 기본적으로 patch라는 명령을 사용한 . patch 명령을 사용하는 방법은 간단하다. patch 명령에 리다이렉션을 이용해 입력으로 패치 파일을주면 된다. 우리는 현재 2.6.18 커널 버전에서 2.6.19-rc4 우리의 널을 업그레이드해볼 것이다커널 업그레이드를 위해 prepatch 파일을 사용할 것이다.

 

 

prepatch?

prepatch 리눅스 커널의 업데이트를 위한 알파 버전이라고 보면 된다 안정적인 버전이 릴리즈되기  여러개발자들에게 테스트를 부탁하는 커널 버전이다그래서 시간이 흘러 버그들이  보고되고 수정되면 새로운 안정적인(Stable) 버전이 나오게 되는 것이다.

 파일들은 리눅스 커널의 archive testing 디렉토리에 존재한다.(http://www.kernel.org/pub/linux/kernel/v2.6/testing/) prepatch 파일을 적용하는 데는 규칙이 있다. prepatch 파일의 이전 버전의 fullrelease 커널에 적용해야 한다는 것이다즉 prepatch-2.6.19-rc3 라면 linux-kernel 2.6.18 적용해야 한다는 것이다. 2.6.18.1이나 2.6.18.2 같은 커널에 적용해서는  된다. rc Release Candidate 약자로써Linux Tovalds 의해 릴리즈 후보가  것이다.

 

 

다음의 명령을 통해 패치 파일을 다운로드할  있다.

 

cd /usr/src

wget http://www.kernel.org/pub/linux/kerne

/v2.6/testing/patch-2.6.19-rc6.b

 

다운로드가 끝났다면 이번에는 다시 우리의 커널 소스 디렉토리로 이동해 다음 명령을 통해 패치파일이이상 없이 적용가능한지 확인해 보고 이상이 없으면 실제로 패치파일을 적용한다.

 

cd /usr/src/linux

bzip2 dc /usr/src/patch-2.6.19-rc6.bz2 |

patch -p1 dry-run

bzip2 dc /usr/src/patch-2.6.19-rc6.bz2 |

patch -p1

 

 번째 명령은 실제로 패치파일을 적용하는 것은 아니다단지 실제로 하는 것처럼 수행해보고 이상 유무를 보고할 뿐이다패치를 이상 없이 끝마쳤다면 위의 커널 빌드 과정을 반복하여 다시 커널을 설치해보자.

 

 

커널 프로그래밍의 특징

지금까지 우리는 커널 프로그래밍에 앞서 커널을 새로 빌드하는 방법커널에 패치를 적용하는 방법들을살펴보았다마지막으로 우리는 실제 커널 프로그래밍에 들어가기에 앞서 커널프로그래밍이 일반 응용어플리케이션 프로그래밍과 다른 , 그리고 커널 프로그래밍을  시작하려는 독자들을 위해 몇몇웹사이트들을 소개하며 이번  강좌를 마무리 지려고 한다.

일반적으로 커널 프로그래밍은 어렵다고 생각한다 그렇게 생각하는 것일까당연히 커널 프로그래밍을 하기 위해서는 리눅스 커널에 관한 많은 지식들을 가지고 있어야만 한다어도 자신이 지금 하려는 것이 커널의 어떤 서브 컴포넌트들과 어떤 인터페이스들을 통해 동작하는지 정확히 이해하고 있어야만 한다하지만 이러한 것들은 지금  커널 프로그래밍

 입문하는 사람들에게는 별로  닿지 않을 것이다. 이러한 문제들은 프로젝트를 진행하며 점차 커널에관한 지식을 쌓아가며 또는 사전에 충분한 스터디를 통해 해결해야 할 문제들이다그러한 문제들은 결코  시간에 해결할  있는 문제가 아니라는 것이다그보다 먼저 부딪히는 문제들은 다음과 같다.

첫째라이브러리와 시스템콜을 사용할  없다처음 입문하는 커널 프로그래머들에게 가장 먼저 다가오는 괴로움은 응용프로그래밍에서와 같이 많은 라이브러리와 시스템콜(System Call) 등을 사용할  없다는 것이다예를 들어 커널에서 어떤 file 만들고 싶다면 어떻게  것인가응용프로그램들처럼 open 시스템콜을 사용할 것인가물론 불가능하다.

둘째커널이 죽는다면 어떻게 디버깅을  것인가커널에는 fault 나면 그것을 해결해  만한 화려한도구가 있지 않다. 임베디드 환경은 더욱 그렇다그나마도   없지만 x86 스템에서  동작하는 커널 디버깅 툴들이 대부분 arm이나 mips 등의 임베디드 환경에서는 동작하지 않는 경우가 많다. 그래서 대부분 커널 개발자들은 printk 같은 원시적인 방법

 의존하고 있는 것이 사실이다하지만 x86환경에서는 보다 좋은 툴들이  가지 있다.

셋째커널은 한정된 스택 사이즈를 갖는다일반 응용 프로그램들은 동적으로 증가될  있는 스택을 갖는다(물론 한계는있다). 반면커널은 기본적으로 8K 스택을 갖는다또한 적으로 커질 수도 없다하지만 현재 x86에서는 8K 너무 커서스택 사이즈를 4K 줄이는 패치가 들어가 있다그러므로 커널 프로그래밍에서는 절대적으로 스택을 아껴서 사용해

 한다게다가 커널 스택은 자신만이 사용하는 것이 아니다. 커널의 여러 Kernel Control Path에서  프로세스의 스택을 공유하여 사용할  있으므로특정 Path에서 너무 많은 스택 사용하게 되면 나중에 사용하게  Path에서는  이상 사용할  있는 공간이 남아 있지 않게 된다문제에 대해서는 나중에 소개할 기회가 있을 것이다기억해야  것은스택은

절대 4K 이상 넘어갈  없다또한 내가 사용하는  스택은 나 혼자만 쓰는 것이 아니다라는 점이다. 넷째로커널에는 메모리 보호장치가 없다는 것이다응용 로그램은 리눅스의 MMU(Memory Managet Unit) 이용한 가상 페이지 할당방식으로 인해 절대 다른 프로세스의 주소를 침범할  없다또한 자신의 주소 공간에서도 금지된(illegal)주소 공간을 침범하게 되면 커널은 error 잡아내고  프로세스에게 신호(Signal) 전달한다.

 신호에 대해서 대비하여 놓지 않은 일반 프로세스들은 Segment Fault 일으키며 죽게 된다다른 프로세스들은 절대 영향을 받지 않으며 자신들만의 주소공간에서 안정적으로 실행되고 있을 것이다하지만 커널 프로그래밍은 상황이 전혀 다르다커널이 금지된(illegal) 메모리 주소에 접근하게 되면 결과는 Oops라는 형태로 나타나게 된다. Oops 인하여 커널이 죽게 되면 시스템이 다운되는 것이다이것은 어떤 환경에서도 용납될  없는 문제이다마치 윈도의 블루스크린과 같다

 

 

필자 김민찬 씨는 운영체제에 많은 관심을 갖고 연구해 왔으며 현재는 kldp.org(리눅스 한글 문서화 프로젝트멤버로 활동하며리눅스 커널과 glibc 관련된 개발 업무를 담당하고 있다.

 

 

출처 : 공개 SW 리포트 7호 페이지 52 ~ 57 발췌(2007 6) - 한국소프트웨어 진흥원 공개SW사업팀 발간