Mac上にRaspberry Pi OS(RaspbianBuster)をQEMUエミュレーターで動かす(Raspi2、Raspi3マシン)

# はじめに
前記事ではRaspi2、Raspi3マシンをLinux上で構築しましたが、今回はIntel Mac上で構築します。

https://qiita.com/yaju/items/edf548efd18f0eaab94a

初代RaspberryPi用のversatilepbマシンの記事は下記になります。

https://qiita.com/yaju/items/9bb341c1b222590a92ba

※記事内容は、Linux上とほぼ同じ内容となります。キャプチャ画像もLinux版と一部共有しています。

# 環境
* Mac Book Pro(2.3 GHz 8コアIntel Core i9) Big Sur 11.3
* QEMU 6.0

※2020年5月にLinuxベースの公式OSの名称を「Raspbian」から「Raspberry Pi OS」に変更した。

## M1 Mac
自分はM1 Macを持っていないので確認が出来ていないですが、下記サイトでM1 MacのQEMUにてRaspberry Pi OS（ARM64）が動作しているようです。

https://qiita.com/hjmr/items/abeb9a4567d08ddcc3b9#raspberry-pi-osarm64

# 導入手順
## QEMUのインストール
QEMUは、CPUエミュレーションをするためのソフトウェアになります。

```zsh
% brew install qemu
```

### Homebrewのインストール
自分の場合、Homebrew 自体がインストールされていなかったので下記の方法でHomebrew をインストールしました。

```zsh
% /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"

% brew -v          
Homebrew 3.1.9
```

### wgetのインストール
wgetもインストールされていなかったので、インストールしました。

```zsh
% brew install wget
```

## イメージファイルのダウンロード
CPU別(armhf[^1],arm64[^２]など)にイメージファイルには3種類用意されています。

[^1]: armhf…ARMというCPUアーキテクチャ上で動かす、浮動小数点数命令を使うバージョン。Raspberry Piなどがこちらを使います。
[^２]: amd64…x86を64ビットに拡張したx64対応のもの。政治的な事情もあってこの命令セットのCPUをAMDが先に出したため、Intelのx64でもamd64版となります。ほとんどのパソコンはこちらです。

* Raspberry Pi OS 軽量版(lite)
* Raspberry Pi OS デスクトップ(Desktop)
* デスクトップと追加パッケージを備えた Raspberry Pi OS(full)

日本からなら北陸先端大にあるミラーサーバーからの方が速くダウンロードできる。
http://ftp.jaist.ac.jp/pub/raspberrypi/

