`
buliedian
  • 浏览: 1190728 次
  • 性别: Icon_minigender_2
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

Linux系统引导过程(BIOS和Bootloader部分)

阅读更多

Linux系统引导过程(BIOS和Bootloader部分)

KEY:x86体系 CPU 系统引导 启动过程 Linux LILO bootstrapping

BIOS(0xfffffff0)

X86体系计算机系统的自举(bootstrapping)过程起始于对CPU的RESET引脚的触发。这个操作会把CPU的一些寄存器置为默认值,比如代码段寄存器CS(code segment)被置为0xf000、指令指针寄存器(EIP)被置为0x0000fff0等,其它寄存器的初始值如下表(下表未列的其它寄存器值均为未定义):

32位还是16位?

细心注意开机时有部分寄存器的值是32位的。其实在386以后的32位处理器在实模式下产生的地址也是32位的,只不过16位程序只使用固定的16位兼容的一个地址空间罢了(KEMIN:这个结论有待进一步的验证)。举例如开机第一指令8086上应该是0xffff0,但是在80368却是0xfffffff0。这个地址在保护模式是通过EIP加上 保存在由段选择子指向的段描述符里的[基址 ]得到的,但是在实模式下[段描述 ]符尚没有初始化,那么基地址从哪来的呢?INTEL解释说为了提高访问的速度,每个段寄存器都有隐藏部分用作缓存,看下面:

The CS register has two parts: the visible segment selector part and the hidden base address part. In real-address mode, the base address is normally formed by shifting the 16-bit segment selector value 4 bits to the left to produce a 20-bit base address. However, during a hardware reset, the segment
selector in the CS register is loaded with F000H and the base address is loaded with FFFF0000H. The starting address is thus formed by adding the base address to the value in the EIP register (that is, FFFF0000 + FFF0H = FFFFFFF0H).

Every segment register has a “visible” part and a “hidden” part. (The hidden part is sometimes referred to as a “descriptor cache” or a “shadow register.”) When a segment selector is loaded into the visible part of a segment register, the processor also loads the hidden part of the segment register with the base address, segment limit, and access control information from the segment descriptor pointed to by the segment selector. The information cached in the segment register (visible and hidden) allows the processor to translate addresses without taking extra bus cycles to read the base address and limit from the segment descriptor. In systems in which multiple processors have access to the same descriptor tables, it is the responsibility of software to reload the segment registers when the descriptor tables are modified. If this is not done, an old segment descriptor cached in a segment register might be used after its memory-resident version has been modified.

因此电脑一开启,工作在实模式下的16位BIOS程序便开始工作,包括系统自检(POST)和硬件初始化工作;BIOS还提供了基本的设备驱动程序,以便进行输入输出,比如磁盘驱动、显示驱动。一些早期的基于实模式的OS还依赖BIOS提供的驱动程序,比如DOS,比如WINDOWS3.1。由于 Linux内核是工作在保护模式下的,所以内核重新实现了所有设备驱动,用以替换实模式BIOS驱动。但在内核正式接管计算机之前,引导加载程序还是利 BIOS的磁盘驱动把内核映像和其它数据从磁盘读出。

在这一阶段BIOS的大概工作为四部分:

1. 第一个部分是对系统硬件进行故障检测,也叫做加电自检(Power On Self Test,简称POST),功能是检查计算机系统是否良好;通常完整的POST自检将包括对CPU,640K基本内存,1M以上的扩展内存,ROM,主板, CMOS存储器,串并口,显示卡,软硬盘子系统及键盘进行测试,一旦在自检中发现问题,系统将给出提示信息或鸣笛警告。自检中如发现有错误,将按两种情况处理:对于严重故障(致命性故障)则停机,此时由于各种初始化操作还没完成,不能给出任何提示或信号;对于非严重故障则给出提示或声音报警信号,等待用户处理。 Recent 80 x 86, AMD64, and Itanium computers make use of the Advanced Configuration and Power Interface(ACPI ) standard. The bootstrap code in an ACPI-compliant BIOS builds several tables that describe the hardware devices present in the system. These tables have a vendor-independent format and can be read by the operating system kernel to learn how to handle the devices.

2. 第二个部分是初始化,包括创建中断向量、设置寄存器、对一些外部设备进行初始化和检测等,其中很重要的一部分是读取BIOS配置,对系统硬件进行状态配置和检查。 This phase is crucial in modern PCI-based architectures, because it guarantees that all hardware devices operate without conflicts on the IRQ lines and I/O ports. At the end of this phase, a table of installed PCI devices is displayed.

3. 最后一个部分是查找引导程序,用来引导DOS或其他操作系统。查找顺序取决于BIOS设置depending on the BIOS setting, the procedure may try to access (in a predefined, customizable order) the first sector (boot sector) of every floppy disk, hard disk, and CD-ROM in the system.

4. As soon as a valid device is found, it copies the contents of its first sector into RAM, starting from physical address 0x00007c00, and then jumps into that address and executes the code just loaded.

KEMIN:把引导自举划分为几个阶段,并明确各个阶段的[逻辑任务 ]对把握引导过程很有裨益。这些[逻辑任务 ]除硬件状态检测,最主要是逻辑环境的构建。因为这些阶段前后有明显的[逻辑层级 ]关系,后一阶段的操作环境由前一阶段来构建和初始化。

16位程序的操作环境?

KEMIN:其实Bootloaders和BIOS一样,都是16位程序(所有DOS程序不管没有界面都是16位程序)。与32位程序运行需要一个操作环境类似,16位程序需不要操作环境?

Boot loaders are programs that reside on the boot device of a computer. A boot loader is called by BIOS after enough system initialization has occurred to support the memory, interrupts, and I/O required to load the kernel.

从上面这段话可知应该是需要的,那么在开机的一刻这样的操作环境建立起来没有?请想想上BIOS的初始化工作一步,并看以下的实模式下的内存布局,非ROM内存类型(比如实模式中断向量表)的数据都是16位程序的操作环境数据。

Physical memory layout of the PC

线性地址范围
实模式地址范围 内存类型 用途
0- 3FF 0000:0000-0000:03FF RAM real-mode interrupt vector table (IVT)
400- 4FF 0040:0000-0040:00FF BIOS data area (BDA)
500- 9FBFF 0050:0000-9000:FBFF free conventional memory (below 1 meg)
9FC00- 9FFFF 9000:FC00-9000:FFFF extended BIOS data area (EBDA)
A0000- BFFFF A000:0000-B000:FFFF video RAM VGA framebuffers
C0000- C7FFF C000:0000-C000:7FFF ROM video BIOS (32K is typical size)
C8000- EFFFF C800:0000-E000:FFFF NOTHING
F0000- FFFFF F000:0000-F000:FFFF ROM motherboard BIOS (64K is typical size)
100000- FEBFFFFF
RAM free extended memory (1 meg and above)
FEC00000- FFFFFFFF
various motherboard BIOS, PnP NVRAM, ACPI, etc.

Boot Loader(0x00007c00)

接上一阶段,这一阶段一开始已经有一段引导程序代码驻留在始于0x00007c00 处,大小为一个扇区512字节,并且处理器下一条指令的地址是 0x00007c00。由于引导的功能需求多种多样(例如有不同的引导介质或多操作系统共存),会有多种不同的引导程序。引导过程细节不尽相同,比如不同的引导介质调用不同的驱动(调用软盘驱动或IDE磁盘驱动),而引导过程本身也有分两个(比如LILO)甚至三个(比如GRUB)前后相继“接力”的16 位程序完成。不管引导的策略如何,引导程序主要任务 还是把操作系统从引导介质加载入内存。下面是利用LILO从硬盘加Linux的一个过程(假设LILO 分两步完成引导,前一步由16位程序LA完成,后一步由16位程序LB完成):

  1. BIOS将硬盘主引导扇区(其中有LA代码)读入至内存中的0x00007c00处,控制权转给该地址程序LA;
  2. LA把自身移动至0x9A000处,并建立堆栈(从0x9B000处向0x9A200增长);
  3. LA将LB读入至内存的0x9B000处,把控制权交给LB(KEMIN:LB在什么地方?目前所知它可以在LA或BIOS能访问到的任何地方);
  4. LB将把[描述符表 ](descriptor table)读入0x9D200处,并把保存[默认命令行 ](default command line)数据的扇区读入0x9D600处;
  5. 接着LB检查用户输入,不管用户输入了一个新的内核镜像还是使用缺省内核镜像信息,[选项扇区 ](options sector)的数据都会被LB读入0x9D600处,而最终生成的[参数行 ](parameter line)会保存在0x9D800处(如果这个参数行中有lock选项,那新参数行会被保存作为默认的参数行);
  6. 如果用户配置了初始化RAMDISK镜像的话,这个镜像文件将被读入到物理内存(或16MB)末尾以下(KEMIN:也就是以内)的空间里,并且文件的起始地址必须[低于]下一[内存页 ] 的边界,以便于启动后系统把它所占的内存回收到[空闲内存池]。这里有一个16MB的限制,这是因为BIOS程序不支持对16MB(24位内存空间)以上内存的访问。(KEMIN:实模式下怎么又会是24位的呢?貌似在开机与正式进入保护模式之前的代码都能够使用CPU所有指令,改变CPU的操作模式。)(KEMIN:为什么需要初始化RAMDISK:initrd?看这里 。)
  7. 下一步,内核镜像的软盘启动扇区(floppy boot sector)被读入0x90000处;操作系统的初始化代码扇区(setup()函数)则被读入0x90200处。内核镜像余下部分被读入 0x00010000处(称为低地址,专为存放用"make zImage"编译的小内核)或0x00100000处(称为高地址,专为存放用"make bzImage"编译的大内核);在读入的过程中,存放map文件的扇区被读入0x9D000处。
  8. 如果读入的image是Linux的内核,控制权将交给处于0x90200的Setup.S。如果读入的是另外的操作系统,过程要稍微麻烦一点:chain loader被读入到内存的0x90200处。该操作系统用于启动的扇区被读入到0x90400。chain loader将把它所包含的分区表移到0x00600处,把引导扇区读入到0x07c00。做完这一切,它把控制权交给引导扇区代码。

图LILO运行后的计算机内存布局

KEMIN:这个过程远没详尽LILO的引导过程。过程中出现很多神秘的信息,比如描述表、参数行数据、软盘启动扇区、setup()函数所在扇区,这里没有讲LILO是怎么知道这些数据的位置的。

LILO怎么找到内核的?

When Lilo boots the system, it uses BIOS calls to load the Linux kernel off the disk (IDE drive, floppy or whatever). Therefore, the kernel must live in some place that can be accessed by the bios.

At boot time, Lilo is not able to read filesystem data, and any pathname you put in /etc/lilo.conf is resolved at installation time (when you invoke /sbin/lilo). Installation time is when the program builds the tables that list which sectors are used by the files used to load the operating system. As a consequence, all of these files must live in a partition that can be accessed by the BIOS (the files are usually located in the /boot directory, this means that only the root partition of your Linux system needs to be accessed via the BIOS).

Another consequence of being BIOS-based is that you must reinstall the loader (i.e., you must reinvoke /sbin/lilo) any time you modify the Lilo setup. Whenever you recompile your kernel and overwrite your old image you must reinstall Lilo.

由此可见,LILO是事先生成启动所需的所有数据,并生成一个元数据文件(map file);并且可看出来,lilo与操作系统的亲缘性强度胜于与BIOS的强度。当然,也别忘记操作系统本身就与硬件是相关的。

LINUX引导磁盘制作

Linux内核经裁减(通过重新配置内核组成的模块并编译)后可被装进一张1.44M的软盘。这张可引导的磁盘布局很简单,引导扇区(也就是第一个扇区)存放[引导程序](源码是/arch/i386/boot/bootsect.S),接着就是内核镜像。当我们编译一个新内核的时候,引导代码只是简单地放在内核镜像的前面,这样只需要把内核镜像从磁盘的第一个扇区开始整个拷进去就可以制作出一张可引导的磁盘了。

参考

分享到:
评论

相关推荐

    嵌入式Linux的Bootloader

    嵌入式Bootloader简介,对于计算机系统来说,从开机上电到操作系统启动需要一个引导过程。嵌入式Linux系统同样离不开引导程序,这个引导程序就叫做BootLoader。 PC机中的引导加载程序由BIOS(其本质就是一段固件程序...

    无BIOS的X86模型及其Linux引导机制设计 (2008年)

    在对典型系统引导和运行原理进行分析的基础上,提出将ARM等新型计算机系统中的Bootloader概念引入标准X86体系的思路.介绍了一种引导Linux操作系统内核的新方法,该方法通过取消X86体系中的BIOS结构,在保证系统稳定运行...

    嵌入式系统/ARM技术中的基于ARM-Linux嵌入式系统引导程序的设计

    摘要:本文介绍了嵌入式操作系统引导程序-Bootloader的概念和作用。以加载Linux操作系统内核为例,重点阐述了Bootloader运行过程的具体步骤及其实现方法。 关键词:Bootloader、S3C2410、引导、嵌入式系统。...

    嵌入式BootLoader 技术内幕

    道,PC 机中的引导加载程序由 BIOS(其本质就是一段固件程序)和位于硬盘 MBR 中的 OS Boot Loader(比如,LILO 和 GRUB 等)一起组成。BIOS 在完成硬件检测和资源分配后 ,将硬盘 MBR 中的 Boot Loader 读到系统的 ...

    Linux 高级篇-定制自己的Linux 系统.md

    制作自己的min linux(基于CentOS7.6)Linux 高级篇-定制...2、如果有多块启动盘的话,需要在BIOS 中选择启动磁盘3、启动MBR 中的bootloader 引导程序 4、加载内核文件5、执行所有进程的父进程、老祖宗systemd6、欢迎界面

    U—BOOT的启动流程及移植

    由于bootloader和 CPU及电路板的配置情况有关,因此不可能有通用 的bootloader,开发时需要用户根据具体情况进行 移植。嵌入式Linux系统中常用的bootloader有 armboot、IL~lboot、blob、u—boot等,其中u—boot是当 ...

    ARM_Linux启动分析.pdf

    当采用MILO这样的引导程序来引导Linux时,不需要上面所说的Bootloader,而只需要 vmlinux或vmlinux.gz,引导程序会主动解压加载内核到0x1000(小内核)或0x100000(大内核),并直接进入内核引导部分,即本文的第二...

    rhce系统管理ppt教程

    Linux 的系统日志 系统日志的书写 系统日志书写配置 高级syslogd配置 系统日志的维护 第七单元 RPM,BootLoader Kisckstart RPM的安装和卸除 RPM包的查询 RPM包的校验及检查 启动引导工具 LILO GRUB KickStart安装 ...

    MultiBootUDisk:在Linux上制作多引导udisk。 可以启动LinuxWindows

    在grub4dos菜单上,有许多条目可以引导各种维护工具,系统和系统安装。 (您可以自定义条目)为什么要这样呢? syslinux是传统的引导加载程序,可与许多计算机竞争。 grub4dos支持.iso文件引导。它可以启动什么现在...

    limine:x86x86_64 BIOS引导程序

    Limine是一种高级x86 / x86_64 BIOS Bootloader,它支持现代PC功能,例如长模式,5级分页和SMP(多核),仅举几例。Limine的启动菜单支持的启动协议Linux stivale和stivale2(Limine的本机启动协议,有关详细信息,...

    CloverISO-4380.zip

    mac系统所使用的引导程序Clover EFI bootloader Boot OS X, Windows, and Linux on Mac or PC with UEFI or BIOS firmware

    Linux 学习之一 多重操作系统

    Linux 多重操作系统的简介  计算机的CMOS是记录各项硬件参数且嵌入在主板上面的储存器,则BIOS则是计算机执行的第一个程序  则BIOS会去读取CMOS中关于各硬件的信息,接着会根据电脑的启动设置,硬盘启动的话,...

    mbr-boot-manager::floppy_disk:主启动记录,带有用Assembly编写的启动菜单

    特征支持Windows,Linux,FreeDOS和任何其他可启动分区加快主操作系统的启动过程支持多个活动分区默认情况下引导第一个活动分区如果在启动过程中按下Shift键,则会出现启动菜单使用向上和向下箭头在启动菜单中选择...

    krabs:用Rust编写的x86引导程序

    krabs:用Rust编写的x86引导程序

Global site tag (gtag.js) - Google Analytics