Last active
November 22, 2021 14:40
-
-
Save luojia65/e6a31563d99aa566a8c61ffd6bbc2d70 to your computer and use it in GitHub Desktop.
sbicall calling convention
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// -- 调用者(操作系统内核) | |
extern "sbicall" fn sbi_call(param: [usize; 6], a6: usize, a7: usize) -> (usize, usize); | |
// 最后两个参数必须是两个usize类型,a6: usize和a7: usize | |
// 除了最后两个参数,前面的参数必须是usize、[usize; N]或(usize, usize, ..)类型 | |
// 依次会被填写到a0, a1, ..., a5寄存器中。 | |
// 返回值可以是(usize, usize), [usize; 2]或者SbiRet(包含两个usize的结构体) | |
fn kernel() { | |
let (err, val) = sbi_call(SBI_POWER, POWER_RESET); | |
println!("err = {}, val = {}", err, val); | |
} | |
// 编译结果: | |
// ; let (err, val) = sbi_call(SBI_POWER, POWER_RESET); | |
// li a6, SBI_POWER | |
// li a7, POWER_RESET | |
// ecall | |
// ; println!("err = {}, val = {}", err, val); | |
// mv {param_1}, a0 | |
// mv {param_2}, a1 | |
// jal {println_funct} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// -- 用户(SBI实现) | |
extern "sbicall" fn handle_ecall(param: [usize; 6], module: usize, funct: usize) -> SbiRet { | |
// 最终得到a0到a7的值,并且能返回到SbiRet里 | |
if module == 1 && funct == 2 { | |
return SbiRet::ok(0) | |
} | |
SbiRet::unsupported() | |
} | |
// 调用约定: | |
// 被调用者保存:保存所有所有用到的临时变量到栈上,填写返回值到a0-a1寄存器 | |
// 调用者保存:所有的参数填写到a0-a7寄存器,不操作栈 | |
extern "sbicall" fn handle_ecall(param: [usize; 6], module: usize, funct: usize) -> SbiRet { | |
let a = param[0] + param[1]; | |
let b = param[2] + param[3]; | |
let c = param[4] + param[5]; | |
hint::black_box((a, b, c)); // 不优化掉未使用的变量 | |
SbiRet::unsupported() | |
} | |
// 编译结果: | |
// ; extern "sbicall" fn handle_ecall(...) -> ... { | |
// addi sp, sp, -3*8 | |
// sd t0, 0(sp) | |
// sd t1, 8(sp) | |
// sd t2, 16(sp) | |
// ; let a = param[0] + param[1]; | |
// add t0, a0, a1 | |
// ; let b = param[2] + param[3]; | |
// add t1, a2, a3 | |
// ; let c = param[4] + param[5]; | |
// add t2, a4, a5 | |
// ; hint::black_box((a, b, c)); | |
// ; SbiRet::unsupported() | |
// li a0, SBI_UNSUPPORTED | |
// li a1, 0 | |
// ; } | |
// ld t0, 0(sp) | |
// ld t1, 8(sp) | |
// ld t2, 16(sp) | |
// addi sp, sp, 3*8 | |
// ret |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 实现方法1:ecall调用,mret返回 | |
extern "sbicall" fn handle_ecall() { | |
// 直接开始调用 | |
} | |
// 但是这种方法会破坏内核的栈 | |
// 可以用attribute解决这个问题 | |
use core::arch::riscv::{swap_stack, interrupt}; | |
#[swap_stack(supervisor)] | |
#[interrupt(machine)] | |
extern "sbicall" fn handle_ecall() { | |
// ... | |
} | |
// 实现方法2:ecall调用,ret返回 | |
// 缺点:需要下面这一大块代码才能用,而且这个调用约定是不完整的,ret返回后函数仍然没有返回 | |
#[naked] | |
unsafe fn handle_trap() { | |
asm!( | |
"csrrw sp, sscratch, sp", | |
"jal {}", | |
"csrrw sp, sscratch, sp", | |
"mret", | |
sym handle_ecall, | |
) | |
} | |
// 实现方法3:call调用,ret返回 | |
// 这种方法是调用约定是完整的,缺点是需要中断处理代码才能使用 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 运行时 | |
fn execute() { | |
let mut rt = Runtime::new(); | |
rt.set_handler(handle_ecall); | |
rt.run(); | |
} | |
struct Runtime { | |
// 所有的 extern "sbicall" fn(PARAMETERS) -> RETURNS类型都能安全地强制转换 | |
handle_ecall: extern "sbicall" fn([usize; 6], usize, usize) -> SbiRet, | |
} | |
impl Runtime { | |
fn run(&mut self) { | |
loop { | |
asm!( | |
"csrrw sp, sscratch, sp", | |
"mret", // 回去了 | |
"csrrw sp, sscratch, sp", | |
"jal {}", | |
sym self.handle_ecall, | |
); | |
} | |
} | |
fn set_handler(&mut self, f: impl Into<extern "sbicall" fn(..) -> ..>) { | |
self.handle_ecall = f.into() as extern "sbicall" fn([usize; 6], usize, usize) -> SbiRet; | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment