본문 바로가기
Xilinx SoC

Raspberry Pi Linux Kernel을 Qemu에서 실행

by 코딩스미스 2021. 9. 23.

개요

라즈베리파이 전용 리눅스 커널 소스코드를 ARM 크로스 컴파일하여 QEMU에서 동작한다.

리눅스 배포판은 사용하지 않으며, 파일시스템과 init 초기 쉘 스크립트는 크로스 컴파일한 Busybox를 사용하여 구성한다.


리눅스 커널 빌드

라즈베리파이 사이트에서 관련 내용을 확인할 수 있다.

 

Raspberry Pi Documentation - The Linux kernel

The official documentation for Raspberry Pi computers and microcontrollers

www.raspberrypi.org

sudo apt install git bc bison flex libssl-dev make libc6-dev libncurses5-dev
git clone --depth=1 https://github.com/raspberrypi/linux

cd linux
KERNEL=kernel7
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- bcm2709_defconfig

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- zImage modules dtbs

크로스 컴파일은 프로그램을 직접 모아서 원하는 타겟 전용으로 빌드할 수 있다. 또한 크로스 컴파일을 자동화할 수 있는 툴(crosstool-ng, ptxdist)의 도움을 받아 만들 수 있다. 가장 간편한 방법은 우분투 아파치 서버에서 다운받아 설치하는 방법이다.

sudo apt install gcc-arm-linux-gnueabi g++-arm-linux-gnueabi gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf
sudo apt install crossbuild-essential-arm64 crossbuild-essential-armel crossbuild-essential-armhf

라즈베리는 ARM코어를 사용하므로 ARM전용 gcc,g++를 설치할 수 있다. 어미에 -hf가 있는 컴파일러는 최적화전용을 의미하는 듯하다. 해당 컴파일러를 묶어서 일괄 설치할 수 있도록 crossbuild-essential-arm***가 준비되어 있으므로 선택하여 설치하면 된다. 이 편에서는 32비트 arm 빌드를 할 예정이지만, 64비트 arm 빌드를 할 경우에는 gcc-aarch64-linux-gnu, g++-aarch64-linux-gnu 혹은 crossbuild-essential-arm64 를 설치하면 될 것이다. 

 

라즈베리파이 커널 소스를 받고, 라즈베리파이 종류에 맞춰 config를 진행해야 한다. 

나의 WSL2 환경에는 Ubuntu 20.04가 설치되어 있으며, 설치된 qemu 버전은 4.2.1이다. 버전 4.2.1 qemu-system-arm에서 지원하는 타겟에서 라즈베리파이 2B가 최신이므로 커널 빌드는 2B 32비트를 기준으로 진행할 것이다.

64비트 ARM 가상화를 지원하는 qemu-system-aarch64는 라즈베리파이 3까지 지원해준다.

우분투 21.04에서 apt로 설치하는 qemu는 5.2 버전이며 해당 버전에서는 비교적 최신 라즈베리파이를 지원한다.

우분투 20.04에서도 최신 qemu 소스를 빌드하면 가장 최신의 타겟까지 지원해 줄 것이다. 

 

커널 빌드가 완료되면 arch/arm/boot 경로에 zImage와 device tree blob(.dtb)가 생성된다.


Busybox 빌드, 파일시스템 준비

git clone git://git.busybox.net/busybox
cd busybox
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- menuconfig

busybox는 리눅스의 명령어를 하나의 프로그램에서 지원한다. menuconfig에서 세부 설정을 진행한다.

  • Settings -> Build static binary (no shared libs)에 체크한다.

glibc나 ulib와 같이 타겟에서 사용 가능한 라이브러리를 설치한다면 위의 static binary 설정은 필요 없을 것이다.

busybox 빌드에 사용하는 크로스 컴파일러는 리눅스커널과 같은 컴파일러를 사용한다.

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- 
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- install

빌드하고, install를 실행하면 _install 아래에 root 파일시스템으로 이용할 수 있는 파일이 생성되어진다.

그 밖에, 필요한 디바이스파일을 포함한 디렉터리나 파일을 생성한다.

cd _install/

mkdir dev
sudo mknod dev/null c 1 3

mkdir proc
mkdir sys
mkdir -p etc/init.d

/etc/init.d/rcS

#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
/sbin/mdev -s

/etc/inittab

::sysinit:/etc/init.d/rcS 
::respawn:-/bin/sh 
::respawn:/sbin/getty -L ttyS5 115200 vt100 
::ctrlaltdel:/bin/umount -a -r

마지막으로 root 파일시스템으로 이용하기 위해서 이미지를 만든다. _instlal 디렉터리 안에서 아래와 같이 실행한다.

find . | cpio -o --format=newc > ../rootfs

qemu 실행

지금까지 작성한 리눅스 커널 압축된 이미지 파일(zImage), 라즈레리파이2b 디바이스 트리 블럽(bcm2709-rpi-2-b.dtb), busybox에서 생성한 루트 이미지(rootfs)를 한 디렉터리에 복사한다.

해당 디렉터리에서 아래를 실행한다.

qemu-system-arm -M raspi2 -m 1G \
                -kernel ./zImage \
                -dtb ./bcm2709-rpi-2-b.dtb \
                -nographic \
                -append "console=ttyAMA0 root=/dev/ram0 rdinit=/sbin/init" \
                -initrd ./rootfs

 

-nographic 설정으로 터미널에서 리눅스 부팅 과정이 표시된다. qemu 실행 중에 커널 패닉이 되는 경우 qemu를 강제종료하여 터미널로 돌아와야 한다.

Ctrl + a, x를 누르면 qemu 종료한다.