操作系统原理之加载系统的流程, 中断,异常和系统调用

bootlooader

Posted by chensong on 2020-05-06 02::33::24

前言

正文

一, 启动流程

  1. 计算机体系结构

CPU

  1. 启动时的计算机内存和磁盘分布图

run

CS:IP = 0XF000:FFF0 (CS:代码段寄存器; IP:指令指针寄存器)

系统处于实模式 (刚刚通电情况下)

PC = 16 * CS + IP

20位地址空间:1MB (可用)

BIOS固件提供功能:

  1. 基本输入输出的程序
  2. 系统设置信息
  3. 开机后自检程序
  4. 系统自启动程序等

流程:

loader

  1. BIOS:

BIOS将加载程序从磁盘的引导扇区(512字节)加载到0X7C00地址处, 跳转到CS:IP = 0000:7C00处 (控制权转加载程序)

  1. 加载程序
  • 将操作系统的代码和数据从硬盘加载到内存中
  • 跳转到操作系统的起始地址

BIOS系统调用

BIOS以中断调用的方式,提供了基本的I/O功能

  • INT 10h: 字符显示
  • INT 13h: 磁盘扇区读写
  • INT 15h: 检测内存大小
  • INT 16h: 键盘输入

1, 计算机的启动流程

computer_run

  1. CPU初始化

  2. CPU加电稳定后从0XFFFF0读第一条指令

  • CS:IP = 0XF000:FFF0
  • 第一条指令是跳转指令
  1. CPU初始状态为16位实模式
  • CS: IP是16位寄存器
  • 指令指针PC = 16 * CS + IP
  • 最大地址空间是1MB 段寄存器
  1. BIOS初始化过程

  2. 硬件自检POST
  3. 检测血糖中内存和显卡等关键部件的存在和工作状态
  4. 查找并执行显卡等接口卡BIOS,进行设备初始化
  5. 执行系统BIOS,进行系统检测
    • 检测和配置系统中安装的即插即用设备
  6. 更新CMOS中的扩展系统配置数据ESCD
  7. 按指定启动顺序从软盘,硬盘或光驱启动

2, 主引导记录MBR格式

master_mbr

  1. 启动代码:446字节
    • 检查分区表正确性
    • 加载并跳转到磁盘上的引导程序
  2. 硬盘分区表:64字节
    • 描述分区状态和位置
    • 每个分区描述信息占据16字节
  3. 结束标志字:2字节(55AA)
    • 主引导记录的有效标志

3, 分区引导扇区格式

slave_mbr

  1. 跳转指令:跳转到启动代码
    • 与平台相关代码
  2. 文件卷头:文件系统描述信息
  3. 启动代码:跳转到加载程序
  4. 结束标志:55AA

4, 加载程序(bootloader)

bootloader

5, 系统启动规范

BIOS

  • 固化到计算机主板上的程序
  • 包含系统设置,自检程序和系统自启动程序
  • BIOS-MBR, BIOS-GPT, PXE

UEFI

  • 接口标准
  • 在所有平台上一致的操作系统启动服务

### 二, 中断,异常与系统调用

为什么需要中断,异常和系统调用

  • 在计算机运行中,内核是被信任的第三方
  • 只有内核可以执行特权指令
  • 方便应用程序

中断和异常希望解决的问题

  • 当外设连接计算机时,会出现什么现象?
  • 当应用程序处理意想不到的行为时,会出现什么现象?

系统调用希望解决的问题

  • 用户应用程序是如何得到系统服务?
  • 系统调用和功能调用的不同之处是什么?

1,内核的进入与退出

kernel_inter

系统调用(system_call)

  • 应用程序主动向操作系统发出的服务请求

异常

  • 非法指令或者其他原因导致当前指令执行失败(如:内存出错)后的处理请求

中断

  • 来自硬件设备的处理请求

2. 中断,异常和系统调用的比较

源头

  • 中断:外设
  • 异常: 应用程序意想不到的行为
  • 系统调用: 应用程序请求操作提供服务

响应方式

  • 中断: 异步
  • 异常: 同步
  • 系统调用: 异常或者同步

