PCIEカードをパススルーしてVM上で直接触ってデバッグしたい!

はじめまして､nilpeと申します｡普段はしがない大学生をやってます｡
さて､日々暮らしてると唐突に､qemuから直接ホストに刺さっているpcieカードが使いたいな､ってなることありますよね? [^1]
しかしながら､chatGPTに聞いてもまともな答えは帰って来なかったので､いろいろ試してうまく行った部分を紹介させていただきます｡

:::note warn
警告(再掲)
この手法は､筆者の環境でのみ検証しています｡再現しようとして何らかの問題が発生しても､筆者は責任を取りかねます｡
:::
# 前提
1. 筆者はmarvell 88se9230と呼ばれる､Linux 6.8.0ではマトモに動かない[^2] ([例1](https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1810239)､[例2](https://askubuntu.com/questions/1499732/kernel-6-5-0-14-errors-on-marvell-88se9230))RAIDカードを使っている｡
1. しかしながら､4.4系~5.15系では正常に動作する(らしい)ことを知っている｡ [^3] 
1. 筆者のマシンはamd ryzen7 5700xとTUF GAMING B550-PLUSで組まれている｡本記事ではintel製cpuを想定していない｡
# 下準備
まずは､必要なソフトウェアを用意します｡
以下のコマンドを実行しましょう｡
```bash
sudo apt install -y qemu qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virt-manager

```
次に､必要なデーモンを立ち上げて､ユーザーを登録します｡
```bash
# libvirtデーモンを有効にして起動
sudo systemctl enable --now libvirtd

# ユーザーをlibvirtグループに追加
sudo usermod -aG libvirt $(whoami)

# 設定を反映するために再ログイン
newgrp libvirt

# KVMの状態を確認
sudo systemctl status libvirtd

# インストールされたQEMU/KVMのバージョンやサポート情報を確認
virsh list --all

```
次に､grubの起動ファイル(/etc/default/grub)を編集します｡ACSと呼ばれる､iommuの分離を有効化します｡[こちら](http://vfio.blogspot.com/2014/08/iommu-groups-inside-and-out.html)もご覧ください｡以下のように編集しましょう｡

:::note warn
警告(再掲)
この手法は､筆者の環境でのみ検証しています｡再現しようとして何らかの問題が発生しても､筆者は責任を取りかねます｡
:::
```plaintext
GRUB_CMDLINE_LINUX_DEFAULT="quiet iommu=pt splash amd_iommu=on pcie_acs_override=downstream,multifunction"
```
できたら､以下のコマンドを実行して編集を有効化しましょう｡
```
sudo update-grub
```
acsはカーネルのメインラインにはなく､パッチがあたっているカーネルを利用しなければなりません｡[ACS Override Kernel Builds ](https://queuecumber.gitlab.io/linux-acs-override/)から､所望のカーネルを取得しましょう｡以下は一例です｡
```bash
wget https://gitlab.com/Queuecumber/linux-acs-override/-/jobs/1244659933/artifacts/download
unar ~/Downloads/artifacts.zip
cd ./artifacts
sudo apt install linux-headers-5.12.2-acso_5.12.2-acso-1_amd64.deb linux-image-5.12.2-acso_5.12.2-acso-1_amd64.deb
```
では､デバッグしたいカードのidを取得しましょう｡
```bash
lspci -nnk
```
```plaintext
03:00.0 SATA controller [0106]: Marvell Technology Group Ltd. 88SE9230 PCIe 2.0 x2 4-port SATA 6 Gb/s RAID Controller [1b4b:9230] (rev 11)
	Subsystem: Marvell Technology Group Ltd. 88SE9230 PCIe 2.0 x2 4-port SATA 6 Gb/s RAID Controller [1b4b:9230]
	Kernel driver in use: vfio-pci
	Kernel modules: ahci

```
今回はmarvellのカードが1枚しか刺さっていないので､これが正解です｡出力結果から､｢03:00.0｣と｢1b4b:9230｣という形式のidをメモしておきましょう｡
ここまで来たらリブートして､先程インストールしたカーネルで立ち上げます｡
このままだと､必要なドライバが当たっていないので､とりあえず今現在動いているドライバを蹴り出し､vfioと呼ばれるドライバを当てます｡
vfioについては他の方が解説を挙げていらっしゃると思うので省きます｡
```bash
echo "03:00.0" | sudo tee /sys/bus/pci/drivers/ahci/unbind
echo 1b4b 9230 | sudo tee -a /sys/bus/pci/drivers/vfio-pci/new_id
```
今回はahciが動いていたのでこのコマンドで大丈夫でしたが､他のカードの場合は適切に読み替えてください｡
エラーもなく動いたら､このカードは/dev/vfio/<num>に割り当てられているので､権限を変更します｡
```bash
sudo chmod 666 /dev/vfio/20
```
最後に､qemuにカードを渡します｡
```bash
qemu-system-x86_64   -enable-kvm   -m 2048   -cpu host   -hda ~/ubuntu_vm.qcow2   -device vfio-pci,host=03:00.0   -vga virtio
```
# 結果
qemuにpcieカードが渡ります｡あとは適当な方法でデバッガを当てれば良いと思います｡
![Screenshot from 2024-10-29 21-35-45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3922224/85d3094c-7991-3ff2-b81c-d4d30b51fe1c.png)
それはそれとして､どうしてlinux6.8.0なのにこのRAIDカードは動いてるんですかね･･･?

# 余談
これで動いたとき､一瞬で忘れそうだからと友人にLINEを送りました｡夜遅くにこれを投げられた友人に合掌｡
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3922224/d15469c4-756e-e06c-6e7f-e7335716a5d9.png)

[^1]: ないです｡
[^2]: こればかりは自分の悪運が嫌になりました｡2万円したのに｡
[^3]: 要はリグレッション｡世界で3番目くらいにこれがリグレッションだと気づいた人類かもしれない(傲慢)