Armadillo-Box WS1(旧 IIJ SA-M0)で遊ぶ準備をする

IIJの低圧向けスマートメーターBルート活用サービスが終了したらしく、機材がヤフオクに流れてきました。

www.iij.ad.jp

この箱はアットマークテクノのArmadillo-Box WS1をちょっとカスタマイズ1したものです。

www.atmark-techno.com armadillo.atmark-techno.com

最近まったくRaspberry Pi Zero 2 Wが買えなくてつまらんので、メモリもCPUクロックも半分だけどしっかりしたドキュメント等必要なものがインターネットに置いてあって(この手の国産ハードにしては)めちゃくちゃ優秀なので、そんなに過酷なことにはならないと踏んで遊んでみることに。

armadillo.atmark-techno.com

ファームを初期化

SA-M0のファームが入ってるけどなんもできないので初心に戻します。バラして後述のようにシリアル接続し、JP2ショートして保守モード2でブートしてtftpでuserlandを投入3

armadillo.atmark-techno.com

この写真あとで撮ったのでJP2オープンしてる。

tftpサーバはホストがWindows4なのでtftpd64を使いました。コマンド例はドキュメントにあるので略。

[root@abws1-0 (pts/1) ~]# cat /proc/version
Linux version 3.14.36-at4-abws1-add-support-a420 (atmark@atde5) (gcc version 4.6.3 (Debian 4.6.3-14atmark1) ) #1 PREEMPT Tue Feb 23 16:45:53 JST 2016
[root@abws1-0 (pts/1) ~]# uname -a
Linux abws1-0 3.14.36-at4-abws1-add-support-a420 #1 PREEMPT Tue Feb 23 16:45:53 JST 2016 armv5tejl GNU/Linux

シリアル接続について

バイスから出てるUARTはTTLレベルでなくRS232Cレベルなので、計算機側がTTLレベルUARTだとレベルコンバータが必要です。

バイス側はTxD(Pin5)/RxD(Pin3)/GND(Pin9)に出ている5のでよしなにUARTに繋いで115200bps6でシリアルターミナルを起動します。

当座の目標

とりあえず遊べることが第一目標なので、このラインを目標にします。

  • sshで入れる
    • UART接続は箱を閉じられないので辛い
  • scpでファイルを出し入れできる
  • socat使ってBP35A1tcpで会話
    • PuTTYで会話したり、ホスト側でsocatしてptyに飛ばしたりできるようになる

本当はuserlandをカスタムしてssh/scp/socatを入れるんだろうけど面倒なので、microSDを刺してpersistent storageを増やしbinaryを放り込む作戦で行きます。

eth0をよしなにして時刻を合わせる

userlandを入れた状態で起動するとeth0がDHCPに失敗してます。これは/etc/config/interface/etc/armsd/udhcpc.scriptを読もうとして/etc/armsd以下がないことによるのでまるごと取っ払います。

また、RTCついてないんでifup時にntpclient7で時間を合わせます。

[root@abws1-0 (pts/1) ~]# cat /etc/config/interfaces
auto eth0
iface eth0 inet dhcp
up ntpclient -i 1 -h ntp.nict.jp -s

NICloがないんでssh local portforwardingが出来ないんですけど、LANにしか繋がないので今回は気にしない。

ちなみにDHCPを使わずstaticにするときは /etc/config/interfacesNICの設定を書き、/etc/config/resolv.confDNSゾルバの設定を書きます8

staticの場合の設定例

NICの設定

[root@abws1-0 (pts/1) ~]# cat /etc/config/interfaces
auto eth0
iface eth0 inet static
up ntpclient -i 1 -h ntp.nict.jp -s
address 192.168.0.2
netmask 255.255.255.0
gateway 192.168.0.1

ゾルバの設定

[root@abws1-0 (pts/1) ~]# cat /etc/config/resolv.conf
nameserver 192.168.0.1

/etc/configのファイルを編集した後は第7章 コンフィグ領域 − 設定ファイルの保存領域 > 7.2. コンフィグ領域の保存にあるとおり、flatfsd -sで保存する必要があります。

ロスコンパイル環境をつくる

ロスコンパイル環境構築済みVMイメージをメーカーが提供してくれているのでVMをいれるだけ。バージョンもドキュメントにある9とおり、v20150727以降のATDE5を拾ってきて入れます。VMware Playerはlatestの「VMware Workstation 17 Player 17.0.1 build-21139696」で動きました。

