Coresight CPU 除錯模組¶
- 作者:
Leo Yan <leo.yan@linaro.org>
- 日期:
2017 年 4 月 5 日
簡介¶
Coresight CPU 除錯模組定義在 ARMv8-a 架構參考手冊 (ARM DDI 0487A.k) 的“H 部分:外部除錯”章節中,CPU 可以整合除錯模組,主要用於兩種模式:自託管除錯 (self-hosted debug) 和外部除錯 (external debug)。通常,外部除錯模式為人們所熟知,即外部偵錯程式透過 JTAG 埠連線到 SoC;另一方面,程式可以探索依賴自託管除錯模式的除錯方法,本文件將重點關注這部分內容。
該除錯模組提供基於取樣的效能分析擴充套件,可用於取樣 CPU 程式計數器、安全狀態和異常級別等;通常每個 CPU 都帶有一個專用的除錯模組用於連線。基於自託管除錯機制,當核心發生 panic 時,Linux 核心可以從 mmio 區域訪問這些相關暫存器。核心 panic 的回撥通知器將為每個 CPU 轉儲相關暫存器;最終這有助於 panic 的輔助分析。
實現¶
在驅動註冊期間,它使用 EDDEVID 和 EDDEVID1 — 兩個裝置 ID 暫存器來判斷是否實現了基於取樣的效能分析功能。在某些平臺上,此硬體功能是完全或部分實現的;如果不支援此功能,則註冊將失敗。
在編寫本文件時,除錯驅動程式主要依賴於核心 panic 回撥通知器從三個取樣暫存器(EDPCSR、EDVIDSR 和 EDCIDSR)收集的資訊:從 EDPCSR 我們可以獲取程式計數器;EDVIDSR 包含安全狀態、異常級別、位寬等資訊;EDCIDSR 是上下文 ID 值,包含 CONTEXTIDR_EL1 的取樣值。
該驅動支援執行在 AArch64 或 AArch32 模式下的 CPU。它們之間的暫存器命名約定略有不同,AArch64 使用 ‘ED’ 作為暫存器字首 (ARM DDI 0487A.k, 第 H9.1 章),而 AArch32 使用 ‘DBG’ 作為字首 (ARM DDI 0487A.k, 第 G5.1 章)。該驅動統一使用 AArch64 命名約定。
ARMv8-a (ARM DDI 0487A.k) 和 ARMv7-a (ARM DDI 0406C.b) 具有不同的暫存器位定義。因此驅動程式整合了兩種差異
如果 PCSROffset=0b0000,則在 ARMv8-a 上未實現 EDPCSR 功能;但 ARMv7-a 定義“PCSR 樣本透過一個取決於指令集狀態的值進行偏移”。對於 ARMv7-a,驅動程式會進一步檢查 CPU 是否執行在 ARM 或 Thumb 指令集下並校準 PCSR 值,偏移量的詳細說明可在 ARMv7-a ARM (ARM DDI 0406C.b) 的 C11.11.34 章“DBGPCSR,程式計數器取樣暫存器”中找到。
如果 PCSROffset=0b0010,ARMv8-a 定義“EDPCSR 已實現,且樣本未應用偏移,並且在 AArch32 狀態下不採樣指令集狀態”。因此,在 ARMv8 上,如果 EDDEVID1.PCSROffset 為 0b0010 且 CPU 在 AArch32 狀態下執行,則不會取樣 EDPCSR;當 CPU 在 AArch64 狀態下執行時,EDPCSR 將被取樣且不應用偏移。
時鐘和電源域¶
在訪問除錯暫存器之前,我們應確保時鐘和電源域已正確啟用。在 ARMv8-a ARM (ARM DDI 0487A.k) 的“H9.1 除錯暫存器”章節中,除錯暫存器分為兩個域:除錯域和 CPU 域。
+---------------+
| |
| |
+----------+--+ |
dbg_clock -->| |**| |<-- cpu_clock
| Debug |**| CPU |
dbg_power_domain -->| |**| |<-- cpu_power_domain
+----------+--+ |
| |
| |
+---------------+
對於除錯域,使用者使用 DT 繫結“clocks”和“power-domains”來指定除錯邏輯的相應時鐘源和電源。驅動程式根據需要呼叫 pm_runtime_{put|get} 操作來處理除錯電源域。
對於 CPU 域,不同的 SoC 設計具有不同的電源管理方案,最終這將嚴重影響外部除錯模組。因此我們可以將其分為以下幾種情況
在具有健全電源控制器且能正確處理 CPU 電源域的系統上,CPU 電源域可以透過驅動中的暫存器 EDPRCR 進行控制。驅動程式首先寫入 EDPRCR.COREPURQ 位以啟動 CPU,然後寫入 EDPRCR.CORENPDRQ 位以模擬 CPU 掉電。結果是,這可以確保在訪問除錯相關暫存器期間,CPU 電源域能夠正確供電;
某些設計會在叢集中的所有 CPU 都掉電時關閉整個叢集的電源 — 包括除錯暫存器中應在除錯電源域內保持供電的部分。在這種情況下,EDPRCR 中的位不受尊重,因此這些設計不支援 CoreSight / 除錯設計者所期望的掉電除錯功能。這意味著即使檢查 EDPRSR 也有可能在目標暫存器未通電時導致匯流排掛起。
在這種情況下,在未通電時訪問除錯暫存器將導致災難;因此我們需要在啟動時或使用者在執行時啟用模組時,阻止 CPU 進入低功耗狀態。有關詳細用法資訊,請參閱“如何使用模組”章節。
裝置樹繫結¶
詳細資訊請參見 Documentation/devicetree/bindings/arm/arm,coresight-cpu-debug.yaml。
如何使用模組¶
如果您想在啟動時啟用除錯功能,可以將“coresight_cpu_debug.enable=1”新增到核心命令列引數中。
該驅動程式也可以作為模組工作,因此可以在 insmod 模組時啟用除錯功能。
# insmod coresight_cpu_debug.ko debug=1
如果在啟動時或 insmod 模組時您未啟用除錯功能,驅動程式會使用 debugfs 檔案系統提供一個開關,以便動態啟用或停用除錯功能
要啟用它,請向 /sys/kernel/debug/coresight_cpu_debug/enable 寫入 ‘1’
# echo 1 > /sys/kernel/debug/coresight_cpu_debug/enable
要停用它,請向 /sys/kernel/debug/coresight_cpu_debug/enable 寫入 ‘0’
# echo 0 > /sys/kernel/debug/coresight_cpu_debug/enable
如“時鐘和電源域”章節所述,如果您在一個具有空閒狀態以關閉除錯邏輯電源且電源控制器無法很好地響應來自 EDPRCR 請求的平臺上工作,那麼在啟用 CPU 除錯功能之前,您應首先限制 CPU 的空閒狀態;這樣才能確保對除錯邏輯的訪問。
如果您想在啟動時限制空閒狀態,可以在核心命令列中使用“nohlt”或“cpuidle.off=1”。
在執行時,您可以透過以下方法停用空閒狀態
可以透過 PM QoS 子系統停用 CPU 空閒狀態,更具體地說,是使用“/dev/cpu_dma_latency”介面 (詳細資訊請參閱PM 服務質量介面)。正如 PM QoS 文件中指定的那樣,請求的引數將一直有效,直到檔案描述符被釋放。例如
# exec 3<> /dev/cpu_dma_latency; echo 0 >&3
...
Do some work...
...
# exec 3<>-
同樣的操作也可以透過應用程式完成。
從 cpuidle sysfs 停用特定 CPU 的特定空閒狀態 (參見CPU 空閒時間管理)
# echo 1 > /sys/devices/system/cpu/cpu$cpu/cpuidle/state$state/disable
輸出格式¶
以下是除錯輸出格式的示例
ARM external debug module:
coresight-cpu-debug 850000.debug: CPU[0]:
coresight-cpu-debug 850000.debug: EDPRSR: 00000001 (Power:On DLK:Unlock)
coresight-cpu-debug 850000.debug: EDPCSR: handle_IPI+0x174/0x1d8
coresight-cpu-debug 850000.debug: EDCIDSR: 00000000
coresight-cpu-debug 850000.debug: EDVIDSR: 90000000 (State:Non-secure Mode:EL1/0 Width:64bits VMID:0)
coresight-cpu-debug 852000.debug: CPU[1]:
coresight-cpu-debug 852000.debug: EDPRSR: 00000001 (Power:On DLK:Unlock)
coresight-cpu-debug 852000.debug: EDPCSR: debug_notifier_call+0x23c/0x358
coresight-cpu-debug 852000.debug: EDCIDSR: 00000000
coresight-cpu-debug 852000.debug: EDVIDSR: 90000000 (State:Non-secure Mode:EL1/0 Width:64bits VMID:0)