# ref1 · RISC-V 非特权规范 §1.6 Exceptions, Traps, and Interrupts（双语对照）

> **来源**：`__note__/riscv-unprivileged.pdf` — *The RISC-V Instruction Set Manual, Volume I: Unprivileged Architecture*，Version 20260120: Official Release
> **位置**：§1.6（书内页码 20–21 → **PDF 第 39–40 页**）
> **用途**：`__note__/lab/lab3/lab3.md`（Lab3 · Traps）的术语基准
> **译者**：AI-TA · 2026-09-22
> **阅读约定**：原文按段拼接为整段（PDF 硬换行与多余空格已清理）；译文忠实原文，技术术语保留英文并在首次出现时给中文。`【📌 锚点】` 是我额外加的 xv6 对照，**不属于原文**。

---

## 🔤 术语速查（先看这个再读正文）

| 英文 | 中文 | 一句话 | 备注 |
|---|---|---|---|
| **hart** | 硬件线程 | Hardware Thread 的缩写 | 一个 hart ≈ 一个可独立执行指令流的"核"；xv6 里 `cpuid()` 取 hartid |
| **EEI** | 执行环境接口 | Execution Environment Interface | 软件看到的那一层"机器"（如 RISC-V S-mode + U-mode 这一套） |
| **exception** | 异常 | **同步**、与某条指令绑定 | 缺页、非法指令、`ecall` |
| **interrupt** | 中断 | **异步**、来自外部 | 时钟、UART、磁盘 |
| **trap** | 陷阱 | **控制转移这个动作本身** | 不是"事件"，是"事件导致的结果" ⚠️ |
| **trap handler** | trap 处理程序 | 接住 trap 的那段代码 | xv6 里是 `usertrap()` / `kerneltrap()` |
| **precise / imprecise** | 精确 / 不精确 | 出错指令的现场是否可被精确定位 | 见文末段 |

---

## 📖 正文双语对照

### ¶1 · 三个术语的定义 ★

**原文**

> We use the term **exception** to refer to an unusual condition occurring at run time associated with an instruction in the current RISC-V hart. We use the term **interrupt** to refer to an external asynchronous event that may cause a RISC-V hart to experience an unexpected transfer of control. We use the term **trap** to refer to the transfer of control to a trap handler caused by either an exception or an interrupt.

**译文**

> 我们用术语 **exception（异常）** 指：当前 RISC-V hart 中，与某条指令相关联的、在运行时出现的不寻常状况。我们用术语 **interrupt（中断）** 指：一种外部异步事件，它可能使某个 RISC-V hart 经历一次非预期的控制转移。我们用术语 **trap（陷阱）** 指：由 exception 或 interrupt 所引起的、向 trap handler 的控制转移。

【📌 锚点】注意三者**不是并列的三个东西**，而是两层关系：

```
exception ─┐
           ├──► trap（= 控制转移这个动作）
interrupt ─┘
```

所以"发生了一次 trap"≠"发生了一次异常"。xv6 book §4 开头用的更宽松（把 system call / exception / interrupt 说成**三类引发 trap 的事件**），与本规范的措辞略有出入但**不矛盾**：book 把 `ecall` 单列，是因为在 RISC-V 里 `ecall` 本身就是一条指令触发的 exception（`scause == 8`）——本规范把它归在 Contained Trap 的例子里（见下）。**两处指的是一回事**：`__note__/book-riscv-rev2.pdf` 第 43 页原文：

> There are three kinds of event which cause the CPU to set aside ordinary execution of instructions and force a transfer of control to special code that handles the event. … This book uses **trap** as a generic term for these situations.

---

### ¶2 · exception 何时引起 trap

**原文**

> The instruction descriptions in following chapters describe conditions that can raise an exception during execution. The general behavior of most RISC-V EEIs is that a trap to some handler occurs when an exception is signaled on an instruction (except for floating-point exceptions, which, in the standard floating-point extensions, do not cause traps). The manner in which interrupts are generated, routed to, and enabled by a hart depends on the EEI.

