Raspberry Pi 2でDebian jessie armhf を動かす

Raspberry Pi 2のCPUはCortex A7でarmv7アーキテクチャです。RaspbianはRaspberry Pi 1との共通化のためにarmv6向けにビルドされています。Debianのarmhfはarmv7向けなので、これをRaspberry Pi 2で動かしてみました。

debootstrapを使ったDebianのルートファイルシステムの構築

NFSサーバとなっているLinuxマシン(今回はUbuntu 14.04 x86_64)の上で以下を実行しNFSディレクトリにarmhf_jessieのルートファイルシステムの元のファイルを置きます。

$ sudo apt-get install debootstrap
$ mkdir armhf_jessie
$ sudo debootstrap --foreign --arch armhf jessie ./armhf_jessie/ http://http.debian.net/debian/
$ sudo cp -a ./armhf_jessie /export/

Raspberry Pi 2のSDカードの/boot/cmdline.txt のカーネルパラメータを以下のようにNFSrootで起動するようにし、init=/bin/sh を追加します。

dwc_otg.lpm_enable=0 console=ttyAMA0,115200 root=/dev/nfs nfsroot=192.168.0.6:/export/armhf_jessie rw ip=dhcp elevator=deadline rootwait init=/bin/sh

これでRasberry Pi 2を起動すると # のshのプロンプトが出るので、そこで以下を実行します。

# /debootstrap/debootstrap --second-stage

これは20分くらいかかります。

各種設定ファイルの編集

NFSサーバの側から以下の4つのファイルを編集します。

  • /export/armhf_jessie/etc/hostname
  • /export/armhf_jessie/etc/hosts
  • /export/armhf_jessie/etc/resolv.conf
  • /export/armhf_jessie/etc/apt/source.list

Raspberry Pi 2のホスト名をarmhf-jessie00とすると
/export/armhf_jessie/etc/hostname

armhf-jessie00

/export/armhf_jessie/etc/hosts

127.0.0.1	localhost
127.0.1.1	armhf-jessie00
1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes ff02::2 ip6-allrouters

/export/armhf_jessie/etc/resolv.conf

nameserver 8.8.8.8

/export/armhf_jessie/etc/apt/sources.list

deb http://http.debian.net/debian jessie main
#deb-src http://http.debian.net/debian jessie main
deb http://http.debian.net/debian jessie-updates main
#deb-src http://http.debian.net/debian jessie-updates main
deb http://security.debian.org jessie/updates main
#deb-src http://security.debian.org jessie/updates main

Raspberry Pi 2でユーザーの登録と初期設定

Raspberry Pi 2のシェルのプロンプトで以下を実行します。
最初に登録するユーザーアカウントをuser とすると

# export PATH=/bin:/usr/bin:/sbin:/usr/sbin
# mount -t proc proc /proc
# adduser user
# adduser user sudo
# apt-get update
# apt-get install sudo locales dialog ssh
# dpkg-reconfigure locales
# dpkg-reconfigure tzdata

完成

これで最小限の設定はできたはずなので、initスクリプトを動かしてみます。

# exec /sbin/init

これで問題なくuserのアカウントでログインできて使用することができたら、SDカードのboot/cmdline.txt の中の init=/bin/sh を外します。

Raspberry Pi 2でのDebain jessie armhfのブートログ
debootstrap --second-stageの後の細かい設定が煩雑ですが、これの面倒を見てくれる便利なスクリプトはないのかな?

Raspberry Pi のインストール方法いろいろ

遅ればせながら、Raspberry Piを触ってみることにしました。
新しく購入した Raspberry Pi 2 model B とかなり昔のどこかの勉強会の懇親会でのじゃんけん大会に勝ってもらったものの、ずっと放置していた Raspberry Pi 1 model B(初期型。RAM 256MB) です。

本家のインストール手順の説明に従ってまずはNOOBSというツールでインストールしてみます。
ダウンロードはここから。
NOOBSとNOOBS Liteの2種類があったので、それぞれ試してみました。今回は全てRaspbianをインストールしています。
(以降、標準サイズのSDカードもマイクロSDカードも区別せずに「SDカード」と記述しています。)

NOOBS

NOOBS_v1_4_1.zipというサイズが約800MBのファイルをダウンロードします。それを展開して、その中身のファイルをSDカードのトップディレクトリにコピーします。コピーの前にSDカードをフォーマットし直せと書いてあったのですが、今回は新品をおろしたので、フォーマットせずにそのままできました。
後は、Rasberry Pi にそのSDカードを挿し、HDMIでテレビに、USBでキーボードとマウスをつないで、マイクロUSBで給電します。
テレビの画面のGUIを操作してRaspbianを選択してインストール開始。40分くらい待つとインストール完了。
インストールの時間はファイルの書き込み速度が支配的なので、速いSDカードを使うとその分早く終わります。今回はclass 4のものを使ったので遅めでした。
起動すると、テレビの画面にログインプロンプトが出るので、ID:pi, Password:raspberry でログインできます。
最初のログインでは自動的にraspi-configコマンドが実行されるので、ここでLocaleやTimezoneを設定します。
startxを実行するとX Windowのデスクトップが起動しますが、Raspberry Pi 2であってもあまり快適な速度ではないので、私はデスクトップを使うことはあまりなさそうです。