处理机制

  • 中断: 持续,对用户应用程序是透明的
  • 异常: 杀死或者重新执行意想不到的应用程序指令
  • 系统调用: 得到和持续

3. 中断处理机制

硬件处理

  • 在CPU初始化时设置中断使能标志
  • 依据内部或外部事件设置中断标志
  • 依据中断向量调用相应中断服务例程

软件

  • 现场保存(编译器)
  • 中断服务处理(服务例程)
  • 清除中断标记(服务例程)
  • 现场恢复(编译器)

4. 中断嵌套

  1. 硬件中断服务例程可被打断
    • 不同硬件中断源可能硬件中断处理时出现
    • 硬件中断服务例程中需要临时禁止中断请求
    • 中断请求会保持到CPU做出响应
  2. 异常服务例程可被打断
    • 异常服务例程执行时可能出现硬件中断
  3. 异常服务例程可嵌套
    • 异常服务例程可能出现缺页

三, bootloader启动ucore流程

  1. 理解X86-32平台的启动过程
  2. 理解X86-32的实模式、保护模式
  3. 理解段机制

1, X86启动顺序 - 寄存器初始值

①, X86启动顺序 - 第一条指令
  1. CS = F000H、EIP = 0000FFF0H (CS是段寄存器)
  2. 实际地址是: Base + EIP = FFFF0000H + 0000FFF0H = FFFFFFF0H (Base兼容老版本的地址) 只是BIOS的EPROM(Erasable Programmable Read Only memory)所在地址
  3. 当CS被新值加载、则地址转换规则将开始起作用
  4. 通常第一条指令是一条长跳转指令(这样CS和EIP都会更新)到BIOS代码中执行
②, X86启动顺序 - 从BIOS到Bootloader
  1. BIOS加载存储设备(比如软盘、硬盘、光盘、USB盘)上的第一个扇区(主引导扇区、Master Boot Record or MBR)的512字节到内存的0X7C00处
  2. 然后跳转到 @0X7C00的第一条指令考试执行
③, X86启动顺序 - 从bootloader到OS系统

实模式切换到保护模式 16字节到32字节

  1. bootloader做的事情

使能保护模式(protection mode) &段机制(segment-level protection) 从磁盘上读取kernel in ELF 格式的ucore kernel(跟在MBR后面的扇区)并放到内存中固定位置跳转到ucore OS的入口点(entry point)执行这时控制权到了ucore OS中

④, X86启动顺序 - 段控制

gdt gdt2

⑤, 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内联汇编

  1. 什么是内联汇编(Inline assembly)
    • 这是GCC对C语言的扩张
    • 可直接在C语言中插入汇编
  2. 有何用处
    • 调用C语言不支持的指令
    • 用汇编在C语言中手动优化
  3. 如何工作?
    • 用给定的模本和约束来生成汇编指令
    • 在C函数内形成汇编源码
汇编代码
     mov1  $0XFFFF, %eax
     
内联汇编
    inline assembly 
      asm ("mov1  $0XFFFF, %%eax\n")

内联汇编的语法:

asm (assembler template  # 字符串
    :output operands (optional) #约束
    :input operands (optional)#约束
    :clobbers (optional)#约束
);

4, X86中的中断处理

  1. 了解X86中的中断源
  2. 了解CPU与操作系统如何处理中断
  3. 能够对中断向量表(中断描述符表,简称IDT)初始化
① X86中的中断处理 - 中断源
  1. 中断 Interrupts
  • 外部中断 Exteranl (hardware generated) interrupts 串口、硬盘、网卡、时钟 、…
  • 软件产生的中断 Software generated interrupts The INT n 指令、通常用于系统调用
    1. 异常 Exceptions
  • 程序错误
  • 软件产生的异常 Software generated exceptions INTO, INT 3 and BOUND
  • 机器检查出的异常S
② X86中断处理 - 确定中断服务例程(ISR)
  1. 每个中断或异常与一个中断服务例程(Interrupt Service Routine,简称ISR)关联,其关联关系储存在中断描述符表(Interrupt Descripor Table,简称IDT)。
  2. IDT的起始地址和大小保存在中断描述符表寄存器IDTR中

硬件完成的工作

idtr

结语