# 自行套用及編譯 Strata／ROCm MES 核心修補指南

日期：2026 年 10 月 30 日（香港時間）

這份指南說明如何將 [MES 修補檔](ubuntu-7.0.0-38-mesfix-complete.patch) 套用到 Linux 核心原始碼，再編譯及安裝成**另一個獨立核心版本**。`.patch` 本身不是可以直接執行或編譯的程式。

本文只提供操作步驟；不會自動執行安裝或重新開機。已經完成安裝的人不需要重複操作。

## 1. 適用範圍與必要準備

本次實際驗證的組合：

| 項目 | 版本／設定 |
|---|---|
| 作業系統 | Ubuntu 26.04.1 LTS，x86-64 |
| 原版核心 | `7.0.0-38-generic` |
| Ubuntu 原始碼套件 | `linux-source-7.0.0=7.0.0-38.38` |
| 原始碼 Makefile 版本 | `7.0.14` |
| 新核心版本名稱 | `7.0.14-strata-mesfix1` |
| GPU | 雙 RX 7900 XTX，GFX11／`gfx1100` |
| 驅動排程設定 | `sched_policy=0` |
| Strata 環境變數 | `GPU_MAX_HW_QUEUES=8` |

**7.0 是 Linux 核心版本，不是 Ubuntu 版本。** 其他發行版或核心版本可能需要先移植修補，不能保證直接套用。上游討論與移植來源見文末。

> **嘗試前，必須先備份並保留原本可正常開機的核心、對應 modules 與 initramfs，並確認 GRUB 可以選回舊核心。不要覆蓋或刪除唯一可用的核心。若新核心完全當機，可能需要實體重啟，再從 GRUB 選擇原版核心。**

