2 4 RISC V::中斷與異常處理 中斷篇 - ianchen0119/AwesomeCS GitHub Wiki

你可曾想過現今的電腦是如何同時運行多個應用程式? 又或是單核心電腦如何做到多工? 為銜接之後的議題,我們需要先認識 RISC-V CPU 中的中斷機制。

複習: CSR 暫存器

CSR 暫存器在RISC-V::中斷與異常處理 – 異常篇也有提到,放置在此篇文章僅是方便讀者查閱。

RISC-V 架構定義了許多暫存器,部分暫存器被定義為控制和狀態暫存器,也就是標題所指出的 CSR (Control and status registers),它被用於配置或是紀錄處理器的運作狀況。 筆者先將 RISC-V 架構中 (Machine Mode)與中斷、異常有關的暫存器都列出來,方便待會兒進行解說:

  • CSR
    • mtvec 當進入異常時, PC (Program counter) 會進入 mtvec 所指向的地址並繼續運行。
    • mcause 紀載異常的原因
    • mtval 紀載異常訊息
    • mepc 進入異常前 PC 所指向的地址。若異常處理完畢, Program counter 可以讀取該位址並繼續執行。
    • mstatus 進入異常時,硬體會更新 mstatus 寄存器的某些域值。
    • mie 決定中斷是否被處理。
    • mip 反映不同類型中斷的等待狀態。
  • Memory Address Mapped
    • mtime 紀錄計時器的值。
    • mtimecmp 儲存計時器的比較值。
    • msip 產生或結束軟體中斷。
    • PLIC

中斷

現今的作業系統都具備多工處理的能力,不管你的電腦是單核心、雙核心甚至是以上,處理器都必須設計有中斷的能力,讓作業系統能指派不同的程式給處理器運行,達成所謂的多工

關於作業系統如何做到多工,筆者會在之後的作業系統系列提到。

在 RISC-V ISA 的定義中,中斷主要分成以下四種,分別是:

  • External Interrupt
  • Timer Interrupt
  • Software Interrupt
  • Dubug Interrupt

RISC-V 其定義了多種模式,如: Machine ModeUser ModeSupervisor Mode 等等,由於筆者所閱讀的技術書都是以 Machine Mode 去做介紹。因此,本篇章同樣也會以 Machine Mode 為主。

External Interrupt

External Interrupt 是指源自處理器外部造成的中斷,像是 UART、GPIO 等外部設備產生的中斷。 通常,因為有多個外部設備,在處理器外面會有一個控制器先將外部的中斷請求做預處理,等到處理完成後,若處理器沒有關閉 Interrupt 的功能,處理器才會真正執行中斷。這個外部控制器叫做: Programmable Interrupt Controller。此外,RISC-V 也定義了 Platform Level Interrupt,細節會在文章的後面補充。

補充: RISC-V 架構對中斷的定義保留了很大的空間,以 mcause register 為例,在 Interrupt 的定義上,Exception Code >= 12 都是被保留的,方便進行擴充。

mcause

Timer Interrupt

RISC-V 架構有規定,系統平台必須要有一個計時器。並且,該計時器必須具備兩個 64-bit 的暫存器 mtime 以及 mtimecmp,前者用於紀錄當前計數器的值,後者則是 mtime 的比較值,當 value of mtime > value of mtimecmp 時便會產生中斷。

補充: 我們可以在 CSR Register 的介紹中看到,mtime 以及 mtimecmp 並沒有被歸類在 CSR 暫存器中而是被放在 Memory address mapped 類,這是因為 RISC-V 並沒有定義這兩個暫存器的 Memory mapped address,具體位址交給 SoC 的系統製造商決定。

Software Interrupt

軟體觸發的中斷。

  • 軟體中斷是否被系統受理由 MIE Register 的 MSIE 域控制(1 為 Enable,0 為 Disable)。
  • 若硬體執行緒將 MSIP 寫入 1 會觸發 Machine Mode 的軟體中斷,當中斷處理完畢後,必須再將 MSIP 歸 0。

Debug Interrupt

該中斷用於 Debugger 的實作。

中斷屏蔽

異常不能被屏蔽,但是中斷可以。

RISC-V 定義了 MIE Register,讓它可以控制中斷的屏蔽。

MIE

以 MEIE 為例,

  • 字首 M 代表 Machine Mode,字首若是 US 則代表 User ModeSupervisor Mode
  • 第二個字母 E 代表 External Interrupt,字母若是 TS 則代表 Timer Interrupt 以及 Software Interrupt
  • 第三個字母 I 代表 Interrupt
  • 第四個字母 E 代表 Enable

中斷等待

RISC-V 定義了 MIP Register,可以用來查詢中斷的等待狀態。

MIP

以 MEIP 為例,

  • 字首 M 代表 Machine Mode,字首若是 US 則代表 User ModeSupervisor Mode
  • 第二個字母 E 代表 External Interrupt,字母若是 TS 則代表 Timer Interrupt 以及 Software Interrupt
  • 第三個字母 I 代表 Interrupt
  • 第四個字母 P 代表 Pending

!補充->中斷的優先級: External > Software > Timer

巢狀中斷

中斷嵌套的概念有點像是,進中斷 A 時又產生了中斷 B,為了幫助讀者,筆者在這邊附上作業系統層的 Nested Interrupt 概念圖:

不過,RISC-V 因為硬體的設計並不支援中斷嵌套,原因如下:

  • 進入異常時,mstatus 的 MIE 域會被更新為 0,代表中斷被關閉,處理器直到中斷退出前不會處理新的中斷請求。

當然,如果真的有中斷嵌套的需求,開發者也可以利用軟體做到:

  • 將 msatus 的 MIE 域設為 1。
  • 考慮中斷的優先級,將 MIE Register 相對應的域做設定。

CSR 指令

RISC-V 定義了一系列的指令讓開發者能夠對 CSR 暫存器進行操作:

  • csrs 把 CSR 中指定的 bit 設為 1。
csrsi mstatus, (1 << 2)

上面的指令會將 mstatus 從 LSB 數起的第三個位置設成 1。

  • csrc 把 CSR 中指定的 bit 設為 0。
csrsi mstatus, (1 << 2)

上面的指令會將 mstatus 從 LSB 數起的第三個位置設成 0。

  • csrr[c|s] 將 CSR 的值讀入通用暫存器。
csrr to, mscratch
  • csrw 將通用暫存器的值寫入 CSR。
csrw	mepc, a0
  • csrrw[i] 將 csr 的值寫入 rd 後,且將 rs1 的值寫入 csr。
csrrw rd, csr, rs1/imm

換個角度思考:

csrrw t6, mscratch, t6

上面的操作可以讓 t6 與 mscratch 的值互換。

這幾個 CSR 指令需要開發者特別留意,之後在閱讀甚至是撰寫作業系統原始碼時,在處理各類的 Interrupt 都必須使用這些操作。

總結

本篇與 RISC-V::中斷與異常處理 – 異常篇完整的介紹了 RISC-V 的中斷與異常處理,考慮到筆者的體力篇幅問題,PLIC 會用額外一篇文章做介紹。

Reference