![]() |
||
---|---|---|
.. | ||
readme.md |
readme.md
设计目标
- 可以在运行时配置I/O设备
- 让主要的系统组件成为与内核分开的独立进程
重要概念
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
系统调用相关。sys_abort:当要求关闭系统或产生panic之后,进程管理器会产生此内核调用;当用户按下
Ctrl-Alt_Del
组合键后,tty设备驱动也会产生此内核调用。sys_getinfo:获取内核的信息。在
include/minix/syslib.h
里定义了获取内核信息的各种宏,它们都是使用的此内核调用。
进程调度
Minix3使用的多级调度算法。具体过程是:先找到优先级最高的非空的队列,然后选择顶头的进程开始执行。IDLE
进程在最低优先级队列里,且始终是处于就绪的状态,这就保证没有其它进程时至少还有一个进程可以跑。
初始状态下,时钟和系统任务在第1级,拥有最高的权限。设备驱动在第2级。服务进程在第3级。用户进程在更低的层级,但可以通过nice
命令来调整。
时钟任务用于监控所有进程的时间。
任务、驱动程序和服务程序除非被阻塞,否则应该是一直运行的,它们会有大的时间片。它们如果运行的太久,也是可能被抢占的,这种机制可以防止有问题的高优先级进程锁死系统。
调度器管理着16个就绪队列。数组rdy_head
保存了每个就绪队列的头,而数组rdy_tail
保存了每个就绪队列的尾。
每个队列上使用的是轮转调度算法。时间片用完的进程会调度到队列的末尾,时间片没用完但被阻塞的进程再唤醒时会放在队列的顶头。
驱动程序注册中断的过程
- 一个用户态的、由中断驱动的设备驱动程序,当它需要注册一个中断处理例程时,会向系统任务发出
sys_irqctl
调用。 - 系统任务再调用
put_irq_handler
。但是在中断例程的字段里保存的将是系统任务所在内核空间的generic_handler
的地址,而不是驱动程序所在用户空间的中断处理例程的地址。 generic_handler
用钩子结构体里的进程号字段定位此驱动程序在priv
表里的入口,此中断在驱动程序的挂起中断位图里的对应位会置1。generic_handler
向驱动程序发一个通知。此通知被识别为来自HARDWARE,驱动程序的挂起中断位图也包含在此消息里。- 钩子结构体里的policy字段决定中断是立即打开还是保持关闭。如果是保持关闭,则驱动程序还需要发出一个内核调用
sys_irqenable
来开打中断。
系统任务
系统任务是从内核中独立出来的进程,它不能像内核函数那样自由,不能进行实际的I/O,也不能操作内核表。
那么系统任务(驱动和服务程序)怎么和内核交互呢?答案是内核向它们提供一组服务。这些服务对普通用户是不可见的,系统任务通过这些服务进行实际的I/O,操作内核表等。
系统任务的工作就是就是接收上层对内核服务的请求并执行它们。上层的进程由于在用户态,无法访问内核里的数据结构,但系统任务可以。
系统任务的主程序在做完必要的初始化后就会进入一个循环。获取消息,发给合适的服务例程,然后发送一个回复。主文件system.c
里有一些的通用支持函数,但处理内核调用是在kernel/system
目录下进行的。