diff --git a/articles/20220819-riscv-irq-pipeline-introduction.md b/articles/20220819-riscv-irq-pipeline-introduction.md
new file mode 100644
index 0000000000000000000000000000000000000000..7cdcceaf9f8864ea5d9ce638bdbbc0133dcca072
--- /dev/null
+++ b/articles/20220819-riscv-irq-pipeline-introduction.md
@@ -0,0 +1,154 @@
+> Author: 天外天 1056572776@qq.com
Date: 2022/08/19
Revisor: Chen Chen [chen1233216@hotmail.com](mailto:chen1233216@hotmail.com)
Project: [RISC-V Linux 内核剖析](https://gitee.com/tinylab/riscv-linux)
Sponsor: PLCT Lab, ISCAS
+
+# RISC-V 异常处理流程介绍
+
+## 前言
+
+在学习 RISC-V 的异常处理流程之前,我们需要对「异常」有一个明确的理解。
+
+中断与异常,站在处理器处理的过程来说,其实并没有区别。当中断与异常发生时,处理器的表现形式都是暂停当前执行的程序,转而执行处理中断或异常的处理程序,处理完后**视情况**恢复执行之前被暂停的程序。通常我们所理解的中断与异常都可以被统称为**广义上的异常**。
+
+广义上的异常分为两种:
+
+1. 同步异常:执行某个程序流,能稳定复现的异常,能比较精确的确定是哪条指令引发的异常。(例如程序流中执行一条非法指令,属于内因)
+2. 异步异常(中断):异常产生的原因与当前的程序流无关,与外部的中断事件有关。(由外部事件引起的,属于外因)
+
+下文中的异常均指广义上的异常,狭义的异常我会用同步异常表达。
+
+对于 RISC-V 的特权架构来说,异常处理是其重要的组成部分。学习 RISC-V 的异常处理流程,主要也就是学习 RISC-V 特权模式下进行异常处理的 CSRs(Control and Status Registers,控制状态寄存器组)的用法。
+
+## RISC-V 的权限模式
+
+在任何时候,一个 RISC-V 的 hart(hardware thread,硬件线程)都会运行在一个权限模式当中,这个权限模式作为一个模式编码在 CSRs 当中。当前一共有三种 RISC-V 的权限模式:
+
+| 编码 | 名称 | 缩写 |
+| ---- | -------------------- | ---- |
+| 00 | User(用户) | U |
+| 01 | Supervisor(监管者) | S |
+| 11 | Machine(机器) | M |
+
+M 模式是 RISC-V 中 hart 可以执行的最高权限模式,也是唯一所有标准 RISC-V 处理器都必须实现的权限模式。所以本文以机器模式下的异常处理为例,介绍 RISC-V 异常处理的大致流程。S 模式是为操作系统提供支持的模式,其异常处理的流程和 M 模式类似,只是用其自己的一套 CSRs ,名称和 M 模式类似,以 s 开头。
+
+## 机器模式 CSRs
+
+RISC-V 处理异常主要依靠 CSRs ,主要关注以下八个控制状态寄存器:
+
+### mcause(Machine Exception Cause)
+
+
+
+机器模式异常原因寄存器,记录发生异常的原因,首位 Interrupt 置 1 时是中断, 0 时为异常。 Exception Code 域记录异常发生的原因编码。下表列出了可能出现的异常编码。
+
+
+
+### mtvec(Machine Trap Vector Base-Address Register)
+
+
+
+机器模式异常入口基地址寄存器,保存发生异常时处理器需要跳转到的地址,实际上就是异常处理程序的入口地址。该寄存器包含基地址 BASE 以及模式 MODE 两个域,其中 MODE 域表示异常处理程序入口地址的寻址方式。注意基地址 BASE 域必须 4 字节对齐,所以在计算异常处理程序的入口地址时,需要把末两位即 MODE 域中的两位恒置 0。
+
+| MODE | 名字 | 说明 |
+| ---- | ---- | --------------------------------------- |
+| 0 | 直接 | 所有的异常都将 PC 设为 BASE |
+| 1 | 向量 | 异步的中断会将 PC 设为 BASE + 4 * cause |
+| >=2 | | 保留 |
+
+例如,如果一个机器模式的时钟中断产生了,那么 PC 会被设置为 `BASE + 7 * 4 = BASE + 0x1c`,7 是机器模式时钟中断在 mcause 寄存器中 Exception Code 域的值。
+
+### mepc(Machine Exception PC)
+
+机器模式异常程序计数器,它指向发生异常的指令。对于同步异常,mepc 指向导致异常的指令;对于中断,它指向中断处理后应该恢复执行的位置。
+
+### mie(Machine Interrupt Enable)
+
+
+
+机器模式中断使能寄存器,记录处理器目前能处理和必须忽略的中断,即相应的中断使能位。值得注意的是,异常在 mcause 寄存器中的异常编码值即 Exception Code 域的值,正好对应 mie 寄存器中相应位置的中断使能位。例如,机器模式时钟中断的异常编码是 7,mie[7] 就表示机器模式时钟中断的使能,MTIE 即 Machine Time Interrupt Enable。
+
+### mip(Machine Interrupt Pending)
+
+
+
+机器模式中断等待寄存器,表示目前正准备处理的中断。它和 mie 有相同的布局。
+
+### mstatus(Machine Status)
+
+
+
+机器模式状态寄存器,它保存全局中断使能,以及许多其他的状态。xIE 保存对应模式的全局中断使能,比如,MIE 保存机器模式的全局中断使能。xPIE 保存对应模式异常发生前的全局中断使能,xPP 保存对应模式异常发生前的权限模式。MPP 有 2 位,SPP 只有 1 位,因为异常进入 S 模式只能是 U 模式或 S 模式,而异常进入 M 模式可以是所有的模式。
+
+处理器在 M 模式下运行时,只有在全局中断使能位 mstatus.MIE 置 1 时才会允许中断。此外,每个中断在 mie 和 mip 中都有自己的对应位。将上述三个控制状态寄存器合在一起考虑,如果 mstatus.MIE = 1,mie[7] = 1,且 mip[7] = 1,则表示开始处理机器模式的时钟中断。
+
+### mtval(Machine Trap Value)
+
+机器模式异常值寄存器,保存了异常的附加信息。比如,地址异常中出错的地址、发生非法指令异常的指令本身。对于其他异常,它的值为 0。
+
+### mscratch(Machine Scratch)
+
+这个寄存器会在实现线程时起到作用,目前仅了解即可。
+
+它暂时存放一个字大小的数据。在 U 模式下,mscratch 保存 M 模式下栈的地址;在 M 模式下,mscratch 的值为 0。可以在发生异常时通过 mscratch 中的值判断异常前程序是否处于 M 模式。为了能够执行 M 模式的中断处理流程,很可能需要使用栈,而程序当前的用户栈是不安全的。因此,我们还需要一个预设的安全的栈空间,存放在这里。
+
+大致用处可以在源码中明晰,如下源码是以 S 模式即内核态为例:
+
+```assembly
+// linux/v5.10/source/arch/riscv/kernel/entry.S:20
+ENTRY(handle_exception)
+ /*
+ * If coming from userspace, preserve the user thread pointer and load
+ * the kernel thread pointer. If we came from the kernel, the scratch
+ * register will contain 0, and we should continue on the current TP.
+ */
+ csrrw tp, CSR_SCRATCH, tp
+ bnez tp, _save_context
+
+_restore_kernel_tpsp:
+ csrr tp, CSR_SCRATCH
+ REG_S sp, TASK_TI_KERNEL_SP(tp)
+_save_context:
+ ...
+```
+
+Linux 内核使用 `CSR_SCRATCH` 寄存器保存发生异常前权限模式的 `tp` 寄存器的值,且如果 `CSR_SCRATCH` 为 0 则表示异常是在内核态触发的。源码先将当前 `tp` 的值与 `CSR_SCRATCH` 的值进行交换,如果发现 `CSR_SCRATCH` 的值为 0,则明显是由内核态进入异常处理的,此时需要将 `tp` 寄存器的值还原,并将此时的内核栈指针保存在 `struct thread_info` 的 `kernel_sp` 字段中。否则,通过交换后 `tp` 寄存器中指向的栈空间保存异常前权限模式的上下文,即通用寄存器组。
+
+## 异常处理流程
+
+当一个 hart 发生异常时,硬件自动经历如下的状态转换:
+
+- 将异常发生前所处的权限模式保存到 mstatus.MPP 中,再把权限模式更改为 M 模式。将异常发生前的 mstatus.MIE 保存到 mstatus.MPIE 当中,再把 mstatus.MIE 置零以禁用中断。这意味着在硬件上,RISC-V 是不支持嵌套中断的。若要实现嵌套中断,则只能通过软件的方式来实现。
+- 根据异常来源设置 mcause,并将异常的附加信息写入 mtval。
+- 异常指令的 PC 被保存在 mepc 中,将 PC 设置为 mtvec 中所定义的异常处理入口地址。对于同步异常, mepc 指向导致异常的指令;对于中断,mepc 指向中断处理后应该恢复执行的位置,一般是中断指令的下一条指令地址,即 mepc + 4。同之前所提到的,mtvec 有两种模式。一种是直接模式,直接跳转到 mtvec 中的基地址执行;另一种是向量模式,根据 mcause 中的中断类型跳转到对应的中断处理程序首地址中执行。
+
+然后执行异常处理程序,注意在程序中实现上下文环境的保存和切换。
+
+当异常处理程序执行完毕后,在程序最后会调用 MRET 指令来退出异常处理程序,S 模式中调用的是 SRET 指令。执行 MRET 指令后处理器硬件的行为如下:
+
+- 更新 mstatus。将异常发生前的 mstatus 的状态恢复,将 mstatus.MPIE 复制到 mstatus.MIE 来恢复之前的中断使能设置,并将权限模式设置为 mstatus.MPP 域中的值。
+- 从 mepc 中保存的地址执行,即恢复到异常发生前的程序流执行。
+
+整体的大致流程如下图所示:
+
+
+
+## 异常委托
+
+默认情况下,发生所有异常(不论在什么权限模式下)的时候,控制权都会被移交到 M 模式的异常处理程序。但是 Unix 系统中的大多数异常都会进行 S 模式下的系统调用。M 模式的异常处理程序可以将异常重新导向 S 模式,但这些额外的操作会减慢大多数异常的处理速度。因此,RISC-V 提供了一种异常委托机制。通过该机制可以选择性地将异常交给 S 模式处理,而完全绕过 M 模式。
+
+RISC-V 通过两个寄存器 medeleg(Machine Exception Delegation,机器同步异常委托)和 mideleg(Machine Interrupt Delegation,机器中断委托)分别控制将哪些同步异常和中断委托给 S 模式。与 mip 和 mie 的布局一样, medeleg 和 mideleg 中的位置对应于 mcause 中的异常编码值。例如,mideleg[5] 对应于 S 模式的时钟中断,如果把它置 1,S 模式的时钟中断将会移交 S 模式的异常处理程序,而不是 M 模式的异常处理程序。
+
+委托给 S 模式的任何异常都可以被 S 模式屏蔽。sie(Supervisor Interrupt Enable,监管者中断使能)和 sip(Supervisor Interrupt Pending,监管者中断待处理)是 S 模式的控制状态寄存器,它们是 mie 和 mip 的子集。它们有着和 M 模式下相同的布局,但在 sie 和 sip 中只有由 mideleg 委托的中断对应的位才能读写,那些没有被委派的中断对应的位始终为 0。
+
+**注意**:无论委派设置是怎样的,发生异常时控制权都不会移交给权限更低的模式。在 M 模式下发生的异常总是在 M 模式下处理。在 S 模式下发生的异常,根据具体的委派设置,可能由 M 模式或 S 模式处理,但永远不会由 U 模式处理。
+
+## 小结
+
+本文对 RISC-V 架构的异常处理流程进行了简单的介绍,主要分析了相关控制状态寄存器的用途,后续会结合 Linux 内核的源码进一步分析其代码的实现流程。
+
+## 参考资料
+
+- [RISC-V 中文手册 v2.1](https://ica123.com/wp-content/uploads/2021/03/RISC-V-%E6%8C%87%E4%BB%A4%E9%9B%86%E6%89%8B%E5%86%8C-v2.1%E4%B8%AD%E6%96%87%E7%89%88.pdf)
+- [RISC-V 特权架构手册](https://github.com/riscv/riscv-isa-manual/releases/download/draft-20220825-1237e31/riscv-privileged.pdf)
+- [RISC-V异常与中断机制概述](http://www.sunnychen.top/2019/07/06/RISC-V%E5%BC%82%E5%B8%B8%E4%B8%8E%E4%B8%AD%E6%96%AD%E6%9C%BA%E5%88%B6%E6%A6%82%E8%BF%B0/)
+- [RISC- V 特权架构介绍](https://dingfen.github.io/risc-v/2020/08/05/riscv-privileged.html)
+- [RISC-V 与中断相关的寄存器和指令](http://rcore-os.cn/rCore-Tutorial-deploy/docs/lab-1/guide/part-2.html)
+- [Linux内核在RISC-V架构下的setup_arch与异常处理](https://crab2313.github.io/post/riscv-setup-arch-exception/)
\ No newline at end of file
diff --git a/articles/images/riscv-irq-pipeline-introduction/exception_code.png b/articles/images/riscv-irq-pipeline-introduction/exception_code.png
new file mode 100644
index 0000000000000000000000000000000000000000..8b0fc69658d33deffcdafacef6ca73f899469201
Binary files /dev/null and b/articles/images/riscv-irq-pipeline-introduction/exception_code.png differ
diff --git a/articles/images/riscv-irq-pipeline-introduction/irq_pipeline.png b/articles/images/riscv-irq-pipeline-introduction/irq_pipeline.png
new file mode 100644
index 0000000000000000000000000000000000000000..49dcf8b777198695f3f4efd49f507213f5d0639f
Binary files /dev/null and b/articles/images/riscv-irq-pipeline-introduction/irq_pipeline.png differ
diff --git a/articles/images/riscv-irq-pipeline-introduction/mcause.png b/articles/images/riscv-irq-pipeline-introduction/mcause.png
new file mode 100644
index 0000000000000000000000000000000000000000..a0718d55f41a5f999c0c70b81927ac1fc7f5aca2
Binary files /dev/null and b/articles/images/riscv-irq-pipeline-introduction/mcause.png differ
diff --git a/articles/images/riscv-irq-pipeline-introduction/mie.png b/articles/images/riscv-irq-pipeline-introduction/mie.png
new file mode 100644
index 0000000000000000000000000000000000000000..e385697032441f99923c91f2ea5bb541c6c0231c
Binary files /dev/null and b/articles/images/riscv-irq-pipeline-introduction/mie.png differ
diff --git a/articles/images/riscv-irq-pipeline-introduction/mip.png b/articles/images/riscv-irq-pipeline-introduction/mip.png
new file mode 100644
index 0000000000000000000000000000000000000000..9b26ba79f2806a6fcf9b3f1bae4a08fd0276b8f0
Binary files /dev/null and b/articles/images/riscv-irq-pipeline-introduction/mip.png differ
diff --git a/articles/images/riscv-irq-pipeline-introduction/mstatus.png b/articles/images/riscv-irq-pipeline-introduction/mstatus.png
new file mode 100644
index 0000000000000000000000000000000000000000..1d91d374a9858a06a541303a398aa8609e9f255e
Binary files /dev/null and b/articles/images/riscv-irq-pipeline-introduction/mstatus.png differ
diff --git a/articles/images/riscv-irq-pipeline-introduction/mtvec.png b/articles/images/riscv-irq-pipeline-introduction/mtvec.png
new file mode 100644
index 0000000000000000000000000000000000000000..f289bed7cf2b2947f209f7056f12fd56a8906ed3
Binary files /dev/null and b/articles/images/riscv-irq-pipeline-introduction/mtvec.png differ