BIOS/UEFI将控制权交过来
作用:读取第一个扇区
分解:
先检查控制器是否正确dx
通过int13是否支持LBA/CHS模式
通过int13将第一个扇区读取到缓存
然后将缓存的数据拷贝到预期位置
跳转到预期的位置,执行第一个扇区的代码
boot.S
.text
/* Tell GAS to generate 16-bit instructions so that this code works
in real mode. */
.code16
.globl _start, start;
_start:
start:
jmp LOCAL(after_BPB)
nop /* do I care about this ??? */
第一次跳转:
/* 啰啰嗦嗦这一堆, 就是保证dl为0x80, 默认为硬盘 */
LOCAL(after_BPB):
. = _start + GRUB_BOOT_MACHINE_DRIVE_CHECK
boot_drive_check:
jmp 3f /* grub-setup may overwrite this jump */
testb $0x80, %dl
jz 2f
3:
/* Ignore %dl different from 0-0x0f and 0x80-0x8f. */
testb $0x70, %dl
jz 1f
2:
movb $0x80, %dl
1:
/*
* ljmp to the next instruction because some bogus BIOSes
* jump to 07C0:0000 instead of 0000:7C00.
*/
ljmp $0, $real_start
第二次跳转:
跳转后检测是否支持LBA
real_start:
/* set up %ds and %ss as offset from 0 */
xorw %ax, %ax
movw %ax, %ds
movw %ax, %ss
/* set up the REAL stack */
movw $GRUB_BOOT_MACHINE_STACK_SEG, %sp //ss:sp 0x0000:0x2000
pushw %dx //入栈保存, 下面有int调用,防止被破坏
/* set %si to the disk address packet */
movw $disk_address_packet, %si
/* check if LBA is supported */
movb $0x41, %ah
movw $0x55aa, %bx
int $0x13
/* 上述代码的解释如下:
磁盘扩展探测: INT 13H, AH=41H
检测磁盘扩展读(LBA/CHS)支持情况。详细描述如下。
参数:
寄存器 描述
AH=0x41 扩展检测函数序号
DL 驱动器编号(第一块硬盘为0x80,第二块为0x81,依次类推)
BX 0x55AA
结果:
寄存器 描述
CF 支持清零,不支持置1
AH 错误码或者主版本号
BX 0x55AA
CX 接口支持掩码
1 – 使用打包结构体存取设备
2 – 驱动器加锁和弹出
4 – 支持增强型磁盘驱动器(EDD)
*/
封装disk_address_packet,读取第一个扇区
/* 下面还有Int调用, dx再保存一下 */
popw %dx
pushw %dx
lba_mode:
xorw %ax, %ax
movw %ax, 4(%si)
incw %ax
/* set the mode to non-zero */
movb %al, -1(%si)
/* the blocks */
movw %ax, 2(%si)
/* the size and the reserved byte */
movw $0x0010, (%si)
/* the absolute address */
movl kernel_sector, %ebx
movl %ebx, 8(%si)
movl kernel_sector + 4, %ebx
movl %ebx, 12(%si)
/* the segment of buffer address */
movw $GRUB_BOOT_MACHINE_BUFFER_SEG, 6(%si)
/*
* BIOS call "INT 0x13 Function 0x42" to read sectors from disk into memory
* Call with %ah = 0x42
* %dl = drive number
* %ds:%si = segment:offset of disk address packet
* Return:
* %al = 0x0 on success; err code on failure
*/
movb $0x42, %ah
int $0x13
/* 上述代码的解释如下:
LBA模式读: INT 13H, AH=42H
LBA模式的读采用打包的数据结构作为参数。
参数:
寄存器 描述
AH=42H 扩展读函数序号
DL 驱动器编号(第一块硬盘为0x80,第二块为0x81,依次类推)
DS:SI segment:offset指针,指向磁盘地址包DAP (Disk Address Packet)
DAP结构体的格式描述如下:
偏移量 大小 描述
00H 1 Byte DAP大小=16=0x10
01H 1 Byte 未用,必须置0
02H~03H 2 Bytes 需要读的扇区数
(有些BIOS限制不能超过127扇区)
04H~07H 4 Bytes segment:offset指针,指向内存缓冲区,读取到的
扇区内容放置在该缓冲区
08H~0FH 8 Bytes 需要读的连续扇区的起始扇区编号
(第一个扇区的编号是0)
结果:
寄存器 描述
CF 失败置1,成功清零
AH 返回码
读取第一个扇区, 把第一个扇区的数据成功则数据被读到了0x7000:0x0000(内存0x700000)位置
*/
movw $GRUB_BOOT_MACHINE_BUFFER_SEG, %bx
jmp LOCAL(copy_buffer)
把数据从0x7000:0x0000(内存0x700000)位置拷贝buff到0x0000:0x8000
LOCAL(copy_buffer):
/*
* We need to save %cx and %si because the startup code in
* kernel uses them without initializing them.
*/
pusha
pushw %ds
movw $0x100, %cx
movw %bx, %ds
xorw %si, %si
movw $GRUB_BOOT_MACHINE_KERNEL_ADDR, %di
movw %si, %es
cld
rep
movsw
popw %ds
popa
/* boot kernel */
jmp *(kernel_address)
深入理解 GNU GRUB - 02 boot.S 2.1 相关BIOS例程
https://blog.csdn.net/cppgp/article/details/6360976
grub2 1.95 源码分析之一 —— boot.S 分析及注释
https://blog.csdn.net/cppgp/article/details/2060146
深入理解 GNU GRUB - 02 boot.S 2.4 boot.S详细注释
https://blog.csdn.net/cppgp/article/details/6361020

本文深入探讨了GRUB启动过程中的关键步骤,包括BIOS/UEFI如何将控制权交给GRUB,GRUB如何检查硬盘驱动器并读取第一个扇区,以及如何检测LBA模式支持,并最终将数据读取到内存指定位置。

872

被折叠的 条评论
为什么被折叠?



