スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

Raspberry Pi の環境構築(失敗談)

Raspberry Pi は2012年の年初に発売されて今年(2014年)はB+という改良版(?)が出てきている状況。今更感が否めないですが、オーディオプレーヤとして最小の構成を目指すべくkrenelのコンパイルと、rootfsの内容を最小構成から増やす方向での構築を試みてみました…が、失敗しました。得た事も多いので記録として残しておきます。


kernelのコンパイルは…多くの方がされているので、その追従です。rootfsの方は、今までSDカードイメージを書き込んでそこからいらない物を止めたり削除したりしていましたが、その逆で、最小構成の物を入れて必要な物を追加するようにします。具体的には、rootfsの方は Linaro にある nano を入れて、そこから apt-get で必要な物を取得して行きます。

何はともあれ、raspbianのSDカードイメージの内容を確認しておきます。これによって必要な物が見えてくると思います(この時点では過去の経験より U-Boot とDevice Tree が必要と思い込んでいました)。そこで、raspbian のSDカードイメージファイルをDLして Win32 Disk Imager でSDカードへ書き込みました。この状態で Raspberry Pi へ差し込んで電源を入れれば raspbian が起動するのですが、今回の目的はそこでは無いので、Raspberry Pi へは差し込まず、PC-Linuxマシンに差し込み、中身を確認しました(正確にはWindows上で動かしている VMware Player 上の Ubuntu で確認)。

$ df -T
Filesystem Type 1K-blocks Used Available Use% Mounted on
/dev/sdb1 vfat 57288 9656 47632 17% /media/jujurou/boot
/dev/sdb2 ext4 7515692 2350248 4814820 33% /media/jujurou/5d18be51-3217-4679-9c72-a54e0fc53d6b

$ sudo ls -l /media/jujurou/boot/
total 9656
-rw-r--r-- 1 jujurou jujurou 17824 Jun 19 19:59 bootcode.bin
-rw-r--r-- 1 jujurou jujurou 120 Jun 20 06:51 cmdline.txt
-rw-r--r-- 1 jujurou jujurou 1180 Jun 20 06:51 config.txt
-rw-r--r-- 1 jujurou jujurou 2090 Jun 19 19:59 fixup_cd.dat
-rw-r--r-- 1 jujurou jujurou 5845 Jun 19 19:59 fixup.dat
-rw-r--r-- 1 jujurou jujurou 8822 Jun 19 19:59 fixup_x.dat
-rw-r--r-- 1 jujurou jujurou 137 Jun 20 10:33 issue.txt
-rw-r--r-- 1 jujurou jujurou 3192224 Jun 19 19:59 kernel.img
-rw-r--r-- 1 jujurou jujurou 18974 Sep 25 2013 LICENSE.oracle
-rw-r--r-- 1 jujurou jujurou 512792 Jun 19 19:59 start_cd.elf
-rw-r--r-- 1 jujurou jujurou 2557720 Jun 19 19:59 start.elf
-rw-r--r-- 1 jujurou jujurou 3500744 Jun 19 19:59 start_x.elf

$ uname -a
Linux raspberrypi 3.12.22+ #691 PREEMPT Wed Jun 18 18:29:58 BST 2014 armv6l GNU/Linux


SD-USB変換を使っているので、デバイスとしては sdb として見えています。SDカードの中身は2つのパーティションに区切られていて、第1パーティションが VFAT(FAT32) で 第2パーティションが EXT4 でフォーマットされていました。第1パーティションの中身は…ファイル名から内容が分かる物と分からない物とが半々です。このあたりは Raspberry Pi の QA 広場に "How does Raspberry Pi boot?" という内容で起動の順が書かれています。簡単に書くとこんな感じでしょうか。

1. Raspberry Piに電源が入った時はGPUが起動し ARM core はoff、SDRAM も disabled な状態
2. GPUが1段階目のブートローダーを起動。
   → このブートローダーはSoCのROMにある。
   → ブートローダーはSDカードを読み込んで2段階目のブートローダー(bootcode.bin)をL2キャッシュに読み込み実行する。
