HPMicro 的 MCU 一直以高性能著稱,之前也一直有想在 HPM 的 MCU 上運(yùn)行 Linux 的想法。直到看見 Linux 6.10 中支持了 RISC-V 架構(gòu)在 S-mode 中運(yùn)行 nommu 內(nèi)核*,才下定決心開始在 HPM6360 上折騰 nommu Linux。
劃線部分鏈接為:
RISC-V 上的 Linux 啟動(dòng)流程
在 ARM 架構(gòu)中,通常 Linux 的啟動(dòng)流程為:

而在具有 S 態(tài)的 RISC-V 架構(gòu)中,通常的啟動(dòng)流程為:

其中 BootROM、Loader 和 SBI Runtime 運(yùn)行 M-mode(機(jī)器模式)下,具體的引導(dǎo)程序和 Linux 等操作系統(tǒng)內(nèi)核運(yùn)行在 S-mode(監(jiān)管者模式)下,而用戶進(jìn)程運(yùn)行在 U-mode(用戶模式)中。我們看到 RISC-V 的啟動(dòng)流程中相比 ARM 多了一個(gè) SBI Runtime,那么什么是 SBI?
SBI (Supervisor Binary Interface)
RISC-V 架構(gòu)中,存在著定義于操作系統(tǒng)之下的運(yùn)行環(huán)境(Runtime)。這個(gè)運(yùn)行環(huán)境不僅將引導(dǎo)啟動(dòng) RISC-V 下的操作系統(tǒng), 還將常駐后臺(tái),為操作系統(tǒng)提供一系列二進(jìn)制接口,以便其獲取和操作硬件信息。RISC-V 給出了此類環(huán)境和二進(jìn)制接口的規(guī)范,稱為“監(jiān)管者二進(jìn)制接口”,即 “SBI”。
SBI 有多種實(shí)現(xiàn),如 Berkeley Boot Loader (BBL)、OpenSBI。而本次項(xiàng)目中使用的 SBI 實(shí)現(xiàn)為 RustSBI。
RustSBI項(xiàng)目源于2020年清華操作系統(tǒng)夏令營(yíng),旨在使用 Rust 語(yǔ)言編寫 RISC-V 指令集中的 SBI 實(shí)現(xiàn),支撐上層系統(tǒng)軟件比如操作系統(tǒng)的運(yùn)行。在國(guó)際 SBI 實(shí)現(xiàn)列表中獲得 編號(hào)四。具有以下功能:
· 多功能且可拓展的操作系統(tǒng)運(yùn)行時(shí)
·為物理機(jī)、虛擬機(jī)、模擬器提供支持和兼容性
·支持 RISC-V SBI 規(guī)范 v2.0
·使用 Rust 編寫,使用穩(wěn)定版本的 Rust 工具鏈構(gòu)建
由于 HPM 系列芯片的啟動(dòng)設(shè)備較為單一(XPI),且 XPI 的初始化工作已經(jīng)在 BootROM 中完成并映射到地址空間中,同時(shí)為了加快啟動(dòng)速度,本項(xiàng)目最終沒有移植 U-Boot;而是基于 RustSBI 庫(kù),編寫操作系統(tǒng)的 Bootloader,實(shí)現(xiàn) SDRAM 初始化、固件加載、設(shè)備樹傳遞和內(nèi)核跳轉(zhuǎn)等功能,以及為操作系統(tǒng)提供監(jiān)管者二進(jìn)制接口(SBI)。
最終在 HPM6360 芯片上的啟動(dòng)流程如下:

啟動(dòng)鏡像布局

