A comprehensive C interface library for OpenSBI (RISC-V Supervisor Binary Interface)
OpenSBI 的完整 C 接口库,为 RISC-V 裸机开发提供标准化的 SBI 调用接口。
SPEC Version: SBI v2.0
中文版本 | English Version
- ✅ 完整的 SBI 规范支持: 实现 SBI v2.0 规范中的所有扩展
- ✅ 类型安全: 使用结构化的返回值和错误码
- ✅ 零依赖: 纯 C 实现,无外部依赖
- ✅ 内联汇编: 高效的 ecall 实现
- ✅ 广泛兼容: 支持所有主流 SBI 实现 (OpenSBI, RustSBI, BBL 等)
- ✅ 完整文档: 详细的 API 文档和使用示例
sbi_get_spec_version()- 获取 SBI 规范版本sbi_get_impl_id()- 获取 SBI 实现 IDsbi_get_impl_version()- 获取 SBI 实现版本sbi_probe_extension()- 探测 SBI 扩展支持sbi_get_mvendorid()- 获取机器厂商 IDsbi_get_marchid()- 获取机器架构 IDsbi_get_mimpid()- 获取机器实现 ID
sbi_set_timer()- 设置定时器
sbi_send_ipi()- 发送处理器间中断
sbi_remote_fence_i()- 远程指令缓存刷新sbi_remote_sfence_vma()- 远程监管者虚拟内存刷新sbi_remote_sfence_vma_asid()- 带 ASID 的远程虚拟内存刷新sbi_remote_hfence_gvma()- 远程客户虚拟内存刷新sbi_remote_hfence_gvma_vmid()- 带 VMID 的远程客户虚拟内存刷新sbi_remote_hfence_vvma()- 远程虚拟化虚拟内存刷新sbi_remote_hfence_vvma_asid()- 带 ASID 的远程虚拟化虚拟内存刷新
sbi_hart_start()- 启动 Hartsbi_hart_stop()- 停止 Hartsbi_hart_get_status()- 获取 Hart 状态sbi_hart_suspend()- 暂停 Hart
sbi_system_reset()- 系统重置
sbi_pmu_num_counters()- 获取计数器数量sbi_pmu_counter_get_info()- 获取计数器信息sbi_pmu_counter_config_matching()- 配置计数器匹配sbi_pmu_counter_start()- 启动计数器sbi_pmu_counter_stop()- 停止计数器sbi_pmu_counter_fw_read()- 读取固件计数器
sbi_debug_console_write()- 调试控制台写入sbi_debug_console_read()- 调试控制台读取sbi_debug_console_write_byte()- 调试控制台写入字节
sbi_system_suspend()- 系统暂停
sbi_cppc_probe()- 探测 CPPC 支持sbi_cppc_read()- 读取 CPPC 寄存器sbi_cppc_read_hi()- 读取 CPPC 寄存器高位sbi_cppc_write()- 写入 CPPC 寄存器
sbi_nacl_probe_feature()- 探测嵌套加速特性sbi_nacl_set_shmem()- 设置共享内存sbi_nacl_sync_csr()- 同步 CSRsbi_nacl_sync_hfence()- 同步 HFENCEsbi_nacl_sync_sret()- 同步 SRET
sbi_sta_set_shmem()- 设置共享内存
#include "opensbi_interface.h"
int main() {
// 获取 SBI 信息
struct sbiret ret = sbi_get_spec_version();
if (ret.error == SBI_SUCCESS) {
uint32_t major = ret.value >> 24;
uint32_t minor = ret.value & 0xFFFFFF;
printf("SBI Spec Version: %d.%d\n", major, minor);
}
// 获取实现信息
ret = sbi_get_impl_id();
if (ret.error == SBI_SUCCESS) {
printf("SBI Implementation: %s\n", SBI_IMPL_ID_NAMES[ret.value]);
}
// 探测扩展支持
ret = sbi_probe_extension(SBI_EXT_TIME);
if (ret.error == SBI_SUCCESS && ret.value == 1) {
printf("Timer extension is supported\n");
}
return 0;
}#include "opensbi_interface.h"
void setup_timer() {
// 设置 1 秒后的定时器中断
uint64_t current_time;
asm volatile("rdtime %0" : "=r"(current_time));
struct sbiret ret = sbi_set_timer(current_time + 10000000); // 假设 10MHz 频率
if (ret.error == SBI_SUCCESS) {
printf("Timer set successfully\n");
}
}#include "opensbi_interface.h"
void send_ipi_to_hart(unsigned long hart_id) {
unsigned long hart_mask = 1UL << hart_id;
struct sbiret ret = sbi_send_ipi(hart_mask, 0);
if (ret.error == SBI_SUCCESS) {
printf("IPI sent to hart %lu\n", hart_id);
}
}#include "opensbi_interface.h"
void start_secondary_hart(unsigned long hart_id, unsigned long start_addr) {
struct sbiret ret = sbi_hart_start(hart_id, start_addr, 0);
switch (ret.error) {
case SBI_SUCCESS:
printf("Hart %lu started successfully\n", hart_id);
break;
case SBI_ERR_INVALID_PARAM:
printf("Invalid hart ID or start address\n");
break;
case SBI_ERR_ALREADY_AVAILABLE:
printf("Hart %lu is already running\n", hart_id);
break;
default:
printf("Failed to start hart %lu: %ld\n", hart_id, ret.error);
}
}#include "opensbi_interface.h"
void debug_print(const char* str) {
while (*str) {
sbi_debug_console_write_byte(*str);
str++;
}
}
void debug_print_string(const char* str) {
int len = strlen(str);
unsigned long addr = (unsigned long)str;
struct sbiret ret = sbi_debug_console_write(len,
addr & 0xFFFFFFFF,
addr >> 32);
if (ret.error != SBI_SUCCESS) {
// 回退到字节写入
debug_print(str);
}
}#include "opensbi_interface.h"
void system_shutdown() {
struct sbiret ret = sbi_system_reset(SRST_RESET_TYPE_SHUTDOWN,
SRST_RESET_REASON_NONE);
// 此函数不应返回
}
void system_reboot() {
struct sbiret ret = sbi_system_reset(SRST_RESET_TYPE_COLD_REBOOT,
SRST_RESET_REASON_NONE);
// 此函数不应返回
}库定义了标准的 SBI 错误码:
enum {
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, // 已经停止
SBI_ERR_NO_SHMEM = -9, // 无共享内存
};库支持以下 SBI 实现:
- OpenSBI (推荐)
- RustSBI
- Berkeley Boot Loader (BBL)
- Xvisor
- KVM
- Diosix
- Coffer
- Xen Project
- PolarFire Hart Software Services
add_subdirectory(path/to/opensbi_interface)
target_link_libraries(your_target opensbi_interface)# 编译静态库
gcc -c src/opensbi_interface.c -I src/include -o opensbi_interface.o
ar rcs libopensbi_interface.a opensbi_interface.o
# 链接到你的项目
gcc your_main.c -L. -lopensbi_interface -I src/include -o your_programopensbi_interface/
├── src/
│ ├── include/
│ │ └── opensbi_interface.h # 主头文件
│ ├── opensbi_interface.c # 实现文件
│ └── CMakeLists.txt
├── test/
│ ├── main.c # 测试示例
│ ├── boot.S # 启动汇编
│ ├── link.ld # 链接脚本
│ └── fw_jump.elf # OpenSBI 固件
├── CMakeLists.txt
└── README.md
项目包含完整的测试示例:
# 构建测试
mkdir build && cd build
cmake ..
make
# 在 QEMU 中运行测试
qemu-system-riscv64 -machine virt -cpu rv64 -smp 4 \
-bios test/fw_jump.elf -kernel test/opensbi_test \
-nographic -serial mon:stdio所有 SBI 调用都通过 ecall 指令实现:
static struct sbiret ecall(unsigned long arg0, unsigned long arg1,
unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5,
unsigned long fid, unsigned long eid) {
struct sbiret ret;
register uintptr_t a0 __asm__("a0") = (uintptr_t)(arg0);
register uintptr_t a1 __asm__("a1") = (uintptr_t)(arg1);
// ... 更多寄存器设置
register uintptr_t a7 __asm__("a7") = (uintptr_t)(eid);
__asm__("ecall"
: "+r"(a0), "+r"(a1)
: "r"(a2), "r"(a3), "r"(a4), "r"(a5), "r"(a6), "r"(a7)
: "memory");
ret.error = a0;
ret.value = a1;
return ret;
}struct sbiret {
long error; // 错误码
long value; // 返回值
};- RISC-V 架构: RV32, RV64
- 特权级别: 监管者模式 (S-mode)
- 编译器: GCC, Clang
- SBI 版本: v0.1 (Legacy), v0.2+, v2.0
MIT License
欢迎提交 Issue 和 Pull Request!