加入星計劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴散
  • 作品版權(quán)保護
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長期合作伙伴
立即加入
  • 正文
    • ISA
    • 名正才能言順,RISC-V 指令集規(guī)范
    •  
    • ISA 簡述
    • 偽匯編
    • 異常處理
    • SBI
  • 相關(guān)推薦
申請入駐 產(chǎn)業(yè)圖譜

RISC-V架構(gòu)系列之1:指令集和特權(quán)模式

2021/02/01
387
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

作者按:在上個月的 os2atc 會議 上,筆者作為 Linux 閱碼場高級顧問分享了 RISC-V 對 Linux 對支持情況。會議后對分享內(nèi)容再次做了迭代,期待和大家一起交流,進步。

從 2010 年開始的 RISC-V 項目,已經(jīng)有 10 年的時間,RISC-V 基金會先后批準了 RISC-V Base ISA, Privileged Architecture,Processor Trace 等規(guī)范。RISC-V 對 Linux 的基本支持也已經(jīng)完成。本文嘗試通俗易懂的介紹 RISC-V 對于 Linux 的基本支持,包括指令集和異常處理。內(nèi)存管理,遷移到 RISC-V,UEFI,KVM 等支持,歡迎繼續(xù)關(guān)注本公眾號。

ISA

眼見為實,下面就是 RISC-V 的匯編語言了。從筆者代碼中反匯編得來,功能是把傳入的字符 c,通過 RISC-V 提供的標準接口(此處指 OpenSBI,見 下文 )輸出到終端。

名正才能言順,RISC-V 指令集規(guī)范

想做好一個生態(tài),需要大家對齊目標,RISC-V 的規(guī)范( Specifications,參考鏈接 1)就起了這樣的作用,目前的規(guī)范分成兩部分,第 1 卷是非特權(quán)指令,第 2 卷是特權(quán)指令。在第一卷中,RISC-V 已經(jīng)定義了 RV32I 和 RV64I 兩個基礎(chǔ)整數(shù)運算,并有如下擴展。

現(xiàn)在問題來了,這么多規(guī)范,大家如果用的指令集不一致,豈不是沒法互操作了?別急,RISC-V 還定義了下面指令集組合。

為了提高指令密度,更節(jié)省存儲空間,RISC-V 還有上述的 C 擴展(壓縮指令),例如 RV32GC 表示使用壓縮指令的 RV32G 指令集,RV64GC 表示使用壓縮指令的 RV64G 指令集。根據(jù) Andrew Waterman 的測試,在 Spec2006(一個測試 cpu 性能的商用測試套)中,RV32GC 和 RV64GC 分別比 RV32G 和 RV64G 節(jié)省 30%+的空間,而性能變化不大,見 參考資料 2 。

除了非特權(quán)指令,RISC-V 的規(guī)范還包括特權(quán)指令。Privileged Spec 里面 Machine ISA 和 Supervisor ISA 已經(jīng) release 了 1.11 版本。而虛擬化 Virtualization ISA 目前是 0.6,還在討論中。

 

ISA 簡述

了解指令集有助于我們了解這個架構(gòu)。RISC-V 是一個 RISC 架構(gòu)。所有的運算都在寄存器之間進行,通過單獨的 load 和 store 指令,把數(shù)據(jù)從內(nèi)存中讀出或?qū)懟亍Uw的指令集架構(gòu)方面,包云崗老師帶領(lǐng)團隊已經(jīng)做了很好的中文翻譯(參考鏈接 3) ,我這邊就不再詳細的展開講,僅僅舉兩個例子

“Addi    sp,sp,-32”是把 sp 寄存器的值減 32 并保存到 sp 寄存器中,這條指令在準備本函數(shù)自己的??臻g。

“Sd      ra,24(sp)”是把本返回地址(ra)保存到棧上,24(sp)表示相對+24 的位置,這是 RISC-V 二進制調(diào)用規(guī)范定義的。

偽匯編

平時讀代碼的時候,除了架構(gòu)中定義的匯編指令還會遇到偽匯編。偽匯編是一些幫助我們平時手寫匯編提高效率的東西。比如說寄存器的賦值,下面的一條 li 偽指令會被翻譯為 lui 和 addiw 兩條指令。

再舉個例子,csrw 用于寫入 csr 寄存器。其中 csr 的全稱是 Control and Status Register,主要是和特權(quán)管理相關(guān)的寄存器。

異常處理

了解了基本的匯編語言,我們就可以進一步的了解 RISC-V 的異常,這是操作系統(tǒng)的職責之一(另一個重要職責是虛擬內(nèi)存的管理,在下一篇文章介紹)。

為了便于理解,我們與 ARM 和 X86 對比下。

