GRUB2及启动过程详解(8)

2019-04-16 00:04

Edi:从保护模式进入实模式函数的地址 Ecx:从实模式进入保护模式函数的地址 eax:实模式中断描述符表的地址

7.3.2.2. 核心代码Startup

这部分代码位于grub-core/kern/i386/pc/startup.S

/*

* 这段代码Startup.S必须加载到0x00100000. */

/* 调用 grub_main进入grub的主函数*/ jmp EXT_C(grub_main)

/* initialize the stack */

movl $GRUB_MEMORY_MACHINE_PROT_STACK, %esp

7.3.3. GRUB主函数即GRUB主要功能

到这来我们已经来到了grub的核心代码部分,这部分代码位于grub-core/kern/main.c

正式开始进入C语言工作,在main函数之后,GRUB2主要工作正式展开,其工作大致如下 - 是grub的模块化框架的初始

- 各种命令的注册 - 各种模块的加载

- 读取/boot/grub2/grub.cfg,显示启动菜单 - 根据菜单配置加载linux kernel

有关怎么配置/etc/grub.d脚本与/etc/default/grub下变量,怎么运行

grub2-mkconfig命令等,已经有很多资料可以查阅,在这里不作描述,有兴趣的读者可以自行研究。

7.3.4. 加载Linux Kernel

我们看看centos7中被加载的内核条目的配置(/boot/grub2/grub.cfg):

menuentry 'CentOS Linux (3.10.0-327.22.2.el7.x86_64) 7 (Core)' --class centos --class gnu-linux --class gnu --class

load_video set gfxpayload=keep insmod gzio insmod part_msdos insmod xfs

set root='hd0,msdos1'

if [ x$feature_platform_search_hint = xy ]; then search else

search --no-floppy --fs-uuid --set=root 149ea7b1-0a88-47aa-ad0a-446b224dd84c fi linux16

/vmlinuz-3.10.0-327.22.2.el7.x86_64

root=/dev/mapper/centos-root

ro

crashkernel=auto

rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet LANG=zh_CN.UTF-8 initrd16 /initramfs-3.10.0-327.22.2.el7.x86_64.img }

--no-floppy

--fs-uuid

--set=root

--hint-bios=hd0,msdos1

--hint-efi=hd0,msdos1

--hint-baremetal=ahci0,msdos1 --hint='hd0,msdos1' 149ea7b1-0a88-47aa-ad0a-446b224dd84c

os

--unrestricted

$menuentry_id_option

'gnulinux-3.10.0-327.el7.x86_64-advanced-a09bce3c-411c-40f4-9487-dcfbe471f022' {

该菜单我们只关心最后两项

linux16 /vmlinuz-3.10.0-327.22.2.el7.x86_64

initrd16 /initramfs-3.10.0-327.22.2.el7.x86_64.img

他们的意思GRUB2会用linux16加载Linux内核vmlinuz-3.10.0-327.22.2.el7.x86_64 然后会用initrd16加载initramfs-3.10.0-327.22.2.el7.x86_64.img

注意,后者被称为:initial RAM disk: The initial RAM disk (initrd) is an initial root file system that is mounted prior to when the real root file system is available.

可以参考:http://www.ibm.com/developerworks/library/l-initrd/index.html

加载的这两个文件都在/boot目录下,可以用file命令查看他们类型

[root@controller boot]# file vmlinuz-3.10.0-327.22.2.el7.x86_64 vmlinuz-3.10.0-327.22.2.el7.x86_64:

Linux

kernel

x86

boot

executable

bzImage,

version

3.10.0-327.22.2.el7.x86_64 (builder@kbuilder.dev.centos.org) #1, RO-rootFS, swap_dev 0x4, Normal VGA [root@controller boot]# file initramfs-3.10.0-327.22.2.el7.x86_64.img

initramfs-3.10.0-327.22.2.el7.x86_64.img: ASCII cpio archive (SVR4 with no CRC)

可以知道内核的类型为bzImage.

可以肯定的是,这个时候GRUB已经有了文件系统(CentOS7的XFS)驱动,不会去调用BIOS INT13去加载这两个文件,而是直接在XFS文件系统/boot目录下加载。

在接下来的讲述之前,看看一个内存的结构

(下面是现代bzImage类型 kernel(version >= 2.02)结构)

~ ~ | Protected-mode kernel | 100000 +------------------------+ | I/O memory hole | 0A0000 +------------------------+ | Reserved for BIOS | Leave as much as possible unused ~ ~ | Command line | (Can also be below the X+10000 mark) X+10000 +------------------------+ | Stack/heap | For use by the kernel real-mode code. X+08000 +------------------------+ | Kernel setup | The kernel real-mode code. | Kernel boot sector | The kernel legacy boot sector. X +------------------------+ | Boot loader | <- Boot sector entry point 0000:7C00 001000 +------------------------+ | Reserved for MBR/BIOS | 000800 +------------------------+ | Typically used by MBR | 000600 +------------------------+ | BIOS use only | 000000 +------------------------+

7.3.4.1. Step1 linux16

/*

* 相关代码在grub-core/loader/i386/pc/linux.c

* 当处理菜单选项”linux16 /vmlinuz-3.10.0-327.22.2.el7.x86_64 ...”时,下面方法会被调用 *

* 在这里只讲述关键代码

* 要理解这部分代码只能去读《THE LINUX/x86 BOOT PROTOCOL》: * https://www.kernel.org/doc/Documentation/x86/boot.txt */

grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), { ......

/* 打开内核文件

The first step in loading a Linux kernel should be to load the real-mode code (boot sector and setup code) and then examine the following header at offset 0x01f1. The real-mode code can total up to 32K, although the boot loader may choose to load only the first two sectors (1K) and then examine the bootup sector size. */

int argc, char *argv[])

file = grub_file_open (argv[0]); ......

/*

* 把文件vmlinuz-3.10.0-327.22.2.el7.x86_64头部读入内存structure1h * 该结构在include/grub/i386/linux.h定义:linux_kernel_header * 里面包含一些内核基本信息,在后面加载内核的时候需要用到

* 该头部与https://www.kernel.org/doc/Documentation/x86/boot.txt一致 */

if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh)) { ...... goto fail;

} ......

/*

*计算实模式代码地址,该地址一般0x90000 */

grub_linux_real_target = grub_find_real_target (); ......

/*

*计算需要载入linux内核大小,包含两个部分,分别载入: * 是模式大小,在内核头部定义

* 保护模式大小,内核文件大小在减去实模式大小,在减去1个扇区0x200 512Byte */

real_size = setup_sects<< GRUB_DISK_SECTOR_BITS; grub_linux16_prot_size = grub_file_size (file) ......

/*

*读取实模式(Real_mode)代码到内存0x90000地址

* Unfortunately, under the following circumstances the 0x90000 memory segment has to be used:

- When loading a zImage kernel ((loadflags & 0x01) == 0). - When loading a 2.01 or earlier boot protocol kernel. -> For the 2.00 and 2.01 boot protocols, the real-mode code can be loaded at another address, but it is internally relocated to 0x90000. For the \ real-mode code must be loaded at 0x90000.

When loading at 0x90000, avoid using memory above 0x9a000. */

- real_size - GRUB_DISK_SECTOR_SIZE;


GRUB2及启动过程详解(8).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:110kV线路断线故障分析专题报告

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: