NCP-HG100/CellularにOpenWRTを入れてUSBメモリからブートする(令和版)

はじめに

SonyNCP-HG100/Cellularというヤクオクやメルカリで未使用品が投げ売りされているガジェットがあります。こいつはLTEモデム(Telit LN940A9)を積んだルータで楽天モバイルを家で使う人などに愛用されていてインターネットには様々な情報があります。

普通に入れたら動くぽいんですけど、USBメモリからブートできるって複数記事に書いてあるので素朴にやってみたら3日溶けた。以下、記録です。

TL;DR

  • OpenWRT Firmware Selectorで落とせるsysupgradeはUSBストレージ関係のkoがkernelに入ってなくて、USB storageにrootfs置くとkernelがmountできない
  • ~/.openwrt/.configでkmod入れてもkernelに入らないことがあるようで、target/linux/ipq40xx/config-5.151を直接いじる必要がある
  • 自力でビルドするときWSLをつかってはいけない

Firmware Selectorで取得するsysupgradeについて

OpenWRT Firmware Selectorからはinitramfsつきのkernel(itb)と、squashfsのrootfsとkernel itbをtarしたsysupgradeをダウンロードできます。また、インストールパッケージをカスタマイズしたsysupgradeを作ってダウンロードすることができます。カスタマイズ時はkernelは変わらずsquashfsに入ってるrootfsの中身のみが変更されます。

ここで取得できるkernelにはUSB Mass Storageサポートなどが入ってないので、USBメモリのストレージを認識してくれません。なので、rootfsのマウントで止まってしまう。

また、kernelが変わらないのでオプションをいじってカスタムイメージにしてもだめ。

sysupgradeの中身について

binwalkすると、tarって出てきます。

walkure@nozomi:~$  binwalk ./openwrt-23.05.2-ipq40xx-generic-sony_ncp-hg100-cellular-squashfs-sysupgrade.bin
DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             POSIX tar archive (GNU), owner user name: "de-sony_ncp-hg100-cellular/"

というわけで展開すると、kernelrootが出てくる。

walkure@nozomi:~$  tar xvf ./openwrt-23.05.2-ipq40xx-generic-sony_ncp-hg100-cellular-squashfs-sysupgrade.bin
sysupgrade-sony_ncp-hg100-cellular/
sysupgrade-sony_ncp-hg100-cellular/CONTROL
sysupgrade-sony_ncp-hg100-cellular/kernel
sysupgrade-sony_ncp-hg100-cellular/root

こいつもbinwalkすると、以下のような結果が出てくる。

walkure@nozomi:~$ binwalk sysupgrade-sony_ncp-hg100-cellular/kernel

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             Flattened device tree, size: 4217876 bytes, version: 17
228           0xE4            gzip compressed data, maximum compression, from Unix, last modified: 1970-01-01 00:00:00 (null date)
4194880       0x400240        Flattened device tree, size: 21628 bytes, version: 17

walkure@nozomi:~$ binwalk sysupgrade-sony_ncp-hg100-cellular/root
DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             Squashfs filesystem, little endian, version 4.0, compression:xz, size: 4624504 bytes, 1808 inodes, blocksize: 262144 bytes, created: 2023-11-14 13:38:11

rootは一目瞭然ですが、kernelは3エントリある。これ、itb落としてbinwalkしたときと結果が同じなので、同じだろって判断しました。

USBメモリからのブートについて

こいつが積んでるU-BootはUSBからの読み込みに対応してるので、itbをUSBに書いたら読んでくれます。bootcmdでUSBから起動できなかったら積んでるFROMから起動するようにしておくと、なんかあったらすっこ抜くだけでいいので安心ですね。USBメモリは適当に小さいエレコムの16GBを買ってみました。

USBメモリは1セクタ512バイトだと勝手に決め打ちして、セクタを適当に配分。表を作ったらfdiskでえいやと最初の29999999セクタまでプライマリパーティションを切る。

開始セクタ 終了セクタ サイズ なかみ
2048 29999999 14.4G rootfs(f2fs)
30000000 30322688 157.6M kernel(raw)

書き込みはこんな感じ。書き込む前に、rootfsを適当にフォーマットしてマウントしておきます(わたしは/mnt/sdfsにした)。あと、blkidで事前にPARTUUIDを調べておきます。fsはf2fsにしてみたけど、ext4でもなんでも。

