本文共 3554 字,大约阅读时间需要 11 分钟。
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 2f3: /* Ignore %dl different from 0-0x0f and 0x80-0x8f. */ testb $0x70, %dl jz 1f2: movb $0x80, %dl1: /* * 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/6360976grub2 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