一文解析RISC-V SiFive U54內(nèi)核——中斷和異常
中斷
U54內(nèi)核支持M模式和S模式中斷。默認(rèn)情況下,所有中斷都在M模式下處理。對(duì)于支持S模式的 hart,可以有選擇地將中斷委托給S模式。
U54中斷架構(gòu)如下:

U54內(nèi)核還支持兩種類型的 RISC-V 中斷:本地和全局。
本地中斷:U54內(nèi)核的本地中斷只有2種,軟件中斷和定時(shí)器中斷,這兩個(gè)中斷都由本地中斷器(CLINT)生成。本地中斷通過專用中斷異常代碼和固定優(yōu)先級(jí)直接發(fā)送給單個(gè) hart。因此,本地中斷沒有仲裁,也不需要額外的內(nèi)存訪問來確定中斷的原因。
全局中斷:通過平臺(tái)級(jí)中斷控制器 (PLIC) 路由,該控制器可以通過外部中斷將中斷定向到系統(tǒng)中的任何 hart。所有的外設(shè)都屬于全局中斷。
中斷優(yōu)先級(jí)
全局中斷的各個(gè)優(yōu)先級(jí)由 PLIC 確定。
U54內(nèi)核的優(yōu)先級(jí)如下,按優(yōu)先級(jí)降序排列:
機(jī)器外部中斷
機(jī)器軟件中斷
機(jī)器定時(shí)器中斷
主管外部中斷
主管軟件中斷
主管定時(shí)器中斷
異常
如果一個(gè) hart 在S模式下運(yùn)行并嘗試訪問一個(gè)僅M模式的控制和狀態(tài)寄存器 (CSR),這會(huì)立即進(jìn)入異常處理程序并確定下一步行動(dòng)。mstatus 寄存器中的異常代碼將保持值 0x2,表明發(fā)生了非法指令異常。根據(jù)系統(tǒng)的要求,監(jiān)督模式應(yīng)用程序可能會(huì)報(bào)告錯(cuò)誤和/或完全終止程序。
沒有特定的啟用位來允許發(fā)生異常,因?yàn)槟J(rèn)情況下它們總是啟用的。然而,在引導(dǎo)流程的早期,軟件應(yīng)該將 mtvec.BASE 設(shè)置為一個(gè)定義的值,其中包含默認(rèn)異常處理程序的基地址。所有異常都會(huì)捕獲 tomtvec.BASE。軟件必須讀取 mcause CSR 以確定異常的來源,并采取適當(dāng)?shù)拇胧?/p>
在中斷處理程序中發(fā)生的同步異常將立即導(dǎo)致程序執(zhí)行中止中斷處理程序并進(jìn)入異常處理程序。中斷處理程序中的異常通常是軟件錯(cuò)誤的結(jié)果,通常應(yīng)該避免,因?yàn)?mepc 和 mcause CSR 將被原始中斷上下文中捕獲的值覆蓋。
RISC-V 定義的同步異常具有優(yōu)先級(jí)順序,當(dāng)單個(gè)指令同時(shí)發(fā)生多個(gè)異常時(shí),可能需要考慮優(yōu)先級(jí)順序。下表描述了同步異常優(yōu)先級(jí)順序。

數(shù)據(jù)地址斷點(diǎn)(watchpoints)、指令地址斷點(diǎn)、環(huán)境斷點(diǎn)異常(EBREAK)都具有相同的異常碼(3),但優(yōu)先級(jí)不同,如上表所示。
指令地址未對(duì)齊異常 (0x0) 的優(yōu)先級(jí)低于其他指令地址異常,因?yàn)樗鼈兪悄繕?biāo)未對(duì)齊的控制流指令的結(jié)果,而不是取指的結(jié)果。
下面描述了一些用于調(diào)試異常和中斷的有用 CSR:

