李治军操作系统
从开机到操作系统的运行
BIOS 采用汇编的好处:可以严格控制内存,可以严格读取确定地址处的内容,C语言做不到。
开机第一件事:(关注CS:IP指向哪里,CPU执行什么命令)
1.CS,IP指向ROM BIOS映射区,执行指令,先检查硬件,RAM,
2.之后将磁盘0磁道0扇区(的内容,供512个字节)读入0x7c00处,设置CS=0x070c,ip=0x0000;CPU开始执行;改扇区称为引导扇区;
读取过程:
引导扇区的代码:
读取第一步:关注start:1~4行设置ds:di,es:si的地址,rep movw将引导区的代码挪动到内存的一个地址处(es:di处),此后继续顺序执行改代码,但由于挪动了位置(原本执行的地址在BIOS区,现在在es:di处,同样的代码,但不在一个位置了),因此使用jmpi go,INITSEG修改CS:IP的值,保证继续向下执行;
读取第二部:继续读取:关注从哪读取,读多少,读到哪,读完干什么?
从cl开始读,读到ex:bx;读多少呢(ax)al是扇区个数,cl是开始扇区,即将set-up的四个扇区读到ex:bx上,是第一步读取的上边。读完后引发中断,int 0x13.
打印LOGO:显示窗口,涉及到操纵显示器.
读如System模块;
以上命令都是在boot扇区内的命令,之后计算机将执行set-up扇区的指令,
总结
检查硬件,将操作系统读入内存内——这些指令都在BIOS内,因此开机后,将执行BIOS里的指令,完成后开始执行操作系统,命令包括:
检查硬件,读入操作系统代码(将set-up,system模块读入内存,之后执行set-up的命令,)打印LOGO四大部分。
可以看到分成了若干个进程,采用int中断指令来实现。
开机第二件事:执行setup模块的内容(操作系统的代码了)
set-up内容:完成信息的初始化,并改变操作系统的位置到0地址处,此后不再改变位置;并进入保护模式
start:读取信息,如读入内存的大小以方便管理内存,该值放在0x90002处;除此之外还有显卡啊参数,光标位置。
内存有多大:
int 0x15中断指令将获得物理内存的大小;获取的值放在ds:2处;ds的值在第一行得到。最终放在0x90002处,
do-move:将system模块(操作系统代码)移动到0地址处,这也是为什么一开始在0x90000处放置set-up模块。
mov ax,1;mov cr0,ax:切换到保护模式,由16位模式切换到32位模式;
此时CS的值相当于哈希表里的键,在GDT表里查到真正的基址,之后偏移与IP相加形成真正的地址;GDT表使用硬件电路实现。
GDT表由set-up完成,此后寻址,中断命令地址的寻址方式都发生了改变;都变成了查表。
System模块
P6
head.s跳转到main.c,
第一行进行压栈压入main.c的参数,第二行压入操作系统的main.c,之后跳转到set_paging,进行操作系统数据结构的初始化操作,该指令结束后操作系统开始执行,如果main.结束,将执行L6:死循环,因此main.c不会结束。
main.c的指令,最后一句如果申请进程失败,将返回。
mem_init,实行内存的初始化,初始化mem_map[]数组,mem_map[]数组表示内存页使用情况,0表示没有使用,每一页是4kb,因此每次>>12,end_mem来自于0x90002的数值。
最终
从开机到操作系统开始执行,需要经历:
boot->setup->head.s->main.c->mem.init四大过程,分别完成操作系统读入内存,初始化,保护模式切换,初始化等事件。
操作系统接口
接口的含义
用户使用操作系统的方式:
命令行,图形按钮,应用程序
如何使用计算机?普通C语言+操作系统接口(重要C函数)
具体的操作系统接口
系统调用的实现
将内存分为两个连续段:用户态(用户段),核心态(内核段)。
操作系统将内存根据CS,DS的最低两位来划分内存,0为内核态,1,2为OS服务,3为用户态。只有当前指令所在的内存段权级高于目标内存段时,程序才能执行(电路才能联通);即指令只能访问同级别及以下的内存段内的指令和数据,
系统调用只有一种进入用户态的方法:中断(int),系统调用就是包含中断指令的代码。
操作系统的历史
操作系统的多进程图像
内核级线程:
1.需要在内核态下切换,需要先存储现在执行的指令(CS:IP)以及是否再堆栈中(SS:SP),
2.之后调用中断,中断使用switch_to切换线程,核心在于切换CS:IP,SS:SP等寄存器信息(赋值),但是切换到的线程是用户态的。因此切换完成后需要使用指令退出内核态,而是使用esp内的信息执行该线程,其中iret指令就是退出内核态的指令;