0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

开发者分享 | 适用于HPM的RustSBI实现

先楫半导体HPMicro ? 2025-02-08 13:44 ? 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

HPMicro 的 MCU 一直以高性能著称,之前也一直有想在 HPM 的 MCU 上运行 Linux 的想法。直到看见 Linux 6.10 中支持了 RISC-V 架构在 S-mode 中运行 nommu 内核*,才下定决心开始在 HPM6360 上折腾 nommu Linux。

划线部分链接为:

RISC-V 上的 Linux 启动流程

ARM 架构中,通常 Linux 的启动流程为:

bf5789a8-e5df-11ef-9434-92fbcf53809c.png

而在具有 S 态的 RISC-V 架构中,通常的启动流程为:

bf84182e-e5df-11ef-9434-92fbcf53809c.jpg

其中 BootROM、Loader 和 SBI Runtime 运行 M-mode(机器模式)下,具体的引导程序和 Linux 等操作系统内核运行在 S-mode(监管者模式)下,而用户进程运行在 U-mode(用户模式)中。我们看到 RISC-V 的启动流程中相比 ARM 多了一个 SBI Runtime,那么什么是 SBI?

SBI (Supervisor Binary Interface)

RISC-V 架构中,存在着定义于操作系统之下的运行环境(Runtime)。这个运行环境不仅将引导启动 RISC-V 下的操作系统, 还将常驻后台,为操作系统提供一系列二进制接口,以便其获取和操作硬件信息。RISC-V 给出了此类环境和二进制接口的规范,称为“监管者二进制接口”,即 “SBI”。

SBI 有多种实现,如 Berkeley Boot Loader (BBL)、OpenSBI。而本次项目中使用的 SBI 实现为 RustSBI

RustSBI项目源于2020年清华操作系统夏令营,旨在使用 Rust 语言编写 RISC-V 指令集中的 SBI 实现,支撑上层系统软件比如操作系统的运行。在国际 SBI 实现列表中获得 编号四。具有以下功能:

· 多功能且可拓展的操作系统运行时

·为物理机、虚拟机、模拟器提供支持和兼容性

·支持 RISC-V SBI 规范 v2.0

·使用 Rust 编写,使用稳定版本的 Rust 工具链构建

由于 HPM 系列芯片的启动设备较为单一(XPI),且 XPI 的初始化工作已经在 BootROM 中完成并映射到地址空间中,同时为了加快启动速度,本项目最终没有移植 U-Boot;而是基于 RustSBI 库,编写操作系统的 Bootloader,实现 SDRAM 初始化、固件加载、设备树传递和内核跳转等功能,以及为操作系统提供监管者二进制接口(SBI)。

最终在 HPM6360 芯片上的启动流程如下:

bfc7b9d0-e5df-11ef-9434-92fbcf53809c.png

启动镜像布局

c000d170-e5df-11ef-9434-92fbcf53809c.png

部分实现细节

Zicntr 指令集拓展支持

Linux 内核中,使用了 TIME TIMEH 这两个 CSR 寄存器来获取系统时钟用于调度。但 HPM6360 使用的 Andes D45 核心并没有实现这两个 CSR 寄存器,在执行 csrrs rd, time, rs1 csrrs rd, timeh, rs1 指令时会产生非法指令异常(Illegal Instruction)。这就需要软件在异常处理函数中模拟这两条指令的执行。

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

c02fbbc0-e5df-11ef-9434-92fbcf53809c.png

这里我使用了 riscv-decode 这个库对机器码进行解码。

1、触发非法指令异常后从 mtval 寄存器中读取到非法指令;

2、将其作为参数调用 riscv_decode::decode() 函数进行解码,获取到 CSR 以及 rd 的值,判断是否为 TIME:0xc01 TIMEH:0xc81 这两个 CSR 寄存器;

3、如果是,则将 MCHTMR 外设中 MTIME 寄存器的值保存至 rd 寄存器中。并恢复现场并从异常指令的下一条指令开始执行;

4、如果不是,则将异常委托给 Linux 内核处理。模拟异常发生时的硬件行为,填充对应寄存器并更新 mstatus:MPP ,使异常返回后的特权级别为 S-mode,最后将 mepc 寄存器覆盖为 stvec 的值,异常返回后将从 Linux 内核的异常处理函数入口开始执行。具体实现细节请参考:

