linux启动流程(一)

linux 启动流程

0x00 What x86

x86是Intel的CPU架构,最初是由16位的8086处理器组成的

CPU和内存之间传递数据需要用到总线

  1. 访问内存中某个地址的数据 把这类总线叫地址总线
  2. 内存中真正的数据 这类总线叫做数据总线

8086处理器的地址总线是20位, ip寄存器和通用寄存器是16位, 那么总线与寄存器之间的关系是把CS和DS寄存器中的值左移4位 。即: 起始地址16+偏移量

拥有20位地址总线的8086能够区分出的地址最多为
2 20 = 1 M 2^{20}=1M 220=1M

因为偏移量只能是16位 所以一个段最多为
2 16 = 64 k 2^{16}=64k 216=64k

32位系统架构下如何兼容8086

32位处理器有32根地址总线,可以访问
2 32 = 4 G 2^{32}=4G 232=4G

  • 实模式
  • 保护模式
0x10从BIOS到bootloader

在计算机主板上 有一个东西叫ROM(Read Only Memory , 只读存储器)。ROM中初始化了一些程序,即 BIOS (Basic Input and Output System,基本输入输出系统)。

0x11 x86中的ROM

在x86系统中,将1M空间最上面的0xF0000到0xFFFFF这64k映射给ROM,也就是说这部分地址可以访问ROM。当电脑通电后会做一些重置工作:

  1. 将CS设置成0xFFFF
  2. 将IP设置成0x0000
  3. 所以第一条指令指向0xFFFF0,正是ROM的地址范围
  4. 使用JMP指令跳转到ROM的初始化工作的代码中
0x12启动盘的工作流程

启动盘:一般位于第一个扇区,占512个字节,以0xAA55结束

Grub2( Grand Unified Bootloader Version 2) 的主要作用是将代码放入启动盘区域,工作流程如下:

  1. 安装boot.img ,它是由boot.S编译而成,一共512字节,安装到第一个扇区,此扇区被称为MBR( Master Boot Record , 主引导记录)

  2. BIOS完成任务后,会将boot.img从硬盘加载到内存中的0x7c00中运行

  3. boot.img加载grub2的另一个镜像core.img,core.img 包括以下几个部分:

    • lzma_decompress.img
    • diskboot.img
    • Kernel.img
    • 其他的模块
  4. boot 先加载core.img的第一个扇区,会执行diskboot. img

    1. diskboot.img会将core.img的其他部分加载进来
    2. diskboot.img会解压lzma_decompress.img ,lzma_decompress.img 对应的代码是startup_raw.S
    3. diskboot.img解压kernel.img
    4. 最后是各个模块module对应的映像
  5. 在实模式下,1M内存可能存放不下我们需要加载的东西,所以在真正解压缩之前,lzma_decompress.img 会调用real_to_prot,切换到保护模式,这样就能在更大的寻址空间里面,加载更多的东西。

0x13从实模式到保护模式

Tips:

  • 段的起始地址放在内存的某个地方,这个地方是一个表格,表格中的一项一项是段描述符(Segment Descriptor)

  • 段描述符内是真正的段起始位置,而段寄存器里面保存的是这个表格中的哪一项,称为选择子(Selector)

  1. 启用分段,辅助进程管理

    在内存中建立段描述符表,将寄存器里面的段寄存器变成段选择子,指向某个段描述符,这样就可以实现不同进程的切换了。

  2. 启动分页,辅助内存管理

  3. 打开Gate A20 也就是第21根地址线的控制线。由函数DATA32 call real_to_prot打开Gate A20。

  4. lzma_decompress.img 解压运行kernel.img(对应的代码是startup.S),kernel.img做以下4件事:

    1. 解析grup.conf文件:由startup.S文件调用grub_main(grub kernel主函数),grub_load_config() 开始解析grup.conf文件。
    2. 选择操作系统:grub_main最后会调用grub_command_execute(“normal”,0,0),最终会调用grub_normal_execute()函数。这个函数里面grub_show_menu() 会显示操作系统列表。
    3. 例如选择linux16,会先读取内核头部数据进行检查,检查通过后加载完整系统内核:调用grub_menu_execute_entry(),开始解析并执行选择的系统文件
    4. 启动系统内核:调用grub_command_execute(“boot”, 0 , 0) 才开始真正启动内核

0x14 Gate A20的理解

例子:想访问0x12345这块内存,

  • 可以使用0x1234段 偏移0x5。即:0x1234*0x10+0x0005=0x12345

  • 也可以使用0x1230段 偏移0x45。即:0x1230*0x10+0x45=0x12345

那么一共出现的组合会是:

  • 0xFFFF:0x000F
  • 0xFFF0:0x00FF
  • 0xFF00:0x0FFF
  • 0xF000:0xFFFF
  • 0xFFFE:0x001F
  • 0xFFFD:0x002F
  • 等等~~~~

以上这些组合内存都是1MB以内的。但如果使用0xFFFF:0x0010 即 0x100000 就超过1MB了,此时内存会重新指向0x00000 。那么0xFFFF:0x0011就会指向0x00001地址。

当Intel 80286处理器问世后,它拥有24位地址总线,可访问的内存变成了
2 24 = 16 M 2^{24}=16M 224=16M
Intel80286提供了实模式用来兼容8086下的所有软件,但出现了一个处理器的bug : 当地址超过1M之后 实模式不会产生环绕,比如 0xFFFF:0x0010 将会映射到0x100000地址上,0xFFFF:0x0011 将会映射到0x100001 ,0xFFFF:0xFFFF将会映射到0x10FFEF上。

于是A20诞生了,默认情况下是关闭的(允许访问0xFFFF:0x0010 - 0xFFFF:0xFFFF)

  • 实模式下:
    • 打开-> 在0x100000-0x10FFEF 会寻找真正地址
    • 关闭-> 回绕到 0x0000-FFEF
  • 保护模式:
    • 打开->可连续访问内存
    • 关闭->只能访问到奇数的1M段,即0x00000-0xFFFFF、0x200000-0x2FFFFF、0x300000-0x3FFFFF…
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值