系统软件启动过程
前言:计算机通过bootloader(引导装置)来完成操作系统程序的加载和运行。下面的实验提供了一个小的bootloader和Ucore OS,注意bootloader执行代码需要小于512个字节才能放到硬盘的主引导扇区中。
主要学习内容有:
- 计算机原理
- CPU的编址与寻址:基于分段机制的内存管理
- CPU的中断机制
- 外设:串口/并口/CGA(显示器),时钟,硬盘
- Bootloader软件
- 编译运行bootloader的过程
- 调试bootloader的方法
- PC启动bootloader的过程
- ELF执行文件的格式和加载
- 外设访问:读硬盘,在CGA上显示字符串
- ucore OS软件
- 编译运行 ucore OS 的过程
- ucore OS的启动过程
- 调试 ucore OS的方法
- 函数调用关系:在汇编级了解函数调用栈的结构和处理过程
- 中断管理:与软件相关的中断处理
- 外设管理:时钟
实验内容:
Lab1包含了一个bootloader和一个OS。这个bootloader可以切换到X86保护模式,能够读取磁盘并加载ELF执行文件格式,并显示字符。而这Lab1中的OS只是一个可以处理时钟中断和显示字符串的级别的OS
练习:
要求:
- 填写练习中要求完成的报告内容
- 完成实验后,分析ucore_lab中提供的参考答案,并在实验报告中说明自己的实现与参考答案中的实现的区别
- 列出你认为本实验中重要的知识点,以及与对应的OS原理中的知识点,并简要说明你对二者的含义,关系,差异等方面的理解(也可能出现时严重的知识点没有对应的知识点)
练习1:
列出本实验中各练习中对应的OS原理的知识点,并说明本实验中的实现部分如何对应和体现了原理中的基本概念和关键知识点。
在此练习中,大家需要通过静态分析代码来了解:
- 操作系统镜像文件 ucore.img 是如何一步一步生成的?(需要比较详细地解释 Makefile 中每一条相关命令和命令参数的含义,以及说明命令导致的结果)?
- 一个被系统认为是符合规范的硬盘主引导扇区的特征是什么?
80386涉及到的运行模式:
3. 实模式:80386加电后处于实模式运行状态,在这种状态下软件可访问的物理内存空间不能1MB,且无法发挥80386以上级别的32位CPU的4GB内存管理能力。
4. 保护模式:可访问232 = 4GB的物理内存空间,支持优先级机制,保护操作系统。
80386的寄存器:
- 通用寄存器:
- EAX:累加器
- EBX:基址寄存器
- ECX:计数器
- EDX:数据寄存器
- ESI:源地址指针寄存器
- EDI:目的地址指针寄存器
- EBP:基址指针寄存器
- ESP:堆栈指针寄存器
- 段寄存器:
- CS:代码段
- DS:数据段
- ES:附加数据段
- SS:堆栈段
- FS:附加段
- GS:附加段
- EIP:指令寄存器。EIP的低16位就是8086的IP,他储存的是下一条要执行指令的内存地址,在分段地址转换中,表示指令的段内偏移地址。
- EFLAGS:标志寄存器。
CPU在加电之后,会先对所有的寄存器进行初始化,然后执行第一条指令。第一条指令在内存中,其寻址方式为:系统初始化代码在ROM中,CPU在初始化之后通过CS:IP读取指令,系统处于实模式。20位地址空间:1MB。
具体过程:BIOS初始化完成之后,会从磁盘上读取引导扇区(512字节)加载到0x7c00,跳转到CS:IP=0000:7c00,然后将控制权交给加载程序。
加载程序将操作系统的代码(操作系统镜像)和数据从硬盘中加载到内存中来,并跳转到操作系统的起始地址。再将控制权交给操作系统。
BIOS以中断调用的方式提供了基本的I/O功能:
- INT 10h:字符显示
- INT 13h:磁盘扇区读写
- INT 15h:检测内存大小
- INT 16h:键盘输入
系统启动流程:
粗略流程:加电之后读BIOS->BIOS读加载程序->加载程序读内核镜像
详细流程:加电之后读BIOS->BIOS读主引导扇区代码->主引导扇区代码读活动分区的引导扇区代码->引导扇区代码读文件系统的加载程序
- CPU初始化
+ CPU加电稳定后从CS:IP = 0xffff0读第一条指令(第一条指令是跳转指令)
+ CPU初始状态位16位实模式,CS:IP是16位寄存器,指令指针PC = 16*CS + IP,最大的地址空间是1MB - BIOS初始化过程
- 硬件自检POST,防止内存出错导致内存操作系统出错
+ 检测系统中内存和显卡等关键部件的存在和工作状态
+ 查找并执行显卡等接口卡BIOS,进行设备初始化 - 执行系统BIOS,进行系统检测
+ 检测和配置系统中安装的即插即用设备 - 更新CMOS中的扩展系统配置数据ESCD
- 按指定启动顺序从软盘,硬盘或光驱启动
- 硬件自检POST,防止内存出错导致内存操作系统出错
- 主引导记录MBR格式
- 启动代码(446字节)
+ 检查分区表正确性
+ 加载并跳转到磁盘上的引导程序 - 硬盘分区表(64字节)
+ 描述每个分区状态和位置
+ 每个分区描述信息占据16字节 - 结束标志字(2字节)
+ 主引导记录的有效标志
- 启动代码(446字节)
- 分区引导扇区格式
- 跳转指令:跳转到启动代码
+ 与平台相关代码 - 文件卷头:文件系统描述信息
- 启动代码:跳转到加载程序
- 结束标志
- 跳转指令:跳转到启动代码
- 加载程序
- 从文件系统中读取启动配置信息->可选的操作系统内核列表和加载参数->依据配置加载指定内核并跳转到内核执行
X86启动顺序-----第一条指令
第一条指令是一条长跳转指令,地址为(CS:EIP = Base + EIP = FFFFFFF0H),跳转到可以被访问的1M的内存空间中(BIOS代码)去执行。
X86启动顺序-----从BIOS到Bootloader
BIOS加载存储设备上的第一个扇区(主引导扇区)的512字节到内存的0x7c00…
然后跳转到 0x7c00的第一条指令并执行(Bootloader也就是这么一个512个字节的执行代码)
BIOS只能加载一个扇区,所以只能先加载bootloader,然后bootloader加载ucore操作系统的代码
bootloader做的事情:
- 使能(enable)保护模式 和 段机制。从16位的寻址空间切换到32位的寻址空间,从1M的寻址切换到4G的寻址。
- 从硬盘上读取kernel in ELF格式的ucore kernel(跟在MBR后面的扇区)并放在内存中固定位置
- 跳转到ucore OS的入口点执行,这是控制权交给了ucore OS
X86启动顺序-----段机制
段描述符:包含起始地址和大小。
段寄存器起了一个指针的作用,指向段描述符。
在一个段寄存器中,保存着一块区域叫做段选择址(index),index会对应一个段描述符,由此我们可以直到起始地址CS,结合EIP可以得到线性地址。没有启动页机制的情况下,线性地址等于物理地址。
实现:需要一个很大的数组来储存段描述符(全局描述符表),数组由操作系统来建立(GDT)。基址都是0,长度都是4G.
X86启动顺序-----加载ELF格式的ucore kernel
内联汇编:可直接在C语句中插入汇编语句,主要是语法。
X86中断处理----中断源
- 中断:外设中断,软件中断
- 异常:程序错误,软件产生的遗产,机器检查出的异常
X86中断处理-----确定中断服务例程
每个中断或异常于一个中断服务例程对应,其关联关系储存在中断描述表(IDT)中。
IDT的起始地址和大小保存在中断描述表寄存器IDTR中