## 异常处理和中断

![流程](./异常处理流程.jpg)

**异常处理和中断主要在一下几个文件中实现**

- trap.c：处理异常和中断的代码。
- plic.c：处理平台级别中断控制器（PLIC）的代码。
- timer.c：处理定时器中断的代码。
- syscall.c：处理系统调用的代码。
- stacktrace.c：用于堆栈跟踪的代码。
- entry.S:用于上下文保存和恢复

## 异常处理

在操作系统中，异常处理是非常重要的一部分。异常是指在程序运行过程中出现的非正常情况，如除数为零、内存访问越界等。当异常发生时，操作系统需要对异常进行处理，以防止程序崩溃或系统崩溃。

异常处理主要在`trap.c`文件中进行。

异常处理的主要流程如下：

1. 初始化异常处理：在trap_init函数中，设置了异常向量表的入口地址为do_exception_vector，并屏蔽了所有中断。
2. 异常处理函数：do_exception函数是处理异常的主要函数。首先，通过判断scause寄存器的值来确定是中断还是异常。如果是中断，根据中断类型调用相应的中断处理函数；如果是异常，根据异常类型进行处理:如果是系统调用，则调用系统调用处理函数，否则调用错误处理函数。
3. 错误处理函数：do_trap_error函数用于处理异常错误，它会打印出错误信息和寄存器的状态。`show_regs`函数用于打印出寄存器的状态。

异常处理流程:

异常到达->do_exception_vector->do_exception->do_trap_error/syscall_handler



## 中断处理

中断是指外部设备或者内部程序对CPU的中断请求。当中断发生时，CPU会暂停当前正在执行的程序，转而去执行中断处理程序。在执行完中断处理程序后，CPU会返回到被中断的程序继续执行。

在本项目中，中断处理主要在`trap.c`、`plic.c`和`timer.c`文件中进行。

在`trap.c`文件中，定义了`handle_timer`函数，用于处理定时器中断。当定时器中断发生时，关闭定时器中断，重置定时器，并调度下一个任务。

在`plic.c`文件中，定义了`handle_plic_irq`函数，用于处理外部设备中断。当外部设备中断发生时，根据中断号调用相应的设备中断处理函数。

在`timer.c`文件中，定义了`reset_timer`函数，用于重置定时器。当定时器到达设定的时间后，会产生一个中断，此时需要重置定时器，并开启定时器中断。

中断处理的主要流程如下：

1. 中断处理函数：在do_exception函数中，如果scause寄存器的值表示是中断，则根据中断类型调用相应的中断处理函数。例如，如果是定时器中断，则调用handle_timer函数；如果是外部中断，则调用handle_plic_irq函数。

2. 定时器中断处理函数：handle_timer函数用于处理定时器中断。它会关闭定时器中断，重置定时器，并调用调度函数。

3. 外部中断处理函数：handle_plic_irq函数用于处理外部中断。它会读取PLIC的中断源，然后根据中断源调用相应的中断处理函数。

外部中断目前只处理uart串口中断和virtio驱动的中断

中断处理流程:

中断到达->do_exception_vector->do_exception->中断处理程序->ret_from_respection->恢复现场->返回



## 栈回溯

在`stacktrace.c`文件中，实现了栈回溯的功能。栈回溯是指在程序运行过程中，记录下函数调用的顺序，当程序出错时，可以通过栈回溯找到出错的位置。

在这个文件中，首先定义了一个栈帧结构`stackframe`，这个结构中包含了函数的帧指针和返回地址。然后，定义了`search_stackframe`函数，这个函数通过遍历栈帧，找到所有函数的调用顺序。最后，定义了`stack_trace`函数，这个函数打印出所有函数的调用顺序。



## 主要文件

### trap.c

trap.c文件主要处理异常和中断。它定义了一系列的错误消息，用于在发生异常时打印错误信息。它还定义了一个函数`trap_init`，用于初始化异常处理，包括设置异常向量表和禁止所有中断。

`do_trap_error`函数用于处理错误，它会打印出错误信息和寄存器的状态。`show_regs`函数用于打印寄存器的状态。

`do_exception`函数用于处理异常，它会根据异常的类型调用相应的处理函数。例如，如果异常是系统调用，它会调用`syscall_handler`函数。

`handle_timer`函数用于处理定时器中断，它会重置定时器并调度下一个任务。



### plic.c

plic.c文件主要处理平台级别中断控制器（PLIC）。它定义了一系列的函数，用于设置中断的优先级，打开或关闭中断，处理中断等。

`handle_plic_irq`函数用于处理PLIC中断，它会根据中断的类型调用相应的处理函数。例如，如果中断是UART中断，它会调用`handle_uart_irq`函数。

`handle_uart_irq`函数用于处理UART中断，它会读取UART的输入并处理。

`plic_init`函数用于初始化PLIC，它会设置所有中断的优先级，并打开S模式的外部中断。



### timer.c

timer.c文件主要处理定时器中断。它定义了一个函数`reset_timer`，用于重置定时器并启用定时器中断。



### syscall.c

系统调用处理主要在`syscall.c`文件中进行。

首先，定义了一个系统调用表`syscall_table`，这个表中存储了所有系统调用的处理函数。然后，定义了`syscall_handler`函数，这个函数是系统调用的入口函数，它根据系统调用号从系统调用表中找到对应的处理函数，并调用这个函数。

在`syscall.c`文件中，还定义了各种系统调用的处理函数，如`callback_sys_chdir`、`callback_sys_execve`、`callback_sys_clone`等。这些函数用于实现系统调用的功能，目前我们OS支持的系统调用还不多