NOOBS Lite

もう一台あるので、Raspberry Pi 1のほうは、NOOBS Liteでインストールしてみました。
NOOBS_lite_v1_4.zipは22MBしかなくて、ずっと小さいです。Raspberry PiEthernetにつなぐ以外は、NOOBSと全く同じようにインストールできます。ネットワークからダウンロードしながらファイルを書き込むことになるのですが、結局SDカードの書き込み速度が支配的なので、NOOBSのときと変わらない時間でインストールが完了しました。
固定回線のある環境では、NOOBS Liteはおすすめです。

NOOBS について

NOOBS とは New Out of Box Software のことだそうです。
ソースコードGithubで公開されており、詳細な説明もここに書いてあります。
実際にこれはramdisk上で動作するLinuxシステムで、UIにはQtが使われいるようです。
インストール後も、NOOBSはリカバリ用のパーティションに格納されていて、起動時にシフトキーを押すとリカバリのためにNOOBSが起動するそうです。

NOOBSを使わずにRaspbianをインストール

確かにNOOBSを使うと初心者でも簡単にインストールすることができます。でも、コマンドラインでddコマンドを使うことをいとわなければ、もっと直接的にRaspbianをインストールすることができます。
Download Raspbian for Raspberry Pi
サイズが約1GBの2015-05-05-raspbian-wheezy.zipというファイルをダウンロードします。それを展開するとサイズが約3GBの2015-05-05-raspbian-wheezy.imgというファイルができるので、それをddコマンドでSDカードに書き込みます。

MacからddコマンドでSDカードに書く手順。
まずは、diskutil list コマンドでSDカードのデバイスファイルを確認します。

koba-mac:raspi koba$ diskutil list
/dev/disk0
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                        *500.3 GB   disk0
   1:                        EFI EFI                     209.7 MB   disk0s1
   2:                  Apple_HFS Macintosh HD            499.4 GB   disk0s2
   3:                 Apple_Boot Recovery HD             650.0 MB   disk0s3
/dev/disk1
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:     FDisk_partition_scheme                        *8.0 GB     disk1
   1:             Windows_FAT_32 boot                    58.7 MB    disk1s1
   2:                      Linux                         7.9 GB     disk1s2

/dev/disk0と/dev/disk1の2つが見えますが、容量からdisk1のほうがSDカードだとわかります。
SDカードをアンマウントします。

koba-mac:raspi koba$ diskutil unmountDisk /dev/disk1
Unmount of all volumes on disk1 was successful

次にddコマンドを使って書き込みを行います。Macの場合はデバイス名のrawを表すrがついた/dev/rdisk1に書き込みます。
コマンドを実行する前に、デバイスファイル名が間違っていないか指差し確認してください。
sudo でddコマンドを使うのは実は非常に危険で、ここでうっかり/dev/rdisk0に書いてしまうと、Macが起動不能になります。

koba-mac:raspi koba$ sudo dd bs=1m if=./2015-05-05-raspbian-wheezy.img of=/dev/rdisk1
Password:
3125+0 records in
3125+0 records out
3276800000 bytes transferred in 260.141958 secs (12596199 bytes/sec)

書き込みには4分半かかりました。class 10のSDカードを使っています。
このとき自動で再度マウントされているので、SDカードを抜く前にもう一度アンマウントしてください。

koba-mac:raspi koba$ diskutil unmountDisk /dev/disk1
Unmount of all volumes on disk1 was successful

できたSDカードをRaspberry Piに挿して起動します。
最初の段階ではルートファイスシステムの容量は以下のように認識されていて、SDカードの容量いっぱいまで使用でできていません。これはパーティションテーブルごと書き込みをおこなったためです。

pi@raspberrypi:~$ df -h
Filesystem      Size  Used Avail Use% Mounted on
rootfs          2.9G  2.4G  335M  88% /
/dev/root       2.9G  2.4G  335M  88% /
devtmpfs         87M     0   87M   0% /dev
tmpfs            19M  224K   18M   2% /run
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs            37M     0   37M   0% /run/shm
/dev/mmcblk0p1   56M   19M   37M  34% /boot

rasp-configコマンドで"Expand Filesystem"の項目を選択して実行します。

pi@raspberrypi:~$ sudo raspi-config

その後、再起動してルートファイスシステムの容量を確認すると以下のようになります。(8GBのカードを使用しました。)

pi@raspberrypi:~$ df -h
Filesystem      Size  Used Avail Use% Mounted on
rootfs          7.2G  2.4G  4.5G  35% /
/dev/root       7.2G  2.4G  4.5G  35% /
devtmpfs         87M     0   87M   0% /dev
tmpfs            19M  224K   18M   2% /run
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs            37M     0   37M   0% /run/shm
/dev/mmcblk0p1   56M   19M   37M  34% /boot