armadillo.atmark-techno.com

storageをつける

まだバラされている状態なので、microSDを刺します10。もし手元にUSBメモリがない場合は、ATDEがmicroSDを認識してる状態で次節のコンパイル済みバイナリを放り込んでから本体に刺することになる11ので適宜入れ替えてください。

microSDはATDEで12ext413フォーマットした上で、起動時に実行される/etc/config/rc.local14で起動時にマウントさせます。ついでに/etc/profileをいじってPATHを通しておきます。

mkdir /mnt/sd
mount -t ext4 /dev/mmcblk0p1 /mnt/sd
echo PATH=\$PATH:/mnt/sd/bin >> /etc/profile
echo export PATH >> /etc/profile

ビルドする

ロスコンパイル環境ATDE5でやっていきます。

ssh

軽量sshDropbear SSHを入れます。 github.com

CFLAGS='-DDEFAULT_PATH=\"/usr/bin:/bin:/mnt/sd/bin\" -DDEFAULT_ROOT_PATH=\"/usr/sbin:/usr/bin:/sbin:/bin:/mnt/sd/bin\" -DDROPBEAR_PATH_SSH_PROGRAM=\"/mnt/sd/bin/dbclient\"' ./configure --host=arm-linux-gnueabi

scp時にPATHが通っている場所にscpdbclientがないと失敗するんですが、scpコマンドは非インタラクティブシェルで起動する15ので/etc/profileをいじってもPATHが通りません。そこで、CFLAGSでセッション起動時のPATHを通します。前項でmicroSDマウントするpathを変えた場合はここのpathもよしなに変更してください。

make allではscpはビルドされないので、make scpでscpバイナリを別途ビルドする必要があります。

socat

公式サイト or git からソースを落としてきてビルド。

何も設定しないでbuildしたら実行時にlibwrapとreadlineがないって怒られたのでdisableしておきます。

./configure --host=arm-linux-gnueabi --disable-libwrap --disable-readline

入れていくぞ

USBメモリ経由でさっきコンパイルした dropbear / scp / dropbearkey / socat をPATH通したmicroSD上の/mnt/sd/binにコピっておきます。

ssh/scp

まず、hostkeyを生成します。ed25519だとATDEのsshが古くて認識しないのでrsaで生成しました。

/mnt/sd/bin/dropbearkey -t rsa -f /mnt/sd/etc/host.key

その上で/etc/config/rc.localに設定を投入します。

# start ssh
iptables -I INPUT -i eth0 -p tcp -m tcp --dport 22 -j ACCEPT
echo /bin/ash > /etc/shells
/mnt/sd/bin/dropbear -r /mnt/sd/etc/host.key 

userlandには/etc/shellsがなくgetusershell(3)がデフォルトの"/bin/sh,/bin/csh"を返す一方でrootユーザのshellは/bin/ashになっていてこのままではssh loginできないので/etc/shellsを雑に生成しています。

sshができるようになると、UART取っ払って箱を閉じることが出来ます。dhcpで拾うIPアドレスdhcpサーバ側でMacアドレス見て固定したので、設定はここまで。

socat

ローカルでtty叩きたくなる日が来るかもしれないので、sshで入って必要に応じて起動できるようにしておく。

[root@abws1-0 (pts/1) ~]# cat /mnt/sd/bin/bp35a1
#!/bin/sh
/mnt/sd/bin/socat -d -d tcp-l:23366,reuseaddr,fork file:/dev/ttymxc2,rawer,echo=0,waitlock=/var/run/ttymxc2.lock,b115200

これで23366/tcpにBP35A1が見えます。socatの引数について詳細はmanを参照してください。

最終的な設定

[root@abws1-0 (pts/1) ~]# cat /etc/config/rc.local
#!/bin/sh

. /etc/init.d/functions

PATH=/bin:/sbin:/usr/bin:/usr/sbin

# mount sd
mkdir /mnt/sd
mount -t ext4 /dev/mmcblk0p1 /mnt/sd
echo PATH=\$PATH:/mnt/sd/bin >> /etc/profile
echo export PATH >> /etc/profile

# start ssh
iptables -I INPUT -i eth0 -p tcp -m tcp --dport 22 -j ACCEPT
echo /bin/ash > /etc/shells
/mnt/sd/bin/dropbear -r /mnt/sd/etc/host.key 

簡単になんか走らせる