**译文**

> 后续各章的指令说明里，描述了执行期间可能引发 exception 的各种情形。大多数 RISC-V EEI 的一般行为是：当某条指令上报告（signaled）了一个 exception 时，就会发生一次到某个 handler 的 trap（浮点 exception 除外——在标准浮点扩展中，它们不引起 trap）。interrupt 如何被产生、如何被路由到 hart、以及 hart 如何使能它，则取决于 EEI。

> [!NOTE] 原文旁注（方框）
> **原文**：Our use of "exception" and "trap" is compatible with that in the IEEE-754 floating-point standard.
> **译文**：我们对 "exception" 与 "trap" 的用法，与 IEEE-754 浮点标准中的用法是相容的。

【📌 锚点】"EEI 决定 interrupt 怎么产生/使能" → 在 xv6 里对应的就是 **CSR + 设备树**这一层：`kernel/trap.c:27` 的 `trapinithart()` 写 `stvec`，`kernel/riscv.h` 里的 `intr_on()/intr_off()` 操作 `sstatus.SIE`。换句话说，**规范把"使能"这件事留给软件**，xv6 的软件做法就是这两个 CSR 操作。

---

### ¶3 · 四种效果（按"环境内部软件"的视角分类）

**原文**

> How traps are handled and made visible to software running on the hart depends on the enclosing execution environment. From the perspective of software running inside an execution environment, traps encountered by a hart at runtime can have four different effects:

**译文**

> trap 如何被处理、以及如何被运行在该 hart 上的软件"看见"，取决于**外围执行环境**（enclosing execution environment）。从执行环境**内部**运行的软件的视角来看，hart 在运行时遇到的 trap 可以有四种不同的效果：

---

#### ① Contained Trap（受控 trap）

**原文**

> The trap is visible to, and handled by, software running inside the execution environment. For example, in an EEI providing both supervisor and user mode on harts, an ECALL by a user-mode hart will generally result in a transfer of control to a supervisor-mode handler running on the same hart. Similarly, in the same environment, when a hart is interrupted, an interrupt handler will be run in supervisor mode on the hart.

**译文**

> 该 trap 对执行环境内部运行的软件是**可见的**，并且**由它处理**。例如，在一个于 hart 上同时提供 supervisor 模式与 user 模式的 EEI 中，由 user 模式 hart 发出的 `ECALL` 通常会转移到运行在**同一个 hart** 上的 supervisor 模式 handler。同样地，在同一环境中，当 hart 被中断时，interrupt handler 会在该 hart 上以 supervisor 模式运行。

【📌 锚点】⭐ **这就是 xv6 的日常**：`ecall` → `stvec`（TRAMPOLINE+`uservec`）→ `usertrap()` → `syscall()`。**"同一个 hart"这个限定词很关键**——xv6 里 trap 绝不会跑到别的 CPU 上处理，`myproc()` 能生效就靠这一点。

---

#### ② Requested Trap（请求 trap）

**原文**

> The trap is a synchronous exception that is an explicit call to the execution environment requesting an action on behalf of software inside the execution environment. An example is a system call. In this case, execution may or may not resume on the hart after the requested action is taken by the execution environment. For example, a system call could remove the hart or cause an orderly termination of the entire execution environment.

**译文**

> 该 trap 是一种**同步 exception**，它是对执行环境的一次**显式调用**，代表执行环境内部的软件请求执行某个动作。一个例子就是 system call（系统调用）。在这种情况下，在执行环境完成所请求的动作之后，hart 上的执行**可能会继续、也可能不会继续**。例如，某个系统调用可能移除该 hart，或导致整个执行环境有序终止。

【📌 锚点】"may or may not resume" 对应的就是 `exit()` / `exec()` 这类**不返回**的 syscall——xv6 里 `exit()` 之后 `usertrapret()` 根本不会被执行到（`usertrap()` 里的 `exit(-1)` 已经把进程干掉了）。这也是你上学期问过的"syscall 一定有返回值吗"的规范级答案。