部分實(shí)現(xiàn)細(xì)節(jié)
Zicntr 指令集拓展支持
Linux 內(nèi)核中,使用了 TIME 和 TIMEH 這兩個(gè) CSR 寄存器來獲取系統(tǒng)時(shí)鐘用于調(diào)度。但 HPM6360 使用的 Andes D45 核心并沒有實(shí)現(xiàn)這兩個(gè) CSR 寄存器,在執(zhí)行 csrrs rd, time, rs1 或 csrrs rd, timeh, rs1 指令時(shí)會(huì)產(chǎn)生非法指令異常(Illegal Instruction)。這就需要軟件在異常處理函數(shù)中模擬這兩條指令的執(zhí)行。
static inline cycles_t get_cycles(void)
{
return csr_read(CSR_TIME);
}
#define get_cycles get_cycles
static inline u32 get_cycles_hi(void)
{
return csr_read(CSR_TIMEH);
}
#define get_cycles_hi get_cycles_hi
#endif /* !CONFIG_RISCV_M_MODE */
#ifdef CONFIG_64BIT
static inline u64 get_cycles64(void)
{
return get_cycles();
}
#else /* CONFIG_64BIT */
static inline u64 get_cycles64(void)
{
u32 hi, lo;
do {
hi = get_cycles_hi();
lo = get_cycles();
} while (hi != get_cycles_hi());
return ((u64)hi << 32) | lo;
}
#endif /* CONFIG_64BIT */
arch/riscv/include/asm/timex.h:51

這里我使用了 riscv-decode 這個(gè)庫(kù)對(duì)機(jī)器碼進(jìn)行解碼。
1、觸發(fā)非法指令異常后從 mtval 寄存器中讀取到非法指令;
2、將其作為參數(shù)調(diào)用 riscv_decode::decode() 函數(shù)進(jìn)行解碼,獲取到 CSR 以及 rd 的值,判斷是否為 TIME:0xc01 和 TIMEH:0xc81 這兩個(gè) CSR 寄存器;
3、如果是,則將 MCHTMR 外設(shè)中 MTIME 寄存器的值保存至 rd 寄存器中。并恢復(fù)現(xiàn)場(chǎng)并從異常指令的下一條指令開始執(zhí)行;
4、如果不是,則將異常委托給 Linux 內(nèi)核處理。模擬異常發(fā)生時(shí)的硬件行為,填充對(duì)應(yīng)寄存器并更新 mstatus:MPP ,使異常返回后的特權(quán)級(jí)別為 S-mode,最后將 mepc 寄存器覆蓋為 stvec 的值,異常返回后將從 Linux 內(nèi)核的異常處理函數(shù)入口開始執(zhí)行。具體實(shí)現(xiàn)細(xì)節(jié)請(qǐng)參考:
https://github.com/rustsbi/rustsbi-hpm/blob/194d9cc7899fef320ac9e4b8e2c57ffca3eafe34/src/trap.rs#L51-L67
請(qǐng)手動(dòng)跳轉(zhuǎn)
SDRAM 區(qū)域原子指令的支持
在調(diào)試過程中發(fā)現(xiàn),HPM6360 無法在 SDRAM 的地址范圍中執(zhí)行原子指令,會(huì)產(chǎn)生存儲(chǔ)/原子指令訪問錯(cuò)誤異常(Store/AMO Access Fault)。而 Linux 內(nèi)核中有部分操作調(diào)用了原子指令(例如加鎖等同步操作),在 CPU 不支持原子指令的情況下 Linux 內(nèi)核無法運(yùn)行。這里同樣可以基于異常對(duì)原子指令進(jìn)行模擬。
1、AMO 指令
在執(zhí)行 AMO 指令時(shí),會(huì)陷入存儲(chǔ)/原子指令訪問錯(cuò)誤異常。同樣的,我們需要從 mepc 指向的指令地址獲取出錯(cuò)的原子指令,并進(jìn)行模擬。
2、lr / sc
對(duì)于 lr (Load Reserved) 和 sc (Store Conditional) 指令的情況則有一些特殊。 lr 指令執(zhí)行時(shí)會(huì)觸發(fā)加載指令訪問錯(cuò)誤異常(Load Access Fault),但 sc 指令在執(zhí)行時(shí)不會(huì)觸發(fā)任何異常,rd 寄存器的結(jié)果直接返回 1 ,則就導(dǎo)致無法直接模擬該指令的執(zhí)行。
這里我選擇的解決辦法是:在執(zhí)行到 lr 指令時(shí),先對(duì) lr 指令進(jìn)行模擬,然后查找后續(xù)內(nèi)存地址中的 sc 指令,并將其替換為非法指令(實(shí)際使用的是 csrrw zero, time, zero)。這樣在執(zhí)行到原先 sc 指令的位置時(shí)就會(huì)觸發(fā)非法指令異常。在異常處理函數(shù)中,判斷是否是原先替換指令的地址,如果是,則還原被替換的 sc 指令,并模擬指令執(zhí)行,隨后異常退出至下一條指令繼續(xù)執(zhí)行;如果不是,則將異常委托給內(nèi)核處理。
設(shè)備樹
/dts-v1/;
/ {
#address-cells = <0x01>;
#size-cells = <0x01>;
compatible = "hpmicro,hpm6360";
model = "HPMicro HPM6360 Evaluate Kit";
aliases {
serial0 = &uart0;
};
chosen {
bootargs = "earlycon=sbi console=hvc0 ignore_loglevel rootwait root=/dev/mtdblock0";
stdout-path = "hvc0";
};
memory@40000000 {
device_type = "memory";
reg = <0x40000000 0x02000000>;
};
cpus {
#address-cells = <0x01>;
#size-cells = <0x00>;
timebase-frequency = <1000000>;
cpu@0 {
phandle = <0x01>;
device_type = "cpu";
reg = <0x00>;
status = "okay";
compatible = "riscv";
riscv,isa = "rv32imafdcp";
riscv,isa-base = "rv32i";
riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicsr",
"zifencei", "zihpm";
mmu-type = "riscv,none";
interrupt-controller {
#interrupt-cells = <0x01>;
interrupt-controller;
compatible = "riscv,cpu-intc";
};
};
};
soc {
#address-cells = <0x01>;
#size-cells = <0x01>;
compatible = "simple-bus";
ranges;
rom@80400000 {
compatible = "mtd-rom";
reg = <0x80400000 0xC00000>;
bank-width = <1>;
};
uart0: uart0@f0040000 {
compatible = "hpmicro,hpm6360-uart";
reg = <0xf0040000 0x40>;
clock-frequency = <24000000>;
status = "okay";
};
};
};
實(shí)現(xiàn)效果
目前已經(jīng)成功實(shí)現(xiàn) Linux 6.10 內(nèi)核啟動(dòng)引導(dǎo),并傳遞設(shè)備樹給內(nèi)核。