https://github.com/rustsbi/rustsbi-hpm/blob/194d9cc7899fef320ac9e4b8e2c57ffca3eafe34/src/trap.rs#L51-L67

请手动跳转

SDRAM 区域原子指令的支持

在调试过程中发现,HPM6360 无法在 SDRAM 的地址范围中执行原子指令,会产生存储/原子指令访问错误异常(Store/AMO Access Fault)。而 Linux 内核中有部分操作调用了原子指令(例如加锁等同步操作),在 CPU 不支持原子指令的情况下 Linux 内核无法运行。这里同样可以基于异常对原子指令进行模拟。

1、AMO 指令

在执行 AMO 指令时,会陷入存储/原子指令访问错误异常。同样的,我们需要从 mepc 指向的指令地址获取出错的原子指令,并进行模拟。

2、lr / sc

对于 lr (Load Reserved) 和 sc (Store Conditional) 指令的情况则有一些特殊。 lr 指令执行时会触发加载指令访问错误异常(Load Access Fault),但 sc 指令在执行时不会触发任何异常,rd 寄存器的结果直接返回 1 ,则就导致无法直接模拟该指令的执行。

这里我选择的解决办法是:在执行到 lr 指令时,先对 lr 指令进行模拟,然后查找后续内存地址中的 sc 指令,并将其替换为非法指令(实际使用的是 csrrw zero, time, zero)。这样在执行到原先 sc 指令的位置时就会触发非法指令异常。在异常处理函数中,判断是否是原先替换指令的地址,如果是,则还原被替换的 sc 指令,并模拟指令执行,随后异常退出至下一条指令继续执行;如果不是,则将异常委托给内核处理。

设备树

/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";
};
};
};

实现效果

目前已经成功实现 Linux 6.10 内核启动引导,并传递设备树给内核。

c08b80ae-e5df-11ef-9434-92fbcf53809c.gif

coremark 跑分结果:

~ # 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 测试结果,可以看出缓内的读取速度是非常快的,超出缓存范围后读取速度受限于 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

最后附上仓库地址,同时也提供了 pre-built 的系统镜像,欢迎各位开发者下载体验。

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

鸣谢

