PCIe: 使用python訪問PCIe進(jìn)行debug
掃描二維碼
隨時(shí)隨地手機(jī)看文章
當(dāng)進(jìn)行問題定位時(shí),我們通常會(huì)使用setpci命令和lspci命令發(fā)起PCIe的cfg請(qǐng)求對(duì)PCIe的配置空間寄存器進(jìn)行訪問。經(jīng)常進(jìn)行PCIe問題定位的朋友可能會(huì)有自己的一套檢查方案,例如檢查某些寄存器是否存在異常,通過腳本輸出相關(guān)打印,從而快速發(fā)現(xiàn)問題。而此時(shí)使用python調(diào)用setpci和lspci命令并且按自己期望的格式輸出打印將會(huì)極大提高debug效率。
本文描述如何通過python調(diào)用setpci命令對(duì)PCIe的配置空間寄存器進(jìn)行訪問。
腳本如下
#!/usr/bin/env python3import?subprocess ?# 導(dǎo)入subprocess模塊,用于執(zhí)行系統(tǒng)命令import?os ? ? ? ? ?# 導(dǎo)入os模塊,用于訪問環(huán)境變量def?pcie_cfg_rd(bdf, addr, n_bytes=4):? ? ws = setpci_width(n_bytes)? ??print(f"setpci -s?{bdf}?{str(addr)}.{ws}")? ? cmd =?f"setpci -s?{bdf}?{str(addr)}.{ws}"??? ? out = subprocess.check_output(cmd, shell=True).decode("ASCII").strip()? ??#out = subprocess.check_output(cmd, shell=True).decode("ASCII")? ? data =?int(out,?16)? ??print(f"out:{out:s}")? ??print(f"data:{data:x}")? ??return?data# setpci_width函數(shù)保持不變def?setpci_width(n_bytes):? ??if?n_bytes ==?4:? ? ? ??return?'L'? ??elif?n_bytes ==?2:? ? ? ??return?'W'? ??elif?n_bytes ==?1:? ? ? ??return?'B'? ??else:? ? ? ??raise?Exception(f"Illegal data width?{n_bytes}?bytes for setpci.")bdf="15:00.0"bar0_low_32b = pcie_cfg_rd(bdf,?"0x10")bar0_hig_32b = pcie_cfg_rd(bdf,?"0x14")ep_lane_err = pcie_cfg_rd(bdf,?"ECAP0019+08")print(f"bar0_low_32b:0x{bar0_low_32b:x}?bar0_hig_32b:0x{bar0_hig_32b:x}")
腳本執(zhí)行結(jié)果如下:
setpci?-s?15:00.0?0x10.Lout:e000000cdata:e000000csetpci?-s?15:00.0?0x14.Lout:0000021fdata:21fsetpci?-s?15:00.0?ECAP0019+08.Lout:00000000data:0bar0_low_32b:0xe000000c bar0_hig_32b:0x21f
如打印描述:腳本執(zhí)行的命令是setpci -s 15:00.0 0x10.L、setpci -s 15:00.0 0x14.L和setpci -s 15:00.0 ECAP0019+08.L。在terminal直接執(zhí)行如上命令結(jié)果如下:
[]e000000c[]0000021f[]00000000[]
python腳本使用的關(guān)鍵語句如下
1.?cmd = f"setpci -s {bdf} {str(addr)}.{ws}"
這是一個(gè)**f-string格式化字符串**,用于動(dòng)態(tài)構(gòu)建
setpci命令(PCIe配置空間讀取工具的命令)。各部分含義:
{str(addr)}:將addr(例如代碼中的"0x10"、"0x14")轉(zhuǎn)換為字符串,代表配置空間的偏移地址(十六進(jìn)制)。{ws}:由setpci_width函數(shù)返回的寬度標(biāo)識(shí)(L表示4字節(jié),W表示2字節(jié),B表示1字節(jié)),用于指定讀取的數(shù)據(jù)長度。setpci:Linux系統(tǒng)中用于讀取/修改PCIe設(shè)備配置空間的工具命令。-s {bdf}:-s參數(shù)指定目標(biāo)PCIe設(shè)備的BDF地址(格式為域:總線:設(shè)備.功能),{bdf}會(huì)被變量bdf的值(例如代碼中的"15:00.0")替換,用于定位具體設(shè)備。{str(addr)}.{ws}:指定讀取配置空間的偏移地址和數(shù)據(jù)寬度:最終構(gòu)建的命令示例:當(dāng)
bdf="15:00.0"、addr="0x10"、ws="L"時(shí),cmd的值為"setpci -s 15:00.0 0x10.L",表示“讀取PCIe設(shè)備15:00.0在配置空間偏移0x10處的4字節(jié)數(shù)據(jù)”。
2.?out = subprocess.check_output(cmd, shell=True).decode("ASCII").strip()
這行代碼通過
subprocess模塊執(zhí)行上述構(gòu)建的cmd命令,并處理輸出結(jié)果:subprocess.check_output(cmd, shell=True):執(zhí)行cmd命令(shell=True表示通過shell解析命令),并返回命令的標(biāo)準(zhǔn)輸出(字節(jié)流)。若命令執(zhí)行失敗(返回非0狀態(tài)碼),會(huì)拋出CalledProcessError異常。.decode("ASCII"):將命令輸出的字節(jié)流(bytes類型)轉(zhuǎn)換為ASCII編碼的字符串(str類型),便于后續(xù)處理。.strip():去除字符串首尾的空白字符(包括換行符\n、空格等)。例如,setpci命令的原始輸出可能帶有換行符(如"e000000c\n"),strip()后會(huì)變?yōu)榧償?shù)據(jù)字符串"e000000c"。最終
out變量的值為命令輸出的純數(shù)據(jù)字符串(例如"e000000c"或"0000021f"),用于后續(xù)轉(zhuǎn)換為整數(shù)。
注意事項(xiàng)
再調(diào)用pcie_cfg_rd功能時(shí),addr需要加上雙引號(hào)表示字符格式是字符串,因?yàn)閟etpci命令支持兩種地址訪問。直接地址訪問,例如0x10,0x14等等。間接地址訪問是以能力結(jié)構(gòu)描述符加偏移量的形式體現(xiàn),例如ECAP0019+08。





