1. 计算机的核心
取址执行
2. 开机发生的事情:
-
CS=0xFFFF; IP=0x0000,寻址0xFFFF0(ROM BIOS映射)检查RAM ,键盘 ,显示器,软硬磁盘
-
将磁盘0磁道0扇区读入0x7c00处(CS=0x07c0,IP=0x0000,即引导扇区(bootsect.s)【存储CMOS】
-
读 入setup模块(4个扇区),读入硬件参数,切换新的寻址模式(1M---->4G)【实模式---->保护模式】,临时初始化gdt表
gdt表:索引结构,存储基址,相当于上面的CS
idt表:中断处理函数入口
-
根据gdt表跳入0地址,即system模块(OS代码),进入head.s,初始化idt和gdt;进入main(),设置页表,各种初始化(内存初始化:mem_init)
3.系统调用
-
操作系统会提供各种接口,接口表现为函数调用 ,又由系统提供 ,所以称为系统调用
-
从安全性考虑,内核程序与用户程序应该隔离(内核态,0表示和用户态,3表示),内核态可以访问任何数据 ,用户态不能 访问内核数据,使用下面两个寄存器
CPL:当前特权级
DCL:目标内存段的特权级
DPL>=CPL【检查】,如何进入内核?通过中断指令int【int 0x80 去IDT表查询】
4. 操作系统包含两大视图
-
多进程视图(多进程图像)并且多进程结构是操作系统历史的基本图谱
包括:CPU管理和内存管理
-
文件视图
包括文件管理
5.cpu管理
-
最直观就是顺序执行,但是有两个问题:
- 多个任务,后面的任务无法及时处理
- 执行一个任务时,遇到IO任务,需要耗费大量的时间,会让cpu长时间等待
-
所以,必须多个任务交替执行,每个任务都对应自己存放信息的的结构(PCB),表现为运行的程序和静态程序的不同,这种运行的程序的概念的描述就是进程
进程=资源+指令执行序列
线程:将一个任务分解多个,只切换指令序列,保留并发优点,避免资源切换代价,引入了线程概念,实质:映射表不变,PC指针变,每个线程有自己的TCB和栈来进行切换
线程分为用户级线程和核心级线程(用户级线程如果阻塞,操作系统感知不到用户级线程的存在,在内核会发生进程切换),创建核心级线程是系统调用,系统知道TCB,调用不由用户决定(yield不可见)
-
核心级线程
用户栈 <====> 内核栈,会发生n个栈到n套栈的切换,因为内核栈切换对应用户栈也要切换
- 中断入口,进入切换
- 可能中断,中断处理,进入schedule(),引发切换
- 找到下一个切换的next,即内核级线程
- 内核栈切换
- 中断出口
-
引出多进程图像,进程的创建核心就是fork,叉子结构,拷贝父进程信息,然后执行自己的任务。创建进程其实就是创建一个线程
Linux0.11用tss(是一个段,根据TR寄存器在dgt表中找到tss描述符,在根据描述符找到段)切换进程,但也可以用栈切换,因为tss中的信息可以写到内核栈
-
多进程如何交替
-
FCFS:First Come,First Served
-
SJF:短作业优先
-
RR:按时间片来轮转调度
-
对于前台任务,RR,对于后台任务SJF,但是可能会饥饿
-
Linux0,.11shedule()实现,保证最大等待时间的上限,counter两个作用:时间片调度和优先级
void Schedule(void) // 在kernel/sched.c中 { while(1) { c=-1; next=0; i=NR_TASKS; p=&task[NR_TASKS]; while(--i){ if((*p->state == TASK_RUNNING&&(*p)->counter>c) c=(*p)->counter, next=i; } if(c) break; // 找 到了最大的counter for(p=&LAST_TASK;p>&FIRST_TASK;--p) (*p)->counter=((*p)->counter>>1) + (*p)->priority; //等待不超过2p switch_to(next); }
-
-
多个进程同时操作同一块内存,生产者消费者模型
-
什么是信号量?通过对这个量的访问和修改,让大家都有序推进
-
为什么需要保护?对信号量操作的原子性无法保证
-
临界区:一次只允许一个进程进入的该进程的那一段代码。读写信号量的代码一定是临界区
-
临界区代码的保护规则
- 满足互斥进入
- 满足有空让进
- 满足有限等待
-
例如:Peterson算法、面包店算法、cli()+sti()【开关中断,只适用单cpu】、硬件原子指令法
信号量的语义,多个进程什么时候停,什么时候推进用
用临界区去保护信号量
用信号量去实现进程同步
-
-
死锁
- 死锁预防:对资源申请必须按序进行,不会出现环路等待
- 死锁避免:使进程按照某个执行序列进行,不发生死锁(银行家算法)
- 死锁检测+恢复:检测死锁后,回滚
- 死锁忽略:重启
6.内存管理
- 程序员眼中的程序,由若干分段组成:main,变量集,动态数组,栈。因此,内存的使用,对于程序员存在段表,运行时重定位,在内存中进行空间分配,此地址是虚拟地址
- 对于操作系统,无论是固定分区还是可变分区去分配内存,会造成内存碎片,如果内存紧缩会耗费大量时间。从而引出页的概念,作为分配基本单位,大小为4k
程序员分配内存是基于段去分配虚拟地址,操作系统分配内存是基于进程的LDT页表建立虚拟内存到页的映射
对于32位操作系统,32位虚拟地址:前10位是页目录号,然后10位是页号,最后12位就是4k
- 多级页表(类比多级目录)和快表(硬件存储最近使用)
- 内存有限,因此存在内存换入和换出
- 换入:缺页就换入,从磁盘到内存
- 换出
- FIFO:先入先出
- MIN:选最远将使用的页淘汰,最优
- LRU:最近最少使用
- Clock Algorithm:LRY近似实现,即最少使用。存在两个指针,一个快定时扫描,一个慢,按规则走
7.文件管理
-
磁盘基本单位是扇区,需要cyl,head,sec(CHS)信息
-
第一层抽象:从盘块到CHS到扇区
-
第二层抽象:多个进程IO,将block放入请求队列,指定调度算法(电梯算法),前两层抽象对应生磁盘使用
-
第三层抽象: 字符流到盘块集合的映射关系(索引结构),即文件拥有FCB信息,即inode信息(描述文件)
-
第四层抽象:文件系统,抽象整个磁盘,结构:引导块|超级块|inode位图|盘块位图|FCB数组|数据盘块
8.结束
参考资料
操作系统(哈工大李治军老师)