(萊昂氏unix原始碼分析導讀-20)中斷、陷入的入口和出口
陷入處理程式的入口都為“trap”(這裡是指一個彙編程式,而非PDP11指令);
中斷則不同。他們有不同的入口,如:
525 .=60^. 當前地址設定為60 octal
526 klin; br4 /(中斷向量地址為60,電傳打字機輸入的中斷處理程式)
527 klou; br4 /(中斷向量地址為64,電傳打字機輸出的中斷處理程式)
但是,如果接著往下看,你會發現所有的中斷處理程式都指向了同一個入口“call”:
0557: .globl _klrint
0558: klin: jsr r0,call; _klrint
0559:
0560: .globl _klxint
0561: klou: jsr r0,call; _klxint
更進一步的,你會發現,陷入程式的入口“trap”在執行了少許操作之後,就會跳到“call”,
也就是說陷入和中斷的處理程式入口最終合二為一。
如果“前狀態”為user態,則“call”在785行跳到真正的處理程式:
0785: jsr pc,*(r0)+
否則,則會在0799行進行這樣的操作:
0799 jsr pc,*(r0)+
對陷入來說,這個處理程式必然是trap函式(2693,c語言函式)——0762的jsr指令將_trap
0762: jsr r0,call1; _trap
而中斷則為不同的中斷處理程式,如電傳打字機輸入:
0558: klin: jsr r0,call; _klrint 打字機輸入的中斷處理程式:klrint
對於“前狀態”為user態的程序來說,從中斷和陷入處理程式返回後,還會執行一項非常重要的操作,即
會檢查runrun標誌,如此時有更高優先順序的程序,則呼叫swtch()切換程序。因此,中斷(陷入)處理程式
為“前狀態為user態”的程序提供了一個程序切換的時機。
為何對“前狀態”為核心態的程式不提供程序切換的機會呢?前面其實已經說明了原因,
還記得那個原則末——減少核心態的程序切換,以減少核心資料結構衝突的可能。
最後,通過“rtt”指令恢復pc和PS,即回到中斷(陷入)前的情形。
萊昂的10.4小節對trap和call程式有很細緻的描述,但可能仍有部分讀者對Return部分有疑問。其實,最好的方法
是拿出紙筆,畫一畫前後的棧圖——你一定會一目瞭然。這裡,我給出一種呼叫情況的棧圖,以供參考:
【情況說明】:User態程序中斷,進入call例程 ---- 返回call例程----直接retrun回user態(runrun == 0)
棧圖還能幫助我們理解Trap入口處那個詭異的操作(0756: mov PS,-4(sp))。
假設中斷髮生,中斷向量指向Trap,且nofault為0。
可見,自此Trap和Call擁有了相同的棧結構,並開始複用後面的程式碼。
需要特別注意的是:
New PS 的low 5 bit,在trap例程中才有意義,可以用來區分中斷原因。
512 Trap; br7+0; /bus error
513 Trap; br7+1; /illegal instruction
514 Trap; br7+2; /bpt trace trap
515 Trap; br7+3;
….
顯然,不同的中斷使用不同的PS,而br7+n中的n即構成new PS的low 5 bit——即中斷原因。