参考资料
SBI
即RISC-V Supervisor Binary Interface
,它通过抽象出特定平台的特定功能,在原来s-u mode
架构中新增了一个hs mode
中间层,从而允许s-mode
应用在所有risc-v
实现中移植
新版本qemu
中默认安装了opensbi
$ qemu-system-riscv64 \
--machine virt \
--nographic \
--bios default
OpenSBI v0.4 (Jul 2 2023 11:53:53)
____ _____ ____ _____
/ __ \ / ____| _ \_ _|
| | | |_ __ ___ _ __ | (___ | |_) || |
| | | | '_ \ / _ \ '_ \ \___ \| _ < | |
| |__| | |_) | __/ | | |____) | |_) || |_
\____/| .__/ \___|_| |_|_____/|____/_____|
| |
|_|
Platform Name : QEMU Virt Machine
Platform HART Features : RV64ACDFIMSU
Platform Max HARTs : 8
Current Hart : 0
Firmware Base : 0x80000000
Firmware Size : 112 KB
Runtime SBI Version : 0.1
PMP0: 0x0000000080000000-0x000000008001ffff (A)
PMP1: 0x0000000000000000-0xffffffffffffffff (A,R,W,X)
SBI
遵循如下调用约定规范:
ecall
指令作为从HS-Mode
到SEE
之间的控制转移指令a7
定义了SBI extension ID(EID)
a6
定义了SBI function ID (FID)
a0
和a1
的其他所有寄存器值a0
和a1
为结构的一个结构体,其中a0
为错误码 struct sbiret {
long error;
long value;
};
SBI
标准返回错误码
Error Type | Value |
---|---|
SBI_SUCCESS | 0 |
SBI_ERR_FAILED | -1 |
SBI_ERR_NOT_SUPPORTED | -2 |
SBI_ERR_INVALID_PARAM | -3 |
SBI_ERR_DENIED | -4 |
SBI_ERR_INVALID_ADDRESS | -5 |
SBI_ERR_ALREADY_AVAILABLE | -6 |
SBI_ERR_ALREADY_STARTED | -7 |
SBI_ERR_ALREADY_STOPPED | -8 |
hart
是什么?一般称为管理RISC-V
处理器的机制,在riscv
模式中会将riscv
的core
称为hart
,有时也称为hardware thread
,即硬件线程
从Hart State Management Extension (EID #0x48534D “HSM”)
可见
如果SBI
函数需要将hart
列表传递到更高权限模式,它必须使用如下所定义的hart
掩码
unsigned long hart_mask
是一个包含hartids
的标量unsigned long hart_mask_base
:是必须计算位向量的起始hartid
在单个SBI
函数调用中,可以设置的最大哈特数总是XLEN
hart_mask_base
可以设置为-1,表示可以忽略hart_mask
,并且必须考虑所有可用的hart
在此提一下RISC-V
的特权级寄存器
首先来看下通用寄存器:RV32I
是其中一种整数指令集,支持32个通用整数寄存器,每一个寄存器有32位,由x0~x31
表示,其中x0
寄存器被预留为常数0,在汇编语言中,通用寄存器组中的每一个寄存器都有别名
Register | ABI Name | Description |
---|---|---|
x0 | zero | Hard-wired zero |
x1 | ra | Return address |
x2 | sp | Stack pointer |
x3 | gp | Global pointer |
x4 | tp | Thread pointer |
x5-7 | t0-2 | Temporaries |
x8 | s0/fp | Saved register/frame pointer |
x9 | s1 | Saved register |
x10-11 | a0-1 | Function arguments/retrurn values |
x12-17 | a2-7 | Function arguments |
x18-27 | s2-11 | Saved register |
x28-31 | t3-6 | Temporaries |
除了通用寄存器,RISC-V
针对各个特权级,还定义了一系列特权级控制状态寄存器
misa
:表示hart支持的架构扩展,包括整数、乘除、原子、浮点数、双精度浮点数和压缩指令扩展等mhartid
:当前正在执行代码的hartid
medeleg
:默认情况下,所有的异常都是在M
模式下处理。当相应的medeleg
位置1时,该异常直接由S
模式或U
模式处理mideleg
:默认情况下,所有的中断都是在M
模式下处理。当相应的mideleg
位置1时,该中断直接由S
模式或U
模式处理mtime
:存储当前的时钟计数值mtimecmp
:时钟计数比较器。当当前mtime
寄存器中的值大于mtimecmp
中的值时,触发时钟中断mstatus
:表示当前处理器的控制状态,包括全局中断使能位。内存特权级,字节序控制位等mtvec
:保存发生trap
时处理器需要跳转到的地址mip
:指示正准备处理的中断类型。EIP
表示外部中断,TIP
表示时钟中断,SIP
表示软件中断。当相应的中断位置1时,表示存在该类型中断待处理mie
:指示处理器目前使能和忽略的中断类型。EIP
表示外部中断,TIP
表示时钟中断,SIP
表示软件中断。当相应的中断位置1时,表示该类型中断可以被处理器响应mscratch
:保存指向当前hart
上下文的指针mepc
:保存引发异常的指令mtval
:它保存了trap
的附加信息:地址例外中出错的地址、发生非法指令例外的指令本身,对于其他trap
,它的值为 0mcause
:指示发生trap
的种类。当最高位为1时,低位字段表示发生中断的类型;当最高位为0时,低位字段表示发生异常或系统调用的类型opensbi
是M
模式的一种实现,每一个hart
都有自己的上下文状态,上下文状态的指针保存在mscratch
寄存器中,opensbi
首先根据平台定义的hart的数量和hart栈的大小分配栈空间,然后依次为每一个hart
初始化sbi scratch
结构体,包括固件在内存中的地址,下一个启动阶段要执行的代码入口地址,参数以及特权级等信息,并将sbi scratch
的地址赋值给mscratch
寄存器
RISC-V
定义了三种特权模式
Machine Mode
:机器模式,简称 M
模式,对应特权等级 3。这是 RISC-V
中 hart
可以执行的最高权限模式Supervisor Mode
:监管者模式,简称 S
模式,对应特权等级 1User Mode
:用户模式,简称 U
模式,对应特权等级 0此外还定义了保留的特权等级 2,在 H
扩展中会将 S
模式扩展为 HS
模式
一般是以下三种组合:
M Mode
:通常为简单的嵌入式系统M Mode + U Mode
:该系统可以实现用户和机器模式的区分,从而实现资源的保护M Mode + U Mode + U Mode
:该系统可以实现类Unix操作系统Base Extension
部分被设计得尽可能小。因此,它只包含探测哪些SBI
扩展可用以及查询SBI
版本的功能
所有SBI
实现都必须支持基本扩展中的所有函数,因此没有定义错误返回
Get SBI specification version (FID #0)
:返回当前SBI
规范版本
struct sbiret sbi_get_spec_version(void);
Get SBI implementation ID (FID #1)
:返回当前的SBI
实现ID
,每个SBI
实现的ID
都不同
struct sbiret sbi_get_impl_id(void);
Get SBI implementation version (FID #2)
:返回当前SBI
实现版本
struct sbiret sbi_get_impl_version(void);
Probe SBI extension (FID #3)
:如果给定的SBI
扩展ID (EID)
不可用,则返回0;如果可用,则返回1,除非实现将其定义为任何其他非零值
struct sbiret sbi_probe_extension(long extension_id);
Get machine vendor ID (FID #4)
:返回一个mvendorid CSR
的合法值,0总是这个CSR
的合法值
struct sbiret sbi_get_mvendorid(void);
Get machine architecture ID (FID #5)
:返回一个对marchid CSR
合法的值,并且0始终是这个CSR
的合法值
struct sbiret sbi_get_marchid(void);
Get machine implementation ID (FID #6)
:返回一个对于mimpid CSR
合法的值,并且0始终是这个CSR
的合法值
struct sbiret sbi_get_mimpid(void);
Legacy Extension
使用了不同的Call Convention
a6
寄存器中的SBI
函数ID
字段被忽略,因为它们被编码为多个SBI
扩展ID
a1
寄存器中不返回任何内容SBI
调用中,被调用方必须保留除a0
之外的所有寄存器a0
寄存器中返回的值是特定于SBI Legacy Extensions
的SBI Legacy Extensions
已弃用,而支持下面列出的其他扩展
Extension: Set Timer (EID #0x00)
:
long sbi_set_timer(uint64_t stime_value)
Extension: Console Putchar (EID #0x01)
:将ch
中出现的数据写入调试控制台
long sbi_console_putchar(int ch)
Extension: Console Getchar (EID #0x02)
:从调试控制台读取一个字节
long sbi_console_getchar(void)
Extension: Clear IPI (EID #0x03)
:
Extension: Send IPI (EID #0x04)
:向hart_mask
中定义的所有hart
发送一个处理器间中断。处理器间中断在接收端显示为管理软件中断
long sbi_send_ipi(const unsigned long *hart_mask)
Extension: Remote FENCE.I (EID #0x05)
:指示远程hart
执行FENCE.I
指令
long sbi_remote_fence_i(const unsigned long *hart_mask)
Extension: Remote SFENCE.VMA (EID #0x06)
:指示远程hart
执行一个或多个SFENCE.VMA
指令,涵盖起始地址和大小之间的虚拟地址范围
long sbi_remote_sfence_vma(const unsigned long *hart_mask,
unsigned long start,
unsigned long size)
Extension: Remote SFENCE.VMA with ASID (EID #0x07)
:指示远程hart执行一个或多个SFENCE.VMA
指令,涵盖起始地址和大小之间的虚拟地址范围。这只包括给定的ASID
long sbi_remote_sfence_vma_asid(const unsigned long *hart_mask,
unsigned long start,
unsigned long size,
unsigned long asid)
Extension: System Shutdown (EID #0x08)
:从管理人员的角度将所有设备置于关机状态
void sbi_shutdown(void)
这将取代遗留的legacy timer extension (EID #0x00)
,即Extension: Set Timer (EID #0x00)
Function: Set Timer (FID #0)
:
struct sbiret sbi_set_timer(uint64_t stime_value)
这个Extension
替换了 legacy extension (EID #0x04)
这个Extension
替换了legacy extensions (EIDs #0x05 - #0x07)
Hart State Management(HSM)
扩展引入了一组Hart State
和一组允许管理模式软件请求改变Hart State
的函数
下面所示的HSM
哈特状态描述了所有可能的HSM
状态以及每个状态的唯一HSM
状态id
State ID | State Name | Description |
---|---|---|
0 | STARTED | hart 被物理启动且正常运行 |
1 | STOPPED | hart 没有在 S 模式或任何更低的特权模式下执行。如果平台有能够关闭 hart 的机制,这可能是因为它被 SBI 的实例关闭了 |
2 | START_PENDING | 其它 hart 要求从 STOPPED 状态继续或启动这个 hart,SBI 实例正在尝试让该 hart 进入 STARTED 状态 |
3 | STOP_PENDING | 该 hart 要求将自己从 STARTED 状态停止或关闭,SBI 实例正在尝试让该 hart 进入 STOPPED 状态 |
4 | SUSPENDED | 该 hart 处于平台特定的挂起(或低功耗)状态 |
5 | SUSPEND_PENDING | 该 hart 要求让自己从 STARTED 状态进入平台特定的低功耗状态,SBI 实例正在尝试让其进入平台特定的 SUSPENDED 状态 |
6 | RESUME_PENDING | 中断或平台特定的硬件事件导致 hart 从 SUSPENDED 状态转为正常执行,SBI 实例正在尝试将该 hart 转为 STARTED 状态 |
任何时刻 hart
的状态只可能是上表中的某一种
Function: HART start (FID #0)
:在 start_addr
处以S
模式执行 hartid
所指定的 hart
,并在开始执行时将 opaque
存入a1
寄存器。其中 opaque
是一个 XLEN
位的值,XLEN
指机器位数
struct sbiret sbi_hart_start(unsigned long hartid,
unsigned long start_addr,
unsigned long opaque)
Function: HART stop (FID #1)
:请求SBI
实现停止在监督模式下执行调用hart
,并将其所有权交还给SBI
实现
struct sbiret sbi_hart_stop(void)
Function: HART get status (FID #2)
:返回 hartid
指定的 hart
的状态
struct sbiret sbi_hart_get_status(unsigned long hartid)
Function: HART suspend (FID #3)
:要求 SBI
实现将调用该函数的 hart
置于 suspend_type
所指定的平台特定挂起(或低功耗)状态,resume_addr
是 hart
在挂起结束之后回到S
模式继续执行的地址,opaque
是一个 XLEN
位的值,其会在 hart
结束挂起状态时被放入 a1
寄存器
struct sbiret sbi_hart_suspend(uint32_t suspend_type,
unsigned long resume_addr,
unsigned long opaque)
系统复位扩展提供了允许管理软件请求系统级重新启动或关机的功能
Function: System reset (FID #0)
:根据提供的reset_type
和reset_reason
重置系统
struct sbiret sbi_system_reset(uint32_t reset_type, uint32_t reset_reason)
RISC-V硬
件性能计数器,如mcycle、minstret
和mhpmcounterX csr
,可以在管理模式下使用cycle、instret
和hpmcounterX csr
以只读方式访问
SBI
性能监控单元(PMU
)扩展是supervisor-mode在machine-mode
(或hypervisor-mode
)的帮助下配置和使用RISC-V
硬件性能计数器的接口
SBI PMU
扩展提供
hart
硬件/固件计数器的接口perf
兼容接口调试控制台扩展定义了一种通用机制,用于从管理模式软件进行调试和引导时早期打印
这个扩展取代了the legacy console putchar (EID #0x01)
和console getchar (EID #0x02) extensions
调试控制台扩展允许管理模式软件在单个SBI
调用中写入或读取多个字节
Function: Console Write (FID #0)
:将字节从输入内存写入调试控制台
struct sbiret sbi_debug_console_write(unsigned long num_bytes,
unsigned long base_addr_lo,
unsigned long base_addr_hi)
Function: Console Read (FID #1)
:将字节从调试控制台读入输出内存
struct sbiret sbi_debug_console_read(unsigned long num_bytes,
unsigned long base_addr_lo,
unsigned long base_addr_hi)
Function: Console Write Byte (FID #2)
:将一个字节写入调试控制台
struct sbiret sbi_debug_console_write_byte(uint8_t byte)
system suspend extension
定义了一组系统级睡眠状态和一个允许管理模式软件请求系统转换到睡眠状态的功能
ACPI
定义了Collaborative Processor Performance Control (CPPC)
机制,这是一种抽象而灵活的机制,用于监督模式电源管理软件与平台中的实体协作以管理处理器的性能