大約 40 年前,x86 架構(gòu)有了如上圖的保護模式。其中 Level0 跑操作系統(tǒng),Level3 跑應(yīng)用。為了支持虛擬化,x86 引入了 VMX operation(如下圖),Guest 操作系統(tǒng)和應(yīng)用運行在 non-root 模式,Hypervisor 運行在 root 模式。在這樣的設(shè)計下,支持 Type-1 和 Type-2 的虛擬機技術(shù)都比較方便,并且原有的操作系統(tǒng)不需要任何修改就可以作為 Guest 操作系統(tǒng)運行。不過早期的 x86 虛擬化也有缺點,例如不支持二級頁表轉(zhuǎn)換,需要用 shadow page table,這樣效率很低,直到 EPT 的引入解決這一問題。

相比之下,ARM 架構(gòu)采取了不同的方式。由于 ARM 架構(gòu)下已經(jīng)有了如下圖的 Normal 和 Secure world 設(shè)計(這里指的是 Normal world 的操作系統(tǒng),例如 Linux,可以不加修改的運行在 Secure world)。沒有用類似 x86 添加 VMX root 和 non-root 的 operation 的形式。

而是如下圖添加了新的一個異常級別 EL2(下圖的 Hypervisor),很容易理解的是 EL2 比 EL1 有更多的級別。問題在于 EL2 并不是 EL1 的復(fù)制,也就是說 Linux kernel 沒法直接運行在 EL2 上。對于 Xen 這種典型的 Type-1 虛擬化機制沒問題,Xen hypervisor 可以很開心的運行在 EL2。但是對于 KVM,KVM 作為 Linux kernel 的一個模塊,就比較尷尬:KVM 需要 EL2 的一些權(quán)限,但是 Linux 又只能運行在 EL1。于是原本在 x86 上完整的 KVM 被拆成了 high-visor 和 low-visor(需要 EL2 特權(quán)能力的部分)兩部分。平時 KVM 的 high-visor 愉快和 Linux kernel 一起運行在 EL1,當需要虛擬化管理的特權(quán)操作時,KVM 從 high-visor 陷入到 low-visor 處理。

ARM 的虛擬化技術(shù)比 x86 的晚了很多年,有個好處是可以完成 x86 多次迭代得到的狀態(tài),例如前文提到的 x86 為了避免 shadow page table 引入的 EPT,在 ARM 虛擬化擴展時是原生支持的。同時,ARM 的虛擬化擴展在 32 位和 64 位架構(gòu)下是完全一樣的,早期的虛擬化工作,不論是 xen 還是 KVM 的工作都是在 32 位的 ARMv7a 架構(gòu)的 Cortex-A15 和 Cortex-A7 上完成的。這樣 ARM64 推出后,虛擬化這部分工作不需要重新做。至于 ARM 虛擬化上更多異常處理導(dǎo)致的性能問題,從 ARMv8.1 開始,有了 VHE 模式,支持把 EL1 下沉到 EL2 運行,這樣 KVM ARM 就沒有了前述的開銷。

從上述歷史可以看出,軟硬件的協(xié)同,靈活可擴展的設(shè)計非常重要。RISC-V 的設(shè)計中也體現(xiàn)了這一點。在沒有虛擬化特性情況下,RISC-V 最多支持三個特權(quán)級別。通常來說,為了支持 Linux 這樣的 Rich OS,需要同時支持這三個模式。每一層有不同的權(quán)限。

Bootloader/BIOS/UEFI 運行系統(tǒng)的最高級別 machine mode,Linux kernel 運行在 supervisor mode,應(yīng)用運行在 user mode。默認情況下,所有的異常都在 machine mode 處理。在有 Linux kernel 時,這樣明顯降低了效率:所有原本可以由 Linux kernel 處理的異常,例如應(yīng)用的缺頁異常,都需要先陷入到 machine mode 再轉(zhuǎn)發(fā)給 kernel。為了允許軟件系統(tǒng)更靈活的管理異常,RISC-V 引入了 delegation 機制,可以選擇把一部分異常和中斷由硬件直接交給 supervisor mode 的 kernel 處理。

 

現(xiàn)在問題來了,RISC-V 的虛擬化是如何設(shè)計的呢?很明顯,虛擬化的特權(quán)級別需要支持 Linux kernel 這種 Rich OS。所以 RISC-V 沒有像早期的 ARM 虛擬化一樣把虛擬化異常直接直接加到 supervisor mode 和 machine mode 之間,而是定義了獨立的 virtualization mode,這個 mode 再與 user 和 supervisor mode 組合,于是有了下面的表格。

(表格來自 The RISC-V Instruction Set Manual, Volume II: Privileged Architecture, Document Version 1.12-draft Table 5.1)

這么說有點抽象,用 RISC-V kVM 作者之一的 Anup Patel 畫的圖表示(圖片已獲得作者授權(quán), 原圖見參考鏈接 4)。

