grub 和 中断解析

深入理解 GNU GRUB - 02 boot.S 2.1 相关BIOS例程

分类: Bootloader   252人阅读  评论(0)  收藏  举报

转载注明出处(cppgp: http://blog.csdn.net/cppgp )

 

2. boot.S: GRUB引导第一步 
boot.S位于目录boot/i386/pc/。这部分指令被加载到0x7C00~0x7DFF。主要工作包括:配置寄存器;设置堆栈;检测引导盘;检测引导盘读取模式;读取另一扇区指令。这个过程用到几个BIOS例程,并且对主引导记录(MBR, Master Boot Record)结构有很大的依赖。因此boot.S我们分作四步进行详细描述:
1)    相关BIOS例程
2)    主引导记录MBR结构
3)    boot.S代码结构
4)    boot.S详细注释
在本节最后,我们实现一个简单的boot.S,这个boot.S仅仅通过BIOS例程,向终端输出文本。
2.1 相关BIOS例程 
boot.S用到五个磁盘相关的BIOS例程。分别是:探测磁盘扩展读支持、LBA方式读、CHS参数获取、CHS方式读、磁盘复位。磁盘读取出现LBA/CHS两种模式(其实LBA又分为28-bit、48-bit、64-bit三种),是因为在磁盘的发展历史上,由于对磁盘容量的错误估量,导致容量屏障的出现,而不得不进行接口更改、扩展。历史上出现的容量屏障主要有四次:
1)    504MiB限制。也称作物理CHS寻址限制。早期的IDE/ATA磁盘接口规定柱面(C=Cylinder)、磁头(H=Head)、扇区(S=Sector)的位宽分别为C/H/S=16/4/8;而BIOS INT 13 H/02H读调用接口规定C/H/S=10/8/6。两者结合取位宽较少者,磁盘寻址参数C/H/S=10/4/6。扇区的起始编号是1而不是0,每扇区数据512字节,因此可寻址容量为210*24*(26-1)*512=528482304bytes=504MiB。
2)    7.88GiB限制。也称作逻辑CHS寻址限制。从1) 可以看出,BIOS INT 13 H/02H接口磁头H有4位是空闲的,因此逻辑上可以扩展磁头H为8位(而实际上连接到IDE/ATA时,磁头H有4位映射到柱面C,或者映射到柱面C和扇区S)。在BIOS接口上看,现在C/H/S寻址范围扩展到210*28*(26-1)*512=8455716864bytes=7.88GiB。
3)    128GiB限制。也称作LBA-28bits限制。在 2) 中,BISO接口的CHS寻址已经到了极限,无法再扩展了,而IDE/ATA是28 位(IDE/ATA内部C/H/S=16:4:8共28位)的,理论寻址容量为228*512=128GB,因此出现了LBA (Logical Block Addressing) 寻址。LBA是一个一维地址,从0~2N-1,其中N是地址宽度,在这里是28,而LBA到CHS的转换由BIOS和磁盘完成。28位LBA寻址容量为228*512=128GiB。
4)    2TiB限制。为了提供更大范围的寻址,Western Digital和Phoenix Technologies制定了EDD (BIOS Enhanced Disk Drive Services) 标准。它使用64位LBA寻址,同时也支持48位和28位寻址。48位LBA寻址容量为128PiB,而64位LBA寻址容量更是高达8ZiB,无论48位LBA或者64位LBA,在当前或可以预见的将来应该是足够的。但是历史悠久的MBR中保存有磁盘分区表DPT,而分区表中分区绝对起始扇区和分区总扇区数都是32位的,因此对于传统分区的磁盘,最大寻址范围由这两个32位值决定,大小为232*512=2TiB。为了解决该问题,引进了GPT (GUID Partition Table) 和EFI (Extensible Firmware Interface) 技术,本文不对其做详细描述,有兴趣的读者可以Google相关主题。
在磁盘容量的计算上,软件按照1024进行单位换算,而厂商按照1000进行单位换算,因此上述的504MiB限制、7.85GiB限制、128GiB限制又称为522MB限制、8.46GB限制、137GB限制。
除了上述限制,历史上还出现过一些软件导致的容量屏障,例如一些BIOS BUG或文件系统体系导致的容量屏障,本文 不再对其做进一步描述,有兴趣可以Google相关细节。BIOS例程及容量屏障描述参考如下网络资源:
http://en.wikipedia.org/wiki/INT_13H
http://en.wikipedia.org/wiki/INT_10H
http://www.pcguide.com/ref/hdd/bios/index.htm

2.1.1磁盘扩展探测: INT 13H, AH=41H 
检测磁盘扩展读(LBA/CHS)支持情况。详细描述如下。
参数:
寄存器        描述
AH=0x41    扩展检测函数序号
DL        驱动器编号(第一块硬盘为0x80,第二块为0x81,依次类推)
BX        0x55AA

