一, 启动流程
- 计算机体系结构
- 启动时的计算机内存和磁盘分布图
CS:IP = 0XF000:FFF0 (CS:代码段寄存器; IP:指令指针寄存器)
系统处于实模式 (刚刚通电情况下)
PC = 16 * CS + IP
20位地址空间:1MB (可用)
BIOS固件提供功能:
- 基本输入输出的程序
- 系统设置信息
- 开机后自检程序
- 系统自启动程序等
流程:
- BIOS:
BIOS将加载程序从磁盘的引导扇区(512字节)加载到0X7C00地址处, 跳转到CS:IP = 0000:7C00处 (控制权转加载程序)
- 加载程序
- 将操作系统的代码和数据从硬盘加载到内存中
- 跳转到操作系统的起始地址
BIOS系统调用
BIOS以中断调用的方式,提供了基本的I/O功能
- INT 10h: 字符显示
- INT 13h: 磁盘扇区读写
- INT 15h: 检测内存大小
- INT 16h: 键盘输入
1, 计算机的启动流程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rv4bmILd-1594562610916)(./img/computer_run.png)]
-
CPU初始化
-
CPU加电稳定后从0XFFFF0读第一条指令
- CS:IP = 0XF000:FFF0
- 第一条指令是跳转指令
- CPU初始状态为16位实模式
- CS: IP是16位寄存器
- 指令指针PC = 16 * CS + IP
- 最大地址空间是1MB
段寄存器
-
BIOS初始化过程
-
硬件自检POST
-
检测血糖中内存和显卡等关键部件的存在和工作状态
-
查找并执行显卡等接口卡BIOS,进行设备初始化
-
执行系统BIOS,进行系统检测
- 检测和配置系统中安装的即插即用设备
- 更新CMOS中的扩展系统配置数据ESCD
- 按指定启动顺序从软盘,硬盘或光驱启动
2, 主引导记录MBR格式
- 启动代码:446字节
- 检查分区表正确性
- 加载并跳转到磁盘上的引导程序
- 硬盘分区表:64字节
- 描述分区状态和位置
- 每个分区描述信息占据16字节
- 结束标志字:2字节(55AA)
- 主引导记录的有效标志
3, 分区引导扇区格式
- 跳转指令:跳转到启动代码
- 与平台相关代码
- 文件卷头:文件系统描述信息
- 启动代码:跳转到加载程序
- 结束标志:55AA
4, 加载程序(bootloader)
5, 系统启动规范
BIOS
- 固化到计算机主板上的程序
- 包含系统设置,自检程序和系统自启动程序
- BIOS-MBR, BIOS-GPT, PXE
UEFI
- 接口标准
- 在所有平台上一致的操作系统启动服务
二, 中断,异常与系统调用
为什么需要中断,异常和系统调用
- 在计算机运行中,内核是被信任的第三方
- 只有内核可以执行特权指令
- 方便应用程序
中断和异常希望解决的问题
- 当外设连接计算机时,会出现什么现象?
- 当应用程序处理意想不到的行为时,会出现什么现象?
系统调用希望解决的问题
- 用户应用程序是如何得到系统服务?
- 系统调用和功能调用的不同之处是什么?
1,内核的进入与退出
系统调用(system_call)
- 应用程序主动向操作系统发出的服务请求
异常
- 非法指令或者其他原因导致当前指令执行失败(如:内存出错)后的处理请求
中断
- 来自硬件设备的处理请求
2. 中断,异常和系统调用的比较
源头
- 中断:外设
- 异常: 应用程序意想不到的行为
- 系统调用: 应用程序请求操作提供服务
响应方式
- 中断: 异步
- 异常: 同步
- 系统调用: 异常或者同步
处理机制
- 中断: 持续,对用户应用程序是透明的
- 异常: 杀死或者重新执行意想不到的应用程序指令
- 系统调用: 得到和持续
3. 中断处理机制
硬件处理
- 在CPU初始化时设置中断使能标志
- 依据内部或外部事件设置中断标志
- 依据中断向量调用相应中断服务例程
软件
- 现场保存(编译器)
- 中断服务处理(服务例程)
- 清除中断标记(服务例程)
- 现场恢复(编译器)
4. 中断嵌套
- 硬件中断服务例程可被打断
- 不同硬件中断源可能硬件中断处理时出现
- 硬件中断服务例程中需要临时禁止中断请求
- 中断请求会保持到CPU做出响应
- 异常服务例程可被打断
- 异常服务例程执行时可能出现硬件中断
- 异常服务例程可嵌套
- 异常服务例程可能出现缺页
三, bootloader启动ucore流程
- 理解X86-32平台的启动过程
- 理解X86-32的实模式、保护模式
- 理解段机制
1, X86启动顺序 - 寄存器初始值
①, X86启动顺序 - 第一条指令
- CS = F000H、EIP = 0000FFF0H (CS是段寄存器)
- 实际地址是:
Base + EIP = FFFF0000H + 0000FFF0H = FFFFFFF0H (Base兼容老版本的地址)
只是BIOS的EPROM(Erasable Programmable Read Only memory)所在地址 - 当CS被新值加载、则地址转换规则将开始起作用
- 通常第一条指令是一条长跳转指令(这样CS和EIP都会更新)到BIOS代码中执行
②, X86启动顺序 - 从BIOS到Bootloader
- BIOS加载存储设备(比如软盘、硬盘、光盘、USB盘)上的第一个扇区(主引导扇区、Master Boot Record or MBR)的512字节到内存的0X7C00处
- 然后跳转到 @0X7C00的第一条指令考试执行
③, X86启动顺序 - 从bootloader到OS系统
实模式切换到保护模式
16字节到32字节
- bootloader做的事情
使能保护模式(protection mode) &段机制(segment-level protection)
从磁盘上读取kernel in ELF 格式的ucore kernel(跟在MBR后面的扇区)并放到内存中固定位置跳转到ucore OS的入口点(entry point)执行这时控制权到了ucore OS中
④, X86启动顺序 - 段控制
⑤, X86启动顺序 - 加载ELF格式的ucore OS kernel
kernel 文件读取ELF格式
/* file header */
struct elfhdr {
uint32_t e_magic; // must equal ELF_MAGIC
uint8_t e_elf[12];
uint16_t e_type; // 1=relocatable, 2=executable, 3=shared object, 4=core image
uint16_t e_machine; // 3=x86, 4=68K, etc.
uint32_t e_version; // file version, always 1
uint32_t e_entry; // entry point if executable
uint32_t e_phoff; // file position of program header or 0
uint32_t e_shoff; // file position of section header or 0
uint32_t e_flags; // architecture-specific flags, usually 0
uint16_t e_ehsize; // size of this elf header
uint16_t e_phentsize; // size of an entry in program header
uint16_t e_phnum; // number of entries in program header or 0
uint16_t e_shentsize; // size of an entry in section header
uint16_t e_shnum; // number of entries in section header or 0
uint16_t e_shstrndx; // section number that contains section name strings
};
/* program section header */
struct proghdr {
uint32_t p_type; // loadable code or data, dynamic linking info,etc.
uint32_t p_offset; // file offset of segment
uint32_t p_va; // virtual address to map segment
uint32_t p_pa; // physical address, not used
uint32_t p_filesz; // size of segment in file
uint32_t p_memsz; // size of segment in memory (bigger if contains bss)
uint32_t p_flags; // read/write/execute bits
uint32_t p_align; // required alignment, invariably hardware page size
};
2, C函数调用的实现
3, GCC内联汇编
- 什么是内联汇编(Inline assembly)
- 这是GCC对C语言的扩张
- 可直接在C语言中插入汇编
- 有何用处
- 调用C语言不支持的指令
- 用汇编在C语言中手动优化
- 如何工作?
- 用给定的模本和约束来生成汇编指令
- 在C函数内形成汇编源码
汇编代码
mov1 $0XFFFF, %eax
内联汇编
inline assembly
asm ("mov1 $0XFFFF, %%eax\n")
内联汇编的语法:
asm (assembler template # 字符串
:output operands (optional) #约束
:input operands (optional)#约束
:clobbers (optional)#约束
);
4, X86中的中断处理
- 了解X86中的中断源
- 了解CPU与操作系统如何处理中断
- 能够对中断向量表(中断描述符表,简称IDT)初始化
① X86中的中断处理 - 中断源
- 中断 Interrupts
- 外部中断 Exteranl (hardware generated) interrupts
串口、硬盘、网卡、时钟 、… - 软件产生的中断 Software generated interrupts
The INT n 指令、通常用于系统调用
-
异常 Exceptions
- 程序错误
- 软件产生的异常 Software generated exceptions
INTO, INT 3 and BOUND - 机器检查出的异常S
② X86中断处理 - 确定中断服务例程(ISR)
- 每个中断或异常与一个中断服务例程(Interrupt Service Routine,简称ISR)关联,其关联关系储存在中断描述符表(Interrupt Descripor Table,简称IDT)。
- IDT的起始地址和大小保存在中断描述符表寄存器IDTR中
硬件完成的工作