/* -*-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:
/*