结果:
寄存器        描述
CF        支持清零,不支持置1
AH        错误码或者主版本号
BX        0x55AA
CX        接口支持掩码
        1 – 使用打包结构体存取设备
        2 – 驱动器加锁和弹出
        4 – 支持增强型磁盘驱动器(EDD)

使用AT&T语法实现这个调用的例子如下(默认使用0x80作为驱动器):

[c-sharp]  view plain copy
  1. boot_driver:  
  2. .byte 0x80  
  3. movb boot_driver, %dl  
  4. movb $0x41, %ah  
  5. movw $0x55aa, %bx  
  6. int $0x13  
  7. movb boot_driver, %dl  
  8. jc chs_mode  
  9. cmpw $0xaa55, %bx  
  10. jne chs_mode  
  11. andw $1, %cx  
  12. lba_mode:  
  13. // Do LBA operation  
  14. Jmp end  
  15. chs_mode:  
  16. // Do CHS operation  
  17. end:  
  18. // Do Normal Works  


调用结束后,如果CF置1、或者BX不等于0xAA55、或者CX不等于1,都表示不支持LBA,因此进入CHS处理。注意,BIOS调用可能更改掉DL寄存器值,因此需要重置。

2.1.2 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        返回码

使用AT&T语法实现这个调用的例子如下(假定我们使用0x80作为驱动器,从第2个扇区开始连续读取4个扇区):
[c-sharp]  view plain copy
  1. boot_driver:  
  2. .byte 0x80  
  3. sector_start:  
  4. .long 2, 0  
  5. sector_num:  
  6. .word 4  
  7. dap:  
  8. /* reserved 16 bytes to hold dap, or disk address packet */  
  9. . = dap + 0x10  
  10. read_buffer:  
  11. /* reserved 512*4bytes to save data */  
  12. . = read_buffer + 512*4  
  13. movb boot_driver, %dl  
  14. movw $dap, %si  
  15. xorw %ax, %ax  
  16. movw %ax, %ds  
  17. movw %ax, 4(%si)  
  18. movb $0x0010, (%si)  
  19. movw sector_num, %ax  
  20. movw %ax, 2(%si)  
  21. movw $read_buffer, 6(%si)  
  22. movl sector_start, %eax  
  23. movl %eax, 8(%si)  
  24. movl sector_start+4, %eax  
  25. movl %eax, 12(%si)  
  26. movb $0x42, %ah  
  27. int $0x13  
  28. jc lba_fail  
  29. // Do LBA-read success operations  
  30. Jmp end  
  31. lba_fail:  
  32. // Do LBA-read fail operations  
  33. end:  
  34. // Do Normal Works  


调用结束后,通过检测CF来判断是否成功。需要注意字节序的问题,80x86采用小端序。

2.1.3 CHS参数获取: INT 13H, AH=08H 
获取驱动器CHS参数。如下。
参数:
寄存器        描述
AH=0x08    驱动器CHS参数读取函数序号
DL        驱动器编号(第一块硬盘为0x80,第二块为0x81,依次类推)
BX        0x55AA

结果:
寄存器        描述
CF        成功清零,失败置1
AH        返回码
DL        驱动器号
DH        逻辑磁头最大索引值(number_of-1因为索引从0开始)
CX        逻辑柱面索引最大值和逻辑扇区数
        逻辑柱面最大索引=number_of-,因为索引从0开始
        逻辑扇区数=number_of,因为索引从1开始
柱面占10位,CH表示柱面低8位,CL高2位表示柱面9~10位
扇区占6位,CL低6位表示扇区

使用AT&T语法实现这个调用的例子很简单:
[c-sharp]  view plain copy
  1. boot_driver:  
  2. .byte 0x80  
  3. movb boot_driver, %dl  
  4. movb $0x08, %ah  
  5. int $0x13  
  6. jc chs_para_fail  
  7. // Do CHS-para success operations  
  8. jmp end  
  9. chs_para_fail:  
  10. // Do CHS-para fail operation  
  11. end:  
  12. // Do Normal Works  


调用结束后,通过检测CF来判断参数获取调用是否成功。

2.1.4 CHS模式读: INT 13H, AH=02H 

CHS模式读扇区。需要注意缓冲区没有超出该段寻址范围。
参数:
寄存器        描述
AH=0x02    CHS模式读扇区函数序号
AL        需读取扇区数
CX        柱面和扇区,柱面占10位,扇区占6位
CH表示柱面低8位,CL高2位表示柱面9~10位
CL低6位表示扇区(从1~63)
DH        磁头
DL        驱动器编号
第一软盘为0x00,第二软盘为0x01,依次类推
第一硬盘为0x80,第二硬盘为0x81,依次类推
ES:BX        segment:offset缓冲区地址指针

