riscv 中断和异常处理
特權(quán)架構(gòu)
處理器在架構(gòu)上一般都會(huì)有幾種特權(quán)模式,比如x86架構(gòu)有“ring0~ring3”4種級(jí)別,一般操作系統(tǒng)內(nèi)核和驅(qū)動(dòng)運(yùn)行在ring0級(jí)別,也就是最高級(jí)別,而普通的應(yīng)用程序運(yùn)行在ring3級(jí)別,也就是權(quán)限最低的級(jí)別;再比如arm架構(gòu)有7種處理器模式,操作系統(tǒng)一般運(yùn)行在Supervisor模式,而應(yīng)用程序運(yùn)行在User模式。
那么為什么處理器架構(gòu)在設(shè)計(jì)時(shí)需要設(shè)計(jì)好幾種級(jí)別不同的模式呢?原因是為了不同作用的程序考慮的。比如一般操作系統(tǒng)享有最高級(jí)別的權(quán)限,可以訪問(wèn)系統(tǒng)所有硬件,執(zhí)行所有特權(quán)指令,例如設(shè)置MMU頁(yè)表等,那么設(shè)置MMU頁(yè)表這種操作能讓普通的應(yīng)用程序來(lái)操作嗎,當(dāng)然是不行的,所以操作系統(tǒng)和普通應(yīng)用這兩種程序肯定是需要運(yùn)行在不同級(jí)別的權(quán)限模式下的,如果普通程序強(qiáng)行去執(zhí)行特權(quán)指令操作,要么沒(méi)有任何反應(yīng)要么系統(tǒng)產(chǎn)生異常,這樣就從硬件上保證了安全性。
同樣的,RISCV架構(gòu)下有三種特權(quán)級(jí)別,分別是Machine、Supervisor和User,簡(jiǎn)稱M模式、S模式和U模式。M模式權(quán)限最高,在這個(gè)級(jí)別下的程序可以訪問(wèn)一切硬件和執(zhí)行所有特權(quán)指令;S模式一般用于運(yùn)行操作系統(tǒng),可以設(shè)置MMU使用虛擬地址;U模式一般是普通應(yīng)用程序使用,權(quán)限最低。
M模式使用物理地址進(jìn)行訪問(wèn),不經(jīng)過(guò)MMU,但是有類似arm下cortex-m中的MPU功能;S模式可以通過(guò)設(shè)置MMU來(lái)使用虛擬地址訪問(wèn)內(nèi)存,所以像Linux這類操作系統(tǒng)都運(yùn)行在S模式下。那么有人要問(wèn)了,為啥RISCV架構(gòu)特權(quán)模式設(shè)計(jì)成這樣,直接把M模式和S模式合二為一不行嗎?這個(gè)得從RISCV架構(gòu)誕生背景來(lái)看了,RISCV架構(gòu)誕生于2010年左右,這時(shí)不管是x86還是arm架構(gòu)都發(fā)展得算是比較成熟了,所以RISCV架構(gòu)設(shè)計(jì)時(shí)就定位了從微控制器到大型超級(jí)計(jì)算機(jī)都可以使用這個(gè)架構(gòu)。在微控制器上使用的RISCV架構(gòu)一般只有M模式,或者使用M和U兩種模式,類似于cortex-m架構(gòu)的定位;而在帶MMU的芯片上,RISCV架構(gòu)一般都使用M、S和U三種模式,這樣通過(guò)“拼積木”的方式就可以讓RISCV架構(gòu)適用于各種場(chǎng)景了。
在arm下的應(yīng)用程序通過(guò)“swi”指令可以將處理器從低特權(quán)級(jí)別切換到高特權(quán)級(jí)別,一般像Linux下的系統(tǒng)調(diào)用都是通過(guò)這種方式來(lái)使用的。類似的,在RISCV中,通過(guò)“ecall”指令可以從低特權(quán)切換到高特權(quán),在U模式下執(zhí)行就切換到S模式,在S模式下調(diào)用就切換到M模式。另外在RISCV中,默認(rèn)產(chǎn)生中斷和異常時(shí),處理器自動(dòng)切換到M模式處理,可以通過(guò)中斷托管設(shè)置將一些中斷和異常直接交給S模式處理。RISCV的架構(gòu)設(shè)計(jì)就決定了必須要有程序運(yùn)行在M模式下,來(lái)為S模式提供一些基礎(chǔ)的服務(wù),RISCV為此定義了SBI(Supervisor Binary Interface)接口規(guī)范,讓運(yùn)行在S模式下的操作系統(tǒng)在不同的RISCV處理器上都可以使用標(biāo)準(zhǔn)的SBI接口來(lái)使用相應(yīng)的功能,這個(gè)其實(shí)就有點(diǎn)類似于x86下的BIOS概念了,詳細(xì)的RISCV下中斷和異常處理以及SBI規(guī)范在后續(xù)章節(jié)會(huì)講解,這里只需要知道就可以。
中斷和異常處理
在RISCV架構(gòu)設(shè)計(jì)中,有一系列的控制和狀態(tài)寄存器(Control and Status Registers)簡(jiǎn)稱CSR,在三種特權(quán)級(jí)別下都有其對(duì)應(yīng)的CSR,比如m模式下的命名都為mxxxx,s模式下的都為sxxxx等等。這些寄存器的作用類似于arm架構(gòu)中的那些cp15寄存器,用于設(shè)置異常向量表、設(shè)置頁(yè)表基址、獲取異常信息等等。這些寄存器大多數(shù)都需要通過(guò)“csr”這類指令來(lái)進(jìn)行訪問(wèn),也有一部分寄存器是采用mmio映射的,可以使用普通訪存指令訪問(wèn),比如timer相關(guān)的寄存器(后面會(huì)講)。這些寄存器比較重要的就是和中斷異常相關(guān)的,下面我們來(lái)一起看看這些寄存器。
1. M模式下重要的CSR
M模式下的比較重要的寄存器如下所示,當(dāng)然除了下圖列出之外的寄存器,m模式下還有其他的一些寄存器,具體的請(qǐng)參考RISCV特權(quán)架構(gòu)官方文檔。
上圖中的寄存器被分為四類,其中和Trap相關(guān)的寄存器比較重要,用于中斷和異常處理:
信息類:主要用于獲取當(dāng)前芯片id和cpu核id等信息。
Trap設(shè)置:用于設(shè)置中斷和異常相關(guān)寄存器。
Trap處理:用于處理中斷和異常相關(guān)寄存器。
內(nèi)存保護(hù):作用類似于conterx-m中的mpu功能。
下面我們來(lái)著重介紹前三類寄存器。
1.1 Machine Information Registers
mvendorid、 marchid和 mimpid 可以獲取芯片制造商、架構(gòu)和實(shí)現(xiàn)相關(guān)信息,最重要的還是 mhartid 這個(gè)寄存器,RISCV中每個(gè)cpu核都被稱為一個(gè)hart,通過(guò)mhartid可以獲取當(dāng)前cpu核的id號(hào)。
1.2 Machine Trap Setup
在RISCV中,中斷(interrupt)和異常(exception)被統(tǒng)稱為trap。在arm中我們知道中斷和異常是通過(guò)中斷向量表中不同入口調(diào)用不同的處理函數(shù)處理的,但是在riscv中,所有中斷和異常一般都是使用的同一個(gè)處理入口。在x86和arm下都存在中斷向量表的概念,用于定義不同異常和中斷的處理入口,但是在riscv下,一般是不存在中斷向量表這個(gè)概念的,只存在trap處理入口這個(gè)概念。為了表述上的方便,后續(xù)的章節(jié)都將trap處理入口稱為中斷入口,但是要明白這個(gè)入口不僅僅是處理中斷的,同時(shí)也是處理異常的入口。中斷入口在m模式和s模式下都有專門的寄存器需要設(shè)置,在本小節(jié)我們只看m模式下的相關(guān)寄存器,在使用中斷和異常處理之前需要進(jìn)行一些設(shè)置,下面就來(lái)看看這些寄存器如何設(shè)置。
1.2.1 mtvec
riscv支持向量中斷和非向量中斷兩種編程模型, 非向量中斷,也就是中斷發(fā)生后,所有的入口只有一個(gè),不固定偏移。
mtvec寄存器全名為Machine Trap-Vector Base-Address Register,用于設(shè)置中斷入口地址,其寄存器格式如下
可以看出mtvec需要中斷入口地址是4字節(jié)對(duì)齊的,因?yàn)樽畹蛢蓚€(gè)bit是用于設(shè)置中斷模式的,其模式定義如下:
Direct模式:所有的中斷和異常使用同一個(gè)中斷入口地址,一般都會(huì)設(shè)置為這種模式。
Vectored模式:所有異常使用同一個(gè)入口地址,但是不同的中斷使用不同的入口地址。
1.2.2mstatus
這個(gè)寄存器顧名思義是用來(lái)控制cpu核當(dāng)前的一些狀態(tài)信息的,比如全局中斷使能等,寄存器的格式如下:
紅框內(nèi)的位域用來(lái)控制全局中斷的使能,SIE控制S模式下全局中斷,MIE控制M模式下全局中斷。這個(gè)有點(diǎn)像arm里cpsr中的F位,只是在RISCV架構(gòu)下還分為S模式和M模式來(lái)控制,像但是不完全像。
綠框里的位域用來(lái)記錄發(fā)生中斷之前MIE和SIE的值。SPIE記錄的是SIE的值,MPIE記錄的是MIE的值。
藍(lán)色框內(nèi)位域用來(lái)記錄當(dāng)特權(quán)級(jí)別由低到高發(fā)生變化時(shí)(比如執(zhí)行ecall指令),之前的特權(quán)級(jí)別。當(dāng)變化后的特權(quán)級(jí)別是S模式時(shí),SPP表示變化之前的特權(quán)級(jí)別是S模式還是U模式,所以只需要1位就可以表示;當(dāng)變化后的特權(quán)級(jí)別是M模式時(shí),MPP表示變化之前是S模式還是U模式還是M模式,由于有三種情況,所以需要使用2位來(lái)表示。
注意:當(dāng)發(fā)生中斷時(shí),SIE和MIE被硬件自動(dòng)設(shè)置為0,用來(lái)屏蔽中斷,這個(gè)行為和大部分架構(gòu)都一樣,同時(shí)MPIE和SPIE被硬件自動(dòng)設(shè)置為MIE和SIE的值,如果特權(quán)級(jí)別還發(fā)生改變的話,之前的特權(quán)級(jí)別是記錄在SPP或者M(jìn)PP中的。當(dāng)從中斷中返回時(shí),SIE和MIE被自動(dòng)設(shè)置為MPIE和SPIE的值,同時(shí)MPIE和SPIE被自動(dòng)設(shè)置為1,特權(quán)級(jí)別恢復(fù)為MPP或者SPP記錄的級(jí)別,然后MPP或者SPP被設(shè)置為U模式。
1.2.3 mie
在RISCV下,將中斷(interrupt)又細(xì)分為三種類型:定時(shí)中斷(timer)、核間中斷(soft)、中斷控制器中斷(external)。定時(shí)中斷可以用于產(chǎn)生系統(tǒng)的tick,核間中斷用于不同cpu核之間通信,中斷控制器則負(fù)責(zé)所有外設(shè)中斷。這個(gè)設(shè)計(jì)和arm下有點(diǎn)不一樣,在arm多核下,架構(gòu)中的定時(shí)器中斷、核間中斷和外設(shè)中斷都是統(tǒng)一由中斷控制器管理的,而在RISCV中定時(shí)器和核間中斷是分離出來(lái)的,這兩個(gè)中斷被稱為CLINT(Core Local Interrupt),而管理其他外設(shè)中斷的中斷控制器則被稱為PLIC(Platform-Level Interrupt Controller)。每個(gè)核都有自己的定時(shí)器和產(chǎn)生核間中斷的寄存器可以設(shè)置,這些寄存器的訪問(wèn)不同于其他的控制狀態(tài)寄存器,采用的是MMIO映射方式訪問(wèn),比如下圖所示為SIFIVE FU540的CLINT寄存器表:
圖中的msip用于產(chǎn)生m模式下的核間中斷,mtime可以讀取出當(dāng)前計(jì)數(shù)器的值,mtimecmp用于設(shè)置比較值,當(dāng)mtime的值增加到mtimecmp的值時(shí)就可以產(chǎn)生中斷。這些寄存器的具體用法在后續(xù)的裸機(jī)程序編寫章節(jié)會(huì)講解,這里只需要簡(jiǎn)單了解即可。
上述講解的三種中斷類型在m模式和s模式下都有相應(yīng)的中斷使能位設(shè)置,這是通過(guò)mie寄存器實(shí)現(xiàn)的,mie寄存器的格式如下:
MSIE、MTIE、MEIE這三個(gè)位域分別控制m模式下核間中斷、定時(shí)中斷、中斷控制器中斷的使能狀態(tài)。
SSIE、STIE、SEIE這三個(gè)位域分別控制s模式下核間中斷、定時(shí)中斷、中斷控制器中斷的使能狀態(tài)。
1.2.4medeleg和mideleg
RISCV下默認(rèn)所有中斷和異常都是在m模式下處理的,但是有些時(shí)候我們需要將中斷和異常直接交給s模式處理,這就是RISCV中的中斷托管機(jī)制。通過(guò)mideleg寄存器,可以將三種中斷交給s模式處理,通過(guò)medeleg寄存器,可以將異常交給s模式處理。下面來(lái)具體看看這些寄存器格式。
當(dāng)我們想把中斷交給s模式處理時(shí),我們可以設(shè)置mideleg寄存器,這個(gè)寄存器格式如下:
bit[1]用于控制是否將核間中斷交給s模式處理。
bit[5]用于控制是否將定時(shí)中斷交給s模式處理。
bit[9]用于控制是否將中斷控制器管理的中斷交給s模式處理。
注意對(duì)于核間中斷和定時(shí)中斷而言,即使使能了mideleg中對(duì)應(yīng)的bit位,當(dāng)產(chǎn)生相應(yīng)中斷時(shí),還是先進(jìn)入m模式進(jìn)行處理,然后可以通過(guò)設(shè)置mip寄存器(下一小節(jié)講解),在退出m模式中斷時(shí)就可以進(jìn)入s模式的中斷處理函數(shù)中處理。
當(dāng)我們想把異常交給s模式處理時(shí),我們可以設(shè)置medelrg寄存器,這個(gè)寄存器格式如下:
可以看出來(lái)有很多異常是可以設(shè)置到s模式下處理的,但是實(shí)際使用時(shí)并不是所有異常都要交給s模式處理的,比如bit[9]代表的異常還是要交給m模式處理,因?yàn)橄瘾@取芯片id、cpu核id、設(shè)置timer等操作只能在m模式下進(jìn)行,所以s模式通過(guò)SBI接口(后面會(huì)講)使用“ecall”切換到m模式調(diào)用不同的服務(wù),所以bit[9]代表的異常必須被m模式處理而不能交給s模式處理。
1.3 Machine Trap Handling
當(dāng)產(chǎn)生中斷或者異常時(shí),會(huì)有一些信息保存在相應(yīng)的寄存器中,下面我們就一起來(lái)看看這些寄存器。
1.3.1 mepc
在arm架構(gòu)中,當(dāng)發(fā)生中斷或異常時(shí),硬件自動(dòng)將要返回的地址保存在lr寄存器中。類似的,在RISCV下產(chǎn)生中斷或異常時(shí),硬件自動(dòng)將返回地址保存在mepc寄存器中,當(dāng)在中斷處理中返回時(shí),硬件自動(dòng)將mepc中的地址賦值給pc運(yùn)行。
要注意的時(shí),在RISCV架構(gòu)中,當(dāng)產(chǎn)生的時(shí)異常時(shí),mepc中保存的是產(chǎn)生異常那條指令的地址,而不是其下一條指令地址,這么設(shè)計(jì)的原因是希望產(chǎn)生異常時(shí),軟件開(kāi)發(fā)人員對(duì)相應(yīng)異常做出處理,當(dāng)處理完之后再次給一個(gè)運(yùn)行之前產(chǎn)生異常指令的機(jī)會(huì),比如缺頁(yè)異常就是通過(guò)這種機(jī)制來(lái)運(yùn)行的。當(dāng)不需要再次運(yùn)行產(chǎn)生異常那條指令時(shí),需要在中斷處理時(shí)手動(dòng)將mepc的值加4,這樣中斷返回時(shí)就是運(yùn)行產(chǎn)生異常那條指令的下一條指令。當(dāng)產(chǎn)生的是中斷時(shí),mepc直接保存的就是被中斷指令的下一條指令的地址,所以需要做修正。
1.3.2 mcause和mtval
當(dāng)產(chǎn)生中斷和異常時(shí),mcause寄存器中會(huì)記錄當(dāng)前產(chǎn)生的中斷或者異常類型,而mtval則針對(duì)某些異常會(huì)記錄一些輔助信息。我們來(lái)看看mcause寄存器的格式:
寄存器的最高位用來(lái)表示產(chǎn)生的是中斷還是異常,1表示中斷0表示異常。剩下的位域表示中斷或者異常的具體類型,如下所示:
可以看出來(lái)中斷有6種類型,分別表示m和s模式下的定時(shí)、核間、中斷控制器這三種中斷,而異常的類型就比較多了。
1.3.3 mip
這個(gè)寄存器可以表明當(dāng)前是否產(chǎn)生了某種中斷,其格式如下所示。
MSIP表示m模式核間中斷,此位只讀,其狀態(tài)反應(yīng)的是CLINT中對(duì)應(yīng)的核間中斷設(shè)置寄存器最低位的狀態(tài),設(shè)置CLINT核間中斷設(shè)置寄存器最低位為1則產(chǎn)生核間中斷,置0則清除核間中斷。
MTIP表示m模式定時(shí)中斷,此位只讀,其狀態(tài)通過(guò)設(shè)置CLINT中對(duì)應(yīng)的mtimecmp寄存器來(lái)清零。
MEIP表示m模式中斷控制器中斷,此位只讀,其狀態(tài)通過(guò)具體的中斷控制器寄存器設(shè)置來(lái)清零。
SSIP表示s模式核間中斷,此位在s模式只讀(s模式下有sip寄存器,下面會(huì)講),在m模式下可讀寫,通過(guò)設(shè)置此位,可以進(jìn)入s模式核間中斷處理。
STIP表示s模式定時(shí)中斷,此位在m模式下可讀寫,通過(guò)設(shè)置此位,可以進(jìn)入s模式定時(shí)中斷處理。
SEIP表示s模式中斷控制器中斷,此位在m模式下可讀寫,通過(guò)設(shè)置此位,可以進(jìn)入s模式中斷控制器中斷處理。
2. S模式下重要的CSR
S模式下的CSR寄存器大部分都和M模式下的類似,只不過(guò)是可以在s模式下進(jìn)行訪問(wèn)而已。因?yàn)樵趍模式可以訪問(wèn)其他模式下的寄存器,在其他模式下只能訪問(wèn)他自己模式下的csr寄存器。S模式下的一些csr寄存器如下所示。
可以看出大部分的寄存器都和m模式下的類似,作用也是一樣的,這里就不再贅述了。我們這里看一個(gè)m模式下沒(méi)有的寄存器satp,這個(gè)寄存器是s模式下用來(lái)設(shè)置頁(yè)表基址的,其格式如下。
PPN位域用于填寫頁(yè)表在內(nèi)存中的物理基址。
ASID可以先不關(guān)心,當(dāng)作都為0。
MODE位域用來(lái)選擇是否開(kāi)啟頁(yè)表,如果是64位還用來(lái)選擇虛擬地址翻譯的位數(shù),如下:
如果是0 表示禁用頁(yè)表翻譯功能,64位架構(gòu)下一般虛擬地址選用sv39。
RISCV基礎(chǔ)開(kāi)發(fā)(三)
總結(jié)
以上是生活随笔為你收集整理的riscv 中断和异常处理的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: switch的用法
- 下一篇: 如何发行自己的TRC20代币,并上线Ju