核心記憶體對映I/O追蹤

主頁和可選使用者空間工具的連結

MMIO tracing 最初由 Intel 在 2003 年左右為他們的故障注入測試工具開發。在 2006 年 12 月 - 2007 年 1 月,Jeff Muizelaar 使用 Intel 的程式碼建立了一個工具,用於跟蹤以 Nouveau 專案為目標的 MMIO 訪問。從那時起,許多人都做出了貢獻。

Mmiotrace 是為逆向工程任何記憶體對映 IO 裝置而構建的,Nouveau 專案是第一個真正的使用者。僅支援 x86 和 x86_64 架構。

樹外 mmiotrace 最初由 Pekka Paalanen <pq@iki.fi> 修改,以便包含在主線和 ftrace 框架中。

準備工作

Mmiotrace 功能透過 CONFIG_MMIOTRACE 選項編譯。 預設情況下,跟蹤被停用,因此將其設定為 yes 是安全的。 支援 SMP 系統,但如果多個 CPU 線上,則跟蹤不可靠且可能錯過事件,因此 mmiotrace 在執行時啟用期間會使除一個 CPU 之外的所有 CPU 離線。 您可以手動重新啟用 CPU,但已被警告,無法自動檢測您是否由於 CPU 競爭而丟失事件。

使用快速參考

$ mount -t debugfs debugfs /sys/kernel/debug
$ echo mmiotrace > /sys/kernel/tracing/current_tracer
$ cat /sys/kernel/tracing/trace_pipe > mydump.txt &
Start X or whatever.
$ echo "X is up" > /sys/kernel/tracing/trace_marker
$ echo nop > /sys/kernel/tracing/current_tracer
Check for lost events.

使用

確保 debugfs 已掛載到 /sys/kernel/debug。 如果沒有(需要 root 許可權)

$ mount -t debugfs debugfs /sys/kernel/debug

檢查要跟蹤的驅動程式是否未載入。

啟用 mmiotrace(需要 root 許可權)

$ echo mmiotrace > /sys/kernel/tracing/current_tracer

開始儲存跟蹤

$ cat /sys/kernel/tracing/trace_pipe > mydump.txt &

“cat”程序應在後臺保持執行(睡眠)。

載入要跟蹤的驅動程式並使用它。 Mmiotrace 僅捕獲在 mmiotrace 啟用時 ioremapped 的區域的 MMIO 訪問。

在跟蹤期間,您可以透過 $ echo “X is up” > /sys/kernel/tracing/trace_marker 將註釋(標記)放入跟蹤中。這使得更容易檢視(巨大)跟蹤的哪個部分對應於哪個操作。建議放置描述性的標記來描述你所做的事情。

關閉 mmiotrace(需要 root 許可權)

$ echo nop > /sys/kernel/tracing/current_tracer

“cat”程序退出。 如果沒有,透過發出“fg”命令並按 ctrl+c 來殺死它。

檢查 mmiotrace 是否由於緩衝區已滿而丟失事件。 可以是

$ grep -i lost mydump.txt

告訴你準確地丟失了多少事件,或者使用

$ dmesg

檢視核心日誌並查詢“mmiotrace has lost events”警告。 如果事件丟失,則跟蹤不完整。 你應該擴大緩衝區並重試。 透過首先檢視當前緩衝區有多大來擴大緩衝區

$ cat /sys/kernel/tracing/buffer_size_kb

給你一個數字。 大約將此數字加倍並寫回,例如

$ echo 128000 > /sys/kernel/tracing/buffer_size_kb

然後從頭開始。

如果您正在為驅動程式專案進行跟蹤,例如 Nouveau,您還應該在傳送結果之前執行以下操作

$ lspci -vvv > lspci.txt
$ dmesg > dmesg.txt
$ tar zcf pciid-nick-mmiotrace.tar.gz mydump.txt lspci.txt dmesg.txt

然後傳送 .tar.gz 檔案。 跟蹤會大大壓縮。 將“pciid”和“nick”替換為您正在調查的硬體的 PCI ID 或型號名稱以及您的暱稱。

Mmiotrace 如何工作

透過呼叫 ioremap_*() 函式之一來對映 PCI 匯流排的地址來獲得對硬體 IO 記憶體的訪問。 Mmiotrace 被掛鉤到 __ioremap() 函式中,並在每次建立對映時被呼叫。 對映是一個記錄到跟蹤日誌中的事件。 請注意,ISA 範圍對映不會被捕獲,因為對映始終存在並直接返回。

MMIO 訪問透過頁面錯誤記錄。 就在 __ioremap() 返回之前,對映的頁面被標記為不存在。 對頁面的任何訪問都會導致錯誤。 頁面錯誤處理程式呼叫 mmiotrace 來處理錯誤。 Mmiotrace 將頁面標記為存在,設定 TF 標誌以實現單步執行並退出錯誤處理程式。 執行出錯的指令,並輸入除錯陷阱。 在這裡,mmiotrace 再次將頁面標記為不存在。 指令被解碼以獲取操作型別(讀/寫)、資料寬度和讀取或寫入的值。 這些儲存到跟蹤日誌中。

在頁面錯誤處理程式中設定頁面存在在 SMP 機器上存在競爭條件。 在單步執行期間,其他 CPU 可能會在該頁面上自由執行,並且可能會在沒有通知的情況下丟失事件。 不鼓勵在跟蹤期間重新啟用其他 CPU。

跟蹤日誌格式

原始日誌是文字,易於使用 grep 和 awk 等工具進行過濾。 一個記錄是日誌中的一行。 記錄以關鍵字開頭,後跟依賴於關鍵字的引數。 引數用空格分隔,或持續到行尾。 版本 20070824 的格式如下

解釋 關鍵字 空格分隔的引數

讀取事件 R 寬度、時間戳、對映 ID、物理地址、值、PC、PID 寫事件 W 寬度、時間戳、對映 ID、物理地址、值、PC、PID ioremap 事件 MAP 時間戳、對映 ID、物理地址、虛擬地址、長度、PC、PID iounmap 事件 UNMAP 時間戳、對映 ID、PC、PID 標記 MARK 時間戳、文字 版本 VERSION 字串“20070824” 讀取器資訊 LSPCI 來自 lspci -v 的一行 PCI 地址對映 PCIDEV 空格分隔的 /proc/bus/pci/devices 資料 未知 opcode UNKNOWN 時間戳、對映 ID、物理地址、資料、PC、PID

時間戳以秒為單位,帶小數。 物理地址是 PCI 匯流排地址,虛擬地址是核心虛擬地址。 寬度是以位元組為單位的資料寬度,值是資料值。 對映 ID 是一個任意 ID 號,用於標識在操作中使用的對映。 PC 是程式計數器,PID 是程序 ID。 如果未記錄,PC 為零。 PID 始終為零,因為尚不支援跟蹤源自使用者空間記憶體的 MMIO 訪問。

例如,以下 awk 過濾器將傳遞目標地址在 [0xfb73ce40, 0xfb800000] 範圍內的所有 32 位寫入

$ awk '/W 4 / { adr=strtonum($5); if (adr >= 0xfb73ce40 &&
adr < 0xfb800000) print; }'

開發人員工具

使用者空間工具包括以下實用程式
  • 用硬體暫存器名稱替換數字地址和值

  • 重放 MMIO 日誌,即重新執行記錄的寫入