diff --git a/articles/20230612-introduction-to-riscv-sbi.md b/articles/20230612-introduction-to-riscv-sbi.md
new file mode 100644
index 0000000000000000000000000000000000000000..8a93ffb9b06adf64b3d7370c8f7d9a4e71e00e6f
--- /dev/null
+++ b/articles/20230612-introduction-to-riscv-sbi.md
@@ -0,0 +1,203 @@
+> Author: groot [gr00t@foxmail.com](gr00t@foxmail.com)
+>
+>Date: 2023/06/12
+>
+>Revisor: Falcon falcon@tinylab.org[falcon@tinylab.org]
+>
+>Project: [RISC-V Linux 内核剖析](https://gitee.com/tinylab/riscv-linux)
+>
+>Proposal: [RISC-V Linux 内核 SBI 调用技术分析](https://gitee.com/tinylab/riscv-linux/issues/I64YC4)
+>
+>Sponsor: PLCT Lab, ISCAS
+
+
+
+# RISC-V SBI概述
+
+
+
+## 什么是SBI?
+
+SBI 全称 Supervisor Binary Interface,是 RISC-V execution environment interface ( EEI ) 之一[[1]](#fn1),目的是使处于 supervisor-sode ( S-mode 或者 VS-mode ) 的程序能够很方便的移植到实现不同扩展指令集的 RISC-V 架构的处理器上。提供SBI接口给监管模式软件的更高特权软件被称为SBI实现或Supervisor Execution Environmen(监管执行环境SEE)。
+
+
+## 为什么要有SBI
+
+
如果没有 SBI(如图一右侧),针对实现的扩展指令集不同的 RISC-V 微架构,可能要采用不同的方式才能够使操作系统内核触发 M-mode 的动作。而有了 SBI 之后,只要在扩展指令集不同的 RISC-V 微架构中实现统一的向上的 SBI 接口,上层的操作系统就可以不再关注具体的微架构细节,而是专注实现 SBI 接口提供的功能即可,大大提升了处于 supervisor-mode 的程序的可移植性。
这其实就是计算机中的一个很重要的哲学——抽象。通过将底层的具体实现屏蔽,向上提供统一的接口,使上层应用不需关注过多底层细节,大大简化了程序的开发难度。
通俗地,我们将 SBI 比作手机充电器接口。曾经市场上可能有非常多种类的充电器接口,如果 A 的手机接口和B的手机接口不一样,那么他们没办法互相使用对方的充电器,但是如果我们将充电器接口全部统一为 type-c 接口,这种尴尬地场景就不会再发生了,大大的方便了用户。
+
+
+
+## SBI的作用
+
+
+
+SBI 的第一个作用我们开头已经讲过了(图一左)。
除此之外,如上图所示,SBI 也可能在 hypervisor-mode(HS-mode)下作为虚拟机管理程序实现。
从更高一级的特权模式来看,SBI implementation 为 supervisor-mode 软件分配物理执行单元(HARTs)。
因此,从 SBI implementation 的角度来看,S-mode 的 HART 被称为虚拟 HART(图一)。而如果实现是一个虚拟机管理程序(图二),那么虚拟HART则表示 VS-mode 的虚拟HART。
+
+
+## SBI Implementations
+
+理论上说,因为 SBI spec 是开源的,只要能够按照spec说明实现其功能就可以称为 BI Implementation。
不过当前经过 riscv 官方认证的 Implementation 有如下几个[[2]](#fn2):
+
+| ImplementationID | Name |
+| ---------------- | -------------------------- |
+| 0 | Berkeley Boot Loader (BBL) |
+| 1 | OpenSBI |
+| 2 | Xvisor |
+| 3 | KVM |
+| 4 | RustSBI |
+| 5 | Diosix |
+| 6 | Coffer |
+
+
+
+# OpenSBI
+
+
+
+## 什么是OpenSBI
+
+OpenSBI 是 SBI spec 的一个 RISC-V SBI C 语言参考实现。 它由 Western Digital 公司发起,并且在 2019 年进行了开源。
+
+
+## 编译openSBI
+
+> 这里已经默认用户安装好 qemu 和 u-boot
+
+1. 下载 OpenSBI 源码
+
+```shell
+git clone https://github.com/riscv/opensbi.git
+```
+
+2. 进入 OpenSBI 文件夹
+
+```shell
+cd qemu-opensbi
+```
+
+3. 新建文件夹并进入
+
+```shell
+mkdir build
+cd build
+```
+
+3. 编译
+
+```shell
+make -C $(pwd)/.. PLATFORM=generic CROSS_COMPILE=riscv64-Linux-gnu- FW_PAYLOAD_PATH=path/to/u-boot.bin
+```
+
+
+
+## 启动 OpenSBI
+
+1. 在 `qemu-opensbi` 文件夹中执行下面的命令
+
+```shell
+qemu-system-riscv64 -M virt -m 256 -nographic -bios build/platform/generic/firmware/fw_payload.el
+```
+
+2. 显示输出
+
+
+
+
+# Linux Kernel SBI代码分析引导
+
+下面分析Linux源码中的SBI代码:
+
+
+## ECALL指令
+
+`ECALL` 指令用于向执行环境发出请求,在不同的特权等级中执行 `ECALL` 指令有不同的效果:在 User Mode 中会引发 environment-call-from-U-mode 异常,在Supervisor Mode 中会引发 environment-call-from-S-mode 异常, 而在Machine Mode 中会引发 environment-call-from-M-mode 异常[[3]](#fn3)。
+
+
+### Linux内核SBI代码
+
+`ECALL` 指令在Linux中用于系统调用,如下为 `arch/riscv/kernel/sbi.c` 中的部分代码。
`sbi_ecall` 指令接受8个参数,分别是
+
+- `ext` : SBI extension ID (EID)
+- `fid` : SBI function ID (FID)
+- `arg0-arg5` : SBI函数调用参数
+
+```c
+struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0,
+ unsigned long arg1, unsigned long arg2,
+ unsigned long arg3, unsigned long arg4,
+ unsigned long arg5)
+{
+ struct sbiret ret;
+
+ register uintptr_t a0 asm ("a0") = (uintptr_t)(arg0);
+ register uintptr_t a1 asm ("a1") = (uintptr_t)(arg1);
+ register uintptr_t a2 asm ("a2") = (uintptr_t)(arg2);
+ register uintptr_t a3 asm ("a3") = (uintptr_t)(arg3);
+ register uintptr_t a4 asm ("a4") = (uintptr_t)(arg4);
+ register uintptr_t a5 asm ("a5") = (uintptr_t)(arg5);
+ register uintptr_t a6 asm ("a6") = (uintptr_t)(fid);
+ register uintptr_t a7 asm ("a7") = (uintptr_t)(ext);
+ asm volatile ("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;
+}
+```
+
+> 使用 `ECALL` 指令时,将异常类型写在a7寄存器, 参数写在a0-a5寄存器,后面会根据异常类型的不同调用不同的异常处理函数
`register` 关键字表明后面的变量直接存储在寄存器中
`asm ("ax")` 表明将后面的变量与 `ax` 寄存器进行绑定
`asm volatile` 表明嵌入汇编代码进入C代码中,并且将 `a0` 和 `a1` 寄存器既作为输入寄存器又作为输出寄存器传给 `ECALL` 指令,而 `a2` - `a6` 寄存器作为输入寄存器传递给 `ECALL`
`ECALL` 函数返回两个值 `a0` 和 `a1` ,`sbi_ecall` 函数将这两个值作为错误和值返回给调用它的函数
+
+
+比如实现一个putchar函数用于打印一个字符到系统控制台上,就如下通过调用 `sbi_ecall` 来实现:
+
+```c
+void sbi_console_putchar(int ch)
+{
+ sbi_ecall(SBI_EXT_0_1_CONSOLE_PUTCHAR, 0, ch, 0, 0, 0, 0, 0);
+}
+```
+
+然后我们进入 `arch/riscv/include/sbi.h` ,观察宏定义:
+
+```c
+enum sbi_ext_id {
+#ifdef CONFIG_RISCV_SBI_V01
+ SBI_EXT_0_1_SET_TIMER = 0x0,
+ SBI_EXT_0_1_CONSOLE_PUTCHAR = 0x1,
+ SBI_EXT_0_1_CONSOLE_GETCHAR = 0x2,
+ SBI_EXT_0_1_CLEAR_IPI = 0x3,
+ SBI_EXT_0_1_SEND_IPI = 0x4,
+ SBI_EXT_0_1_REMOTE_FENCE_I = 0x5,
+ SBI_EXT_0_1_REMOTE_SFENCE_VMA = 0x6,
+ SBI_EXT_0_1_REMOTE_SFENCE_VMA_ASID = 0x7,
+ SBI_EXT_0_1_SHUTDOWN = 0x8,
+#endif
+ SBI_EXT_BASE = 0x10,
+ SBI_EXT_TIME = 0x54494D45,
+ SBI_EXT_IPI = 0x735049,
+ SBI_EXT_RFENCE = 0x52464E43,
+ SBI_EXT_HSM = 0x48534D,
+ SBI_EXT_SRST = 0x53525354,
+ SBI_EXT_PMU = 0x504D55,
+
+ /* Experimentals extensions must lie within this range */
+ SBI_EXT_EXPERIMENTAL_START = 0x08000000,
+ SBI_EXT_EXPERIMENTAL_END = 0x08FFFFFF,
+
+ /* Vendor extensions must lie within this range */
+ SBI_EXT_VENDOR_START = 0x09000000,
+ SBI_EXT_VENDOR_END = 0x09FFFFFF,
+};
+```
+
+观察到 `SBI_EXT_0_1_CONSOLE_PUTCHAR` 定义为 `0x1` 。
+
+---
+
+
+1. Volume I: RISC-V Unprivileged ISA V20191214-draft [↩︎](#fnref1)
+2. RISC-V Supervisor Binary Interface Specification Version -v2.0-rc1, 2023-06-01: Draft [↩︎](#fnref2)
+3. Volume II: RISC-V Privileged Architectures V1.12-draft [↩︎](#fnref3)
\ No newline at end of file