前置き
リアル事情とか体調とかでうまく取り組めずにいるうちにFreeBSDのPi3対応実装は進み、ついにSMPが動くようになったという記事が登場しました。
手元に動いているFreeBSDがあるのだから、ビルド済みのkernelとworldをチャチャっとscp
してきてinstallkernel
とinstallworld
をやればお話はおしまいだろうと多寡をくくっているとまた痛い目にあったわけです。
何しろ、portsnap extract
に失敗する有様でコンパイラがきちんと動くわけもなく、ビルドが終わっていてインストールだけだからビルドシステムのどっかがおかしくてもなんとかなるだろうという甘々妄想は見事打ち砕かれたというわけです。というか「cc --version
でセグフォすんだけど」とか言われてさすがに狼狽。コンパイラが動くとかうごかないとかいうレベルを超越してしまっている。
こういう事態になっている理由は明らかに、とある当時何故か書かなかった愚行のせいなのですが……この後それに近いことをもう一回やるため、その時このことを説明いたします。
そんなわけでまるでOSの体をなしていないとはいえ構築済みのシステムのことは可愛いので、今回も近い手順を取りまして現行FreeBSD12-CURRENT原稿書いてから公開までだいぶかかってしまったのでちょっと前のFreeBSD12-CURRENTへのカーネルアップデートを行います。
用意したもの
基本前回のままです。ビルド環境は前回作業時故障中だったi7-6700K/DDR4-2133 16GB*4 など無駄に豪華なWindowsデスクトップ上のVirtualBox VMに変更したので、Mac miniの内蔵SDカードスロットの代わりとして
・大昔愛用してた初代eye-fiに付いてきたUSB2.0用SDHCリーダライタ
が追加されています。
手順のあらまし
自分で書いた記事と、s_mitu先生のありがたい記事と、「愚民はそんなことせんでよろしい!」とばかりに手動ビルド手順が消されてしまったFreeBSD WikiのRPI3ページとの三つを見比べながら手順を練った結果が以下:
- 単なるNTPサーバとして動いてたPiに
shutdown -p now
を投げて止める
2. なお、切れてもメインの赤いLEDは消えてくれないのでLAN端子のLEDが全部消えてからざっくり2秒くらい待って電源を引っこ抜いている。もちろん内部でトラブってたら破綻するので本来はきちんとディスプレイを繋いでやるべき。
3. ついでに言えば今の所shutdown -r now
でも同じ感じになって電源抜き差ししない限りきちんとリブートしてくれないのでこの辺はまだ暫定版な感じ。 - 停止したPiからmicroSDを引っこ抜いて(適切なアダプタで)PCに挿す。
- VirtualBox VMを起動して、USBアダプタをVMに割り当てる。
5. 仮にUSBじゃないアダプタを用いた場合があったとしたら、Macでやったvmdk生成をWinでやる必要がある。当然欠片もUNIXじゃない感じのコマンドやパス類に狼狽することになるけど問題なく可能だと聞いている - WorldとKernelをビルド
7.MAKEOBJDIRPREFIX
をきちんと指定してあれば、このビルドは事前にやっておいてもOK
8. SMPを試すべく、kernconf=GENERIC-UP
ではなくGENERIC
でビルドする。 - VMに刺さっているmicroSDはすでにパーティションが切ってあるのでそれぞれに入ったり出たりしながらSMP仕様に整備する
10. EFI領域をマウントして、「3つのポイント」に従った変更を施す。
11. ufsをマウントして、make installworld installkernel
する - SDカードを挿し直し、念のためディスプレイケーブルも繋いどいてwatch awesomeness happen.
13. もう初回起動じゃないのに何がawesomeなのかというと、binutilsがOS側にないからpkg(8)からaarch64-binutilsを入れてシンボリックリンクという泥臭い行為はもはや不要らしく、かつて3.9.0が動かないと言っていたclangはいま4.0.0が完全動作しているらしいのだ!
ある程度前回とった手順をなぞるように手順を並べているので、効率を考えるといくつかの作業は並列にやったり並び替えたりできます。真似する~~……人はいない気がしますが、万一取り組む~~ならばその辺りをお好みで調整してください。
新しいシステムをビルド
ビルド作業を行うマシンについて
今回は前回書いたところの「ちゃんとしたマシン」で、i7-6700K/DDR4-2133 64GB/システムSATA 250GB SSD/VM用NVMe 400GB*2 RAID0/Win10 Pro 1607という明らかに無駄なハイスペックPC上にVirtualBox VMを構築……と言いたいところでしたがなぜか最近のCURRENTをインストールしようとするとtxzダウンロードの段でcorruptって言われちゃうので諦めてスナップショットイメージ(3月1日版VHDK、r314495)を拝借、使用しました。
VirtualBox仮想マシンの設定は前回と同様を基本にプロセッサ数だけ8つにしてあります。
VirtualBox起動、USBデバイスフィルタ指定
まあ特別なことはありませんね。VMを通常起動してPCにリーダライタを挿し、ウィンドウ下のUSBアイコンからリーダライタの名前を選択してOKです。デスクトップPCの場合はリーダライタを積んでても大概は内部4ピンなので同じ手順で大丈夫でしょう。
ノートPCなどでアイコン押した時のリストにリーダライタらしき名前が出てこなかった場合は……御愁傷様です(笑)。なんとかググってrawvmdkを作りましょう。
なお、デバイスフィルタの設定は中を触り始める寸前でも別に問題はないので、worldとkernelのビルドだけ先にやらせることもできます。
Worldのビルド
setenv MAKEOBJDIRPREFIX /usr/local/rpi3-build/obj
make buildworld TARGET=arm64 TARGET_ARCH=aarch64
worldの方は前回と一切同一です。並列コンパイル用指定も私の場合は-j9
を付け足しました。
Gentooのカーネルビルドだったらおやつを食べる程度の時間でやってくれるi7-6700Kですが、FreeBSDではGENERICカーネルなのも大きいかとは思いますが特にWorld側で思った以上に待ちました(けどきちんと測ってないという絶妙な無能具合orz)
最適化について
さて、ここでお話しするのが前回私がやらかした「愚かなこと」で、ソース内にbsd.cpu.mkというファイルがあります。
ここにはCPUTYPEに関するひっじょ〜〜に賢く行き届いた指定の仕組みが書かれているのですが、末尾に# Add in any architecture-specific CFLAGS.
となんでも書き加えられる場所がありまして、極めて愚かなる私はここにmcpu=cortex-a53
を書き加えてから両方をビルドしたのであります。CPUの命令セットとシステムの動作可否に密接な関係があるのは/etc/make.conf
記述における常識であり、私自身Intel CPUですら一定以上新しいモデルはカーネルコンパイル時に指定するとシステムが動かなくなってしまうことを知っていたにも拘らず興味本位でその行動に走り、挙句記事に書いた時にはこれを隠してすっとぼけるというあまりに迷惑なアウトプットに繋がっておりまして……あの記事にはこの旨も書き足さねばなりませんな。
そして懲りたかというと……反省してここに記述こそしていますが懲りてはいないのであります、当該ソースのコメントにcortex-a53が登場したのを見てベースシステムのビルドに使えると決まったわけじゃないのに大喜びでCPUTYPE=cortex-a53
を付け加えています。真似しなければ普通のまともなFreeBSD(といってもCURRENTな訳ですが)が出来上がるはずです。
Kernelのビルド
こちらはSMP対応のことが入ってくるので少し違う指定をします。
なお、出来上がりのシステムに要らなくなったとはいってもこっちは当然devel/aarch64-binutils
が必要ですから、なければpkg(8)にて調達しておいてください。
setenv MAKEOBJDIRPREFIX /usr/local/rpi3-build/obj
make buildkernel TARGET=arm64 TARGET_ARCH=aarch64 KERNCONF=GENERIC
一つ目のポイントであるところの新しいGENERICカーネルを指定しておきます。GENERICなので、この指定は省略できる可能性もあります。
SDカードの準備
USBデバイスを特定
まぁ、VMなので「あっ、こいつが挿したUSBだな」ってのはわかります。確実なのはdmesg、あるいはtty1に流れたり/var/log/messages
に流れたりした接続ログからそれってものを見つけ出す方法ですが、正直言ってls /dev
でパーティション構成がそれっぽいのを見つけてEFI領域らしきものをマウント、中にu-bootがあるのを確認するのが一番楽な気がしてます。
EFI領域をいじる
手元の環境ではUSBリーダライタの中身がda0
になってました。適宜自分の環境に読み替えてください。
ls /dev
mount -t msdosfs /dev/da0s1 /mnt
書き換わったかもしれないEFIを上書きしとく
ついSMP環境向けの準備にばかり気を取られそうになりますが、当然UEFIに読ますブートローダもリビルドされてるわけなので忘れずに上書きしておきます。
cd /mnt
cp -r /usr/local/rpi3-build/obj/arm64.aarch64/usr/src/sys/boot/efi/boot1/boot1.efi /mnt/EFI/BOOT/bootaa64.efi
2つのファイルを設置
s_mitu先生記事の記述に従います。
cd /mnt
fetch https://people.freebsd.org/~gonzo/arm/rpi3-smp/u-boot.bin
fetch https://people.freebsd.org/~gonzo/arm/rpi3-smp/armstub8.bin
なお、httpsはsecurity/ca_root_nss
をインストールしてないと使えないので、なければpkg(8)しときましょう。
config.txtを編集
device_tree_addressの行編集ですが、これは.txtであって.confではないので行頭に#でコメントアウトができるか不明。思い切って完全に書き換えちゃった方が良いですね。
rootfsをマウントして新しいシステムをインストール
umount /mnt
mount ufs /dev/da0s2a /mnt
cd /usr/src
make -s installworld installkernel distribution KERNCONF=GENERIC DESTDIR=/mnt TARGET=arm64 TARGET_ARCH=aarch64
umount /mnt
前回に引き続き、ソースフォルダを/usr/src
以外としてる人は適宜読み替えてください。
起動試験
待望のwatch awesomeness happenタイムですが、私は前述の通り不穏な行為に走っているので悪い意味でワクワクしながらの起動試験です。
久々にHDMIケーブルを挿し、LANケーブルは抜いておいて、MicroUSBケーブルを……南無三!!
起動に成功しました。CPUも四つあります!
そしてユーザ情報が消えててrootに空パスで入れる、そのくせrc.confは無事というおっそろしぃ状態でした。mdnsd(何故か最近機能してないのですが)もsshdも生きてる。ルータにファイアウォールがあるとはいえ、LANケーブルを挿さなくてよかった。
サクッとadduser
とrootのpasswd
を済ませ、LANを接続。鬼門だったportsnap fetch
に挑戦!
→これも成功!もちろんextractも成功しました。一晩かかったけど
ソフトウェアビルドテスト
さて、Piはつつがなく起動し、書庫解凍もつつがなくできたわけですがビルドシステムがしっかり動作することまで確認できないと安心できないのが人情というもの。
一方使い古しSDカードの寿命をマッハで消耗する行為に少したりとも過剰規模のソフトウェアは選べません。
ここで思いついたのはftp/axel
、分割ダウンロードするマン。運用はアクセス先の方針と衝突しない程度にどうぞ。なお/etc/make.conf
は真っ白なのでここではCPUTYPE
無しです。
pkg install gmake
pkg install gettext-tools
cd /usr/ports/ftp/axel
make config-recursive
make
驚くべきことなのか当たり前なのか、これもあっさり成功。
make install
make deinstall
make clean
使うわけじゃないのでインストールが正常終了したこと(本当は動くことまで確認したほうがいいかもしれませんが……)までで満足しておきます。
しかし、とりあえず比較的安泰という状況を目指すにあたっては、まだ
- どうにか
/var
をSDカード以外に。できれば/usr/src
や/usr/ports
もどっかに。 - でも本当はベータファームウェアでシステム自体をUSBブートさせたい。。
- こういったことがもうしばらくできないとすれば、流石に8GBは手狭じゃない?
……うーん。
さて、最後にdmesg貼って終わりにしたいところですが一言だけ。
手組みしたこの環境ではtopコマンドちゃんと動いてます。
ので、多分現行のddイメージは大丈夫なのかな?無線LAN対応の不足やwatchdogといった細部を除けばだいぶ完全に近いシステムになっていると思います。
付録:組み上がったシステムのdmseg
cpufreq0の「電圧データもらえないんですけど」が入ってる辺りがs_mitu先生とこのと違ってます。powerdを走らせてみているのですが、この分ではまだきちんと機能しないのかもしれません。
KDB: debugger backends: ddb
KDB: current backend: ddb
Copyright (c) 1992-2017 The FreeBSD Project.
Copyright (c) 1979, 1980, 1983, 1986, 1988, 1989, 1991, 1992, 1993, 1994
The Regents of the University of California. All rights reserved.
FreeBSD is a registered trademark of The FreeBSD Foundation.
FreeBSD 12.0-CURRENT #0 r314984: Fri Mar 10 03:38:47 UTC 2017
****@******.****:/usr/local/rpi3-build/obj/arm64.aarch64/usr/src/sys/GENERIC arm64
FreeBSD clang version 4.0.0 (branches/release_40 296509) (based on LLVM 4.0.0)
WARNING: WITNESS option enabled, expect reduced performance.
VT: init without driver.
Starting CPU 1 (1)
Starting CPU 2 (2)
Starting CPU 3 (3)
FreeBSD/SMP: Multiprocessor System Detected: 4 CPUs
random: unblocking device.
random: entropy device external interface
kbd0 at kbdmux0
ofwbus0: <Open Firmware Device Tree>
simplebus0: <Flattened device tree simple bus> on ofwbus0
ofw_clkbus0: <OFW clocks bus> on ofwbus0
clk_fixed0: <Fixed clock> on ofw_clkbus0
clk_fixed1: <Fixed clock> on ofw_clkbus0
clk_fixed2: <Fixed clock> on ofw_clkbus0
clk_fixed3: <Fixed clock> on ofw_clkbus0
clk_fixed4: <Fixed clock> on ofw_clkbus0
clk_fixed5: <Fixed factor clock> on ofw_clkbus0
clk_fixed6: <Fixed clock> on ofw_clkbus0
psci0: <ARM Power State Co-ordination Interface Driver> on ofwbus0
local_intc0: <BCM2836 Interrupt Controller> mem 0x40000000-0x400000ff on simplebus0
intc0: <BCM2835 Interrupt Controller> mem 0x7e00b200-0x7e00b3ff irq 16 on simplebus0
generic_timer0: <ARMv7 Generic Timer> irq 37,38,39,40 on simplebus0
Timecounter "ARM MPCore Timecounter" frequency 19200000 Hz quality 1000
Event timer "ARM MPCore Eventtimer" frequency 19200000 Hz quality 1000
bcm_dma0: <BCM2835 DMA Controller> mem 0x7e007000-0x7e007eff irq 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 on simplebus0
mbox0: <BCM2835 VideoCore Mailbox> mem 0x7e00b880-0x7e00b8bf irq 17 on simplebus0
bcmwd0: <BCM2708/2835 Watchdog> mem 0x7e100000-0x7e100027 on simplebus0
gpio0: <BCM2708/2835 GPIO controller> mem 0x7e200000-0x7e2000b3 irq 18,19 on simplebus0
gpiobus0: <OFW GPIO bus> on gpio0
gpioc0: <GPIO controller> on gpio0
uart0: <PrimeCell UART (PL011)> mem 0x7e201000-0x7e201fff irq 20 on simplebus0
uart0: console (115200,n,8,1)
spi0: <BCM2708/2835 SPI controller> mem 0x7e204000-0x7e204fff irq 22 on simplebus0
spibus0: <OFW SPI bus> on spi0
spibus0: <unknown card> at cs 0 mode 0
spibus0: <unknown card> at cs 1 mode 0
sdhci_bcm0: <Broadcom 2708 SDHCI controller> mem 0x7e300000-0x7e3000ff irq 27 on simplebus0
mmc0: <MMC/SD bus> on sdhci_bcm0
iichb0: <BCM2708/2835 BSC controller> mem 0x7e804000-0x7e804fff irq 31 on simplebus0
iicbus0: <OFW I2C bus> on iichb0
bcm283x_dwcotg0: <DWC OTG 2.0 integrated USB controller (bcm283x)> mem 0x7e980000-0x7e98ffff,0x7e006000-0x7e006fff irq 33,34 on simplebus0
usbus0 on bcm283x_dwcotg0
gpioled0: <GPIO LEDs> on simplebus0
gpioled0: <led0> failed to map pin
fb0: <BCM2835 VT framebuffer driver> on simplebus0
fbd0 on fb0
VT: initialize with new VT driver "fb".
fb0: 656x416(656x416@0,0) 24bpp
fb0: fbswap: 1, pitch 1968, base 0x3db33000, screen_size 818688
pmu0: <Performance Monitoring Unit> irq 36 on simplebus0
cpulist0: <Open Firmware CPU Group> on ofwbus0
cpu0: <Open Firmware CPU> on cpulist0
bcm2835_cpufreq0: <CPU Frequency Control> on cpu0
cpu1: <Open Firmware CPU> on cpulist0
cpu2: <Open Firmware CPU> on cpulist0
cpu3: <Open Firmware CPU> on cpulist0
cryptosoft0: <software crypto>
Timecounters tick every 1.000 msec
usbus0: 480Mbps High Speed USB v2.0
ugen0.1: <DWCOTG OTG Root HUB> at usbus0
uhub0: <DWCOTG OTG Root HUB, class 9/0, rev 2.00/1.00, addr 1> on usbus0
mmcsd0: 8GB <SDHC SD08G 3.8 SN C243D48B MFG 07/2009 by 2 TM> at mmc0 41.6MHz/4bit/65535-block
mbox0: mbox response error
bcm2835_cpufreq0: can't get turbo
mbox0: mbox response error
bcm2835_cpufreq0: can't get voltage
mbox0: mbox response error
bcm2835_cpufreq0: can't get voltage
bcm2835_cpufreq0: ARM 600MHz, Core 250MHz, SDRAM 400MHz, Turbo OFF
Release APs
CPU 0: ARM Cortex-A53 r0p4 affinity: 0
Instruction Set Attributes 0 = <CRC32>
Instruction Set Attributes 1 = <0>
Processor Features 0 = <AdvSIMD,Float,EL3 32,EL2 32,EL1 32,EL0 32>
Processor Features 1 = <0>
Memory Model Features 0 = <4k Granule,64k Granule,MixedEndian,S/NS Mem,16bit ASID,1TB PA>
Memory Model Features 1 = <>
Debug Features 0 = <2 CTX Breakpoints,4 Watchpoints,6 Breakpoints,PMUv3,Debug v8>
Debug Features 1 = <0>
Auxiliary Features 0 = <0>
Auxiliary Features 1 = <0>
CPU 1: ARM Cortex-A53 r0p4 affinity: 1
CPU 2: ARM Cortex-A53 r0p4 affinity: 2
CPU 3: ARM Cortex-A53 r0p4 affinity: 3
WARNING: WITNESS option enabled, expect reduced performance.
Trying to mount root from ufs:/dev/mmcsd0s2a [rw]...
warning: no time-of-day clock registered, system time will not be set accurately
uhub0: 1 port with 1 removable, self powered
ugen0.2: <vendor 0x0424 product 0x9514> at usbus0
uhub1 on uhub0
uhub1: <vendor 0x0424 product 0x9514, class 9/0, rev 2.00/2.00, addr 2> on usbus0
uhub1: MTT enabled
uhub1: 5 ports with 4 removable, self powered
ugen0.3: <vendor 0x0424 product 0xec00> at usbus0
smsc0 on uhub1
smsc0: <vendor 0x0424 product 0xec00, rev 2.00/2.00, addr 3> on usbus0
smsc0: chip 0xec00, rev. 0002
miibus0: <MII bus> on smsc0
smscphy0: <SMC LAN8700 10/100 interface> PHY 1 on miibus0
smscphy0: 10baseT, 10baseT-FDX, 100baseTX, 100baseTX-FDX, auto
ue0: <USB Ethernet> on smsc0
ue0: Ethernet address: **:**:**:**:**:**
fuse-freebsd: version 0.4.4, FUSE ABI 7.8
smsc0: chip 0xec00, rev. 0002
ue0: link state changed to DOWN
ue0: link state changed to UP