ZYNQにUbuntu 18.04LTSを入れる方法(USB WiFi付)


# はじめに

この記事ではZYNQにUbuntu 18.04LTSをインストールし、USB-WiFiが使えるようにする方法を解説します。
Petalinuxを使わずにセットアップするので、作業内容をブラックボックスにせずに、何が起こっているかを理解しながら進めることができます。また、ダウンロードする量も少なく済みます。

## 準備するもの
- ホストマシン(Ubuntu 18.04が動く仮想PC)
- ZYNQが動くボード (ここでは [CosmoZ Mini](http://www.cosmoz.jp/mini.html) )
- カーネル (uImage)
- デバイスツリー (devicetree.dtb)
- カーネルモジュール (/lib/modules以下の一式)
- boot.bin

使ったFPGAボード

<img src="http://www.cosmoz.jp/images/upload/1527731222_1525757428_cszmini_sma_front.jpg" width=160><img src="http://www.cosmoz.jp/images/upload/1527731387_1525757828_cszmini_sma_rear.jpg" width=160>

※boot.bin, uImage, devicetree.dtb, uEnv.txtなどの作り方はいずれ別の記事で紹介します。ZYBOとかPYNQでやりたい方は、既に動いているZYBOとかPYNQからboot.bin,uImage,devicetree.dtbを引っこ抜いてください。

また、絶版ではありますが、[**拙著 ZYNQのLinuxが動くまで**](http://nahitafu.cocolog-nifty.com/nahitafu/2018/01/zynqlinux-f00e.html) に詳しくまとめてあります。

## ホストマシンでの作業

ホストマシン(Ubuntu 18.04LTSを推奨)に必要なパッケージをインストールしておく。ホストマシンがUbuntu 14では失敗することは確認済み。

```
sudo apt install qemu-user-static debootstrap
```

第一パーティションを100MBくらい、第二パーティションを2GByte以上にしたSDカードを用意し、SDカードの第2パーティションをマウントする。

```
$ sudo mount -o loop /dev/sdb2 /mnt
```

ubuntuのイメージをダウンロードする。

```
$ sudo debootstrap --foreign --arch armhf bionic /mnt http://ports.ubuntu.com/
```

上のbionicがUbuntuのバージョンを表す。ここを書き換えると異なるバージョンのUbuntuが入る。

- bionic・・・18.04LTS
- disco・・・19
- focal・・・20.04LTS

## エミュレータへの切り替え
以下のコマンドでQEMUをコピーして仮想環境に切り替える。なお、chrootでSDカード上のフォルダをrootにした瞬間からQEMUの仮想環境に切り替わり、ホストPCがARMのコードを実行できるようになる。

```
$ sudo cp /usr/bin/qemu-arm-static /mnt/usr/bin/
$ sudo chroot /mnt
/usr/bin/groups: cannot find name for group ID 0
I have no name!@ubuntu:/#
```

まだ名前がないのでユーザ名のところにI have no name!と表示されているので驚く。
次に、QEMU上で第2ステージのセットアップを行う。

```
I have no name!@ubuntu:/# ./debootstrap/debootstrap --second-stage
```

この作業には5分くらいかかる。メッセージの最後に

```
・・・
I: Configuring console-setup...
I: Configuring ubuntu-minimal...
I: Configuring libc-bin...
I: Configuring systemd...
I: Configuring ca-certificates...
I: Configuring initramfs-tools...
I: Base system installed successfully.
I have no name!@ubuntu:/#
```

と、 **Base system installed successfully** が表示されていれば成功。
それ以外の表示は失敗だ。なぜかわからないが、たまに失敗することがある。
SDカードをクリーンにしてから再度チャレンジしよう。

成功したらQEMU上でパスワードを設定し、最初のユーザを作る。
なお、gccとかg++,makeなどは大きいので、ZYNQ上の実機でやるよりも仮想環境でインストールしたほうが早い。apt iinstall build-essentialでgccとかg++,makeが入る。

```
I have no name!@ubuntu:/# passwd
I have no name!@ubuntu:/# su
root@ubuntu:/# passwd
root@ubuntu:/# apt update
root@ubuntu:/# apt install build-essential
root@ubuntu:/# adduser cosmoz ←作成したいユーザ名
root@ubuntu:/# exit
I have no name!@exit
```

1回目のexitではQEMU上のsuから抜け、2回目のexitではQEMUから抜ける。だんだん自分がどこにいるかわからなくなるね。
SDカードをアンマウントして、取り出す。

# ZYNQ実機での作業
SDカードを実機に挿して、前の作業で作ったユーザ名でログインする。
rootでは入れないのでユーザはちゃんと作っておこう。

```
Ubuntu 18.04 LTS ubuntu ttyPS0

ubuntu login: cosmoz
Password:
Welcome to Ubuntu 18.04 LTS (GNU/Linux 4.9.0-cszmini armv7l)
・・・
```

suしてルートユーザになって、/rootへ移動する。

```
cosmoz@ubuntu:~$ su
root@ubuntu:/home/cosmoz:# cd
root@ubuntu:~:# 
```

## 基本の設定

デフォルトではホスト名がUbuntuをセットアップした仮想Linuxマシンの名前になっているので、任意のわかりやすい名前に変更しよう。

```
root@ubuntu:~# sudo hostnamectl set-hostname cszmini
```

次に、viが正しく動作するように.vimrcを作る。
これをしないとviで各種設定ファイルを触るときに先頭の行が化けたりすることがある。
いろいろな設定を変更する前にviが正しく動作するようにしよう。
この時点ではviが信頼できないのでcat > でファイルを作る。

```
root@ubuntu:~# cat > .vimrc
set encoding=utf-8
set fileencodings=iso-2022-jp,sjis,utf-8
```

cat > でファイルを作ったら、**CTRL+D** で抜ける。


電源を入れてシリアルコンソールでつなぐたびにユーザ名とパスワードを聞かれるのは面倒なので、自動でログインできるようにしよう。（セキュリティの関係で自動ログインしないようにするにはこの作業は省く）

```
# systemctl edit --force serial-getty@ttyPS0
```

viが開くので以下のとおり記述する。

```
[Service]
ExecStart=
ExecStart=-/sbin/agetty --noissue --autologin root %I $TERM
Type=idle
```

書き間違えると起動時に止まってしまうので注意。
ファイルは/etc/systemd/system/serial-getty@ttyPS0.service.d/override.conf にあるので、もし書き間違えたら、別のLinuxマシンからSDカードをマウントして直そう。

次にタイムゾーンを変更する。日本式の時間で表示されるようにしよう。シンボリックリンクを張るだけだ。

```
ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
```

sudoersを書き換えてsudoできるようにする。使うコマンドはvisudo。

```
root@ubuntu:~# visudo
```

エディタが開くので、

```
・・・
root    ALL=(ALL:ALL) ALL
cosmoz  ALL=(ALL:ALL) ALL  <-この行を追加
・・・
```

これで基本的な設定はできた。

## 有線ネットワークの設定
ubuntu 18ではnetplanを使ってネットワークの設定を行う。ずーーとお世話になってきたifconfigは、もうない。

```
root@ubuntu:~# sudo vi /etc/netplan/50-cloud-init.yaml
```

エディタが開くので以下のように書く。各行の#←以降は説明なので書かないこと。

```
network:
    version: 2
    renderer: networkd
    ethernets:
        eth0:
            dhcp4: yes
            dhcp-identifier: mac #← MACアドレスを使ってDHCPの識別を行わせる
            #macaddress: 02:11:10:00:22:01 #← インタフェースのMACアドレスを固定したいなら
            dhcp6: no
            optional: true #← これを設定しないと、起動時にネットがないと待たされる
            #addresses: [192.168.1.80/24] #← 以下はDHCPではなく固定する場合の設定
            #gateway4: 192.168.1.1
            #nameservers:
            #addresses: [192.168.1.1, 8.8.8.8, 8.8.4.4]
```

optionalをtrueにしないと、LANがケーブルが外れていたりする場合に延々と待たされてシステムが起動しなくなるので注意。

netplan applyで設定を反映し、ip addressで見て、どこかにpingを飛ばしてネットワークの接続を確認する。

```
root@ubuntu:~# sudo netplan apply
root@ubuntu:~# ip a
root@ubuntu:~# ping 8.8.8.8
```

このへんで一度再起動しよう。

```
root@ubuntu:~# reboot
```

## 追加のパッケージのインストール
再起動するとコンソールからrootで自動ログインできるようになっているはずだ。
各人の好みにもよるが、vimとemacsとgitとopenssh-serverをいれる。
なお、Ubuntu 20のaptにはなぜかemacsがないようだ。

```
# apt install vim
# apt install emacs
# apt install git
# apt install openssh-server
```

emacsが正しく動作するようにcat > で.emacsファイルを作る

```
root@cszmini:~# cat > .emacs
(keyboard-translate ?\C-h ?\C-?)
(global-set-key (kbd "C-h") 'delete-backward-char)
```

sshの設定は特に変更しなくても、

- rootではログインできない
- パスワードでログインする
- ポートは22

になっているようだ。セキュリティにこだわる人は変えればよい。


# USB-WiFiの設定
まずは、lsusbとiwlistが使えるようにするため、USB診断ツールとWiFiのツールを入れる。
ここではELECOMのWDC-150SU2Mを使って無線LAN接続する。

```
apt install -y usbutils wireless-tools
```

## カーネルモジュールのインストール
USB WiFiのような着脱可能な周辺機器を使うには /lib/modules 以下にカーネルモジュールが必要だ。

ブログの [**ZYNQ Linuxの/lib/modulesフォルダやmodules.dep等の作り方**](http://nahitafu.cocolog-nifty.com/nahitafu/2019/09/post-e84457.html ) で作ったカーネルモジュールを展開しておく。

```
# mkdir /lib/modules
# tar -zxvf /mnt/modules.tgz
# mv lib/modules/4.9.0-cszmini/ /lib/modules/$(uname -r)
```

そして、[**ELECOMのWDC-150SU2MをZYNQのLinuxから使う**](http://nahitafu.cocolog-nifty.com/nahitafu/2019/09/post-d45021.html)で作った8188eu.koを/lib/modules/4.9.0-cszmini/drivers/ にコピーする。また、/lib/firmwareと/lib/firmware/rtlwiriフォルダを作り、ファームウェアをコピーする。最後にdepmodして完了。

```
# mkdir /lib/firmware
# mkdir /lib/firmware/rtlwifi
# cp 8188eu.ko /lib/modules/4.9.0-cszmini/drivers/
# cp rtl8188eufw.bin /lib/firmware
# cp rtl8188eufw.bin /lib/firmware/rtlwifi
# depmod
```

Linuxのカーネルに応じて作り直さなければならないので、詳しい作り方は上のブログを参考にしてください。

## ネットワークマネージャのインストール
Ubuntu 18ではネットワークマネージャというツールを使ってSSIDの設定などを行うようだ。wpa-supplicantはもう使わない。

```
# apt install -y network-manager
# systemctl enable network-manager
# systemctl start network-manager
```

まずは、飛び交っているWIFIの一覧を調べる。

```
iwlist scan | grep SSID
```

目的のSSIDが出てきたことを確認できたら、

```
nmcli device wifi connect <SSID> password <パスワード>
```

で接続する。

切断するには

```
nmcli connection show
```

で現在接続中のコネクション名を確認して、

```
nmcli connection delete <コネクション名>
```

で切断する。

# その他の便利な設定
## 起動スクリプト
Ubuntuの14のころは、起動時に自動実行させたいコマンドは /etc/rc.local に書いておけばよかったのですが、Ubuntu18でもこの方法は有効であるようです。（ただし推奨はされていないようだ。systemdに登録しろと言われる)
様々な起動スクリプトを書いたり、自作のFPGA部分を初期化したりしましょう。

## UIOをユーザ権限で使えるようにする
ZYNQのLinuxですから、ユーザプログラムからFPGAを操作することもあるだろう。

PL(FPGAの部分)を操作するにはUIO(ユーザIO)というデバイスドライバを使うことが一般的だけど、UIOはデフォルトではrootしか使えない。以下のように起動スクリプトでパーミッションを変更してユーザ権限で動かせるようにしよう。

```
# vi /etc/rc.local
```

で開いて、ファイルに以下のように書く。

```
#!/bin/sh -e
chmod 666 /dev/uio0
chmod 666 /dev/uio1
exit 0
```

なお、rc.localを作成したら

```
# chmod 755 /etc/rc.local
```

で実行許可を与えるのを忘れないようにしてください。


## apache2のインストール
apache2をインストールしてCGIが動くようにしよう。

```
# apt install apache2
```

設定は、000-default.confの、ServerAdmin webmaster@localhost以降の数行を変更する。

```
# vi /etc/apache2/sites-available/000-default.conf
```

ファイルが開くのでServerAdmin以降の数行を変更する。

```
	ServerAdmin webmaster@localhost
	#ここから変更
	DocumentRoot /var/www/ #ドキュメントルートとなるフォルダ
        <Directory /var/www/>
            Options -Indexes +FollowSymLinks +MultiViews +ExecCgi
            AllowOverride All
            Order allow,deny
            allow from all
        </Directory>

        AddHandler cgi-script .cgi .pl  #追加
	# ここまで
```

CGIが動くようにするにはserve-cgi-bin.confの変更も必要。デフォルトでは/cgi-bin/や/usr/lib/cgi-bin/でしかCGIが動かないようになっている。

```
# vi /etc/apache2/conf-available/serve-cgi-bin.conf
```

で設定ファイルを開く。IfDefine ENABLE_USR_LIB_CGI_BINの中身をコメントアウトする。

```
	・・・
	<IfDefine ENABLE_USR_LIB_CGI_BIN>
#		ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
#		<Directory "/usr/lib/cgi-bin">
#			AllowOverride None
#			Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
#			Require all granted
#		</Directory>
	</IfDefine>
	・・・
```

以下のコマンドでCGIを有効にして、Apache2を再起動する。

```
# a2enmod cgi
# a2enconf serve-cgi-bin.conf
# systemctl restart apache2
```


## 共有フォルダを作成してsambaで共有しよう。
sambaを入れるとsmbd(ファイル共有)とnmbd(名前解決)が動くようになる。
windowsから **\\\\ホスト名** で探せるようになるし、 **viとかemacsとかnanoみたいなドMな使いにくいディタ** ではなく、Windows上の使い慣れたエディタで編集できるようになる。とても便利だからぜひ入れよう。誰も気にしていないと思うが、私の好きなエディタはWZだ。

まず、適当な共有フォルダを作る。

```
# mkdir /home/share
# chmod 777 /home/share
```

sambaをインストールし、設定ファイル開く。

```
# apt install samba
# vi /etc/samba/smb.conf
```

エディタが開いたら、smb.confの最後に以下のように追加する。

```
[Share]
   path = /home/share
   writable = yes
   guest ok = yes
   guest only = yes
   create mode = 0777
   directory mode = 0777
```

これでOK。
smbdとnmbdを有効にしておこおう。

```
# systemctl enable smbd
# systemctl enable nmbd
```

## 低消費電力モードを有効にする

ZYNQには低消費電力モードがある。低消費電力モードというのはPS(CPU)の動作を止めてしまうわけだが、普通に構築したZYNQのLinuxならこの機能が使えるようになっている。
なお、低消費電力モードにしたあと戻れないと困るので、UARTを受信したときに戻れるようにしておこう。やり方は

```
echo enabled > /sys/devices/soc0/amba/e0000000.serial/tty/ttyPS0/power/wakeup
```

だが、覚えられないので、この設定をrc.localに書いておけば起動時に自動的に「UARTで復帰」が有効になる。

いざ低消費電力にしたい場合は

```
echo mem > /sys/power/state
```

を実行すればよい。これを/usr/binあたりにstandbyとかいう名前でスクリプトにしておけばよい。

# まとめ
この方法でUbuntu 18,19,20はインストールできた。Ubuntu 20ではemacsが動かなかったり、rc.localの警告が増えたり、QEMUが403というエラーを出したりいろいろ怪しくなってくるが、それなりに動いている。

Ubuntu 12や14をLinaroで入れていたころに比べて本当に簡単になった。
PetaLinuxではなく、いろいろ充実したUbuntuを自分で入れて快適なZYNQライフを！