我們在編寫裸機程序(baremetal)、虛擬化管理程序(hypervisor)和操作系統(tǒng)(OS)時,Debug分析程序是必不可少的。不像linux內(nèi)核,有大量的調(diào)試方法,很多裸機程序、hypervisor沒有完善的調(diào)試分析方法。
異常相關寄存器
但也不是無計可施,在硬件上,ARM架構為程序的異常行為提供了詳細的寄存器:
ESR_ELx寄存器(x=1,2,3)
保存發(fā)生異常時的特征,比如異常分類(ESR_ELx.EC)、異常具體原因(ESR_ELx.ISS)等。
ELR_ELx寄存器(x=1,2,3)
保存發(fā)生異常時,保存要返回的地址,一般情況下就是發(fā)生異常時的指令地址。
FAR_ELx寄存器(x=1,2,3)
保存錯誤地址。
HPFAR_EL2寄存器
保存stage-2階段的地址轉換發(fā)生的錯誤IPA地址。
ARM從硬件架構上設計了4層異常級:EL0、EL1、EL2和EL3。不同特權等級的程序,運行在不同的異常級上。本文從hypervisor虛擬機管理程序的角度,講解如何利用這些寄存器,對程序的異常情況進行分析。
hypervisor本身的abort異常
我們以meta-hypervisor出現(xiàn)的具體異常為例:
esr_el2=0x97010046 elr_el2=0xfd8000005880 far_el2=0xfd8000005880
在這兒,esr_el2的值為0x97010046,對應的位域為:
EC | IL | ISS |
---|---|---|
100101 | 1 | 1_0000_0001_0000_0000_0100_0110 |
EC = 100101:
說明是數(shù)據(jù)abort異常,但是沒有發(fā)生異常級改變(EL2);或者,當支持嵌套虛擬化時與VNCR_EL2相關的訪問產(chǎn)生的數(shù)據(jù)abort異常。
ISS編碼(數(shù)據(jù)abort異常的具體原因)
ISV | SAS | SSE | SRT | SF | AR | VNCR | LST | FnV | EA | CM | S1PTW | WnR | DFSC |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
24 | 23-22 | 21 | 20-16 | 15 | 14 | 13 | 12-11 | 10 | 9 | 8 | 7 | 6 | 5-0 |
1 | 00 | 0 | 00001 | 0 | 0 | 0 | 00 | 0 | 0 | 0 | 0 | 1 | 000110 |
通過上面各個位域的信息,綜合得出:把W1寄存器中一個字節(jié)的數(shù)據(jù)寫入內(nèi)存時發(fā)生的錯誤。
我們再來看匯編代碼中,0xfd8000005880地址處的內(nèi)容:
void *memset(void *dest, uint32_t c, uint32_t count) { // ......省略 *d = c; fd8000005874: b94007e0 ldr w0, [sp, #4] fd8000005878: 12001c01 and w1, w0, #0xff fd800000587c: f9400fe0 ldr x0, [sp, #24] fd8000005880: 39000001 strb w1, [x0] d++; fd8000005884: f9400fe0 ldr x0, [sp, #24] fd8000005888: 91000400 add x0, x0, #0x1 fd800000588c: f9000fe0 str x0, [sp, #24] }
代碼中,fd8000005880: 39000001 strb w1, [x0]確實是往x0寄存器中的地址寫入一個字節(jié)。這正好與我們對異常原因分析的結果相同。說明異常正是memset函數(shù)發(fā)生的錯誤。
ISV: 1, 說明23-14位保存著合法指令的異常信息
SAS: 00, 說明訪問字節(jié)數(shù)據(jù)時產(chǎn)生的錯誤
SSE: 0, 字節(jié)訪問不要求符號擴展
SRT: 00001,錯誤指令的Wt/Xt/Rt操作數(shù)的寄存器編號
SF: 0, 指令訪問的是32位通用寄存器
AR: 0, 指令沒有aquire/release語義
VNCR:0, 保留
LST: 00, 產(chǎn)生abort異常的指令未指定
FnV: 0, FAR寄存器是合法的
EA: 0, 表示不是外部abort
CM: 0, 表示錯誤不是由cache維護指令產(chǎn)生的
S1PTW: 0, 表示不是stage-2錯誤
WnR: 0, 表示寫內(nèi)存
DFSC:000110,L2地址翻譯錯誤
如果memset函數(shù)只有一處調(diào)用的話,Bug原因結合代碼就很容易分析出來了。但是,我們自己編寫的hypervisor中有很多處調(diào)用memset函數(shù)的地方。所以,就文中的bug示例而言,目前還不能分析出原因。所以,我們需要使用qemu模擬器,通過gdb進行單步調(diào)試,看看出問題的代碼位置(參見下一篇《QEMU+GDB調(diào)試ARM程序》)。
Guest OS的abort異常
我們設計的hypervisor支持Guest OS觸發(fā)的4類異常,具體定義如下:
abort_handler_tabort_handlers[64]= { [ESR_EC_DALEL]=aborts_data_lower, [ESR_EC_SMC64]=smc64_handler, [ESR_EC_SYSRG]=sysreg_handler, [ESR_EC_HVC64]=hvc64_handler };
ESR_EC_HVC64 = 0x16:用于處理Guest OS發(fā)起的HVC調(diào)用,我們設計使用HVC指令在VM之間建立通信。
ESR_EC_SMC64 = 0x17:用于處理Guest OS發(fā)起的SMC調(diào)用,我們知道ARM規(guī)定了PSCI規(guī)范,通過將電源管理等代碼在ATF代碼中實現(xiàn),這樣就實現(xiàn)了資源的安全管理。PSCI規(guī)范的底層就是通過SMC指令實現(xiàn)的。hypervisor需要將Guest OS發(fā)起的虛擬核的PSCI調(diào)用轉發(fā)給物理核。
ESR_EC_SYSRG = 0x18:模擬寄存器和外設。因為Guest OS需要訪問一些特殊寄存器和外設,而外設有時候需要多個VM共享,hypervisor對其進行模擬。
ESR_EC_DALEL = 0x24:用于處理Guest OS發(fā)生的abort異常。比如,Guest OS訪問我們未指定的物理內(nèi)存。
對于ESR_EL2寄存器的分析,與前面的一段一樣,不在具體詳述。
而HPFAR_EL2寄存器保存著出錯的IPA地址,通過該地址,我們就可以知道,Guest OS訪問哪塊內(nèi)存出錯,就能解決某些bug了。
審核編輯:湯梓紅
-
ARM
+關注
關注
134文章
9179瀏覽量
369400 -
寄存器
+關注
關注
31文章
5369瀏覽量
121264 -
Linux
+關注
關注
87文章
11351瀏覽量
210490
原文標題:ARM深入理解-hypervisor調(diào)試方法一(異常寄存器分析)
文章出處:【微信號:嵌入式ARM和Linux,微信公眾號:嵌入式ARM和Linux】歡迎添加關注!文章轉載請注明出處。
發(fā)布評論請先 登錄
相關推薦
QEMU+GDB調(diào)試ARM程序
電源管理入門:Hypervisor中的電源管理
![電源管理入門:<b class='flag-5'>Hypervisor</b>中的電源管理](https://file1.elecfans.com/web2/M00/B4/8A/wKgZomVvzlmAXIxBAAAce8I3vwY608.png)
學習hypervisor嵌入式產(chǎn)品安全設計
【「嵌入式Hypervisor:架構、原理與應用」閱讀體驗】+第一二章讀后感
【「嵌入式Hypervisor:架構、原理與應用」閱讀體驗】+第三四章閱讀報告
【「嵌入式Hypervisor:架構、原理與應用」閱讀體驗】+全文學習心得
【「嵌入式Hypervisor:架構、原理與應用」閱讀體驗】+ 了解Hypervisor
【「嵌入式Hypervisor:架構、原理與應用」閱讀體驗】+ Hypervisor應用場景調(diào)研
解密ACRN:一個專為物聯(lián)網(wǎng)而設計的Hypervisor
嵌入式Hypervisor的相關資料分享
怎樣通過波形分析方法調(diào)試UART收發(fā)呢
Enea推出實現(xiàn)系統(tǒng)整合技術Enea Hypervisor
Enea Hypervisor技術培訓簡化多核開發(fā)過程
嵌入式Hypervisor了解
![嵌入式<b class='flag-5'>Hypervisor</b>了解](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
評論