操作系统 - CPU管理
操作系统 - CPU管理
启动流程
细节不同系统不同
物理存储
- 磁盘
- Bootloader (且在磁盘的第一个主引导扇区,且512MB。自己写系统的话首先就会先接触这个东西)
- OS
- 主板内存
- BIOS
流程
- CPU执行BIOS指令:(1) 自检,(2) 加载 BootLoader 的内存
- CPU执行BootLoader指令:将OS和数据加载到内存
- CPU执行OS指令:(1) 开始操作系统初始化工作,(2) 创建各种应用,(3) 直至启动完成
操作系统、CPU、内存三者 关系:CPU不断从内存中取出操作系统/应用的指令执行
内核态 vs 用户态
vs
运行的东西
- 软件
- 用户态:应用程序、用户接口程序
- 内核态:操作系统
- 硬件
权限
- 用户态:只能执行一部分机器指令 (mov、add、sub、push、ret ……)
- 内核态:完全访问所有的硬件 (in、out、……等特权指令,能控制计算机、直接操作硬件)
定义
- 用户态:应用程序在运行时CPU所属的状态,此时CPU为低级别,不能直接访问某些机器指令,或不能直接访问I/O
- 内核态:操作系统在运行CPU所属的状态,此时CPU为高级别,可以运行任何指令(包括特权指令、直接访问I/O)
系统调用 - 用户态和内核态的切换
用户态**陷入(trap)**内核态
int add (int a, int b) {
return a + b;
}
int main () {
int c = add(1, 2);
printf("%d", c);
return 0;
}
调用链:(从上往下)
- 用户态部分
- 应用程序部分
- main()
- 用户接口程序 (库函数 glibc)
- printf()
- ……
- 用户态write()
- 应用程序部分
- 内核态部分
- 内核态write()
- ……
- sys_write()
- out
这里面
- 用户态调用用户态函数有栈
- 内核态调用内核态函数,也有个内核栈
- 问题在于 —— 如何从用户态**陷入(trap)**内核态。方法:
- linux 32位操作系统:80中断
- linux 64位操作系统:syscall 汇编指令
80软中断
write()会使用 ENTER_KERNEL
,产生中断的指令,int $0x80
然后CPU会指向:系统调用中断服务程序 entry_INT80_32
……
系统调用号,用来查 系统调用表 (sys_call_table)
……
- 用户态的寄存器保存到 pt_regs 中
- 在 sys_call_table 中根据调用号找到对应的函数
- 执行函数实现,将返回值写入 pt_regs 的 ax 位置
- 通过指令 iret 根据 pt_regs 恢复用户态程序
64位过程差不多
syscall 汇编指令
特殊模块寄存器 (Model Specific Registers, MSR)
……
……
内核态回用户态
无
CPU 和 IO 设备交互
操作系统如何和外设交互,两种方式:
- 汇编指令:in、out、mov 等 (通常都是特权指令)
- 中断机制
方式一:汇编方式
分层架构与总线
设备控制器
- 设备控制器
- 命令寄存器
- 数据寄存器
- 状态寄存器
- 接口控制电路
轮询 / 忙等待
端口映射IO 和 内存映射IO
Out指令,如:out 0x03B0 EAX
,这里的0x03B0是数据寄存器
CPU怎么知道将数据给哪个控制器的寄存器?
方式一:端口映射IO。操作系统为每个控制器中的寄存器设置唯一的端口号
方式二:内存映射IO。把IO设备的各个寄存器都编址,看成 “内存地址”
两种方式都有,各位有优缺点。
Windows可以这样查看:设备管理器 > 选中设备右击属性 > 资源 标签栏 > 资源类型,会看到 “内存范围” 和 “IO范围”,分别是内存映射IO和端口映射IO
方式二:中断机制 - 键盘原理
为什么需要中断机制:在上面的基础上,不忙等待,而是充分利用CPU时间,提高CPU利用率
例如CPU通知打印机打印,并去做其他事了,那CPU怎么知道打印机设备完成了?
键盘原理
- 键盘:输入字符 -> 键盘编码器
- 键盘编码器:知道按了什么,上报数据给键盘控制器
- 键盘控制器:解码保存数据到数据寄存器
- 中断控制器:由中断控制器发起中断请求 (InterruptRequest),将对应的键盘中断号发给CPU
- Windows可以这样查看:设备管理器 > 选中键盘右击属性 > 资源 > IRQ (InterruptRequestQuest)
- CPU:维护一张中断向量表 (map<中断号, 中断服务程序内存基地址>),然后CPU找到对应的地址中,对应的是 “键盘中断服务程序”
- 向量表在系统初始化时就有了
- 中断服务程序:具体流程
- (1) 保存之前程序的状态
- (2) IN EAX 0x03FA (将这个地址写到寄存器中)
- (3) OUT 0x06B1 EAX (将寄存器内容输出到显卡)
- (4) 恢复之前的程序状态
Q:中断后,CPU寄存器状态存在哪?rip、rsp、状态寄存器等,放在内存中
中断机制如何提高CPU利用率
(步骤序号根据打印机中断服务程序来)
CPU指向应用程序1:该程序为打印字符串
CPU指向内核态:处理out命令进行打印,而后打印机需要10ms来处理,但CPU不等待
CPU指向应用程序2:处理其他东西 (打印机正在打印的同时)
打印机完成后,直到发出中断信号给中断控制器,中断控制器再告诉CPU
CPU去中断向量表去找,根据中断号找到 “中断服务程序内存基地址”
CPU指向打印机中断服务程序:继续处理打印相关的事项,从步骤二开始循环流程,直到中断服务程序的所有事件处理完成
CPU指向回应用程序1
DMA再加速 (DMA+中断)
前面还是比较慢,打印1个字符中断一次,原因在于CPU参与的移动比较多
可以使用 DMA (DIrect Memory Access,直接内存访问) 机制减少CPU开销。
DMA是什么:
DMA控制器是设备上配套的,如打印机有打印机的DMA控制器,磁盘有磁盘的DMA控制器。
DMA内容:
- 数据源地址
- 数据目的地址
- 数据长度
新流程
- CPU设置DMA控制器,设置完后,其他事情都交给DMA控制器。CPU不再参与移动,DMA参与移动
- DMA负责持续从内存中读取字符,并交给打印机,将所有输出完成后,才再来通知CPU返回打印机中断服务程序
这种方式,不会再那么频繁去用CPU