码迷,mamicode.com
首页 > 移动开发 > 详细

linux启动从bios到bootleader

时间:2019-04-10 10:27:48      阅读:451      评论:0      收藏:0      [点我收藏+]

标签:公司   主函数   存储位置   main   芯片   数据   引导   ESS   a20   

BIOS(Basic Input / Output System)启动,首先系统会进行自检,检测CPU,内存,显卡,I/O是否正常,如发现异常这个阶段会报错。

上一个阶段成功后会读取MBR(Master Boot Record)硬盘的0柱面,0磁盘,1扇区称为主引导扇区。它由三部分组成,主引导程序(bootleader),硬盘分区表DPT(disk partition table)和硬盘有效标志(55AA),如下图所示技术图片
使用grub2启动系统时,启动顺序如下图
技术图片
grub2第一个需要安装的是boot.img,它由boot.S编译而成,一共512个字节,正是安装到启动盘的第一个扇区,这个扇区通常被称作MBR(Master Boot Record / 主引导记录扇区)

BIOS完成任务后,会将boot.img从硬盘加载到内存的0x7c00中,为什么是0x7c00呢,0x7c00这个地址来自Intel的第一代个人电脑芯片8088,以后的cpu为了保持兼容一直使用这个地址。1981年8月,IBM公司最早的个人电脑IBM PC 5150上市,就用了这个芯片。当时搭配的操作系统是86-DOS, 这个操作系统需要的内存最少是32KB,我们知道,内存地址从0x0000开始编号,32KB的内存就是0x0000-0x7FFF可以使用。8088芯片本身需要占用0x0000-0x03FF,用来保存各种中断处理程序的存储位置(主引导记录本身就是中断信号 INT 19h的处理程序),所以内存只剩下0x0400-0x7FFF可以使用,为了把尽量多的连续内存留给操作系统,主引导记录就被放到了内存地址的尾部,由于一个扇区是512个字节,主引导记录本身也会产生数据,需要另外留出512字节保存。所以他的预留位置就变成了0x7FFF-512-512+1=0x7c00。
由于512个字节很有限,boot.imp做不了太多的事情,它能坐的最重要的一个事情就是加载grub2的另一个镜像core.img,它是由lzma_decompress.img、diskboot.img、kernel.img和一系列模块组成,功能比较丰富,能做很多事情。

boot.imp先加载的是core.img的第一个扇区。如果从硬盘启动的话,这个扇区里面是diskboot.img,对应的代码是diskboot.S

boot.img将控制权交给diskboot.img后,diskboot.img的任务就是将core.img的其他部分加载进来,显示解压缩程序lzma_decompress.img,再往下是kernel.img,最后是各个模块module对应的映像。这里需要注意,它不是linux的内核,而是grub的内核。

lzma_decompress.img对应的代码是startup_raw.S,本来kernel.img是压缩过的,现在执行的时候,需要解压缩。
在这之前,我们所有遇到过的程序都非常非常小,完全可以在实模式下运行,但是随着我们加载的东西越来越大,实模式这1M的地址空间实在放不下了,所以再真正的解压缩之前,lzma_decopress.img做了一个重要的决定,就是调用real_to_prot,切换到保护模式,这样就能在更大的寻址空间里面,加载更多的东西。

从实模式切换到保护模式,第一项是启用分段,就是再内存里面简历段描述符表,将寄存器里面的段寄存器编程段选择子,指向某个段描述符,这样就能实现不同进程的切换了。第二项是启动分页。能够管理的内存变大了,就需要将内存分成相等大小的块。
保护模式需要做一项工作,那就是打开Gate A20,也就是第21根地址线的控制线。在实模式8086下面,一共就20个地址线,可访问1M的地址空间。如果超过了这个限度,在保护模式下,第21根要起作用了,于是我们就需要打开Gate A20.切换保护模式的函数DATA32 call real_to_prot 会打开Gate A20,也就是第21根地址线的控制线。有了空间之后,接下来我们要对压缩过的kernel.img进行解压缩,然后跳转到kernel.img开始运行。
kernel.img对应的代码是startup.S以及一堆c文件,再startup.S中会调用grub_main,这是grub kernel的主函数。在这个函数里面,grub_load_config()开始解析,我们上面写的那个grub.conf文件里的配置信息。如果是正常启动,grub_main最后会调用grub_command_execute("normal",0,0),最终会调用grub_normal_execute()函数。在这个函数里面,grub_show_menu()会显示出让你选择那个操作系统的列表。
一定你选择了启动某个操作系统,就要开始调用grub_menu_execute_entry(),开始解析并执行你选择的那一项。
例如里面的linux16命令,表示装载指定的内核文件,并传递内核启动参数。于是grub_cmd_linux()函数会被调用,它会首先读取linux内核镜像头部的一些数据结构,放到内存中的数据结构来,进行检查。如果检查通过,则会读取整个linux内核镜像到内存,如果配置文件里面还有initrd命令,用于为即将启动的内核传递init tamdisk路径。于是grub_cmd_initrd()函数会被调用,将initramfs加载到内存中来。当这些事情做完之后,grub_command_execute("boot",0,0)才开始真正地启动内核。

linux启动从bios到bootleader

标签:公司   主函数   存储位置   main   芯片   数据   引导   ESS   a20   

原文地址:https://blog.51cto.com/liuminkun/2376340

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!