### 使用するイメージファイル
* Raspi2マシン用に「[2021-05-07-raspios-buster-armhf](http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_armhf/images/raspios_armhf-2021-05-28/)」
* Raspi3マシン用に「[2020-08-20-raspios-buster-arm64](http://ftp.jaist.ac.jp/pub/raspberrypi/raspios_arm64/images/raspios_arm64-2020-08-24/)」

※Raspi3マシン用(qemu-system-aarch64)では「2021-03-04-raspios-buster-arm64.img」と「2021-05-07-raspios-buster-arm64.img」を使用すると何も起こらない、メッセージ表示すら出ない状態になります。

# Raspi2マシン
## フォルダ作成
home直下に「RaspberryPi2」フォルダを作成します。
ダウンロードした「2021-05-07-raspios-buster-armhf.zip」を「RaspberryPi2」フォルダに展開します。

## カーネルとデバイスツリーソースファイルの抽出
イメージファイルをダブルクリックすればマウントされるので、「kernel7.img」と「bcm2709-rpi-2-b.dtb」を抽出します。

RaspberryPi2フォルダには3ファイルがある状態にします。

* 2021-05-07-raspios-buster-armhf.img
* kernel7.img
* bcm2709-rpi-2-b.dtb

## イメージファイルのリサイズ
実行する際のイメージファイルは2のべき乗になっている必要があります。そうしないと下記エラーになります。
「Invalid SD card size: 3.71 GiB
SD card size has to be a power of 2, e.g. 4 GiB.
You can resize disk images with 'qemu-img resize <imagefile> <new-size>'
(note that this will lose data if you make the image smaller than it currently is).」

```txt
% qemu-img resize 2021-05-07-raspios-buster-armhf.img 8G

WARNING: Image format was not specified for '2021-05-07-raspios-buster-armhf.img' and probing guessed raw.
         Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
         Specify the 'raw' format explicitly to remove the restrictions.
Image resized.
```

## 初回起動
RaspberryPi2フォルダに下記の「run.sh」を作成します。
※raspi2マシンの場合、qemu-system-aarch64でも動作します。
2021/07/06 appendオプションに画面サイズを追記

```bash:run.sh
#!/bin/sh
cd `dirname $0`

qemu-system-arm \
-m 1024 \
-M raspi2 \
-kernel kernel7.img \
-dtb bcm2709-rpi-2-b.dtb \
-drive format=raw,file=2021-05-07-raspios-buster-armhf.img \
-append "console=ttyAMA0 root=/dev/mmcblk0p2 rw rootwait rootfstype=ext4 dwc_otg.fiq_fsm_enable=0 bcm2708_fb.fbwidth=1280 bcm2708_fb.fbheight=720" \
-serial stdio \
-no-reboot \
-device usb-kbd \
-device usb-tablet \
-device usb-net,netdev=net0 \
-netdev user,id=net0,hostfwd=tcp::2222-:22
```

ターミナル上でrun.shに実行権限を追加してから実行すれば、 数分でRaspberry Pi OSが起動します。

```
% chmod 755 run.sh
% ./run.sh
```

# Raspi3マシン
## フォルダ作成
home直下に「RaspberryPi3」フォルダを作成します。
ダウンロードした「2020-08-20-raspios-buster-arm64.zip」を「RaspberryPi3」フォルダに展開します。

## カーネルとデバイスツリーソースファイルの抽出
イメージファイルをダブルクリックすればマウントされるので、「kernel8.img」と「bcm2710-rpi-3-b.dtb」を抽出します。

RaspberryPi3フォルダには3ファイルがある状態にします。

* 2020-08-20-raspios-buster-arm64.img
* kernel8.img
* bcm2710-rpi-3-b.dtb

## イメージファイルのリサイズ
実行する際のイメージファイルは2のべき乗になっている必要があります。そうしないと下記エラーになります。
「Invalid SD card size: 3.52 GiB
SD card size has to be a power of 2, e.g. 4 GiB.
You can resize disk images with 'qemu-img resize <imagefile> <new-size>'
(note that this will lose data if you make the image smaller than it currently is).」

```txt
% qemu-img resize 2020-08-20-raspios-buster-arm64.img 8G

WARNING: Image format was not specified for '2020-08-20-raspios-buster-arm64.img' and probing guessed raw.
         Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
         Specify the 'raw' format explicitly to remove the restrictions.
Image resized.
```

## 初回起動
RaspberryPi3フォルダに下記の「run.sh」を作成します。
2021/07/06 appendオプションに画面サイズを追記

```bash:run.sh
#!/bin/sh
cd `dirname $0`

qemu-system-aarch64 \
-m 1024 \
-M raspi3 \
-kernel kernel8.img \
-dtb bcm2710-rpi-3-b.dtb \
-drive format=raw,file=2020-08-20-raspios-buster-arm64.img \
-append "console=ttyAMA0 root=/dev/mmcblk0p2 rw rootwait rootfstype=ext4 dwc_otg.fiq_fsm_enable=0 bcm2708_fb.fbwidth=1280 bcm2708_fb.fbheight=720"  \
-serial stdio \
-no-reboot \
-device usb-kbd \
-device usb-tablet \
-device usb-net,netdev=net0 \
-netdev user,id=net0,hostfwd=tcp::2222-:22
```

ターミナル上でrun.shに実行権限を追加してから実行すれば、 数分でRaspberry Pi OSが起動します。

```
% chmod 755 run.sh
% ./run.sh
```

# 共通
ここからは、Raspi2マシンとRaspi3マシン共通となります。

## QEMUエミュレータ
|エミュレータ|Raspberry Piモデル|
|:--|:--|
|qemu-system-arm|RaspberryPi 2向けのCortex-A53|
|qemu-system-aarch64|RaspberryPi 2、3向けのCortex-A53|

## QEMUオプション
[QEMUオプション](https://wiki.gentoo.org/wiki/QEMU/Options)

主なQEMU起動時のオプションについての説明をまとめておきます。

### -M マシン名
エミュレートするマシン名を指定します。
最新情報は、次のコマンドで一覧が表示できます。

```
qemu-system-arm -M help
or
qemu-system-aarch64 -M help
```

### -m メモリ数
RAMの容量を指定します。
raspi2マシンとraspi３マシンを指定した場合は最大１GiBで、それ以上を指定するとエラー「Invalid RAM size, should be 1 GiB」になります。

### -append 画面サイズ
【2021/07/06追記】
mt08 さんから[Linux側の記事にコメント](https://qiita.com/yaju/items/edf548efd18f0eaab94a#comment-d6f87290a766f6d1284f)を頂き、appendオプションに画面サイズを指定することで画面サイズを変更することが出来ました。
bcm2708_fb.fbwidth=XXX bcm2708_fb.fbheight=YYY

```text:例
-append "console=ttyAMA0 root=/dev/mmcblk0p2 rw rootwait rootfstype=ext4 dwc_otg.fiq_fsm_enable=0 bcm2708_fb.fbwidth=1280 bcm2708_fb.fbheight=720"
```
しかも、画面サイズ800x480で背景が青系統だったのが、画面サイズ1280x720で背景が本来のオレンジ系統になりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/5599818b-abe8-5f95-0367-bd0b9f6b9fb2.png)

## マウス操作
### QEMUを抜ける
マウスカーソルがラズパイの画面に持っていかれた場合、抜けるにはQEMUウィンドウのタイトルバー「QEMU-Press Ctrl + Alt + G release grab」に記載されているように、「Ctrl + Alt + G」を同時に押します。
ここは改善されたのか、ラズパイの画面範囲を超えると自動的に抜けるようになっています。

## 起動
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/1be3bd66-0377-f44c-7bd9-cf657b0e2389.png)
ログインを求められますが、入力しても、しなくても問題ありません。
デフォルトの管理者 ユーザー名:pi パスワード:raspberry

## 初期設定画面
背景画像がversatilepbマシン時はオレンジ系統でしたが、今回は青系統になっています。

初期設定画面では国の設定以外は Nextボタンをクリック(パスワード変更なども)、アップグレードは空き容量が足りないのでSkipボタンをクリックして最終的にDone(Later)ボタンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/ffbe3dee-84f9-22fa-6de6-27c61f0e4581.png)

