Linux 커널, Busybox 빌드 후 QEMU에서 실행하기(2/2)

May 23, 2019    #kernel   #buildroot   #busybox  

지난 번 포스팅에서는 단순하기 initramfs 램디스크를 만들어 busybox에 올리는 방법을 기술했었다. 그러면서 램디스크가 무엇인지 busybox는 무엇인지, 그리고 대략적인 빌드 디렉토리 구조를 파악할 수 있었던 기회였다.

두 번째 포스팅에서는 직접 busybox를 빌드하지 않고 crosstool-ng라는 크로스 컴파일러 생성 스크립트 도구와 buildroot라는 Makefile 패키지를 이용하여 램디스크를 만드는 방법에 대해 기술하겠다.

Crosstool-ng 이용하여 크로스 컴파일러 만들기

crosstool-ng는 미리 설정된 config를 이용해 손쉽게 크로스 컴파일러를 만들 수 있는 패키지이다. 이를 어떻게 이용하는지 자세히 설명하겠다.

먼저 crosstool-ng를 받는다. 이 때, 깃허브 에 있는 경로를 이용해 직접 받아쓰는 경우가 있을텐데 만약, 받아쓰는 경우라면 반드시 릴리즈 버전으로 checkout해서 사용해야 한다. master로 그냥 받아서 사용하면 이상한데서 고생하게 된다. git을 사용하지 않는 경우는 여기 를 통해 홈페이지에서 직접 받아서 사용할 수 있다.

$ git clone https://github.com/crosstool-ng/crosstool-ng $ git fetch –all $ git checkout tags/crosstool-ng-1.24.0-rc3

압축을 푼 후 내부에서 아래와 갈이 설정해준다.

$ ./configure –local $ make $ make install

이제 크로스컴파일러를 만들어보자. 컴파일러 생성을 위해 필요한 패키지(binutls, glibc, gcc, mpc, flex..등등)들을 자동으로 다운로드하고 빌드한다. 예전 LFS(Linux from scratch)에서 이 방법을 썼다면 정말로 편하게 작업할 수 있었을텐데 하는 아쉬움이 남는 순간이었다.

아래와 같이 list-samples 옵션을 주어 실행하면 사용 가능한 샘플 목록들이 출력된다. 여기에 없다면 앞으로 수행할 menuconfig에서 필요한 설정들을 직접 해주어야 한다.

root@19893213a218:~/Workspaces/crosstool-ng# ./ct-ng list-samples Status Sample name (생략) … [L…] x86_64-multilib-linux-gnu [L..X] x86_64-multilib-linux-musl [L…] x86_64-multilib-linux-uclibc [L..X] x86_64-w64-mingw32,x86_64-pc-linux-gnu [L…] x86_64-ubuntu12.04-linux-gnu [L…] x86_64-ubuntu14.04-linux-gnu [L…] x86_64-ubuntu16.04-linux-gnu [L…] x86_64-unknown-linux-gnu [L…] x86_64-unknown-linux-uclibc [L..X] x86_64-w64-mingw32 [L..X] xtensa-fsf-elf [L…] xtensa-fsf-linux-uclibc

L (Local) : sample was found in current directory G (Global) : sample was installed with crosstool-NG X (EXPERIMENTAL): sample may use EXPERIMENTAL features B (BROKEN) : sample is currently broken O (OBSOLETE) : sample needs to be upgraded

커널 해킹을 위한 것이지만 임베디드용 커널을 살펴볼 것은 아니기 때문에 필자는 x86_64-unknown-linux-gnu를 선택하였다.

$ ./ct-ng x86_64-unknown-linux-gnu $ ./ct-ng menuconfig # 옵션을 추가로 선택할 경우 $ ./ct-ng build

BuildRoot 이용하여 rootfs 만들기