3. bootcode.bin はSDRAMを有効にし、3段階目のブートローダー(loader.bin)をSDカードからRAMへ読み込んで実行する。
4. loader.bin は GPU firmware(start.elf) を読み込む
5. start.elf は config.txt、cmdline.txt の内容を元に kernel.img を SDRAM のアドレス0x8000に置く。
6. start.elf は ARM core をリセットして kernel.img のある 0x8000 から実行を開始させる。

loader.bin は elfファイルの読み込みとその先頭にジャンプするような簡単なプログラムと思われるので、bootcode.bin に取り込まれた可能性ありです。

この内容を見て驚いたのが、最初に起動する部分がGPUだという点です。いきなり ARM core に行くのではなく、GPUから起動させるという構成。何故そうなっているかは分からないですが、そこは "そういう物だ" と割り切りましょう。何せ、GPUのプログラム部分(bootcode.bin, start.elf)は作れないのですから。

GPUの動きは のぶさん のblog (bobuhiro11's diary) に 「CPUがカーネルを走らせ始めた後もGPUのコードはアンロード されないということが分かりました. GPUは,VCOS (Video Core Operating System)と呼ばれる小さなOSを走らせ, カーネル側とmailboxというプロトコルや割り込みを通して,グラフィックの 操作を行います. 驚いたことにGPUはグラフィックだけでなくクロック制御やオーディオの制御 も行うようです.」 と書かれていました(情報元は "Level of Hackability of raspberry pi" の様だ)。何か、マルチコアちっくな感じです。

Linux の kernel は 3.12.22 が使われています。私の記憶では kernel 3.1 から Device Tree が必要で、".dtb" ファイルが必要だと思っていたのですが、ここでは出現して来ませんでした。Device Tree が必要な場合は kernel のコンパイル時に設定するみたいです(Device tree driven kernel for raspberry pi)。

これである程度 Raspberry Pi に必要な構造が分かってきました。


と、ここで突然ですが、Linuxの大まかな構成について私が知っている事…というか知ったかぶりになっている構造を書いておきます。

Linux…特に Raspberry PiBeagleBone Black, pcDuino, ODROID といった組み込み系Linuxを触りだしてから分かったことは、非常に大雑把に区分けすると、bootloader, Linux kernel + kernel driver, rootfs(ユーザ空間の物) という3つの部分に分ける事ができると言う事です。

「bootloader」は圧縮されている kernel image を解凍してRAM上に展開します(物によっては非圧縮であったり、RAMに展開せずにROM上で動かす事もあります)。この部分はハードウェアにかなり依存していて、kernel を動かすボード毎に異なります。

「Linux kernel + kernel driver」はOSの中核機能を実行するのと、ハードウェアに依存する部分を kernel driver という形で一挙に引き受けています。

「rootfs(ユーザ空間の物)」はアプリケーションです。ハードウェアに依存する部分は kernel と driver が引き受けてくれているので、rootfs 部分はハードウェアにほとんど依存しない形で形成されています。"ls", "cd" といったコマンドもこの部分に該当します。大抵、アーキテクチャが同じであればコンパイル済みのバイナリを使い回す事ができます。

つまり、大抵の場合、用意する必要があるのは bootloader, Linux kernel + kernel driver の2つの部分です。Raspberry Pi に関して言えば、前述した様に bootloader 部分はバイナリ公開なので "Linux kernel + kernel driver" を用意すれば良いことになります(ここでアーキテクチャの事をもっとまじめに考えていれば失敗に至らなかったのに…)。

PC-Linuxで kernel と ドライバ をクロスコンパイルします。
以下のコマンドでコンパイルしました。回線速度にもよりますが、git clone のところで2時間くらいかかりました。

$ sudo apt-get update
$ sudo apt-get install git build-essential
$ git clone https://github.com/raspberrypi/linux.git
$ git clone https://github.com/raspberrypi/tools.git
$ git clone https://github.com/raspberrypi/firmware.git
$ export CROSS_COMPILE=`pwd`/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin/arm-linux-gnueabihf-
$ export ARCH=arm
$ cd ./linux/
$ make mrproper
$ make ARCH=arm bcmrpi_defconfig
$ make ARCH=arm
$ make ARCH=arm modules
$ mkdir ../modules
$ sudo make ARCH=arm INSTALL_MOD_PATH=`pwd`/../modules modules_install
$ sudo make ARCH=arm INSTALL_MOD_PATH=`pwd`/../modules firmware_install


rootfsの内容は Linaro の armhf版を取ってきて使用します。
そのまま使用すると、システム出力先の ttyAMA0 にログが出力されないので、少々手を加えています。

$ wget http://releases.linaro.org/14.07/ubuntu/trusty-images/nano/linaro-trusty-nano-20140727-680.tar.gz
$ tar jxvf linaro-trusty-nano-20140727-680.tar.gz
$ cd ./binary/
$ cp ./etc/init/tty1.conf ./etc/init/ttyAMA0.conf
$ vi ./etc/init/ttyAMA0.conf
$ cat ./etc/init/ttyAMA0.conf
# ttyAMA0 - getty
#
# This service maintains a getty on ttyAMA0 from the point the system is
# started until it is shut down again.

start on stopped rc RUNLEVEL=[2345] and (
not-container or
container CONTAINER=lxc or
container CONTAINER=lxc-libvirt)

stop on runlevel [!2345]

respawn
exec /sbin/getty -8 115200 ttyAMA0


後はこれらの内容をSDカードへ書き込みます。
今回は raspbian を書き込んだSDカードの内容にVFAT領域は上書きで、EXT4の領域は一端全て削除して書き込みを行いました。

$ sudo cp ./firmware/boot/* /media/jujurou/boot/
$ sudo cp ./linux/arch/arm/boot/Image /media/jujurou/boot/kernel.img
$ sudo rm -rf /media/jujurou/5d18be51-3217-4679-9c72-a54e0fc53d6b/*
$ cp -r ./binary/* /media/jujurou/5d18be51-3217-4679-9c72-a54e0fc53d6b/
$ cd ./modules/
$ sudo cp ./* /media/jujurou/5d18be51-3217-4679-9c72-a54e0fc53d6b/


これでSDカードの準備は出来ました。
SDカードを Raspberry Pi へセットし、電源ONします。
あっ、私は万が一を想定して Raspberry Pi の UART出力端子とPCを繋いで起動ログを取るようにしてから実行しました。

その結果が以下です。

[    0.000000] Booting Linux on physical CPU 0x0
[ 0.000000] Initializing cgroup subsys cpu
[ 0.000000] Initializing cgroup subsys cpuacct
[ 0.000000] Linux version 3.12.26+ (jujurou@ubuntu) (gcc version 4.8.3 20140106 (prerelease) (crosstool-NG linaro-1.13.1-4.8-2014.01 - Linaro GCC 2013.11) ) #1 PREEMPT Sat Aug 9 18:03:44 JST 2014
[ 0.000000] CPU: ARMv6-compatible processor [410fb767] revision 7 (ARMv7), cr=00c5387d
[ 0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT nonaliasing instruction cache
[ 0.000000] Machine: BCM2708
[ 0.000000] cma: CMA: reserved 8 MiB at 1b800000
[ 0.000000] Memory policy: ECC disabled, Data cache writeback
[ 0.000000] Built 1 zonelists in Zone order, mobility grouping on. Total pages: 113792
[ 0.000000] Kernel command line: dma.dmachans=0x7f35 bcm2708_fb.fbwidth=656 bcm2708_fb.fbheight=416 bcm2708.boardrev=0xf bcm2708.serial=0xb9e9487d smsc95xx.macaddr=B8:27:EB:E9:48:7D sdhci-bcm2708.emmc_clock_freq=250000000 vc_mem.mem_base=0x1ec00000 vc_mem.mem_size=0x20000000 dwc_otg.lpm_enable=0 console=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait
[ 0.000000] PID hash table entries: 2048 (order: 1, 8192 bytes)

 中略

[ 2.824167] EXT4-fs (mmcblk0p2): recovery complete
[ 2.830518] EXT4-fs (mmcblk0p2): mounted filesystem with ordered data mode. Opts: (null)
[ 2.841306] VFS: Mounted root (ext4 filesystem) on device 179:2.
[ 2.860680] devtmpfs: mounted
[ 2.865847] Freeing unused kernel memory: 140K (c05b8000 - c05db000)
[ 2.903622] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b
[ 2.903622]
[ 2.917044] CPU: 0 PID: 1 Comm: init Not tainted 3.12.26+ #1
[ 2.924189] [] (unwind_backtrace+0x0/0xec) from [] (show_stack+0x10/0x14)
[ 2.935638] [] (show_stack+0x10/0x14) from [] (panic+0x94/0x1d8)
[ 2.946397] [] (panic+0x94/0x1d8) from [] (do_exit+0x880/0x970)
[ 2.957170] [] (do_exit+0x880/0x970) from [] (do_group_exit+0x40/0xdc)
[ 2.968641] [] (do_group_exit+0x40/0xdc) from [] (get_signal_to_deliver+0x180/0x634)
[ 2.981453] [] (get_signal_to_deliver+0x180/0x634) from [] (do_signal+0xd0/0x440)
[ 2.994159] [] (do_signal+0xd0/0x440) from [] (do_work_pending+0xa4/0xb4)
[ 3.006191] [] (do_work_pending+0xa4/0xb4) from [] (work_pending+0xc/0x20)


最後の方を見れば分かりますが、起動時にカーネルパニックを起こして停止してしまいました。不安要素が沢山あったので、パニックになる事は想定内でしたが、この原因を調べているうちに超重要な事をこの計画段階で忘却していたのが分かってきました。

その原因とは……
「rootfsのアーキテクチャが異なっている!」
でした("あそびばLinux", Debian wiki)。

いやはや、この原因に行き着いたときには愕然としましたね。簡単な事です。Linaro で公開されている armhf版の rootfs の内容は ARMv7用(いわゆるCortex-A/Rシリーズ用) で、Raspberry Pi の ARM core は ARMv6 なんです。ARMv6でもVFPv2を搭載していて、armhf(hard float) のコンパイル結果を使用できるのですが、所詮 ARMv6+VFPv2、ARMv7 アーキテクチャとは異なります。現実をたたきつけられ、しばらくボーっとしてしまいました。



色々と考えはしてみたものの、良い案が浮かびませんでした。
なので、あても無くググってググって……を繰り返している時、偶然にも minibian なる物の存在を知ったのです。SDカードイメージで公開されてます。そうです、ココまでやってきた事全てを無かったことにして、簡単にSDカードの内容を構築する事ができる方法が合ったのです。

この minibian ですが、raspbian をサーバ用途に絞った構成で、描画関連を取り除いてRAMの確保と起動の早さをUPさせているみたいです。最初からSSHサーバが起動しているところを見ると、自分の仕様(MPDサーバ専用機)にでは必要の無い物が多く含まれている可能性はありますが、raspbian から削除しただけの構成なので、apt-get で raspbian 側のバイナリを取ってくる事ができる点が良いです。自分でソースコードからコンパイルをして構築する手もありますが、構築が大変な上に update まで大変になるので、このあたりで妥協しようと思います。

※ Arch Linux とかにするのも手ですが、Debian系(主にUbuntu)に慣れているので、これはパスしてます。
スポンサーサイト

tag : RaspberryPi

tag : Linux

コメントの投稿

非公開コメント

黒ねこ時計 くろック D02
プロフィール

jujurou

Author:jujurou
運営HP:チャコの部屋
Twitter:jujurou

カレンダー
09 | 2017/10 | 11
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31 - - - -
最新記事
最新コメント
カテゴリ
ユーザタグ

ぺるけ RaspberryPi Linux トランジスタ式ミニワッター TRminiWatterPart4 MPD OpenOCD イーサネットコンバータ FON2405E DAC buildroot FM3ペリフェラル BeagleBoneBlack FM3評価ボード library OpenGL mingw ODROID-U2 TL-WR700N Edison bitbake KiCad 計測 VMware シングル FM4 ミニワッター 6N6P プリアンプ 

月別アーカイブ
ランキング

FC2 Blog Ranking

カウンター
検索フォーム
リンク
RSSリンクの表示
QRコード
QRコード
ライセンス
クリエイティブ・コモンズ・ライセンス
Twitter
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。