sudo dd if=./build_dir/target-arm_cortex-a7+neon-vfpv4_musl_eabi/linux-ipq40xx_generic/sony_ncp-hg100-cellular-uImage.itb of=/dev/sdb bs=512 seek=30000000
sudo tar -xzf ./bin/targets/ipq40xx/generic/openwrt-23.05.2-ipq40xx-generic-sony_ncp-hg100-cellular-rootfs.tar.gz -C /mnt/sdfs

その上で、U-Bootに設定を書く。usb readではkernelを読み込むセクタ番号を16進数で書く2ので、30000000 = 0x1C9C380になります。

set bootusb 'set bootargs console=ttyMSM0,115200n8 root=PARTUUID=xxxxxxxx-01 rw rootfstype=f2fs rootwait; usb start; usb read 0x84000000 0x1C9C380 0x4000; bootm'
set fallback 'set bootargs console=ttyMSM0,115200n8; bootipq'
set bootcmd 'run bootusb; run fallback'

console指定しておくとブートログをUART繋いだ際に読めて安心です。

kernel(itb)にドライバをもたせる

cloneしたOpenWRTのカスマイズは.configをよしなにする感じで、わたしは参考記事のパッチを読んだりして色々入れました。ここで色々kmod入れてますが、どうやらこいつらrootfsに置かれるっぽく、これだけではrootfsマウントできずブートできない。これも参考記事のパッチを睨んでいてようやく気づけた。

kernelビルドの設定はtarget/linux/ipq40xx/config-5.15なので、こいつを直接いじります

CONFIG_SCSI=y
CONFIG_PHY_QCOM_IPQ4019_USB=y
CONFIG_PHY_QCOM_QUSB2=y
CONFIG_USB=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_COMMON=y
CONFIG_USB_DWC3=y
CONFIG_USB_DWC3_HOST=y
CONFIG_USB_DWC3_QCOM=y
CONFIG_USB_STORAGE=y
CONFIG_USB_SUPPORT=y
CONFIG_USB_UAS=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_XHCI_PLATFORM=y

CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_SD=y
CONFIG_BLK_SCSI_REQUEST=y

CONFIG_F2FS_FS=y
CONFIG_EXT4FS_FS=y

こんな感じで、雑に書き足します。これに対応するkmod-*を消したほうがいいような気もしますが、面倒なので一旦放置…。

OpenWRTのビルドについて

というわけで、kernelでUSBストレージを認識してもらうのを目標にOpenWRTをビルドします。

まず大事なこととして、Windows上でビルドする場合はWSL2を使わずVirtualBoxなどでVM立ててビルドすること。公式3にも「A native GNU/Linux environment is recommended.」って書いてあり、わたしはWSL2でビルドしようとして様々4な苦労をして2日ぐらい溶かしました。ちなみにVirtualBoxはUSBデバイス認識がVMのメニューから認識させたいやつ選ぶだけなので超ラク(対WSL25比)。

ビルドそのものは、[OpenWrt Wiki] Build system setupを参考にapt-getでパッケージ放り込んで[OpenWrt Wiki] Build system usageにあるようにmakeするだけ。

するだけですが、初回はクロスビルド用コンパイラを落とすなどの準備をするので相当な時間がかかります。終わってみるとストレージ24Gぐらい使っていたので、VM作るときは30GぐらいvDisk用意する必要がある。

最初のcloneもつらいんですが、shallow cloneするとちょっとだけ速くなります。

git clone --depth=1 -b v23.05.2 https://github.com/openwrt/openwrt.git

  1. これはOpenWRT 23.05のとき。kernel version変わると、当然ファイル名も変わる。
  2. u-boot/doc/README.usb at master · u-boot/u-boot · GitHub
  3. [OpenWrt Wiki] Build system setup WSLには空白のあるWindows由来のPATHを消せとだけ書いてあるが、これやってもビルドが途中でコケてしまった。
  4. WSL2なぜかkernelがUSBストレージ対応してない(お前もか!!!)ので、せっかく最近のstock kernelはusbipd-win対応してるのにkernelをbuildする必要があります。また、f2fsみたいなマニアックなのも対応してないので、こいつを使うにもbuildする必要がある。
  5. USB デバイスを接続する | Microsoft Learn にあるように、ホスト側でCLI叩く必要がある。