# 空き容量を増やす
空き容量が195.1 MiBしかありません。後述する方法で空き容量を2.5GiB(8Gの場合)まで増やすことができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/6c896cc5-f8ce-1ec8-eac0-b15129db4959.png)
ターミナルで以下を実行し、ディスクの容量分だけ利用できるようにファイルシステムを拡張する。

```bash
$ sudo raspi-config  --expand-rootfs
```

容量は再起動後に反映されますので、一旦QEMU画面を閉じます。
ターミナル上で「run.sh」を実行して、Raspberry Pi OSを再度起動します。

# スワップ領域増加
スワップ領域も少ないので下記コマンドで修正を行います。
初心者にも比較的使いやすい nanoテキストエディターを使用します。
アンダーバーが入力できないので数値のみを変更する。

```bash
$ sudo nano /etc/dphys-swapfile
/etc/dphys-swapfile

CONF_SWAPSIZE=2048
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/df41f771-4a02-4447-0ecf-9cf93688e680.png)

```bash
$ sudo dphys-swapfile install
$ sudo dphys-swapfile swapon
$ swapon　-s
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/cbd1a328-3676-7884-eb40-3b14dc76d598.png)

# アップデート
空き容量を増えたので、アップデートしておきます。

```bash
$ sudo apt update
```

