#### 概述

从应用程序的角度看，内核是辅助应用程序执行的一个程序。从硬件的角度看，内核是管理硬件的程序。这两者都是外部视角，本章就以maturin为例，从外部视角来看内核。

通过观察ramfs里的内容，看到并没有暴露内核里的任何数据，也没有把设备抽象为设备文件，所以maturin对上的接口仅是系统调用。

通过观察qemu启动时的参数，看到maturin对下的接口是qemu virt物理机。

#### 系统调用

##### 执行流程

1. 用户程序执行`ecall`指令进入用户态。
2. 内核态下`stvec`寄存器保存了自陷处理的入口，这是在内核启动时执行`trap::init()`来设置的。
3. 从`trap::init()`可见，`__alltraps`是所有自陷处理的入口。
4. `__alltraps`先保存了上下文信息，然后调用了`trap_handler()`。
5. `trap_handler()`分发自陷给相应的处理函数。这是通过`sstatus`寄存器的SPP位得到进入S模式之前的特权级，进而实现函数的分发。如果进入S模式之前是U模式，则执行`user_trap_handler()`。
6. `user_trap_handler()`处理来自用户态的各种自陷（系统调用，异常，时钟中断），以及当前线程的信号。关于自陷的种类，是通过读`scause`寄存器获得的。如果是系统调用，则调用`syscall()`。
7. `syscall()`是系统调用的处理者，它通过系统调用号来把系统调用分发给不同的函数处理。
8. `syscall()`处理完成返回到`user_trap_handler()`，再返回到`trap_handler()`，再返回到`__alltraps`。
9. 在`__alltraps`里恢复上下文，执行`sret`返回用户程序继续执行。

##### 系统调用的列表

- 文件系统

   文件描述符操作：DUP， DUP3， FCNTL64
  
  文件操作：UNLINKAT，LINKAT，OPEN，CLOSE，READ，LSEEK，WRITE，WRITEV，READV，PREAD，SENDFILE64
  
  获取文件状态：STATFS，FSTATAT，FSTAT，UTIMENSAT
  
  目录操作：GETCWD，MKDIR，CHDIR，UMOUNT，MOUNT，GETDENTS64
  
  其它：PIPE, IOCTL
  
- 进程
  
  状态管理：EXIT，EXIT_GROUP，YIELD，KILL，FUTEX，CLONE, EXECVE, WAIT4，, PPOLL
  
  ID管理：SET_TID_ADDRESS，GETPID，GETPPID，GETUID，GETEUID，GETGID，GETEGID，GETTID
  
  其它：TIMES, PRLIMIT64 
  
- 时间
  
   NANOSLEEP，CLOCK_GET_TIME，GET_TIME_OF_DAY
   
- 信号
  
   SIGACTION，SIGPROCMASK，SIGRETURN , SIGTIMEDWAIT
   
- 网络

   SOCKET, SENDTO, RECVFROM

- 内存

   BRK, MUNMAP, MMAP , MEMBARRIER

- 其它

   UNAME

#### virt物理机

通过`qemu-system-riscv64 -M virt -M dumpdtb=riscv64-virt.dtb -bios default`导出设备树，可以观察virt物理机的内容。也可以在qemu控制台，通过`info ptree`命令观察virt物理机的内容：

- plic, clint
- pci总线
- uart串口
- rtc时钟
- cpu
- 内存