陷阱trap
術(shù)語陷阱描述了軟件應(yīng)用程序中的控制轉(zhuǎn)移,其中陷阱處理通常在更特權(quán)的環(huán)境中執(zhí)行。例如,一個(gè)特定的 hart 包含三種權(quán)限模式:機(jī)器、管理員和用戶。每種特權(quán)模式都有自己的軟件執(zhí)行環(huán)境,包括專用的堆棧區(qū)域。此外,每種特權(quán)模式都包含用于陷阱處理的單獨(dú)控制和狀態(tài)寄存器 (CSR)。在用戶模式下操作時(shí),需要上下文切換來處理主管模式下的事件。軟件為上下文切換設(shè)置系統(tǒng),然后執(zhí)行 ECALL 指令,將控制同步切換到 Environment call-from-User 模式異常處理程序。
復(fù)位后的默認(rèn)模式是機(jī)器模式。軟件以最高權(quán)限級(jí)別開始執(zhí)行,這允許在任何權(quán)限級(jí)別更改之前初始化所有 CSR 和系統(tǒng)資源。下面的步驟描述了將特權(quán)模式從機(jī)器模式更改為用戶模式所需的步驟,在特定設(shè)計(jì)上也包括管理員模式。
應(yīng)首先通過將?
mstatus.MIE
?寫入 0(默認(rèn)復(fù)位值)來全局禁用中斷。將機(jī)器模式異常處理程序的基地址寫入?
mtvec CSR
。這是任何引導(dǎo)流程中的必需步驟。將?
mstatus.MPP
?寫入 0 以將之前的模式設(shè)置為 User,這允許我們返回到該模式。設(shè)置物理內(nèi)存保護(hù) (PMP) 區(qū)域以將所需區(qū)域授予用戶和主管模式,并可選擇從機(jī)器模式撤消權(quán)限。
用主管模式異常處理程序的基地址寫入?
stvec CSR
。編寫?
medeleg
?寄存器,將異常委托給主管模式。考慮?ECALL
?和頁面錯(cuò)誤異常。編寫?
mstatus.FS
?以啟用浮點(diǎn)(如果支持)。將機(jī)器模式用戶寄存器存儲(chǔ)到堆?;驊?yīng)用程序特定的幀指針。
用用戶態(tài)軟件的入口點(diǎn)編寫
mepc
執(zhí)行
mret
指令進(jìn)入用戶模式。
Note:只有一組用戶寄存器 (x1 - x31) 用于所有權(quán)限級(jí)別,因此應(yīng)用軟件負(fù)責(zé)在進(jìn)入和退出不同級(jí)別時(shí)保存和恢復(fù)狀態(tài)。
【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【749907784】整理了一些個(gè)人覺得比較好的學(xué)習(xí)書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦!?。。ê曨l教程、電子書、實(shí)戰(zhàn)項(xiàng)目及代碼)? ??


