#### 设计目标

##### 整体设计目标

- 可以在运行时配置I/O设备
- 让主要的系统组件成为与内核分开的独立进程
- 把功能都放到用户进程

##### I/O软件的设计目标

1. 设备无关性

   意思是应用程序可以访问任意I/O设备而无需指定具体的设备。

2. 统一的命名

   意思是文件或设备的名字完全不依赖于设备。即所有的文件和设备都通过相同的方式编址：路径名。

3. 在尽可能接近硬件的层面处理错误

   在许多情况下，错误恢复可以在较低级别上透明地完成，而上层甚至不知道发生了错误。

4. 同步(阻塞)与异步(中断驱动)

   系统层面的I/O应该是中断驱动的。用户层面的I/O操作大多是阻塞的，因为这样更容易。让实际上是中断的操作变为用户程序看起来是阻塞的操作，这是操作系统的工作。

5. 缓冲

   来自于设备的数据通常不能直接放在最终的目的地，而是需要缓冲。缓冲涉及到大量的复制，通常对I/O性能有很大的影响。

6. 共享设备与独占设备

   共享设备是多个用户可以同时使用的设备。独占设备是同一时间只能由单个用户使用的设备。引入独占设备会带来各种问题，比如死锁。操作系统在设计的时候要考虑到这些问题。

#### 重要概念

##### minix3的四层结构

| 层级         | 进程类型 | 包含的进程                                         |
| ------------ | -------- | -------------------------------------------------- |
| 4 (用户模式) | 用户进程 | init进程, 若干用户进程                             |
| 3 (用户模式) | 服务进程 | 进程管理器，文件系统，信息服务程序，网络服务程序等 |
| 2 (用户模式) | 设备驱动 | TTY驱动程序，以太网驱动程序等                      |
| 1 (内核模式) | 内核进程 | 内核，时钟任务，系统任务                           |

##### 各种调用

- 系统调用

  在宏内核里，系统调用指内核提供的所有调用。

  在Minix3里，系统调用在形式上和宏内核是一样的，但它不直接向内核请求服务，而是向服务进程发消息。服务进程之间，服务进程与驱动、内核之间也是通过消息来通信的。

- 内核调用

  直接向内核请求服务的调用。用户进程无法进行内核调用，服务进程和驱动程序才能进行内核调用。内核调用和系统调用常有类似的名字，因为有些操作只能在内核里进行。

- 消息原语

  用于进程间通信，如send、receive、notify等。有时也被叫**IPC原语**或**自陷**。它们确实调用了系统，但即不应称为系统调用也不应称为内核调用。

##### 系统任务接收的消息

其实就是内核调用，共有28个。

- 进程管理

  sys_fork, sys_exec, sys_exit, sys_trace : 与POSIX系统调用相关的内核调用

  sys_nice：设置进程的调度优先级

  sys_privctl : 再生服务程序RS用它来改变进程的特权。驱动程序和不在启动镜像里的服务程序通过`/etc/rc`脚本启动时，将会需要特权转换。

- 信号

  sys_kill : 与系统调用`kill`相关

  sys_getksig, sys_endksig, sys_sigsend, sys_sigreturn : 进程管理器用它们来操作信号

- 设备驱动的支持

  sys_irqctl : 开启、关闭或配置中断

  sys_devio ：读写I/O端口

  sys_sdevio：从I/O端口读写字符串。例如访问串口时会用到它。

  sys_vdevio：执行一个I/O所请求的向量。向量指的是一串(port, value)对。

- 关于内存

  sys_newmap：当进程的内存发生改变时，进程管理器调用它来更新内核里的进程表。

  sys_regctl：设备驱动用它来获取一个段选择子，这样就可以访问I/O设备占用的内存区域了(0xa0000~0xfffff)。

  sys_memset：服务进程用它来写数据到不属于自己的内存里。当新进程创建时，进程管理器用它来为新进程清空内存。

- 复制内存

  sys_umap：把虚拟地址转换为物理地址。

  sys_vircopy, sys_physcopy：使用虚拟或物理地址复制内存。

  sys_virvcopy, sys_physcopy：使用向量化的I/O请求，它们可以向系统任务请求一系统的内存复制操作。把多个消息请求打包成一个消息可以从一定程度上解决消息传递机制的效率不足问题。

- 其它

  sys_times：对应了`times`系统调用。

  sys_setalarm：与`alarm`系统调用相关。为用户空间的系统进程初始化计时器，这个系统进程需要接收一个同步alarm并在计时器超时的时候通知到用户进程。

  sys_abort：当要求关闭系统或产生panic之后，进程管理器会产生此内核调用；当用户按下`Ctrl-Alt_Del`组合键后，tty设备驱动也会产生此内核调用。

  sys_getinfo：获取内核的信息。在`include/minix/syslib.h`里定义了获取内核信息的各种宏，它们都是使用的此内核调用。

##### 时钟驱动程序提供的与时间相关的服务

| 服务        | 访问方式 | 响应 | 使用者与功能描述                         |
| ----------- | -------- | ---- | ---------------------------------------- |
| get_uptime  | 函数调用 | 滴嗒 | 内核或系统任务，获取运行时间             |
| set_timer   | 函数调用 | 无   | 内核或系统任务，设置计时器               |
| reset_timer | 函数调用 | 无   | 内核或系统任务，重置计时器               |
| read_clock  | 函数调用 | 计数 | 内核或系统任务，读取时钟芯片里的计数器   |
| clock_stop  | 函数调用 | 无   | 内核或系统任务，恢复BIOS的时钟频率       |
| 同步alarm   | 系统调用 | 通知 | 服务程序或驱动程序，激活内核空间的看门狗 |
| POSIX alarm | 系统调用 | 信号 | 用户进程，通过PM请求系统任务激活看门狗   |
| time        | 系统调用 | 消息 | 任何进程，通过PM                         |

##### I/O软件的四层结构

| 层级   | 描述               |
| ------ | ------------------ |
| 第四层 | 用户级的I/O软件    |
| 第三层 | 设备无关的系统软件 |
| 第二层 | 设备驱动程序       |
| 第一层 | 中断处理例程       |