raspi-configコマンドはシェルスクリプトなので、何をやっているのかを確認できます。
"Expand Filesystem"ではfdiskコマンドでrootfsのパーテョンを一度削除してから、容量一杯のサイズでパーティションを再作成し、次に起動したときに一度だけresize2fsが実行されるようにinitスクリプトに登録を行っていました。

RaspbianはRaspberry Pi 1/2 どちらも共通

Raspbianをインストール済みのSDカードはRaspberry Piの1と2のどちらでも使えます。1と2ではCPUが異なるのでカーネルは別々になりますが、ブートパーティションの中には両方のカーネルが格納されていて、ブートローダーがCPU種別を判別して適切なカーネルを選んで起動してくれます。
ルートファイルシステムは共通で、armv6向けにFPUを有効にしてビルドされています。Raspbianのgccはデフォルトでそのようなコードを生成するようにconfigされています。

まとめ

Raspberry Pi 1/2 にRaspbianをインストールするいろいろな方法を試しました。
人にすすめるならば、NOOBS Liteかな。安全で簡単なので。自分ではさくっとddで書く方法を使います。
なお、SDカードのサイズは4GBでRaspbianをインストールできますが、それだと残り容量にあまり余裕が無いので8GBをおすすめします。

Raspberry Piにシリアルコンソールをつなぐ

ハンダ付けは得意でないので、ありものを買ってきてつなぎました。
PL2303HX内蔵USBシリアル変換ケーブル

Raspberry Piのボードの接続は以下の写真の通り。

一番端から一個あけて、赤、黒、白、緑です。Raspberry Pi 1も2もこの位置は同じ。
赤は5Vの電源です。これをつなげばマイクロUSBからの給電しなくても起動します。Ethernetのみの接続ならこれでいけそうです。
USBホストに何かをつなぐときには、これでは電流不足になると思うので赤をはずしてマイクロUSBからACアダプタで給電したほうがよいと思います。

Mac用のPL2303のドライバは以下のサイトから入手しました。
http://www.prolific.com.tw/US/ShowProduct.aspx?p_id=229&pcid=41

Macからコンソールに接続するには以下のコマンドを実行します。

$ sudo cu -l /dev/tty.usbserial -s 115200

Raspberry Piにはディスプレイ、キーボード、マウスはつながずに、Ethernetとシリアルコンソールで使うのが好みです。

VMWare Fusionでvmnet1のIPアドレスを変更する方法

VPNがどうもうまくいかないと思ったら、VMWare Fusionのvmnet1のIPアドレスとぶつかっていることが判明しました。
VMWare Fusionを終了させると、VPNが使えるようになるのですがこのままでは不便です。
以下のようにしたらvmnet1のIPアドレスを変更できて、VMWare Fusionを使用したままでもVPNが使えるようになりました。

OS X バージョン 10.9.5
VMWare Fusion バージョン 7.1.1

(1) VMWare fusionを止める
(2) 以下のファイルをroot権限で編集する
/Library/Preferences/VMware Fusion/networking
/Library/Preferences/VMware Fusion/vmnet1/dhcpd.conf
今回は全ての172\.16を172\.19に置換しました。

(3) VMare fusionを起動する
(4) netstat -rn でvmnet1のアドレスが変わっていることを確認する

vmnet8も同様の手順で変更可能だと思います。
さらに、VMWare Fusion上で動かす仮想マシンのネットワークをNATにしておくと、その仮想マシンからMacVPN接続を経由してVPN先につなぐことができることも確認しました。

Go言語のARMのsoft floatのトリッキーな実装

kernel/VM Night! で発表してきました。



スライドは発表時から少し追記しています。

この日のライブ配信も担当しました。発表よりも実はそっちの方が大変でした。LiveWedgeというビデオスイッチャーを使ってカメラ3台体制で行いました。会社のブログのほうにライブ配信体験談を書く予定です。

そういえば、発表に出てきたARMv5のLinuxの実機ってどれのことですか?とは誰にも質問されなかったな。

"Non-temporal" あえてキャッシュに入れない

8/29に開催されたカーネル読書会でARM 64bitの話をしてきました。同じスライドで話すのは3回目なのですが質問が多くでて今回が最も盛り上がりました。

(撮影:@hyoshiok さん)


特にキャッシュの操作に関しての食いつきはすごかったです。

Aarch64ではキャッシュの操作がきめ細かくユーザーモードからでも行うことができるようになりました。さらに、再度アクセスする可能性が低いデータ(ストリーミングなど)のときにはあえてキャッシュに入れないという指定も可能です。(Non-temporal load/store)

Non-temporal load/storeはx86ではかなり前に導入されていることを前回発表したときに教えてもらいました。(movnt命令)
Linuxカーネルの中ではそれがどこに使用されているか、ソースコードを検索したらカーネルとユーザー空間の間のメモリのコピーを行うところで使用されていることがわかりました。(arch/x86/lib/copy_user_noncache_64.S など)

今回のカーネル読書会では、吉岡さんがコントリビュートしたパッチがまさにNon-temporal命令によるノンキャッシュのコピーの追加だったということを知りました。

そのパッチはこれです。
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c22ce14
2006年のものなので、ファイルの構成は現在のカーネルと変わっています。