-
Notifications
You must be signed in to change notification settings - Fork 7
接下来要做……
本篇文章讲述目前的RustSBI HiFive Unmatched中已经完成和仍然需要完成的任务。
在您第一次贡献这个项目时,建议先跟随文档,至少启动过一次RustSBI,然后开始贡献工作。对RustSBI的实现,建议分支(fork按钮)本项目,完成部分功能后,提交Pull Request,项目成员将在检查之后合并。如果RustSBI框架有改进空间,也建议分支和提出合并请求。如果要制作一个新的RustSBI实现,例如为新平台或复杂功能,建议新建仓库,并将RustSBI作为依赖项。
目前的U-Boot引导链包含以下的部分:
U-Boot SPL -> RustSBI -> U-Boot -> Linux
RustSBI二进制包处于中间的位置,已经可以被SPL复制到DDR内存中,五个核都能启动并且输出panic信息。接下来,它需要进入下一个引导阶段。
解决方案:加载U-Boot镜像,1-4核跳转到U-Boot,0核被SBI HSM停止并待命(参见 #多核管理函数)。这种解决方案和目前的OpenSBI路线是相同的。
需要探索如何将U-Boot加载到需要的内存位置,然后才能跳转到U-Boot并启动。这部分也许需要引入一些设备驱动,或者探索SPL是否也会把U-Boot加入到镜像中。
在RustSBI启动时,SPL将设备树信息传入a1(opaque)寄存器中。读取设备树,发现每个CPU的设备树信息都被加上了u-boot,dm-spl
的标记,这个标记的意义有待探索,或许它对启动的过程有影响。
这种方案可以用于引导Linux启动。如果这之后Linux用户要使用小核完成特定地任务,或许可以植入内核模块,使用带参数的启动函数,带一个参数地指定第0个核启动到特定的位置,不过这部分代码也许需要对Linux的内核保护机制有一定的了解。
这种方案要求0、1-4核都进入下一个分区的操作系统内核,而绕开U-Boot。
下一个阶段的内核直接放在一个磁盘或存储卡分区中,通过某种方式鉴别(可能是SD卡的GUID)。把内核复制到DDR内存中,然后跳转到内核。
如果同时实现直接进入路线和U-Boot路线,或许可以选择先扫描是否存在一个U-Boot镜像,如果有,就尝试进入U-Boot。如果没有,就尝试直接进入内核。
这种方法的引导链较为简便,适用于竞赛、科研用的操作系统内核。目前(2021/12/21)它不适用于Linux,因为Linux暂时不能在0核上直接运行。
RISC-V SBI的0.3版本包括若干扩展,RustSBI HiFive Unmatched应当尽量实现完整的扩展。
RustSBI HiFive Unmatched实现了TIMER、IPI扩展,能模拟rdtime指令。它仍然需要实现HSM模块,来完成较完整的多核启动流程。
HSM模块是SBI 0.3规范版本中加入的,预期中它有多种应用场景(详见ppt)。即使Linux系统暂未支持0.3版本(2021/12/21),它仍然对竞赛、科研和其它用途的内核有较大的作用,是SBI实现功能的重要组成部分。
HSM模块实现过程的注意事项:
- 注意0、1-4核之间的同步操作,详见这篇笔记。如果你在操作同步机构时遇到了非法指令异常,或许需要注意这点。
- 注意易失性和非易失性暂停的区别。可以使用
wfi
指令实现非易失性暂停。 - 单元测试时,需要使用IPI唤醒暂停的核。
Unmatched主板具有一片电源管理芯片,它和处理器通过I2C协议通信。使用这块芯片,可以完成SBI扩展要求的电源关机和硬重启功能。I2C通信部分fu740-hal包暂未实现,I2C外设可能已经被SPL启动了,不需要在SBI中再启动一遍,只需要操作相关的寄存器去写I2C命令就可以了。
软重启功能可以参考HSM模块的停止和启动完成,等待所有的核软停止之后,可能需要读取MSEL的值,而后跳转到U-Boot SPL的启动部分。如果软重启不好实现,短期内可使用硬重启代替。
参考社区代码,实现这一功能。社区代码有不完善的地方,需要更好的方法去完善这部分代码,加入RustSBI的具体实现中。
参考Freedom U740芯片的文档。处理器的cease指令在sifive-core包中有包装好的函数,建议直接使用。详细阅读U740芯片关机的流程,它不仅需要使用cease指令,还需要其它的过程。cease指令之后处理器将停机。
cease函数运行后,当前函数占有的空间将未被释放。为了理解这一点,可以将cease函数看成是一条loop {}语句。错误做法:
#[panic_handler]
fn machine_panic(info: &PanicInfo) -> ! {
HSM.lock().set_cur_hart_state(State::Stopped);
// 此时HSM.lock()尚未释放
unsafe { sifive_core::asm::cease() } // 这个函数不会返回,HSM.lock()死锁了
}
正确做法:
#[panic_handler]
fn machine_panic(info: &PanicInfo) -> ! {
let mut lock = HSM.lock();
lock.set_cur_hart_state(State::Stopped);
drop(lock); // 显式释放锁
unsafe { sifive_core::asm::cease() }
}
其它平台的RustSBI实现拥有一个测试用的内核,它能依次执行SBI功能,来验证SBI实现的正确性。这个内核可以用来做RustSBI的单元测试。
需要执行的功能包括SBI规范定义的模块,以及rdtime指令模拟,和其它一些平台相关的情况。
测试用内核在HiFive Unmatched平台应当和Linux位于相同的存储位置。另一种方案是,直接把测试内核和RustSBI以FIT格式打包并填写到第二个SD卡分区,这种方法在开发SBI实现的时候只需要烧录一次。
如果HiFive Unmatched主机可以制作成一种用于测试的集群,它将可以帮助RustSBI社区更好地维护项目,提高RustSBI的代码质量,帮助更多厂商过渡到RustSBI技术中。
SSD比SD卡的连接更可靠,集成测试、在线测试环节可用性更好。在项目中远期探索一种SSD上烧录和运行RustSBI和有关项目的方法。
Oreboot是一个纯Rust实现的引导程序,它支持的多种平台也包括RISC-V。它的目标就像Coreboot,直接提供一个适用于Linux的启动环境。它的引导步骤十分简单,开机之后Oreboot,然后就直接进入Linux。它将是U-Boot软件强有力的替代品。
因为Oreboot是由Rust实现的,它和OpenSBI假如使用静态链接的方式,对项目的可控性有一定的影响。RustSBI也可以作为一个依赖库,导入到Cargo.toml中,这时就方便Oreboot直接提供SBI环境的实现了。