QEMU ARM異常處理流程

precise exception必須考慮暫存器和內存,其中我理解的暫存器爲CPUState,在二進制翻譯中,我們關注的是guest的precise exception。因此必須確保當guest代碼發生異常時,guest的暫存器(CPUState)和內存必須滿足precise exception的要求,這樣guest的exception handler才能正確處理該異常。

QEMU在每一個可能發生異常的指令或是helper function之前,會將CPUState的大部分內容更新,少數未更新的內容會在guest真正發生異常時重新再計算,對於arm來說,pc和condition code屬於後者。在二進制翻譯中,出於效率上的考慮,通常會在一個basic block的結尾才更新guest pc,而非每翻譯一個guest指令就更新guest pc。


下面以guest發生缺頁時產生的異常爲例,觀察QEMU是如何維護正確的guest暫存器和內存的。

配置qemu下的SConstruct文件,打開qemu調試宏,根據x86的translate.c文件中的gen_pc_load函數中的調試宏,在arm中添加修改這個宏,使其在debug模式下可以輸出引發異常的host pc,和與其相對應的guest pc。

因爲真正發生異常的是host binary,因此必須通過它找到guest pc,查出是哪一條guest指令發生異常,並做相應的處理。

因此使用gdb加載qemu-syste-arm,在gdb下啓動v5的os,打開日誌文件開關,輸出in_asm,op,out_asm,和自己添加的spc和esp,之後continue,在內核引導的過程中,會出現異常,bt發現沒有stack信息,說明這是翻譯過來的host binary代碼產生的,也就是guest cpu產生的異常。

打開日誌文件,搜索spc,發現第一個引起異常的host pc爲0x405156bc,對應的guest pc爲0xc0140a98,這時查看第一次翻譯0xc0140a98所得到的host binary


可以看出,spc 0x405156bc = 0x405156bd – 1,也也就是callq 0x5fe7c0下一條指令所在的地址減1,因此是調用 0x5fe470這個函數時發生了異常;嘗試在gdb下打印print __st{b,w,l,q}_{cmmu, mmu}和__ld{b,w,l,q}_{cmmu,mmu},發現恰巧是__stw_mmu出現異常


根據搜索找到qemu/softmmu_tempate.h中,


不命中執行else分支,在else分支中,會根據GETPC的返回值區分是一般C函數還是code cache中調用的,如果不爲零,則爲code cache中所調用;

只後調用tlb_fill函數,這個函數在target-arm/op-helper.c中定義,


在tlb_fill函數中,首先進入cpu_arm_handle_mmu_fault函數根據返回值判斷是否要處理異常


如果返回值爲1,且taddr不爲0,則執行異常處理,見下圖:


首先,將retaddr轉換爲ulong,這個值代表發生異常的host binary所在的地址;之後根據發生異常的host binary所在的地址(retaddr),調用tb_find_pc函數查找是哪一個tb中的host binary發生異常,如果找到了,則確定這是一個guest的異常,qemu通過調用cpu_restore_state()函數,restore guest CPUState以便guest exception handler處理guest的缺頁異常


如本文檔開頭所描述,通常情況下qemu在翻譯quest binary時是不會記錄guest pc的,這時爲了定位guest pc,qemu在翻譯guest binary會記錄額外的信息,包含guest pc。(這是通過傳遞searched_pc來判斷是否記錄額外信息),可參看上圖中的註釋;

比較重要的函數是target-arm/translate.c中的gen_intermediate_code_internal這個函數,比較長,就不貼圖了,裏面提高如何處理condexec bit,保存完必要的信息後,重新翻譯,覆蓋原來的翻譯結果(翻譯的結果應該是一樣的,只是爲了保存必要信息)

之後重要的是


其中j爲某個數已經在這個函數中被標記了,這裏的遍歷是爲了找到這個j,詳情可看函數tcg_gen_code_search_pc。

之後調用


其中#if中的內容不用在意,是我爲了調試加上去的,重點是下面那兩個語句,給我的感覺是設置pc(這個還沒看手冊)和條件位。

回到


這個地方,執行raise_exception,參數是異常信息,在cpu_restore_state中設置的,

Raise_exception最終是調用了longjmp函數,這是程序會長跳轉到cpu-exec.c中的cpu_exec(cpu_arm_exec)這個主要的函數中,調用do_interrput函數處理異常。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章