本地中斷
軟件中斷(中斷 ID #3):通過寫入特定 hart 的內(nèi)存映射中斷掛起寄存器 msip 來觸發(fā)。
定時(shí)器中斷:當(dāng)寄存器 mtime 大于或等于寄存器 mtimecmp 并且兩個(gè)寄存器都是 CLINT 內(nèi)存映射的一部分時(shí),會(huì)觸發(fā)定時(shí)器中斷(中斷 ID #7)。mtime 和 mtimecmp 寄存器通常僅在機(jī)器模式下可用,除非 PMP 授予用戶或管理員模式訪問它們所在的內(nèi)存映射區(qū)域的權(quán)限。

全局中斷通常首先路由到 PLIC,然后使用外部中斷進(jìn)入 hart(中斷 ID #11)
中斷操作
在特權(quán)模式 m 內(nèi),如果相關(guān)的全局中斷使能 {ie} 清零,則在該特權(quán)模式下不會(huì)產(chǎn)生任何中斷,但更高特權(quán)模式下的待決啟用中斷將搶占當(dāng)前執(zhí)行。如果設(shè)置了 {ie},則在相同特權(quán)模式下處于更高中斷級(jí)別的掛起啟用中斷將搶占當(dāng)前執(zhí)行并運(yùn)行更高中斷級(jí)別的中斷處理程序。
當(dāng)發(fā)生中斷或同步異常時(shí),會(huì)修改特權(quán)模式以反映新的特權(quán)模式。處理程序特權(quán)模式的全局中斷使能位被清除
中斷進(jìn)入和退出
當(dāng)中斷發(fā)生時(shí):
??mstatus.MIE
?的值被復(fù)制到mcause.MPIE
?中,然后mstatus.MIE
?被清除,有效地禁用了中斷。
? 中斷前的特權(quán)模式在mstatus.MPP
?中編碼。
? 當(dāng)前?pc
?被復(fù)制到?mepc
?寄存器中,然后將?pc
?設(shè)置為?mtvec
?指定的值
此時(shí),控制權(quán)移交給中斷處理程序中的軟件,并禁用中斷。執(zhí)行?mret
?指令時(shí),會(huì)發(fā)生以下情況:
? 特權(quán)模式設(shè)置為在?mstatus.MPP
?中編碼的值。
? 全局中斷使能?mstatus.MIE
?設(shè)置為?mcause.MPIE
?的值。
??pc
?設(shè)置為mepc
?的值。
此時(shí),控制權(quán)交給軟件。
中斷控制和狀態(tài)寄存器
Machine Status Register (mstatus)
mstatus 寄存器跟蹤并控制 hart 的當(dāng)前操作狀態(tài),包括是否啟用中斷。

通過設(shè)置 mstatus 中的 MIE 位來啟用中斷。在寫入 mstatus.MIE=1 之前,建議先在 mie 中開啟中斷。
Machine Trap Vector (mtvec)
mtvec 寄存器有兩個(gè)主要功能:定義陷阱向量的基地址,以及設(shè)置 U54內(nèi)核處理中斷的模式。對(duì)于 Direct 和 Vectored 模式,中斷處理模式在 mtvec 寄存器的 MODE 字段中定義。mtvec 寄存器在表 86 中描述,mtvec.MODE 字段在表 87 中描述。

Mode Direct
在直接模式下操作時(shí),所有中斷和異常都會(huì)捕獲到 mtvec.BASE 地址。在陷阱處理程序內(nèi)部,軟件必須讀取 mcause 寄存器以確定觸發(fā)陷阱的原因。
在直接模式下操作時(shí),BASE 必須是 4 字節(jié)對(duì)齊的。
Mode Vectored
在向量模式下運(yùn)行時(shí),中斷將 pc 設(shè)置為 mtvec.BASE + 4 × 異常代碼(mcause.EXCCODE)。例如,如果發(fā)生機(jī)器定時(shí)器中斷,則將 pc 設(shè)置為 mtvec.BASE + 0x1C。通常,陷阱向量表填充有跳轉(zhuǎn)指令,以將控制轉(zhuǎn)移到特定于中斷的陷阱處理程序。
在向量中斷模式下,BASE 必須是 256 字節(jié)對(duì)齊的。
所有機(jī)器外部中斷(全局中斷)都映射到異常代碼 11。因此,當(dāng)啟用中斷向量時(shí),pc 設(shè)置為任何全局中斷的地址 mtvec.BASE + 0x2C。
Machine Interrupt Enable (mie)
通過設(shè)置 mie 寄存器中的相應(yīng)位來啟用各個(gè)中斷。

Machine Interrupt Pending (mip)
機(jī)器中斷掛起 (mip) 寄存器指示當(dāng)前哪些中斷處于掛起狀態(tài)。

特權(quán)模式中斷
U54內(nèi)核支持有選擇地將中斷和異常定向到S模式。
該功能由中斷和異常委托CSR處理:mideleg
和medeleg
。S模式中斷和異常可以通過stvec、sip、sie 和 scause 管理。
在M模式下,軟件還可以直接寫入SIP寄存器,從而有效地向S模式發(fā)送中斷。這對(duì)于定時(shí)器和軟件中斷特別有用,因?yàn)榭赡苄枰贛模式和S模式下處理這些中斷。
Delegation Registers (mideleg and medeleg)
默認(rèn)情況下,所有的trap
都在M模式下處理。M模式下軟件可以通過CSR 有選擇地將中斷和異常委托給S模式。具體的映射如表 92 和表 93 。


注意,本地中斷可以委托給M模式。
Supervisor Status Register (sstatus)
與M模式類似,S模式有一個(gè)寄存器,專門用于跟蹤 hart 的當(dāng)前狀態(tài),稱為?sstatus
。sstatus
?實(shí)際上是 mstatus 的受限視圖,因?yàn)閷?duì) sstatus 所做的更改反映在 mstatus 中。
通過在 sstatus 中設(shè)置 SIE 位并在 sie 寄存器中啟用所需的單個(gè)中斷來啟用中斷。
Supervisor Interrupt Enable Register (sie)
通過在 sie 寄存器中設(shè)置適當(dāng)?shù)奈粊韱⒂霉芾韱T中斷。