---

#### ③ Invisible Trap（不可见 trap）

**原文**

> The trap is handled transparently by the execution environment and execution resumes normally after the trap is handled. Examples include emulating missing instructions, handling non-resident page faults in a demand-paged virtual-memory system, or handling device interrupts for a different job in a multiprogrammed machine. In these cases, the software running inside the execution environment is not aware of the trap (we ignore timing effects in these definitions).

**译文**

> 该 trap 由执行环境**透明地**处理，处理完毕之后执行照常继续。例子包括：仿真（emulating）缺失的指令、在**请求分页**（demand-paged）的虚拟内存系统中处理**非驻留页缺页**（non-resident page fault）、或在**多道程序**（multiprogrammed）机器上为另一项作业处理设备中断。在这些情况下，执行环境内部运行的软件**感知不到**该 trap（在这些定义中我们忽略时序上的影响）。

【📌 锚点】⭐ **这一条是后面三个 lab 的理论根**：xv6 现在的 `usertrap()` 碰到 page fault 是**直接 `p->killed = 1`**（`kernel/trap.c:70-73` 的 `else` 分支，即当致命处理——`devintr()` 对 page fault 返回 0，于是落到这里），而 `lazy` lab 与 `cow` lab 要做的事，正是把它变成 **Invisible Trap**——用户程序读写一个"还没分配"或"被标成只读"的页，内核在背后悄悄补上，程序自己毫无感觉。"we ignore timing effects" 也值得注意：现实中透明处理**有代价**，只是定义层面不看它。

---

#### ④ Fatal Trap（致命 trap）

**原文**

> The trap represents a fatal failure and causes the execution environment to terminate execution. Examples include failing a virtual-memory page-protection check or allowing a watchdog timer to expire. Each EEI should define how execution is terminated and reported to an external environment.

**译文**

> 该 trap 表示一次致命失败，并导致执行环境终止执行。例子包括：虚拟内存的**页保护检查**失败，或者**看门狗定时器**（watchdog timer）超时。每个 EEI 都应定义"执行如何终止、以及如何向外部环境报告"。

【📌 锚点】xv6 的对应物：`kernel/trap.c:70-73` 那个 `else` 分支——不认识的 `scause` 就 `printf("usertrap(): unexpected scause …")`（:71）+ `p->killed = 1`（:73），随后 `exit(-1)`。**这就是 xv6 版的 fatal trap 上报通道**（打到 console，而不是上报给某个 hypervisor）。

---

### 📊 表 1 · 各类 trap 的特征（原文 + 译文）

**原文 Table 1. Characteristics of traps**

| | Contained | Requested | Invisible | Fatal |
|---|---|---|---|---|
| Execution terminates | No | No¹ | No | Yes |
| Software is oblivious | No | No | Yes | Yes² |
| Handled by environment | No | Yes | Yes | Yes |

> ¹ Termination may be requested
> ² Imprecise fatal traps might be observable by software

**译文 表 1. 各类 trap 的特征**

| | Contained（受控） | Requested（请求） | Invisible（不可见） | Fatal（致命） |
|---|---|---|---|---|
| 执行终止（Execution terminates） | 否 | 否 ¹ | 否 | 是 |
| 软件无感知（Software is oblivious） | 否 | 否 | 是 | 是 ² |
| 由执行环境处理（Handled by environment） | 否 | 是 | 是 | 是 |

> ¹ 终止可以被请求。
> ² 不精确的致命 trap 可能被软件观察到。

【📌 锚点】⚠️ **这张表最容易读错的是第三行**：`Contained` 那一列，**"由执行环境处理"居然填"否"**。

原因是"**执行环境**"与"**执行环境内部的软件**"是两个层次：Contained trap 是被**环境内部的软件**（例如 supervisor 模式的 handler，也就是 xv6 内核）接住并处理的，所以"由**执行环境本身**处理"= 否；而 Requested trap（系统调用）是让**执行环境自己**代表内部软件去执行动作，所以 = 是。
记忆抓手：Contained 是"**内部软件替自己挡下了**"，Requested 是"**内部软件向环境提出了请求**"。