備注:RISC-V 虛擬化規(guī)范目前處于 0.6 草稿狀態(tài),未來可能還會有些小的變化。

SBI

了解了 RISC-V 的特權(quán)模式,不同層次的軟件調(diào)用遵循什么樣的規(guī)范呢?RISC-V 的設(shè)計中,下層(硬件 / 軟件)對上層透明,規(guī)范會定義二進制接口,對具體如何實現(xiàn)沒有要求。例如 Linux kernel 在 supervisor mode,對下面的特權(quán)級別,通過 SBI(Supervisor Binary Interface)訪問,SBI 訪問的軟件稱為 SEE(Supervisor Execution Environment),SEE 可以是 bootloader,BIOS,也可以 Hypervisor。和 SEE 類似的還有支持應(yīng)用的運行環(huán)境 AEE。

(圖片來自 The RISC-V Instruction Set Manual, Volume II: Privileged Architecture, Document Version 1.12-draft Figure 1.1)

SBI 的規(guī)范見參考鏈接 5,規(guī)范定義了 SBI 的能力,例如獲得 SBI 規(guī)范的版本,發(fā)送或接收一個字符,remote fence,設(shè)置 timer,發(fā)送 IPI 中斷,管理 RISC-V 處理器(RISC-V 中稱為 hart)等,以及 SBI 的二進制調(diào)用規(guī)范。截止這篇文章,SBI 是 0.3 draft,這個版本主要是增加了用于系統(tǒng)復(fù)位的 SBI 接口。既然 SBI 是個規(guī)范,那就有各種實現(xiàn),OpenSBI 就是其中一個實現(xiàn),這個實現(xiàn)支持 generic(用于支持 qemu 的 RISC-V virt machine),sifive 和 k210 等芯片。

這么說有點抽象,咱們舉個簡單的例子。如果想寫一個簡單的從 supervisor mode 調(diào)用 SBI 接口打印字符的代碼,要怎么做呢?

首先,假設(shè),我們以及有了 c 語言的運行環(huán)境,那我們需要根據(jù) SBI 定義的二進制調(diào)用規(guī)范,使用寄存器 a7 傳遞指定的 extension ID。

(圖片來自 RISC-V Supervisor Binary Interface Specification Version 0.3-rc0 p6)

從下圖可以看到,extension ID 是 1。同時我們看到函數(shù)原型是通過第一個參數(shù)傳入字符 ch。

(圖片來自 RISC-V Supervisor Binary Interface Specification Version 0.3-rc0 p6)

RISC-V 使用哪個寄存器保存第一個參數(shù)呢?根據(jù) RISC-V ELF psABI

specification 的整數(shù)寄存器調(diào)用約定( 參考鏈接 6 ),我們可以看到寄存器 a0 用于傳遞第一個參數(shù)。發(fā)送一個字符的對應(yīng)的代碼是這個樣子

寫了 SBI 調(diào)用接口,還沒有萬事大吉,如果希望 bootloader 直接加載我們的代碼,我們還需要自己準備 c 語言運行環(huán)境。加上下面幾行匯編即可。

cpu_enter 里面會打印字符串。我們選擇使用 OpenSBI 的 fw_jump 從固定的 0x80200000 加載我們的二進制,啟動效果如下。最后一行“Hello XU Xiake“是上面代碼打印的。希望我們像徐霞客一樣,通過編寫代碼,游覽 RISC-V 的各種特性。

參考鏈接

[1] RISC-V 規(guī)范: https://riscv.org/technical/specifications/

[2] Design of the RISC-V Instruction Set Architecture https://www2.eecs.berkeley.edu/Pubs/TechRpts/2016/EECS-2016-1.pdf

[3] RISC-V 架構(gòu)簡述:http://riscvbook.com/chinese/

[4] RISC-V 虛擬化擴展:https://static.sched.com/hosted_files/osseu19/4e/Xvisor_Embedded_Hypervisor_for_RISCV_v5.pdf

[5] SBI 規(guī)范:https://github.com/riscv/riscv-sbi-doc

[6] RISC-V Integer Register Convention https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md#integer-register-convention-

[7] RISC-V 軟件狀態(tài) https://github.com/riscv/riscv-software-list

相關(guān)推薦

登錄即可解鎖
  • 海量技術(shù)文章
  • 設(shè)計資源下載
  • 產(chǎn)業(yè)鏈客戶資源
  • 寫文章/發(fā)需求
立即登錄

專業(yè)的Linux技術(shù)社區(qū)和Linux操作系統(tǒng)學(xué)習(xí)平臺,內(nèi)容涉及Linux內(nèi)核,Linux內(nèi)存管理,Linux進程管理,Linux文件系統(tǒng)和IO,Linux性能調(diào)優(yōu),Linux設(shè)備驅(qū)動以及Linux虛擬化和云計算等各方各面.