[root@abws1-0 (pts/1) ~]# cat /proc/cpuinfo
processor       : 0
model name      : ARM926EJ-S rev 4 (v5l)
BogoMIPS        : 133.00
Features        : swp half thumb fastmult edsp java
CPU implementer : 0x41
CPU architecture: 5TEJ
CPU variant     : 0x0
CPU part        : 0x926
CPU revision    : 4

Hardware        : Armadillo-420
Revision        : 0300
Serial          : 0000000000000000

というわけで、armv5lのarchでcross compileをGoやRustで試してみます。単にハロワするだけなので、より複雑な実装を書いていく場合に何が起きるかはまだ未確認。

Go

go1.20.3 windows/amd64で確認。

package main

import "fmt"

func main() {
        fmt.Println("hello,world")
}

GOOS=linux GOARCH=arm GOARM=5 go build harowa.goでbuildしたbinaryをscpしてシュッと実行できた。

Rust

stable-x86_64-pc-windows-msvc (default) rustc 1.69.0 (84c898d65 2023-04-16) で確認しました。

armv5te-unknown-linuxのtargetはgnueabimusleabiのふたつあります。

glibcに依存するarmv5te-unknown-linux-gnueabiだとATDE5でRustを走らせることになるけど、ATDE5に入ってるglibcがv2.13でRustは2.3116でビルドされてるので動かない。ちなみにx86_64-unknown-linux-muslのrustup-initを直接17落としてATDE内で実行するとインストールはできるけど、rustcが「error: command failed: 'rustc': No such file or directory (os error 2)」というめちゃくちゃつらいエラーを出して死ぬ。古すぎて何かがないんだろうけど、何がないかがそもそもわからない。

そこで、glibcに依存しないarmv5te-unknown-linux-musleabiWindowsホストに入れて試してみる。

fn main() {
    println!("hello, world!");
}

rustc --target=armv5te-unknown-linux-musleabi -C linker=rust-lld ./harowa.rs でビルド18して実行できた。


  1. 具体的にはRTCが実装されておらず、第8章 Linuxカーネル仕様 > 8.3.7. RTCに記述がある通りのエラーを起動時に吐いています。他にもカスタマイズされているところがあるかもしれないけど未確認。
  2. 起動モードのジャンパ設定は第14章 ハードウェア仕様 > 14.10. 起動モード設定ジャンパを参照。
  3. 第12章 フラッシュメモリの書き換え方法 > 12.4. TFTPを使用してフラッシュメモリを書き換えるを参照。
  4. Windows Firewallでtftp64.exeの通信を許可しても69/udpを蹴飛ばしてくれてちょっと大変だった。
  5. ピン配置は第14章 ハードウェア仕様 > 14.9. デバッグシリアルインターフェースを参照。
  6. デフォルトの速度については第8章 Linuxカーネル仕様 > 8.2. デフォルト起動オプションを参照。
  7. ntpclientの引数-iはtimeoutを指定できて、defaultは600秒らしいんで1秒にしてあります。ntpclient時刻合わせで返ってこない | Armadilloサイトを参照。
  8. ネットワークの設定について詳細は第6章 動作確認方法 > 6.2.3. 有線LANを見てください。
  9. 第4章 Armadilloの電源を入れる前に > 4.2.1.2. ATDE5アーカイブの取得
  10. 第14章 ハードウェア仕様 > 14.8. microSDインターフェースを参照。
  11. ホスト側で/binディレクトリを切って、そこに次節以降で生成するbinaryをコピーする感じ。
  12. ATDE上でUSBメモリ/SDカードのパーティションを作成・フォーマットする方法 | Armadilloサイト
  13. microSDをホストで読む術がない場合は本体に挿してmkfs.vfatあたりでformatすることになりそう。userlandに入っているのはBusyBox v1.20.2なのでext2などのformatはできない。その場合は後段のmount時引数が変わります。
  14. 第9章 ユーザーランド仕様 > 9.2.4. /etc/config/rc.local
  15. セッション起動時のshell種別についてはssh,sftp,scp時のログインシェル、インタラクティブシェル - 朝から昼寝に詳しい記述があります。
  16. https://github.com/cross-rs/crossarmv5te-unknown-linux-gnueabiのlibcが2.31になってるし、ビルドコンテナubuntu:20.04になっている。
  17. rustup-initのbinary一覧はOther Installation Methods - Rust Forge > Other ways to install rustupにあります。
  18. rust-lldをつけないと「error: linker cc not found」でコンパイルが落ちます。rust-lldcargo-binutils入れなくても実行できました。