结果:
寄存器        描述
CF        成功清零,失败置1
AH        返回码
AL        实际读取的扇区数

CHS读存在7.88GiB容量限制,现在几乎没有硬盘使用这种模式读,并且也很少有人使用软盘(你还有软驱吗?),因此CHS读扇区只是作为残留机制存在,很少用到。
使用AT&T语法实现这个调用的例子如下,因为要用到移位等,汇编代码看起来稍微有点麻烦。这里我们依然假定使用0x80作为驱动器,以C/H/S=0/0/1开始连续读取4个扇区。另外,需要用到2.1.3描述的CHS参数获取的结果。
[c-sharp]  view plain copy
  1. boot_driver:  
  2. .byte 0x80  
  3. cylinder_start:  
  4. .word 0  
  5. head_start:  
  6. .byte 0  
  7. sector_start:  
  8. .byte 1  
  9. sector_num:  
  10. .word 4  
  11. chs_sectors:  
  12. .byte 0  
  13. chs_heads:  
  14. .word 0  
  15. chs_cylinders:  
  16. .word 0  
  17. read_buffer:  
  18. /* reserved 512*4bytes to save data */  
  19. . = read_buffer + 512*4  
  20. movb boot_driver, %dl  
  21. movb $0x08, %ah  
  22. int $0x13  
  23. jc chs_para_fail  
  24. /* saved the CHS parameters */  
  25. /* 
  26.   * dh : numbers_of_heads-1, 8-bits 
  27.   * cx : numbers_of_cylinders-1, number_of_sectors 
  28.   */  
  29. movzbl %dh, %eax  
  30. incw  %ax  
  31. movw %ax, chs_head  
  32. movzbw %dl, %dx  
  33. shlw $2, %dx  
  34. movb %ch, %al  
  35. movb %dh, %ah  
  36. incw %ax  
  37. movw %ax, chs_cylinders  
  38. movzbw %dl, %ax  
  39. shrw $2, %ax  
  40. movw %ax, chs_sectors  
  41. /* CHS read */  
  42. movb sectors_start, %al  
  43. movb %al, %cl  
  44. movw cylinder_start, %ax  
  45. movb %al, %ch  
  46. xorb %al, %al  
  47. shrw $2, %ax  
  48. orb %al, %cl  
  49. movb head_start, %al  
  50. movb %al, %dh  
  51. movb boot_drive, %dl  
  52. xorw %ax, %ax  
  53. movw %ax, %es  
  54. movw $read_buffer, %bx  
  55. movb sector_num, %al  
  56. movb $2, %ah  
  57. int $0x13  
  58. jc chs_read_fail  
  59. // Do CHS-read success operations  
  60. jmp end  
  61. chs_para_fail:  
  62. // Do CHS-para fail operations  
  63. jmp end  
  64. chs_read_fail:  
  65. // Do CHS-read fail operations  
  66. jmp end  
  67. end:  
  68. // Do Normal Works  


CHS读结束后,通过CF判断是否成功。

2.1.5 复位磁盘驱动器: INT 13H, AH=00H 
复位磁盘驱动器。如下。
参数:
寄存器        描述
AH=0x00    驱动器复位函数序号
DL        驱动器编号(第一块硬盘为0x80,第二块为0x81,依次类推)

结果:
寄存器        描述
CF        成功清零,失败置1
AH        状态

使用AT&T语法实现这个调用的例子非常简单:
[c-sharp]  view plain copy
  1. boot_driver:  
  2. .byte 0x80  
  3. xorb %ah, %ah  
  4. movb boot_driver, %dl  
  5. int $0x13  
  6. jc reset_fail  
  7. // Do Disk Reset success operations  
  8. jmp end  
  9. reset_fail:  
  10. // Do Disk Reset fail operations  
  11. end:  
  12. // Do Normal Works  


通过CF判断复位是否成功。软盘的读取和CHS模式的读

2.1.6 字符输出: INT 10H, AH=0EH 
BIOS使用INT 10H图形服务,可以用来设置图形模式、输出字符或字符串、以及基本图形(图形模式下读取/写入像素)。
AH=0EH提供用来向终端输出单一字符。如下。
参数:
寄存器        描述
AH=0x0E    电传输出函数序号
AL=Character    需要输出的字符
BL=Color    输出字符颜色,只对图形终端有效

结果:
无返回

使用AT&T语法实现这个调用的例子如下:
[c-sharp]  view plain copy
  1. char_value:  
  2. .byte ‘A’  
  3. char_color:  
  4. .byte 0  
  5. movb char_value, %al  
  6. movb char_color, %bl  
  7. movb $0x0E, %ah  
  8. int $0x10  

INT 10H, AH=0EH调用无返回值。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值