앞서 빌드한 크로스 컴파일러들을 /opt/crosstool/x86_64-unknown-linux-gnu 경로에 설치했다고 가정하고 buildroot를 이용하여 이미지 파일을 생성한다. buildroot 를 이용할 경우 크로스컴파일러를 이용해 컴파일한 응용 프로그램과 커널 모듈을 함께 빌드하여 추가할 수 있기 때문에 용이하다.

$ export BUILDROOT=$OPT/buildroot $ export BUILDROOT_BUILD=$BUILDS/buildroot $ mkdir -p $BUILDROOT_BUILD $ cd $BUILDROOT_BUILD $ touch Config.in external.mk $ echo ’name: mini_linux’ > external.desc $ echo ‘desc: minimal linux system with buildroot’ » external.desc $ mkdir configs overlay $ cd $BUILDROOT $ make O=$BUILDROOT_BUILD BR2_EXTERNAL=$BUILDROOT_BUILD qemu_x86_64_defconfig $ cd $BUILDROOT_BUILD $ make menuconfig

이 후, 아래와 같이 설정해준다. 이 때 중요한 것은 System configuration ---> Network interface to configure through DHCP 부분을 빈칸으로 해줘야한다는 점이다. 기본값이 eth0으로 되어있을텐데, init 스크립트에서 해당 인터페이스가 로드될 때까지 기다리며 없을 경우에는 셸이 실행되지 않게된다.

 1Build options ---> Location to save buildroot config ---> $(BR2_EXTERNAL)/configs/mini_linux_defconfig
 2Build options ---> Download dir ---> /some/where/buildroot_dl
 3Build options ---> Number of jobs to run simultaneously (0 for auto) ---> 8
 4Build options ---> Enable compiler cache ---> yes
 5Build options ---> Compiler cache location ---> /some/where/buildroot_ccache
 6Toolchain ---> Toolchain type ---> External toolchain
 7Toolchain ---> Toolchain ---> Custom toolchain
 8Toolchain ---> Toolchain origin ---> Pre-installed toolchain
 9Toolchain ---> Toolchain path ---> /opt/toolchains/x86_64-unknown-linux-gnu
10Toolchain ---> Toolchain prefix ---> x86_64-unknown-linux-gnu
11Toolchain ---> External toolchain gcc version ---> 5.x
12Toolchain ---> External toolchain kernel headers series ---> 4.3.x
13Toolchain ---> External toolchain C library ---> glibc/eglibc
14Toolchain ---> Toolchain has C++ support? ---> yes
15System configuration ---> System hostname ---> mini_linux
16System configuration ---> System banner ---> Welcome to mini_linux
17System configuration ---> Run a getty (login prompt) after boot ---> TTY port ---> ttyS0
18System configuration ---> Network interface to configure through DHCP --->
19System configuration ---> Root filesystem overlay directories ---> $(BR2_EXTERNAL)/overlay
20Kernel ---> Linux Kernel ---> no
21Filesystem images ---> cpio the root filesystem (for use as an initial RAM filesystem) ---> yes
22Filesystem images ---> Compression method ---> gzip

아래와 같이 설정 저장 후 init 스크립트를 추가해준뒤 빌드한다.

 1$ make savedefconfig
 2$ vim $BUILDROOT_BUILD/overlay/init
 3
 4#!/bin/sh
 5/bin/mount -t devtmpfs devtmpfs /dev
 6/bin/mount -t proc none /proc
 7/bin/mount -t sysfs none /sys
 8exec 0</dev/console
 9exec 1>/dev/console
10exec 2>/dev/console
11cat <<!
12
13
14Boot took $(cut -d' ' -f1 /proc/uptime) seconds
15!
16exec /bin/sh
17
18
19# vim 종료 후 스크립트에 권한 부여
20$ chmod +x overlay/init
21$ make

이제 qemu를 통해 실행시켜보면 정상적으로 실행되는 것을 확인할 수 있다.

1qemu-system-x86_64 -kernel $LINUX_BUILD/arch/x86_64/boot/bzImage \
2  -initrd $BUILDROOT_BUILD/images/rootfs.cpio.gz -nographic \
3  -append "console=ttyS0"

출처