---

### ¶4 · precise / imprecise（精确性）

**原文**

> The EEI defines for each trap whether it is handled precisely, though the recommendation is to maintain preciseness where possible. Contained and requested traps can be observed to be imprecise by software inside the execution environment. Invisible traps, by definition, cannot be observed to be precise or imprecise by software running inside the execution environment. Fatal traps can be observed to be imprecise by software running inside the execution environment, if known-errorful instructions do not cause immediate termination.

**译文**

> 每一种 trap 是否被**精确地**（precisely）处理，由 EEI 定义；不过建议尽可能保持精确性。受控 trap 与请求 trap 可能会被执行环境内部的软件**观察到是不精确的**。不可见 trap 按定义就无法被执行环境内部运行的软件观察到"精确或不精确"。而如果已知会出错的指令并没有导致立即终止，那么致命 trap 也可能被执行环境内部运行的软件观察到是不精确的。

【📌 锚点】"precise" 的含义：trap 发生时，**出错指令之前的指令都已完成、之后的都没执行，且现场寄存器可精确定位到那条指令**。xv6 的示例：`usertrap()` 里 `p->trapframe->epc` 精确指向那条 `ecall`，所以 `+= 4` 才能算对"下一条"——**这就是 precise 带来的便利**。

---

### ¶5 · 本文档的边界

**原文**

> Because this document describes unprivileged instructions, traps are rarely mentioned. Architectural means to handle contained traps are defined in the privileged architecture manual, along with other features to support richer EEIs. Unprivileged instructions that are defined solely to cause requested traps are documented here. Invisible traps are, by their nature, out of scope for this document. Instruction encodings that are not defined here and not defined by some other means may cause a fatal trap.

**译文**

> 由于本文档描述的是**非特权指令**，trap 很少被提及。处理受控 trap 的架构层面手段，定义在《**特权**架构手册》中，与支持更丰富 EEI 的其他特性放在一起。那些**仅仅**是为了引起请求 trap 而定义的非特权指令，则记录在本文档里。不可见 trap 就其本质而言超出了本文档的范围。在此未定义、也未由其他方式定义的指令编码，可能导致**致命 trap**。

【📌 锚点】📚 **读书路线（重要）**：这段话等于官方给你指路了——

| 想查 | 去哪 |
|---|---|
| `stvec` / `sepc` / `scause` / `sstatus` / `sret` 的完整语义 | `__note__/riscv-privileged.pdf`（Volume II 特权手册）§4.1 "CSRs" |
| `ecall` 指令本身的编码与语义 | `__note__/riscv-unprivileged.pdf` §9 "Environment Call and Breakpoints" |
| xv6 怎么用这些 | `kernel/trap.c`、`kernel/trampoline.S`、`kernel/kernelvec.S` |

---

## 🎯 三句话小结

1. **exception / interrupt 是"事件"，trap 是"事件引起的控制转移"**——前者是原因，后者是动作。
2. **四种效果是按"环境内部软件能否看见"来切的**：能看见且自己处理 = Contained；主动请求 = Requested；完全无感 = Invisible；环境直接挂掉 = Fatal。
3. xv6 的日常 = **Contained（syscall/timer）+ 相当粗糙的 Fatal（未知 scause）**；而 Invisible 是 lazy/cow lab 要亲手造出来的那个。

---

## ❓ 自查（读完自己回答）

1. 按本规范的定义，`ecall` 引起的到底是 exception 还是 trap？（想清楚"原因 vs 动作"）
2. 表 1 第三行为什么 Contained 是 "No"？用一句话说清"执行环境"和"执行环境内部的软件"的区别。
3. xv6 的 `usertrap()` 里，哪个分支 = Requested Trap？哪个 = Fatal Trap？page fault 现在落在哪一类，做完 `lazy` lab 之后又是哪一类？
