grub2 1.95 源码分析之一 —— boot.S 分析及注释

本文档详细分析了 GRUB2 的引导加载器 boot.S 的源码,主要功能是从硬盘或软盘的 MBR 读取 512 字节的代码并执行。boot.S 首先根据 BIOS 设置的寄存器值和中断调用来判断引导驱动器类型,然后读取指定扇区内容到内存。在读取过程中,如果出现错误,会输出错误信息并进入死循环。最终,boot.S 会将控制权交给 bootdisk.S。代码中涉及的标签包括磁盘、BIOS、汇编、引导加载器和GRUB。
摘要由CSDN通过智能技术生成

/* -*-Asm-*- */
/*
 *  GRUB  --  GRand Unified Bootloader
 *  Copyright (C) 1999,2000,2001,2002,2005,2006  Free Software Foundation, Inc.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

// cppgp 注释版
// 转载请注明原作者
// 注释版本号 : 1.00
// 日期 : 2008-01-22
// 联系方式 :
// email yanyg02@163.com
// msn  yanyg02@hotmail.com
// qq  281607998

// boot.S 流程及功能简介 :
// boot.S 生成 512 字节的机器码存储在硬盘或者软盘的 MBR 中 , 被 BIOS 加载
// 到内存 0x7C00 处 , 然后 BIOS 设置 CPU 跳转至 0x7C00 处开始执行 , 控制权到了
// boot.S 手中 . boot.S 根据 BIOS 设置的寄存器初始值和一些 INT 中断调用 , 判断
// 引导驱动器是 LBA硬盘/CHS硬盘/软盘 中的哪一种 , 并保存磁盘参数到磁盘参数块地
// 址(BPB) , 然后读取由 kernel_sector 处的 8 字节确定的扇区块 ( 即diskboot.img
// 由 bootdisk.S 生成的二进制码文件 )内存储的 512 字节的内容到内存地址 0x70000
// 处 , 再拷贝到内存 0x8000 处 , 然后跳转至 0x8000 开始执行 , 由 bootdisk.S 获
// 得控制权 , 而 boot.S 就功成身退了. 但是 boot.S 设置的实模式下的堆栈及寄
// 存器值,以及引导驱动器的模式和参数 , 在 bootdisk.S 中都有用到 . 具体请看代码
// 注释及 diskboot.S 的注释 . 如果在加载 diskboot.img 的过程中出错, 则输出错误
// 提示信息 , 进入死循环 , 等待手工重起或者关闭.
// boot.S 生成的机器码被加载在 0x7C00~0x7DFF 处, 具体机器码见文档最后部分


// 这个头文件里面只定义了一个版本号
#include <grub/boot.h>

// 这个头文件即../.././include/grub/i386/pc/boot.h , 定义引导需要的系统常量定义
#include <grub/machine/boot.h>

// 在代码中使用宏的地方 , 我都做了宏的说明 , 读者不需要跟踪到对应 .h 文件中看宏定义

/*
 *  defines for the code go here
 */

/* Absolute addresses
   This makes the assembler generate the address without support
   from the linker. (ELF can't relocate 16-bit addresses!)
*/

// ABS(x)计算x的绝对地址,用来生成不受连接器限制的地址(ELF不能生成可重入的地址).
#define ABS(x) (x-_start+0x7c00)

/* Print message string */
// 打印 x 指向的字符串到终端
#define MSG(x) movw $ABS(x), %si; call message

/* XXX: binutils-2.9.1.0.x doesn't produce a short opcode for this. */
#define MOV_MEM_TO_AL(x) .byte 0xa0;  .word x
// binutils-2.9.1.0.x不能生成short操作码,使用这个宏传递x给AL
 
 .file "boot.S"

 .text

/* Tell GAS to generate 16-bit instructions so that this code works
   in real mode.
*/
// 告知GAS生成16位的指令,使以下代码可以工作在实模式下
// 说明 : GAS是gcc的汇编器

 .code16

// 以下代码被BIOS启动例程加载至0X7C00处并且跳转到此处执行,过程描述如下:
// (为降低分析复杂度,我们假设从硬盘启动.)
// BIOS读取硬盘的MBR扇区共512字节,并放在地址0X0000:0X7C00处
// 跳转到0X0000:0X7C00处去执行
// 此时设置寄存器如下:
// CS:IP = 0X0000:0X7C00 !即代码段基址为0,偏移量为0X7C00
// ES:SI   !指向BIOS中硬盘分区表的地址.
// DL   !引导设备number,00x80~0xFF

