気ままなタンス*プログラミングなどのノートブック

プログラミングやRPGツクール、DTM等について、学んだことや備忘録をアウトプットとして残し、情報を必要としている誰かにとって「かゆいところに手が届く」ブログとなることを願いながら記事を書いています。

【Linux】Linuxカーネルをx86_64向けにビルドしてQEMUで実行するまでの記録

スポンサーリンク

なぜカーネルのビルド・実行を体験したかったのか(ポエム)

  • そもそものコンピュータ・アーキテクチャ、ソフトウェア工学的な知識がなく、今後応用が効かないのではないかという危惧
  • (個人的に)ブラックボックス化の上に成り立つ仕組みの栄枯盛衰をいくつか見て、無常を感じた
    • ブラックボックスなレイヤはほぼ変わっていない
    • 10年後に別のものに変わらないとは必ずしも言い切れないけど、ほぼ必ず存在すると思われる
  • こんなことを考えていると、低レイヤの仕組みについて知りたい欲が抑えきれない
    • 自分の中で完全にブラックボックスになっている部分に手を出したい
    • しかし挙動や全体像が不明のままソースを読んでも迷子になって挫折するだけ
  • 取っ掛かりとして、実際に手元で動かすことができるカーネル環境を試す

目次

今回試したカーネルバージョン

  • linux-4.19.63

ビルド環境

実行環境・ツールなど

  • QEMU 2.11(apt-get経由)
  • BusyBox 1.31.0

パッケージのインストール

$ sudo apt update -y
$ sudo apt upgrade -y
$ sudo apt install -y git build-essential ncurses-dev bison flex libelf-dev openssl libssl-dev 
$ sudo apt-get install -y qemu
# 下記は必要に応じて
$ sudo apt-get install -y bzip2 vim wget

Linuxカーネル取得

# clone完了まで30分~1時間程度
$ git clone https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
$ cd ./linux
$ git tag|grep v4.19.63
$ git checkout -b v4.19.63 v4.19.63

Linuxカーネルのビルド

  • 今回はx86_64を対象としてビルドする
# x86_64の設定ファイルを配置する
$ cp arch/x86/configs/x86_64_defconfig ./.config
$ # .configをもとに関連ファイルを設定する
$ # 有効にすべき機能の取捨選択を判断できる知見を持っていないので、今回はEnter押しっぱなしにした
$ make oldconfig
$ make
  • arch/x86_64/boot/bzImageが作成されている

qemuの-initrdオプションに指定するイメージを作成

busyboxのソースをダウンロード

$ wget https://busybox.net/downloads/busybox-1.31.0.tar.bz2
$ tar -jxvf ./busybox-1.31.0.tar.bz2
$ cd ./busybox-1.31.0

busyboxのビルド (make menuconfig)

  • ポイント
    • Setting -> Build static binary (no shared libs)をチェックする
    • Networking Utilities -> Enable IPv6 Supportのチェックを外す
$ make menuconfig
# Setting -> Build static binary (no shared libs)をチェックする
# Networking Utilities -> Enable IPv6 Supportのチェックを外す

$ make install

busyboxディレクトリに_installディレクトリが作成されている

dev, dev/null, proc, sys, etc/init.dを作成

$ cd ./_install
$ mkdir dev
$ sudo mknod dev/null c 1 3
$ mkdir proc
$ mkdir sys
$ mkdir -p etc/init.d

_install/etc/init.d/rcSを作成

$ vim ./etc/init.d/rcS

# 以下の内容を記述
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
/sbin/mdev -s

_install/etc/inittabを作成

$ vim ./etc/inittab
# 以下の内容を記述

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

初期化プロセスのプログラムを作成(_install/init.c)

  • ここではbusyboxの_installディレクトリ直下で作業を実施
/* init.c */
#include <stdio.h>

void main() {
    printf("Hello World!");
    while(1);
}
  • init.cをコンパイル(_install/init)
$ gcc -static -o init ./init.c

パーミッションの変更

$ chmod 755 ./init ./etc/init.d/rcS

_installディレクトリ以下でコマンドを実行し、cpio形式イメージを作成

$ find . | cpio -o --format=newc | gzip > ../initrd.img

ビルドしたカーネルをqemuで起動

$ qemu-system-x86_64 -m 1024 -nographic -kernel ~/linux/arch/x86_64/boot/bzImage  -initrd ~/linux/busybox-1.31.0/initrd.img -append "console=ttyS0 root=/dev/mem0 rdinit=/sbin/init"
  • 正しくビルド、起動できている!

f:id:rinne_grid2_1:20190812183259p:plain
kernel4.19.63

今後どうしたいのか

  • (個人的)ブラックボックスを少しずつ減らしたい
  • デバッグしてみたい

参考

busyboxの設定やデバイスファイル生成など、下記のサイト様を参考にしました。

blog.hirokikana.com