本指南採用我們實際使用的原始碼直接建置方式，**不會產生 `.deb` 核心套件，也不會安裝可供所有 DKMS 套件使用的 headers 套件**。Ubuntu 官方另有 `.deb` 建置流程；不要把兩種流程的安裝步驟混在一起。[Ubuntu 官方建置指南](https://ubuntu.com/kernel/docs/how-to/develop-customise/build-kernel/)

若開機所需的儲存設備或檔案系統依賴 ZFS 等外掛模組，或需要 NVIDIA 等第三方驅動，必須另行為新核心建置及驗證對應模組；以下 `modules_install` 只安裝這份核心原始碼建出的模組。

先確認環境與磁碟空間：

```bash
uname -r
cat /etc/os-release
df -h "$HOME" /boot
mokutil --sb-state
```

編譯一般需要數十分鐘，時間取決於 CPU、儲存裝置及平行工作數。完整 Ubuntu 設定含除錯資料，應預留充足磁碟空間；空間需求可能超過數十 GiB。

**Secure Boot：本次實測環境是關閉狀態。** 如果你的 Secure Boot 已啟用，這份手動建置的核心不能直接視為可開機：需要另外簽署核心、處理模組簽章並註冊可信任的 MOK。先完成該流程再試開機；本文沒有代替你關閉 Secure Boot。[Ubuntu Secure Boot 說明](https://documentation.ubuntu.com/security/security-features/platform-protections/secure-boot/)

以下命令在**同一個 Bash 工作階段**依序執行；每一步成功後才進入下一步。命令中的原版核心名稱是本次驗證版本，不能直接當作所有讀者機器的版本。

## 2. 備份原核心，並保護它不被自動移除

若已有完整、可用的備份，可核對後沿用，不需要每次重複備份。第一次操作可使用以下方式。

```bash
OLD_KERNEL=7.0.0-38-generic
BACKUP_DIR="$HOME/kernel-backups/mesfix-$(date +%Y%m%d-%H%M%S)"

# 確認原核心及模組仍在；任一項不存在就先停止。
test -s "/boot/vmlinuz-$OLD_KERNEL"
test -s "/boot/initrd.img-$OLD_KERNEL"
test -d "/lib/modules/$OLD_KERNEL"

mkdir -p "$BACKUP_DIR"
chmod 700 "$BACKUP_DIR"
printf '%s\n' "$OLD_KERNEL" > "$BACKUP_DIR/original-kernel-version.txt"

# tar 保留檔案權限及符號連結；不會刪除原檔。
sudo tar -cpf "$BACKUP_DIR/original-kernel.tar" -C / \
  "boot/vmlinuz-$OLD_KERNEL" \
  "boot/initrd.img-$OLD_KERNEL" \
  "boot/config-$OLD_KERNEL" \
  "boot/System.map-$OLD_KERNEL" \
  "lib/modules/$OLD_KERNEL"

sudo tar -cpf "$BACKUP_DIR/boot-settings.tar" -C / \
  etc/default/grub etc/default/grub.d etc/grub.d \
  etc/modprobe.d boot/grub/grub.cfg boot/grub/grubenv

sudo tar -tf "$BACKUP_DIR/original-kernel.tar" | head -20
sudo sha256sum "$BACKUP_DIR/original-kernel.tar" \
  "$BACKUP_DIR/boot-settings.tar" > "$BACKUP_DIR/SHA256SUMS"

sudo apt-mark manual \
  "linux-image-$OLD_KERNEL" \
  "linux-modules-$OLD_KERNEL"
```

確認備份完成且可讀；最好另外保存一份到可在救援環境存取的裝置。`apt-mark manual` 是防止這些已安裝套件被自動移除，並不是完整備份，也不會禁止一般 Ubuntu 更新。

如果你的套件名稱不同，請先查詢實際安裝套件，不能忽略找不到套件的錯誤：

```bash
dpkg-query -W '*7.0.0-38*'
```

## 3. 在安裝新核心前，先把舊核心保留為預設

這一步適用於使用 Ubuntu GRUB 的系統。先從目前 GRUB 設定找出原核心的 menu ID，避免把本機 UUID 寫死給其他人使用：

```bash
OLD_ENTRY=$(sudo python3 - "$OLD_KERNEL" <<'PYTHON'
import pathlib, re, sys
text = pathlib.Path('/boot/grub/grub.cfg').read_text()
submenu = re.search(r"'(gnulinux-advanced-[^']+)'", text)
entry = re.search(
    r"'(gnulinux-" + re.escape(sys.argv[1]) + r"-advanced-[^']+)'", text)
if not submenu or not entry:
    raise SystemExit('找不到原核心的 GRUB menu ID，請停止並人工確認。')
print(submenu.group(1) + '>' + entry.group(1))
PYTHON
)
```

確認上一步沒有錯誤，而且 `OLD_ENTRY` 不是空值，才繼續。若已有同名 drop-in，先保留一份：

```bash
test -n "$OLD_ENTRY"

if sudo test -f /etc/default/grub.d/99-strata-mesfix-default.cfg; then
  sudo cp -a /etc/default/grub.d/99-strata-mesfix-default.cfg \
    "$BACKUP_DIR/grub-default-before-mesfix.cfg"
fi

sudo tee /etc/default/grub.d/99-strata-mesfix-default.cfg >/dev/null <<EOF
# 在驗證新核心前，讓原本可正常開機的核心維持為預設。
GRUB_DEFAULT="$OLD_ENTRY"
GRUB_SAVEDEFAULT=false
GRUB_TIMEOUT_STYLE=menu
GRUB_TIMEOUT=10
GRUB_RECORDFAIL_TIMEOUT=10
EOF

sudo update-grub
sudo grub-script-check /boot/grub/grub.cfg
sudo grep -F "set default=\"$OLD_ENTRY\"" /boot/grub/grub.cfg
sudo grub-editenv /boot/grub/grubenv list
```

最後的 `grep` 必須找到原核心的預設設定。若其他 `/etc/default/grub.d/*.cfg` 覆寫了它，先排除衝突再繼續。若 `grubenv` 中存在非空的 `next_entry`，代表還有一次性開機選擇，需先確認其用途；不要以為永久預設值一定會套用到下一次開機。

## 4. 安裝編譯工具及指定原始碼套件

```bash
sudo apt update
sudo apt install build-essential bc bison flex libssl-dev \
  libelf-dev libdw-dev dwarves cpio rsync libncurses-dev \
  zstd gawk patch xz-utils bzip2 python3

sudo apt install linux-source-7.0.0=7.0.0-38.38
```

如果套件庫已沒有這個版本，**不要直接改成最新版並假設附件仍相容**。需要取得相同的可信任 Ubuntu 原始碼版本，或先對其他版本重新移植與檢查修補。

這份 Ubuntu 核心設定啟用了 Rust；本次使用以下工具組：

```bash
sudo apt install rustc rust-1.93-src bindgen clang-21 llvm-21 lld-21
```

這些套件名稱是 Ubuntu 26.04 的實測例子；其他版本不一定提供相同名稱或版本。

## 5. 準備原始碼與修補檔

建立全新的工作目錄，避免混入之前的建置產物：

```bash
BUILD_DIR="$HOME/kernel-mesfix-build"
mkdir "$BUILD_DIR"
cd "$BUILD_DIR"
tar -xf /usr/src/linux-source-7.0.0.tar.bz2
```

把下載的 `ubuntu-7.0.0-38-mesfix-complete.patch` 複製到 `$BUILD_DIR` 內，與解壓後的 `linux-source-7.0.0` 目錄並列。不要在尚未修補前的目錄中執行其他版本的 patch。

```bash
cd "$BUILD_DIR/linux-source-7.0.0"
PATCH_FILE="$BUILD_DIR/ubuntu-7.0.0-38-mesfix-complete.patch"
test -s "$PATCH_FILE"
head -6 Makefile

patch --batch --dry-run --fuzz=0 -p1 < "$PATCH_FILE"
```

只有 dry-run 完整成功後，才正式套用：

```bash
patch --batch --fuzz=0 -p1 < "$PATCH_FILE"
find . -name '*.rej' -print
```

**若出現 FAILED、反向套用提示或 `.rej`，先停止。不要強行忽略失敗的 hunk，也不要對已套用的來源重複套用。** 沒有 `.rej` 也不代替檢查 `patch` 的退出狀態與完整輸出。

## 6. 使用原核心設定，給新核心獨立版本名稱

```bash
cp "/boot/config-$OLD_KERNEL" .config

scripts/config --set-str LOCALVERSION '-strata-mesfix1'
scripts/config --disable LOCALVERSION_AUTO
scripts/config --set-str SYSTEM_TRUSTED_KEYS ''
scripts/config --set-str SYSTEM_REVOCATION_KEYS ''

make olddefconfig
make rustavailable
make -s kernelrelease
```

此處應顯示：

```text
7.0.14-strata-mesfix1
```

清空上面兩個憑證路徑，是因為直接建置的原始碼樹沒有 Ubuntu 發行套件所引用的 Canonical 憑證檔。這不是完整的 Secure Boot 簽署流程；建置過程會為模組產生自己的簽署金鑰，不能因此假設韌體已信任新核心。

可以檢視與原設定的差異：

```bash
scripts/diffconfig "/boot/config-$OLD_KERNEL" .config
```

不要為了讓編譯通過，任意關閉 NVMe、ext4、AMDGPU／KFD 或你開機所需的驅動。若 Rust 或工具版本檢查失敗，先處理工具鏈問題。

## 7. 編譯核心

以下用 8 個平行工作作為例子；依記憶體及需要保留給其他服務的 CPU 資源調整：

```bash
set -o pipefail
make -j8 2>&1 | tee "$BUILD_DIR/build.log"
```

**建置退出狀態必須成功，不能只因為產生了 `bzImage` 就認為所有模組也成功。** 若失敗，先查明第一個錯誤。缺少工具或 header 時，補齊後通常可在同一工作目錄重新執行 `make -j8`，不必每次清除所有已編譯檔案。

成功後確認：

```bash
test -s arch/x86/boot/bzImage
test -s System.map
make -s kernelrelease
```

## 8. 設定本次要測試的驅動排程方式

先檢查既有設定，避免重複或互相矛盾的 `sched_policy`：

```bash
grep -Rns --include='*.conf' 'sched_policy' \
  /etc/modprobe.d /lib/modprobe.d
sudoedit /etc/modprobe.d/amdgpu.conf
```

在檔案中將既有值調整為 0，或在沒有該選項時加入以下設定；保留其他原有 AMDGPU 選項：

```ini
options amdgpu sched_policy=0
```

再檢查實際合併結果：

```bash
modprobe -c | grep '^options amdgpu '
```

更改檔案不會立即改變已載入的驅動。後續建立新核心的 initramfs 時會納入此設定；也可以更新保留的原核心 initramfs，使其下次使用同一設定：

```bash
sudo update-initramfs -u -k "$OLD_KERNEL"
```

原 initramfs 已在第 2 步備份。這裡不需要卸載 AMDGPU，也不要為了套用參數而強制重設正在使用中的 GPU。

## 9. 安裝成另一個獨立核心

先確認不會覆蓋已存在的相同版本：

```bash
NEW_KERNEL=$(make -s kernelrelease)
test "$NEW_KERNEL" = '7.0.14-strata-mesfix1'
test "$NEW_KERNEL" != "$OLD_KERNEL"
test ! -e "/boot/vmlinuz-$NEW_KERNEL"
test ! -e "/lib/modules/$NEW_KERNEL"
```

任何一項檢查失敗就停止；若該版本已安裝，先確認原因，不能直接覆蓋。

接著逐項安裝，每項都必須成功：

```bash
sudo make -j8 modules_install INSTALL_MOD_STRIP=1
sudo install -m 0600 arch/x86/boot/bzImage "/boot/vmlinuz-$NEW_KERNEL"
sudo install -m 0600 System.map "/boot/System.map-$NEW_KERNEL"
sudo install -m 0644 .config "/boot/config-$NEW_KERNEL"

sudo depmod -a "$NEW_KERNEL"
sudo update-initramfs -c -k "$NEW_KERNEL"
sudo update-grub
sudo grub-script-check /boot/grub/grub.cfg
```

這不會刪除原核心。也不要執行核心清理或移除舊核心的命令。

檢查必要檔案及模組版本：

```bash
sudo ls -lh "/boot/vmlinuz-$NEW_KERNEL" "/boot/initrd.img-$NEW_KERNEL"
modinfo -k "$NEW_KERNEL" -F vermagic amdgpu
modinfo -k "$NEW_KERNEL" -F vermagic nvme
sudo grep -F "set default=\"$OLD_ENTRY\"" /boot/grub/grub.cfg
```

模組 vermagic 應以新核心版本開頭。這是檔案檢查，尚不代表新核心一定可以開機。

## 10. 首次從 GRUB 手動選擇新核心

先儲存工作，正常關閉正在執行的推論及其他需要保護的工作，再由你決定何時重新開機。

在 GRUB 的 **Advanced options for Ubuntu／Ubuntu 進階選項** 中，選擇：

```text
Ubuntu, with Linux 7.0.14-strata-mesfix1
```

保持第 3 步的舊核心預設值及 `GRUB_SAVEDEFAULT=false`，這次手動選擇就不會把新核心永久設為預設。若測試失敗，下一次正常開機仍應選舊核心；如果完全凍結，可能需要實體重啟。選單名稱可能因系統語言而不同，請以版本號辨識。

如果開機進入舊核心，先確認當時選擇的項目，不要把「系統能開機」當成「修補核心已生效」。

## 11. 新核心開機後的驗證

```bash
uname -r
cat /sys/module/amdgpu/parameters/sched_policy
ls -l /dev/kfd /dev/dri/render*
```

預期新核心為 `7.0.14-strata-mesfix1`，實際 `sched_policy` 為 `0`。

使用你自己的 ROCm 環境執行：

```bash
rocminfo
```

若 `rocminfo` 沒有加入 PATH，請使用你安裝的 ROCm 執行檔完整路徑及所需 library 環境。雙 RX 7900 XTX 應偵測到兩個 `gfx1100` GPU agent；單卡或其他硬體不可照抄此預期數量。

再將環境變數設定到**實際啟動 Strata 的程序或啟動器 profile**：

```bash
export GPU_MAX_HW_QUEUES=8
```

這個 `export` 只影響目前 shell 與其後啟動的子程序，**不會修改已在執行的 Strata 引擎**，也不會自動傳入另外啟動的桌面 launcher 或 systemd service。

先確認 GPU 偵測與模型載入正常，再從較短提示逐步測試長提示，並觀察模型載入後及推論完成後的待機負載。記錄 hang、watchdog、GPU fault/reset 等錯誤，不能只看一次請求成功。

## 12. 若新核心不能正常使用，如何切回

1. 重新開機；若完全凍結，可能需要實體重啟。
2. 在 GRUB 進階選項選擇原版 `7.0.0-38-generic`。
3. 開機後以 `uname -r` 確認已回到原版。
4. 保留失敗紀錄，再調查原因；不要刪掉仍可使用的原核心。

本指南在測試階段維持舊核心為永久預設，所以正常情況下不需要先登入新核心才能回復。若你之後自行把新核心設為永久預設，復原時要先從 GRUB 手動選回原版，再把永久預設值改回原版。

**只有在完成驗證、並明確決定採用新核心後，才改永久預設值。** 即使採用新核心，也應保留原版與復原入口。

## 13. 後續維護與本次限制

- 這份修補是針對特定 Ubuntu 原始碼版本的移植；新的官方核心不會自動繼承這份本機修改。
- 手動安裝的測試核心不會因為一般 Ubuntu 更新而自動重新建置或取得後續安全修正。之後需檢查官方核心是否已納入上游修正，並規劃更新。
- 若 GRUB 永久固定某個舊版本，未來新安裝的官方核心也不會自動變成實際開機版本；驗證完成後應重新檢視這項設定。
- 本次觀察中，queue=8 待機持續 100% 的症狀沒有再出現；但曾有一次 150K 請求停滯並由 watchdog 終止，之後才有連續 12 次長提示成功。這仍是實驗性 workaround，不能保證所有系統長期穩定。
- 若要分享預先編譯的核心，應另外製作可安裝的核心與匹配 modules／headers 套件；讓接收端產生自己的 initramfs，不要只分享一個 `vmlinuz`。

## 參考來源

- [ROCm/TheRock issue #9141](https://github.com/ROCm/TheRock/issues/9141)
- [AMD 維護者的 MES workaround backport 分支](https://kernel.googlesource.com/pub/scm/linux/kernel/git/superm1/linux/+/refs/heads/superm1/amdgpu-100-7.2.y)
- [GPU reset 期間跳過通知的後續修補](https://www.mail-archive.com/amd-gfx%40lists.freedesktop.org/msg153442.html)
- [Ubuntu 官方：建置自訂核心](https://ubuntu.com/kernel/docs/how-to/develop-customise/build-kernel/)
- [Linux 核心：設定、編譯、模組安裝及保留備用核心](https://docs.kernel.org/admin-guide/README.html#compiling-the-kernel)
- [Ubuntu：UEFI Secure Boot](https://documentation.ubuntu.com/security/security-features/platform-protections/secure-boot/)