感谢华中科技大学洛佳同学 (https://github.com/luojia65)在本项目开发过程中提供的建议和支持!同时他也是 RustSBI 的作者。

感谢华中科技大学王振辰同学(https://github.com/Plucky923)完善了 riscv-decode 库对 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

以上内容来自先楫开发者的原创分享。

我们始终相信开发者共创的力量。先楫社区坚持开源共享、互惠互利,贴近每一个开发者,一步一个脚印,一点一滴积累,为成为更好的我们而不断努力。

心之所向,锐意进取,星辰大海,恣意成长。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • mcu
    mcu
    +关注

    关注

    146

    文章

    18074

    浏览量

    370876
  • Linux
    +关注

    关注

    88

    文章

    11535

    浏览量

    214876
  • HPM
    HPM
    +关注

    关注

    1

    文章

    43

    浏览量

    8051
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    开发者分享|先楫半导体hpm_sdk使用vscode进行开发

    一、概述先楫半导体的hpm_sdk,对于习惯用keil的开发者可能不太习惯,但是从开发角度上看,是比较灵活的,可以给开发者一定的发挥空间。该sdk支持cmake构建,可以在多个支持cm
    的头像 发表于 06-30 10:01 ?4854次阅读
    <b class='flag-5'>开发者</b>分享|先楫半导体<b class='flag-5'>hpm</b>_sdk使用vscode进行<b class='flag-5'>开发</b>

    开发者分享 | 基于先楫RT-Thread BSP,使用CLion开发应用

    本期开发者:朱彦祖RT-Thread资深工程师,HPM6700/6400元老级开发者及骨灰级用户,先辑生态社区常驻优秀开发者,江湖人称杭州吴彦祖。背景最近在使用先辑
    的头像 发表于 06-07 08:17 ?3907次阅读
    <b class='flag-5'>开发者</b>分享 | 基于先楫RT-Thread BSP,使用CLion<b class='flag-5'>开发</b>应用

    适用于每个LabVIEW开发者的巧妙调试技巧

    调试一个大型的高度并行应用程序,则包含NI开发者套件 2011的LabVIEW桌面执行跟踪工具包就是您进行LabVIEW代码分析的“利器”。 它可提供关于正在运行的应用程序的各种信息,包括详细的内存
    发表于 10-27 14:32

    适用于STM32芯片的开发教程

    安富莱的论坛上也有很多有关单片机方面的有用的资料,大家可以参考。本文不仅适用于STM32芯片的开发,也适用于其它芯片。正文学习一款新的芯片,需要大家从官方获取两方面的资料,一个是相关的技术文档,比如参数手册、数据手册、应用笔记等
    发表于 12-09 06:54

    适用于移动终端的GUI设计与实现

    介绍一种适用于移动终端的图形用户界面(GUI)系统的设计与实现,使基于该GUI系统开发的移动终端应用程序具有美观统一的图形界面,使用方便快捷。
    发表于 09-22 09:57 ?10次下载

    适用于PDA的PLC编程系统开发

    适用于PDA的PLC编程系统开发:传统上调试PLC通常采用手持式PLC编程器,且只能适用于相应型号的PLC,上位计算机上的编程软件无法适用于现场实时调试、编辑程序. 本系统在分析PLC
    发表于 12-29 23:49 ?35次下载

    中国大陆开发者可以注册Apple Developer应用程序

    从今天开始,中国的开发人员现在可以使用适用于iOS的Apple Developer应用程序加入苹果开发者计划。
    的头像 发表于 12-18 10:43 ?4143次阅读

    微软Windows 10将适用于Your Phone应用

    微软在Build 2018开发者大会上宣布了适用于Windows 10用户的Your Phone(你的手机)应用,作为Windows 10 PC和安卓等手机的传输管理工具。
    的头像 发表于 03-01 15:13 ?2596次阅读

    Graphcore发布基于IPU开发者云,适用于AI模型的训练和推理

    7月8日消息,Graphcore今日正式发布基于IPU的开发者云,面向中国的客户、大学、研究机构和个人研究免费使用,使得前沿的机器智能创新可以轻松获取IPU进行前沿AI模型的云端训练与推理,从而
    的头像 发表于 07-09 14:28 ?2475次阅读

    适用于M1 MacBook的Firefox和Chrome浏览器上线

    援引外媒 9to5Google 报道,适用于 Apple Silicon Mac 设备的 Chrome 浏览器已经开放下载。此外,开发者也表示适用于 M1 Mac 的 Firefox 84 Beta 目前正在
    的头像 发表于 11-19 11:12 ?2772次阅读

    华为开发者大会2021智能硬件开发— 使用HPM定制产品

    2021年10月22日~24日,华为将在中国松山湖举行2021华为开发者大会,聚焦鸿蒙系统、智能家居、智慧办公、HMS Core 等热门话题,与华为专家、行业大咖、全球开发者一起探讨全场景智慧
    的头像 发表于 10-23 12:30 ?1521次阅读
    华为<b class='flag-5'>开发者</b>大会2021智能硬件<b class='flag-5'>开发</b>— 使用<b class='flag-5'>HPM</b>定制产品

    2021 OPPO开发者大会主会场:多模态、简单AI,赋能开发者价值实现

    2021 OPPO开发者大会主会场:多模态、简单AI,赋能开发者价值实现
    的头像 发表于 10-27 10:49 ?1610次阅读
    2021 OPPO<b class='flag-5'>开发者</b>大会主会场:多模态、简单AI,赋能<b class='flag-5'>开发者</b>价值<b class='flag-5'>实现</b>

    适用于学生和爱好的ATMega16 AVR开发

    电子发烧友网站提供《适用于学生和爱好的ATMega16 AVR开发板.zip》资料免费下载
    发表于 07-15 14:19 ?1次下载
    <b class='flag-5'>适用于</b>学生和爱好<b class='flag-5'>者</b>的ATMega16 AVR<b class='flag-5'>开发</b>板

    适用于低视力用户的触觉接近模块(HPM)

    电子发烧友网站提供《适用于低视力用户的触觉接近模块(HPM).zip》资料免费下载
    发表于 11-14 09:25 ?1次下载
    <b class='flag-5'>适用于</b>低视力用户的触觉接近模块(<b class='flag-5'>HPM</b>)

    NVIDIA cuPQC帮助开发适用于量子计算时代的加密技术

    NVIDIA cuPQC 可为相关开发者提供加速计算支持,帮助开发适用于量子计算时代的加密技术。cuPQC 库可利用 GPU 并行性,为要求严苛的安全算法提供支持。
    的头像 发表于 03-22 09:53 ?931次阅读