# その他
## SSH
スタートボタンメニューから「設定」の「Raspberry Pi設定」をクリックします。
Raspberry Pi設定画面のインターフェイスタブにて、SSHを有効にして「OK」ボタンをクリックします。
設定後に再起動確認画面が出てくるので「はい」ボタンをクリックします。
[Raspberry Pi 4にSSHとVNCで接続してみた](https://dev.classmethod.jp/articles/raspberry-pi-4-ssh-vnc-remote/)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/32c99173-2e33-c18f-09d7-715d3963cf6c.png)

ターミナル上で「run.sh」を実行して、Raspberry Pi OSを再度起動します。

Raspberry Pi OS上のターミナル画面から、「hostname -i」でホスト名のipアドレスを確認できます。

```bash
# ホスト名のipアドレスを表示
$ hostname -i
127.0.0.1
```

ターミナルをもう一つ起動してSSHに接続します。
Raspberry Piのホスト名が「127.0.0.1」になっているので、下記を入力します。

```
% ssh pi@127.0.0.1 -p 2222

パスワード入力 raspberry
```

Raspberry Pi OS上に接続できたので、lsb_releaseコマンドでバージョンを確認してみます。

```bash
pi@raspberrypi ~ $ lsb_release -a
No LSB modules are available.
Distributor ID: Raspbian
Description:    Raspbian GNU/Linux 10 (buster)
Release:        10
Codename:       buster
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/43cb916e-e6f0-1d7c-2e19-8f50f5783886.png)
sshコマンド時に「WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!」が出たら下記サイトを参考に対応して下さい。
[SSH接続時にエラー](https://qiita.com/hanlio/items/179add527421c3b7839c)

## Web Browser
Web Browserのアイコンをクリックすれば、数分かかりますがブラウザが起動します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/0c252b7f-d98b-cb6b-1d68-56a50a693eb9.png)

## VSCode
Raspberry Piのクロスコンパイルをしたかったので、一番インストールしたいアプリケーションであった。

```bash
$ sudo apt install code
```

インストールが完了するまで時間がかなりかかります。
スリープするとネットワークまで停止するので、一時的にスリープを解除しておくといいでしょう。

インストールが完了するとメニューのプログラミング配下に「Visual Studio Code」が追加されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/06c40b9d-c87d-997f-306c-604f1b98b290.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/dff2d789-4bfe-3722-db5c-894b131a7d00.png)
動きますが、ものすごく重たいです。また、C++とかコンポーネントのダウンロード中で進まない状態など使用するには難あり。

### Remort SSH
**Remort SSHするだけなら、Raspberry Pi OS側にVSCodeをインストールする必要はありません。**

親側のMacにもVisual Studio Codeをインストールして、「Remort SSH」で動くことを期待したのですが、残念ながらリモート側にVSCodeをインストールしようとしてエラーになってしまいます。

```txt
[01:23:33.672] Spawned 6088
[01:23:33.769] > local-server> Spawned ssh: 6091
[01:23:33.771] stderr> OpenSSH_8.1p1, LibreSSL 2.7.3
[01:23:48.772] stderr> ssh: connect to host 127.0.0.1 port 2222: Operation timed out
[01:23:48.773] > local-server> ssh child died, shutting down
[01:23:48.776] Local server exit: 0
[01:23:48.777] Received install output: OpenSSH_8.1p1, LibreSSL 2.7.3
ssh: connect to host 127.0.0.1 port 2222: Operation timed out

[01:23:48.780] Resolver error: Error: The operation timed out
```

【2021/07/08追記】
接続が安定しないながらも何度かリトライすることで、Remort SSHが実現することが出来ました。
開発言語にC++として拡張機能をインストールしました。

* C/C++
* C/C++ IntelliSense

Hello Worldではつまらないのでフィボナッチ数列を求めるプログラムを作成し、デバッグしています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/75b6d96e-8590-d767-9a91-43b3105909ef.png)
クライアントとリモートホストが両方ともMacという組み合わせですが、ホストとの通信が安定せず接続が度々切れてしまうのが残念です。

# 不満点
* アンダーバーとパイプと円マークがキーボードで入力できない
* ~~画面サイズが変更できない~~
* ~~Visual Studio CodeでRemort SSHが動作しない~~

画面サイズは、Raspberry Pi設定にあるDisplayタブの解像度の設定はDefaltしか存在しない。下記サイトを参考に「/boot/config.txt」の設定を変更してみたのですが何も変わりませんでした。
[RaspberryPiの解像度が変えられない時の対処法](https://www.mechatronahibi.com/raspi-disp-resolution-config/)

## キー入力の調査結果
【2021/07/08追記】
versatilepbマシンではアンダーバーとパイプと円マークは入力できるので、`xev`でキーコードを調べるとKeyCodeは97(underscore)と132(yen bar)でした。Raspi2、Raspi3マシンで`xev`でキーコードを調べようとしても反応しないのです。
つまり、キースキャンができないのでXmodmapでKeyCode 97と132に割り当てしても反応しない。
そのため、空いているところに(例 シフト+スペースキーにアンダーバー)割り当てることなら可能です。

# 最後に
Linuxで動作することができたので、Macでも試してみると同様に動作させることが出来ました。

今回の件でネットでかなり検索しましたが、raspi2マシンとraspi３マシンで画面まで表示しているサイトはありませんでした。需要がないのか、SSHのみならlite版で済ますからそこまでやらないのかって感じですかね。


不満点のキーボードと~~画面サイズ~~の件が分かる方がいたらコメントを頂けると嬉しいです。

# 参考
* [How to emulate Raspios natively in QEMU](https://peterbabic.dev/blog/how-emulate-raspios-natively-qemu/)
* [Emulate RaspberryPi 2 on Ubuntu 20.04 using qemu](https://lynxbee.com/emulate-raspberrypi-2-on-ubuntu-20-04-using-qemu/)
* [QEMUとRaspberry PI - 山の上のブログ](http://www.yamanoue.atnifty.com/2020/08/qemuraspberry-pi.html)
* [QEMU on WindowsでネイティブのRaspberry Pi OS (64-bit) を動かす](https://blog.k-san.info/raspios-arm64-on-qemu-on-win)
* [QEMU on M1 Mac](https://qiita.com/hjmr/items/abeb9a4567d08ddcc3b9)
* [arm raspi2/raspi3 emulation has no USB support](https://bugs.launchpad.net/qemu/+bug/1772165)