coremark 跑分結(jié)果:
~ # coremark
2K performance run parameters for coremark.
CoreMark Size : 666
Total ticks : 13913
Total time (secs): 13.913000
Iterations/Sec : 1437.504492
Iterations : 20000
Compiler version : GCC13.3.0
Compiler flags : -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -O2 -g0 -fPIC -Wl,-elf2flt=-r -static -lrt
Memory location : Please put data memory location here
(e.g. code in flash, data on heap etc)
seedcrc : 0xe9f5
[0]crclist : 0xe714
[0]crcmatrix : 0x1fd7
[0]crcstate : 0x8e3a
[0]crcfinal : 0x382f
Correct operation validated. See readme.txt for run and reporting rules.
CoreMark 1.0 : 1437.504492 / GCC13.3.0 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -O2 -g0 -fPIC -Wl,-elf2flt=-r -static -lrt / Heap
ramspeed 測(cè)試結(jié)果,可以看出緩內(nèi)的讀取速度是非常快的,超出緩存范圍后讀取速度受限于 SDARM 的速度:
~ # ramspeed -b 2 -g 1 -m 1 -r
RAMspeed (GENERIC) v2.6.0 by Rhett M. Hollander and Paul V. Bolotoff, 2002-09
1Gb per pass mode
INTEGER & READING 1 Kb block: 1460.57 Mb/s
INTEGER & READING 2 Kb block: 1487.33 Mb/s
INTEGER & READING 4 Kb block: 1498.92 Mb/s
INTEGER & READING 8 Kb block: 1505.16 Mb/s
INTEGER & READING 16 Kb block: 1507.90 Mb/s
INTEGER & READING 32 Kb block: 1301.73 Mb/s
INTEGER & READING 64 Kb block: 116.71 Mb/s
INTEGER & READING 128 Kb block: 116.79 Mb/s
INTEGER & READING 256 Kb block: 116.81 Mb/s
INTEGER & READING 512 Kb block: 116.82 Mb/s
INTEGER & READING 1024 Kb block: 116.74 Mb/s
最后附上倉(cāng)庫(kù)地址,同時(shí)也提供了 pre-built 的系統(tǒng)鏡像,歡迎各位開發(fā)者下載體驗(yàn)。
1、rustsbi-hpm:
https://github.com/rustsbi/rustsbi-hpm
2、linux:
https://github.com/hpm-rs/linux
3、buildroot:
https://github.com/hpm-rs/buildroot
HPMICRO
鳴謝
感謝華中科技大學(xué)洛佳同學(xué) (https://github.com/luojia65)在本項(xiàng)目開發(fā)過程中提供的建議和支持!同時(shí)他也是 RustSBI 的作者。
感謝華中科技大學(xué)王振辰同學(xué)(https://github.com/Plucky923)完善了 riscv-decode 庫(kù)對(duì) RVA 指令集解碼的支持!(https://github.com/fintelia/riscv-decode/pull/6)
參考
https://riscv.org/wp-content/uploads/2019/06/13.30-RISCV_OpenSBI_Deep_Dive_v5.pdf
https://github.com/rustsbi/rustsbi
https://github.com/fintelia/riscv-decode
以上內(nèi)容來自先楫開發(fā)者的原創(chuàng)分享。
我們始終相信開發(fā)者共創(chuàng)的力量。先楫社區(qū)堅(jiān)持開源共享、互惠互利,貼近每一個(gè)開發(fā)者,一步一個(gè)腳印,一點(diǎn)一滴積累,為成為更好的我們而不斷努力。
心之所向,銳意進(jìn)取,星辰大海,恣意成長(zhǎng)。
-
mcu
+關(guān)注
關(guān)注
147文章
18923瀏覽量
397976 -
Linux
+關(guān)注
關(guān)注
88文章
11758瀏覽量
219001 -
HPM
+關(guān)注
關(guān)注
2文章
51瀏覽量
8254
發(fā)布評(píng)論請(qǐng)先 登錄
開發(fā)者分享|先楫半導(dǎo)體hpm_sdk使用vscode進(jìn)行開發(fā)
開發(fā)者分享 | 基于先楫RT-Thread BSP,使用CLion開發(fā)應(yīng)用
適用于每個(gè)LabVIEW開發(fā)者的巧妙調(diào)試技巧
適用于STM32芯片的開發(fā)教程
適用于移動(dòng)終端的GUI設(shè)計(jì)與實(shí)現(xiàn)
適用于PDA的PLC編程系統(tǒng)開發(fā)
中國(guó)大陸開發(fā)者可以注冊(cè)Apple Developer應(yīng)用程序
微軟Windows 10將適用于Your Phone應(yīng)用
Graphcore發(fā)布基于IPU開發(fā)者云,適用于AI模型的訓(xùn)練和推理
適用于M1 MacBook的Firefox和Chrome瀏覽器上線
華為開發(fā)者大會(huì)2021智能硬件開發(fā)— 使用HPM定制產(chǎn)品
2021 OPPO開發(fā)者大會(huì)主會(huì)場(chǎng):多模態(tài)、簡(jiǎn)單AI,賦能開發(fā)者價(jià)值實(shí)現(xiàn)
適用于學(xué)生和愛好者的ATMega16 AVR開發(fā)板
適用于低視力用戶的觸覺接近模塊(HPM)
開發(fā)者分享 | 適用于HPM的RustSBI實(shí)現(xiàn)
評(píng)論