computer_knowledge_notes/OS/Minix
shzhxh 80d69f4cd1 update 2022-06-18 2022-06-18 17:24:18 +08:00
..
readme.md update 2022-06-18 2022-06-18 17:24:18 +08:00

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_setalarmalarm系统调用相关。

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

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

进程调度

Minix3使用的多级调度算法。具体过程是先找到优先级最高的非空的队列然后选择顶头的进程开始执行。IDLE进程在最低优先级队列里,且始终是处于就绪的状态,这就保证没有其它进程时至少还有一个进程可以跑。

初始状态下时钟和系统任务在第1级拥有最高的权限。设备驱动在第2级。服务进程在第3级。用户进程在更低的层级但可以通过nice命令来调整。

时钟任务用于监控所有进程的时间。

任务、驱动程序和服务程序除非被阻塞,否则应该是一直运行的,它们会有大的时间片。它们如果运行的太久,也是可能被抢占的,这种机制可以防止有问题的高优先级进程锁死系统。

调度器管理着16个就绪队列。数组rdy_head保存了每个就绪队列的头,而数组rdy_tail保存了每个就绪队列的尾。

每个队列上使用的是轮转调度算法。时间片用完的进程会调度到队列的末尾,时间片没用完但被阻塞的进程再唤醒时会放在队列的顶头。

驱动程序注册中断的过程

  1. 一个用户态的、由中断驱动的设备驱动程序,当它需要注册一个中断处理例程时,会向系统任务发出sys_irqctl调用。
  2. 系统任务再调用put_irq_handler。但是在中断例程的字段里保存的将是系统任务所在内核空间的generic_handler的地址,而不是驱动程序所在用户空间的中断处理例程的地址。
  3. generic_handler用钩子结构体里的进程号字段定位此驱动程序在priv表里的入口此中断在驱动程序的挂起中断位图里的对应位会置1。
  4. generic_handler向驱动程序发一个通知。此通知被识别为来自HARDWARE驱动程序的挂起中断位图也包含在此消息里。
  5. 钩子结构体里的policy字段决定中断是立即打开还是保持关闭。如果是保持关闭则驱动程序还需要发出一个内核调用sys_irqenable来开打中断。

系统任务

系统任务是从内核中独立出来的进程它不能像内核函数那样自由不能进行实际的I/O也不能操作内核表。

那么系统任务(驱动和服务程序)怎么和内核交互呢答案是内核向它们提供一组服务。这些服务对普通用户是不可见的系统任务通过这些服务进行实际的I/O操作内核表等。

系统任务的工作就是就是接收上层对内核服务的请求并执行它们。上层的进程由于在用户态,无法访问内核里的数据结构,但系统任务可以。

系统任务的主程序在做完必要的初始化后就会进入一个循环。获取消息,发给合适的服务例程,然后发送一个回复。主文件system.c里有一些的通用支持函数,但处理内核调用是在kernel/system目录下进行的。