Supervisor Interrupt Pending (sip)
S模式中斷掛起 (sip) 寄存器指示當(dāng)前哪些中斷掛起。

Supervisor Cause Register (scause)
當(dāng)S模式下捕獲陷阱時(shí),將導(dǎo)致陷阱的事件的代碼寫入 cause。當(dāng)導(dǎo)致陷阱的事件是中斷時(shí),最高有效位 scause 設(shè)置為 1,最低有效位表示中斷號(hào),使用與 sip 中的位置相同的編碼。例如,S模式定時(shí)器中斷導(dǎo)致 cause 被設(shè)置為 0x8000_0000_0000_0005。
scause 也用于指示同步異常的原因,在這種情況下,scause 的最高有效位設(shè)置為 0。有關(guān)同步異常代碼的列表,請(qǐng)參見表 98。


Supervisor Trap Vector (stvec)
默認(rèn)情況下,所有中斷都會(huì)捕獲到 stvec 寄存器中定義的單個(gè)地址。由中斷處理程序讀取原因并做出相應(yīng)的反應(yīng)。RISC?V 和 U54 內(nèi)核還支持選擇性地啟用中斷向量的能力。當(dāng)啟用向量時(shí),在 sie 中定義的每個(gè)中斷都會(huì)陷入到它自己的特定中斷處理程序中。
當(dāng) stvec 寄存器的 MODE 字段設(shè)置為 1 時(shí),向量中斷被啟用。

如果向量中斷被禁用 (stvec.MODE=0),所有中斷都會(huì)陷入 stvec.BASE 地址。如果啟用矢量中斷 (stvec.MODE=1),中斷將 pc 設(shè)置為 stvec.BASE + 4 × 異常代碼 (scause.EXCCODE)。例如,如果發(fā)生管理定時(shí)器中斷,則 pc 設(shè)置為 stvec.BASE + 0x14。通常,陷阱向量表中填充有跳轉(zhuǎn)指令,以將控制轉(zhuǎn)移到特定于中斷的陷阱處理程序。
在向量中斷模式下,BASE 必須是 128 字節(jié)對(duì)齊的。
所有主管外部中斷(全局中斷)都映射到異常代碼 9。因此,當(dāng)啟用中斷向量時(shí),pc 被設(shè)置為任何全局中斷的地址 stvec.BASE + 0x24。
Delegated Interrupt Handling
接受委派陷阱后,會(huì)發(fā)生以下情況:
sstatus.SIE
?的值被復(fù)制到?sstatus.SPIE
,然后?sstatus.SIE
?被清除,有效地禁用中斷。當(dāng)前
pc
被復(fù)制到sepc
寄存器中,然后pc
被設(shè)置為stvec
的值。在啟用矢量中斷的情況下,pc
?設(shè)置為?stvec.BASE
?+ 4 × 異常代碼 (scause.EXCCODE
)。中斷前的特權(quán)模式編碼在?
sstatus.SPP
?中
此時(shí),控制權(quán)移交給中斷處理程序中的軟件,中斷被禁用??梢酝ㄟ^顯式設(shè)置?sstatus.SIE
?或執(zhí)行?SRET
?指令退出處理程序來重新啟用中斷。執(zhí)行?SRET
?指令時(shí),會(huì)發(fā)生以下情況:
特權(quán)模式設(shè)置為?
sstatus.SPP
?中編碼的值status.SPIE
?的值被復(fù)制到?status.SIE
pc
?設(shè)置為?sepc
?的值
此時(shí),控制權(quán)交給了軟件
中斷延遲
U54內(nèi)核的中斷延遲為四個(gè) external_source_for_core_N_clock 周期,計(jì)算方式是從向 hart 發(fā)送中斷信號(hào)到處理程序的第一個(gè)指令獲取所需的周期數(shù)。
通過 PLIC 路由的全局中斷會(huì)導(dǎo)致三個(gè)時(shí)鐘周期的額外延遲,其中 PLIC 由時(shí)鐘計(jì)時(shí)。這意味著全局中斷的總延遲(以周期為單位)為:4 + 3 × (external_source_for_core_N_clock Hz ÷ clock Hz)。這是最佳情況下的循環(huán)計(jì)數(shù),并假定處理程序已緩存。它沒有考慮來自外圍源的額外延遲
不可屏蔽中斷
rnmi(可恢復(fù)不可屏蔽中斷)中斷信號(hào)是 hart 的電平敏感輸入。不可屏蔽中斷比 hart 上的任何其他中斷或異常具有更高的優(yōu)先級(jí),并且不能被軟件禁用。具體來說,它們不會(huì)通過清除 mstatus.mie 寄存器來禁用。
Handler Addresses
NMI 有一個(gè)關(guān)聯(lián)的異常陷阱處理程序地址。該地址由外部輸入信號(hào)設(shè)置。
RNMI CSRs
這些 M 模式 CSR 啟用可恢復(fù)非屏蔽中斷 (RNMI)。

