クロスコンパイル環境でNetBSD-hpcmipsなカーネルをビルドしてみる

# クロスコンパイル環境でNetBSD-hpcmipsなカーネルをビルドしてみる

![img002.JPG](https://qiita-image-store.s3.amazonaws.com/0/61137/af011efe-eeb5-31af-aad3-c6501979e72d.jpeg)

## NetBSDのクロスコンパイル環境

NetBSDはMIPSやPowerPC,SHやVAX,SPARCといった、Intel系以外のCPUアーキテクチャでも動作します。これらのアーキテクチャには、自身でカーネルをビルドするとかなり時間がかかったりするものもあります。NetBSDではクロスコンパイルに対応したツールチェインが用意されており、他のCPUアーキテクチャ向けにカーネルをクロスコンパイルすることが容易に行えます。

今日のNetBSD Advent Calendarでは、このツールチェインの構築と、これを利用してクロスコンパイルしたNetBSD-hpcmipsなカーネルを実機(初代シグマリオン)で動かしてみる記事を書こうと思います。

## 前準備

### ソースコードの展開

まずはNetBSDのソースコードを展開します。[前回のカーネルコンパイルの記事](http://qiita.com/furandon_pig/items/d9b2782372edc1b93263 "NetBSDカーネルをビルドしてみる")と同じく、仮想マシン上でクロスコンパイル環境を構築してみます。

仮想マシンにソースCD-ROM(NetBSD-5.1.5-source.iso)をセットして、NetBSD側から以下の手順でmountします。/cdromというマウントポイントが存在しているので、そこにmountするとよさそうです。

```sh
nibossy ~ $ sudo mount -t cd9660 /dev/cd0a /cdrom
nibossy ~ $ mount | grep cdrom
/dev/cd0a on /cdrom type cd9660 (read-only, local)
```

NetBSDのソースコード一式を展開します。展開先のトップディレクトリを"-C /"としている点に注意してください。

```sh
nibossy ~ $ sudo -i
nbsd515_yuusyabu# cd /cdrom/source/sets/
nbsd515_yuusyabu# ls
MD5          gnusrc.tgz   src.tgz      xsrc.tgz
SHA512       sharesrc.tgz syssrc.tgz
# for i in *.tgz; do tar zxvf $i -C / ; done
```

## ツールチェインの構築

次に、NetBSD-hpcmipsをクロスコンパイルするためのツールチェインを作成します。といっても、展開したソースコードに含まれるbuild.shスクリプトが全部やってくれるので、そんなに難しくありません。

/usr/src/BUILDINGを見ると、build.shは以下のように説明されています。

```
# cat BUILDING
BUILDING(8)             NetBSD System Manager's Manual             BUILDING(8)

NAME
     BUILDING -- Procedure for building NetBSD from source code
...中略...
     build.sh       Bourne-compatible shell script used for building the host
                    build tools and the NetBSD system from scratch.  Can be
                    used for both native and cross builds, and should be used
                    instead of make(1) for any source tree that is updated and
                    recompiled regularly.
```

ツールチェインの格納先として/usr/cross/NetBSD-5.1.5/hpcmipsを指定し、以下の手順を実行してみます。

```
nibossy ~ $ sudo -i
# cd /usr/src/
# mkdir /usr/cross
# uname -r
5.1.5
# ./build.sh -m hpcmips -a mipsel -T /usr/cross/NetBSD-5.1.5/hpcmips -r -o -U tools
```

こんな感じでツールチェインが生成されます。

```sh
# time ./build.sh -m hpcmips -a mipsel -T /usr/cross/NetBSD-5.1.5/hpcmips -r -o -U tools
===> build.sh started: Thu Dec 18 02:09:55 JST 2014
===> NetBSD version:   5.1.5
===> MACHINE:          hpcmips
===> MACHINE_ARCH:     mipsel
===> Build platform:   NetBSD 5.1.5 amd64
===> HOST_SH:          /bin/sh
===> No /usr/cross/NetBSD-5.1.5/hpcmips/bin/nbmake, needs building.
===> Bootstrapping nbmake
...中略...
===> build.sh ended:   Thu Dec 18 02:16:29 JST 2014
===> Summary of results:
         build.sh command: ./build.sh -m hpcmips -a mipsel -T /usr/cross/NetBSD-5.1.5/hpcmips -r -o -U tools
         build.sh started: Thu Dec 18 02:09:55 JST 2014
         NetBSD version:   5.1.5
         MACHINE:          hpcmips
         MACHINE_ARCH:     mipsel
         Build platform:   NetBSD 5.1.5 amd64
         HOST_SH:          /bin/sh
         No /usr/cross/NetBSD-5.1.5/hpcmips/bin/nbmake, needs building.
         Bootstrapping nbmake
         TOOLDIR path:     /usr/cross/NetBSD-5.1.5/hpcmips
         DESTDIR path:     /usr/src/destdir.hpcmips
         RELEASEDIR path:  /usr/src/releasedir
         Removing /usr/cross/NetBSD-5.1.5/hpcmips
         Removing /usr/src/destdir.hpcmips
         Created /usr/cross/NetBSD-5.1.5/hpcmips/bin/nbmake
         makewrapper:      /usr/cross/NetBSD-5.1.5/hpcmips/bin/nbmake-hpcmips
         Updated /usr/cross/NetBSD-5.1.5/hpcmips/bin/nbmake-hpcmips
         Tools built to /usr/cross/NetBSD-5.1.5/hpcmips
         build.sh ended:   Thu Dec 18 02:16:29 JST 2014
===> .
  394.82s real   283.10s user    62.80s system
```

ここまででクロスコンパイル用のツールチェインの準備は完了です。

## hpcmips向けのカーネルをクロスビルドしてみる

### カーネルのビルド

単にカーネルをビルドするだけでは面白みに欠けるので、[NetBSDカーネルをビルドしてみる](http://qiita.com/furandon_pig/items/d9b2782372edc1b93263 "NetBSDカーネルをビルドしてみる")の記事にならい、カーネルソースコードを少し修正してみます。この記事ではNetBSD-6.1.5を対象にした手順でしたが、今回は都合上、NetBSD-5.1.5を対象にします。

このNetBSD-5.1.5でも起動時に好きなメッセージを表示するようにしてみます。ただ、NetBSD-6.1.5では起動時に呼ばれていたbanner()関数が存在していません。

そこで、"total memory"という文字列を元にソースコードをgrepしてみます。sys/arch/hpcmips/hpcmips/machdep.cを修正すればよさそうです。

```sh
nibossy ~ $ cd /usr/src/sys
nibossy sys $ find . -type f | grep \\.c$ | xargs grep 'total memory' | grep hpcmips
./arch/hpcmips/hpcmips/machdep.c:       printf("total memory = %s\n", pbuf);
./arch/hpcmips/hpcmips/machdep.c:               printf("total memory banks = %d\n", mem_cluster_cnt);
```

sys/arch/hpcmips/hpcmips/machdep.cを見ると、cpu_startup()という関数の中で"total memory"を出力しています。ここに自分の好きなメッセージを表示する処理を追加します。

```c
sys/arch/hpcmips/hpcmips/machdep.c:
    538 /*
    539  * Machine-dependent startup code.
    540  * allocate memory for variable-sized tables, initialize CPU.
    541  */
    542 void
    543 cpu_startup()
    544 {
    ...
    558         printf("%s%s", copyright, version);
    559         sprintf(cpu_model, "%s (%s)", platid_name(&platid), cpu_name);
    560         printf("%s\n", cpu_model);
    561         format_bytes(pbuf, sizeof(pbuf), ctob(physmem));
    562         printf("total memory = %s\n", pbuf);
    563         if (bootverbose) {
    564                 /* show again when verbose mode */
    565                 printf("total memory banks = %d\n", mem_cluster_cnt);
    ...
    592         printf("avail memory = %s\n", pbuf);
    593 }
```

今回は「[結城友奈は勇者である](http://yuyuyu.tv "結城友奈は勇者である")」の[Wikipediaの記事](http://en.wikipedia.org/wiki/Yūki_Yūna_wa_Yūsha_de_Aru "Yūki Yūna wa Yūsha de Aru")の一部を表示してみましょう。

修正内容は以下のような感じです。

```sh
# diff -u arch/hpcmips/hpcmips/machdep.c.orig arch/hpcmips/hpcmips/machdep.c
--- arch/hpcmips/hpcmips/machdep.c.orig 2014-12-18 02:43:53.000000000 +0900
+++ arch/hpcmips/hpcmips/machdep.c      2014-12-18 02:56:07.000000000 +0900
@@ -590,6 +590,11 @@
 #endif
        format_bytes(pbuf, sizeof(pbuf), ptoa(uvmexp.free));
        printf("avail memory = %s\n", pbuf);
+
+       printf("Y^ki Y^na wa Ysha de Aru (Y^na Y^ki is a Hero) is \n");
+       printf("a Japanese anime television series produced by \n");
+       printf("Studio Gokumi and directed by Seiji Kishi as part of \n");
+       printf("a media project called Takahiro IV Project. \n");
 }

 void
```

### カーネルのクロスコンパイル

NetBSD-hpcmipsなカーネルをビルドする際、一点確認しておくことがあります。それは実機のCPUがTX39XXなのか、VR41XXのどちらなのか、という点です。私が持っているのは初代シグマリオンで、[Wikipedia](http://ja.wikipedia.org/wiki/モバイルギア "モバイルギア")によると、CPUはVR4121(MIPS)です。

hpcmipsのカーネルコンフィグには、VR41XXというファイルが用意されているので、これを使います。

```sh
# cd /usr/src/sys/arch/hpcmips/conf/
# ls
CVS                 MPC303              VR41XX              std.hpcmips.tx39
GENERIC             NULLCONF            files.hpcmips       std.hpcmips.vr41
INSTALL_TX3912      RAMDISK             ioconf.incl.hpcmips std.lcard
LCARD               TX3912              majors.hpcmips
LROUTER             TX3922              std.hpcmips
```

カーネルコンフィグを好きな名前でコピーします。今回は矢澤にこ...ではなく、[にぼっしー](http://dic.nicovideo.jp/a/三好夏凜 "三好夏凜")にしてみます(自分で分かればどんな名前でもOKです)。

```sh
# cp VR41XX NIBOSSY
```

### カーネルをビルドする

ここからカーネルをクロスコンパイルします。といっても、クロスコンパイル用のコマンド(ツールチェイン)を使うというだけで、手順としては[NetBSDカーネルをビルドしてみる](http://qiita.com/furandon_pig/items/d9b2782372edc1b93263 "NetBSDカーネルをビルドしてみる")で紹介した手順と同じです。

こんな感じで、同じ手順で他アーキテクチャ向けのNetBSDカーネルがクロスコンパイル可能というお手軽さがNetBSDを使う利点の一つですね！

```sh
# /usr/cross/NetBSD-5.1.5/hpcmips/bin/nbconfig NIBOSSY
Build directory is ../compile/NIBOSSY
Don't forget to run "make depend"
# cd ../compile/NIBOSSY/
# /usr/cross/NetBSD-5.1.5/hpcmips/bin/nbmake-hpcmips depend
# /usr/cross/NetBSD-5.1.5/hpcmips/bin/nbmake-hpcmips
```

そうこう言っているうちに、カーネルのクロスコンパイルが完了です。

```sh
# time /usr/cross/NetBSD-5.1.5/hpcmips/bin/nbmake-hpcmips
...中略...
NetBSD 5.1.5 (NIBOSSY) #0: Thu Dec 18 03:08:47 JST 2014
   text    data     bss     dec     hex filename
3091252   59840  381400 3532492  35e6cc netbsd
  123.10s real   107.22s user    13.90s system
```

fileコマンドでファイルの種類を確認してみます。amd64な環境でhpcmips(MIPS)なNetBSDカーネルが生成されています。

```sh
# uname -a 
NetBSD nbsd515_yuusyabu 5.1.5 NetBSD 5.1.5 (GENERIC) #0: Sat Nov 15 19:01:43 UTC 2014  snj@b45.netbsd.org:/home/builds/ab/netbsd-5-1-5-RELEASE/amd64/201411151803Z-obj/home/source/ab/netbsd-5-1-5-RELEASE/src/sys/arch/amd64/compile/GENERIC amd64
# file ./netbsd
./netbsd: ELF 32-bit LSB executable, MIPS, MIPS-II version 1 (SYSV), statically linked, for NetBSD 5.1.5, not stripped
```

念のため、ホントにNIBOSSYコンフィグが使われているのか確認してみます。ちゃんとNIBOSSYなコンフィグですね。

```sh
# strings ./netbsd | grep -i nibossy
@(#)NetBSD 5.1.5 (NIBOSSY) #0: Thu Dec 18 03:08:47 JST 2014
        root@nbsd515_yuusyabu:/usr/src/sys/arch/hpcmips/compile/NIBOSSY
NetBSD 5.1.5 (NIBOSSY) #0: Thu Dec 18 03:08:47 JST 2014
        root@nbsd515_yuusyabu:/usr/src/sys/arch/hpcmips/compile/NIBOSSY
NIBOSSY
```

カーネルサイズは3.8Mほど。

```sh
# ls -lha ./netbsd
-rwxr-xr-x  1 root  wheel  3.8M Dec 18 03:08 ./netbsd
```

ついでにバイナリの中身も少し見てみます。以下のような感じです。

```sh
# /usr/cross/NetBSD-5.1.5/hpcmips/bin/mipsel--netbsd-objdump -CxS ./netbsd | grep -A 20 '<main>:'
8015385c <main>:
8015385c:       27bdffb8        addiu   sp,sp,-72
80153860:       afbf0040        sw      ra,64(sp)
80153864:       afb10034        sw      s1,52(sp)
80153868:       afb3003c        sw      s3,60(sp)
8015386c:       afb20038        sw      s2,56(sp)
80153870:       afb00030        sw      s0,48(sp)
80153874:       8ee3000c        lw      v1,12(s7)
80153878:       3c028030        lui     v0,0x8030
8015387c:       2451d0e0        addiu   s1,v0,-12064
80153880:       ae23000c        sw      v1,12(s1)
80153884:       0c0888b4        jal     802222d0 <consinit>
80153888:       00000000        nop
8015388c:       0c05a469        jal     801691a4 <kernel_lock_init>
80153890:       00000000        nop
80153894:       0c065923        jal     8019648c <once_init>
80153898:       00000000        nop
8015389c:       3c048034        lui     a0,0x8034
801538a0:       00003021        move    a2,zero
801538a4:       24845dc0        addiu   a0,a0,24000
801538a8:       0c05b19f        jal     8016c67c <mutex_init>
```

興味がある方は、以下のURLでMIPSの命令が解説されていますので、照らし合わせてみるのも面白いかと。

 * R3000命令解説
   * http://www21.big.or.jp/~dram/kouza/r3000_ex.html

## NIBOSSYコンフィグなカーネルで起動してみる

では早速、ビルドしたNIBOSSYコンフィグなカーネルを実機で起動させてみます。

まず、WindowsCE上でhpcboot.exeを起動します。

![20000101125634.png](https://qiita-image-store.s3.amazonaws.com/0/61137/63d58595-4f61-876f-daac-f067b290f257.png)

"DoCoMo Sigmarion"な設定が既に用意されているので、これを指定し、起動するカーネルとして、先ほどビルドしたNetBSDカーネル(予めFAT領域にコピーしておく)を指定します。

![20000101125706.png](https://qiita-image-store.s3.amazonaws.com/0/61137/4690efd6-c693-345c-a96b-4326f8de8705.png)

"Boot"ボタンを押すと、諸々の設定とNetBSDカーネルの読み込みが行われ...

![20000101131101.png](https://qiita-image-store.s3.amazonaws.com/0/61137/6def7e09-a883-d067-8497-e41197e2893d.png)

NetBSD-hpcmipsが起動し始めます。よく見ると、先ほど追加したメッセージが表示されています！

![img002.JPG](https://qiita-image-store.s3.amazonaws.com/0/61137/ed73207c-7da3-761d-a7be-760be0596a1b.jpeg)

無事にクロスコンパイルしたNetBSD-hpcmipsなカーネルで起動できました。

![img001.JPG](https://qiita-image-store.s3.amazonaws.com/0/61137/710c6576-0570-7a3f-79c8-aa0dbdf1657e.jpeg)

## まとめ

昨日に引き続き、NetBSD-hpcmipsなネタで記事を書いてみました。クロスコンパイルしたバイナリが実機で動作すると、「よっしゃー、動いたー！」感がありますね。

明日からは[@tisihara](https://twitter.com/tisihara "@tisihara")さんのAdvent Calendarになります。お楽しみに！