.globl _start; _start:
 /*
  * _start is loaded at 0x7c00 and is jumped to with CS:IP 0:0x7c00
  */

 /*
  * Beginning of the sector is compatible with the FAT/HPFS BIOS
  * parameter block.
  */
 // 扇区开始处和BIOS参数块都是FAT/HPFS格式兼容的.

 // 跳转到after_BPB内存处
 jmp after_BPB
 nop /* do I care about this ??? */
 // nop 永远不会执行!

 /*
  * This space is for the BIOS parameter block!!!!  Don't change
  * the first jump, nor start the code anywhere but right after
  * this area.
  */
 // 以下空间是留给BIOS参数块的!!!
 // 不要更改跳转指令
 // 除了恰在BIOS参数块后的位置,也不要开始执行指令

 . = _start + 4
 // 保留空间 : 使本节代码占用的空间到_start+4处.如下分析:
 // jmp after_BPB  占用2字节
 // nop   占用1字节
 // 因此多保留一字节地址并以0填充.
 // 事实上,在生成的.img文件中,开始处四字节的机器码是:eb4b9000
 // Address  0x7C00  0x7C01  0x7C02  0x7C03
 // Value  eb  4b  90  00
 // Operator jmp  sfter_BPB nop  00

 /* scratch space */
 //保留的空间
 //占用 4 字节 , _start+0x00 ~ _start+0x03

// 磁盘信息参数块
// CHS 寻址方式用到 11 字节 _start+0x04 ~ _start+0x0E
// mode = 0 ; 然后依次是通过 BIOS INT 0x13 , AH = 0x08 调用得来的"扇区/磁头/柱面"参数
// LBA 寻址方式用到 16 字节 _start+0x04 ~ _start+0x14
// mode = 1 ; 然后会通过此后数据块的值和调用要求填充磁盘参数块
// 此时 , 诸如 sectors/heads/cylinders 等标签是无用的 , 具体参数格式见 lba_mode 一节对代码的注释

mode:
 .byte 0
disk_address_packet:
sectors:
 .long 0
heads:
 .long 0
cylinders:
 .word 0

sector_start:
 .byte 0
head_start:
 .byte 0
cylinder_start:
 .word 0
 /* more space... */

 . = _start + GRUB_BOOT_MACHINE_BPB_END
 //保留空间

 /*
  * End of BIOS parameter block.
  */
 //BIOS参数块结束地址

// 现在,空间已经分配到了_start + GRUB_BOOT_MACHINE_BPB_END
// 其中
// 数据空间是 : _start+0x04 ~ _start+0x12
// 保留空间是 : _start+0x13 ~ _start+0x3D

// grub自身信息保存地址:
// 共 14 字节 : _start + 0x3E ~ _start + 0x4B
// boot_version !版本
// kernel_address !内核加载地址
// kernel_segment !内核加载段地址
// kernel_sector !扇区绝对地址,默认为0磁头0柱面1扇区
// boot_drive !从哪个磁盘加载,0xff表示使用boot驱动器加载
boot_version:
 .byte GRUB_BOOT_VERSION_MAJOR, GRUB_BOOT_VERSION_MINOR
 //  4   0
kernel_address:
 .word GRUB_BOOT_MACHINE_KERNEL_ADDR
 //  0x8000
kernel_segment:
 .word GRUB_BOOT_MACHINE_KERNEL_SEG
 //  0x800
kernel_sector:
 .long 1, 0
boot_drive:
 .byte 0xff /* the disk to load kernel from */
   /* 0xff means use the boot drive */

after_BPB:

/*

/boot/grub2/i386-pc/boot.img 文件是一个针对x86架构的引导镜像文件,它包含了用于引导启动计算机的程序和参数等信息。 以下是/boot/grub2/i386-pc/boot.img文件的源码注释: ``` /* * This file contains the source code for the x86 version of the GRUB * boot loader. It is responsible for loading the operating system kernel * from the hard disk and transferring control to it. */ #include <grub/types.h> #include <grub/i386/pc/boot.h> #include <grub/i386/pc/loadfile.h> /* * The main function of the boot loader. It is called by the BIOS when the * computer is powered on or reset. It initializes the hardware, loads the * kernel from the hard disk, and transfers control to it. */ int main (void) { /* Initialize the hardware */ init_hw (); /* Load the kernel from the hard disk */ if (load_kernel () != 0) { /* Error loading the kernel */ return 1; } /* Transfer control to the kernel */ transfer_control (); /* Should never get here */ return 0; } /* * Initializes the hardware, including the console output and disk system. */ void init_hw (void) { /* Initialize the console */ init_console (); /* Initialize the disk system */ init_disk (); } /* * Loads the kernel from the hard disk into memory. */ int load_kernel (void) { /* Read the kernel from the hard disk */ if (read_kernel () != 0) { /* Error reading the kernel */ return 1; } /* Initialize the kernel */ init_kernel (); return 0; } /* * Transfers control to the kernel by jumping to its entry point. */ void transfer_control (void) { /* Jump to the kernel entry point */ jump_to_kernel (); } ``` 以上是x86架构/boot/grub2/i386-pc/boot.img文件的源码注释。其中,主要包括了引导加载程序的主函数、硬件初始化函数、内核加载函数和转移控制函数等。通过这些函数的调用,boot.img文件可以成功地将计算机引导到操作系统内核。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值