mnscratch CSR 擁有一個(gè) 64 位讀寫寄存器,它使 NMI 陷阱處理程序能夠保存和恢復(fù)被中斷的上下文。
mnepc CSR 是一個(gè) 64 位讀寫寄存器,在進(jìn)入 NMI 陷阱處理程序時(shí),它保存接受中斷的指令的 PC。mnepc 的最低位硬連線為零。
mncause CSR 包含 NMI 的原因,第 63 位設(shè)置為 1,并且 NMI 原因編碼在最低有效位中,如果不支持 NMI 原因,則為零。mncause 的低位,定義為 exception_code,如下:

mnstatus CSR 包含一個(gè)兩位字段,在進(jìn)入陷阱處理程序時(shí),它包含以與 mstatus.mpp 相同的方式編碼的中斷上下文的特權(quán)模式
MNRET Instruction
此僅 M 模式指令使用 mnepc 和 mnstatus 中的值分別返回中斷上下文的程序計(jì)數(shù)器和特權(quán)模式。該指令還設(shè)置內(nèi)部 rnmie 狀態(tài)位。
編碼與 MRET 相同,除了第 30 位設(shè)置(即 funct7=0111000)。例如:
RNMI Operation
當(dāng)檢測到RNMI中斷時(shí),將中斷的PC寫入mnepc CSR,RNMI的類型寫入mncause CSR,中斷上下文的特權(quán)模式寫入mnstatus CSR。內(nèi)部微體系結(jié)構(gòu)狀態(tài)位 rnmie 被清除以指示處理器處于 RNMI 處理程序中并且不能接受新的 RNMI 中斷。清除時(shí),內(nèi)部 rnmie 位還會(huì)禁用所有其他中斷
這些中斷被稱為不可屏蔽的,因?yàn)檐浖o法屏蔽中斷。但是,為了正確操作,必須推遲同一中斷的其他實(shí)例,直到處理程序完成,因此內(nèi)部狀態(tài)位
RNMI 處理程序可以使用 MNRET 指令(在第 7.11.3 節(jié)中描述)恢復(fù)原始執(zhí)行,該指令從 mnepc 恢復(fù) PC,從 mnstatus 恢復(fù)特權(quán)模式,并設(shè)置內(nèi)部 rnmie 狀態(tài)位,重新啟用其他中斷。
如果hart在rnmie位清零時(shí)遇到異常,則將異常狀態(tài)寫入mepc和mcause,mstatus.mpp設(shè)置為M-mode,hart跳轉(zhuǎn)到RNMI異常處理程序地址。
RNMI 處理程序中的陷阱只有在處理程序正在服務(wù)發(fā)生在機(jī)器模式之外的中斷時(shí)發(fā)生時(shí)才能恢復(fù)。
原文作者:嵌入式Linux充電站
