diskboot

本文解析了GRUB启动过程中diskboot.S的作用与实现细节,包括执行环境、代码结构及其模拟实现。介绍了如何加载GRUB内核到内存指定位置,并通过BIOS中断完成数据读取。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

深入理解 GNU GRUB - 03 diskboot.S 3.1 diskboot.S执行时的环境 & 3.2 diskboot.S代码结构

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

转载注明出处(cppgp: http://blog.youkuaiyun.com/cppgp )

 

diskboot.S位于目录boot/i386/pc/,最终生成diskboot.img。这部分指令被加载到0x8000~0x81FF。diskboot.img加载GRUB内核到0x8200开始的内存位置,并将系统控制权交给GRUB内核。用到的BIOS例程和boot.S中相同。因此本章只描述如下内容:
  1)    diskboot.S执行时的环境
  2)    diskboot.S代码结构
  3)    diskboot.S详细注释
  4)    diskboot.S模拟实现


本章最后也模拟一个diskboot的实现。

 3.0 对boot.s而言,diskboot.s进入内核默认是在1扇区,而grubkernel默认是在“2扇区开始”,但“2扇区开始”,这个信息不是直接指定的,而是通过blocklist这样的结构编译生成时写入的。读取blocklist中的元素,就可以知道int中断去哪里把kernel读到8200处

3.1 diskboot.S执行时的环境 
boot.img跳转到bootdisk.img之前,已经配置好堆栈和一些寄存器及参数值。因此diskboot假设如下条件已经是满足的:
  1)    堆栈。SS和SP已配置好,有可用的堆栈。
  2)    寄存器DL。DL中保存正确的引导驱动器。
  3)    寄存器SI。SI中保存DAP地址。
  4)    寄存器DS。设置有正确的数据段DS。
事实上,在跳转到diskboot.img之前,boot.img确实做好了配置。堆栈SS:SP=0x0000:0x2000;DL中包含正确的引导驱动器;SI指向DAP地址,因此-1(%si)确定磁盘读取模式(LBA为1,CHS为0),如果是CHS读取,磁盘CHS参数含有正确值;数据段寄存器DS=0。

 

3.2 diskboot.S代码结构 
diskboot.S生成512字节机器码,其中0x0~0x147共328字节是指令,0x148~0x1FF共184字节用来保存数据集,每个数据集占用12字节,可以保存15个数据集。对于每个数据集,其中0~7字节表示起始扇区数,在安装时候指定;8~9字节表示扇区数,10~11字节表示目的段地址,都在生成镜像(grub-mkimage)时确定。必须存在一个扇区数为0的数据集表示数据集读取结束,因此可以存在14个有效数据集。当前只使用了一个。我反解了一个安装后的diskboot.img,显示只用了一个数据集,其值如下:
  起始扇区LBA地址: 0x0000 0000 0000 0002
  扇区数: 0x002e
  目的段地址: 0x0820

数据集:blocklist,表示一串连续的扇区;blocklist是一个链表
可知,grub内核的起始扇区是2扇区(note:一般情况下,mbr【boot.s】在0扇区,kerneladdress【diskboot.s】在第1扇区,grub内核在第2扇区),扇区数46(0x2E==46),加载到0x8200起始内存处。这个grub内核的大小为46*512=23KiB。
diskboot.S压栈首先保存驱动器。输出提示信息”loading”,设置第一个数据集的地址,然后进入循环读取数据。
根据boot.img中设置的读取模式(LBA/CHS)和数据集中的起始扇区、扇区数、目的段地址,读取数据并保存到内存中(偏移量为0,因此目的段地址唯一确定内存地址)。每调用一次读中断,都提示一个”.”到终端,对于慢速存储设备,用户可以快速得到反馈,以免在加载数据期间,用户误以为死机而进行强制性关机措施等。
在一个数据集内循环读取时,循环标签是LOCAL(setup_sectors),一个数据集完成后,设置处理上一数据集,并跳转到LOCAL(bootloop)开始处理,如果这个数据集的扇区数为0,则跳转到LOCAL(bootit),否则继续数据集内的循环LOCAL(setup_sectors)。
数据读取完毕后,执行LOCAL(bootit)处代码,这里将输出提示信息”/r/n”,还原DX寄存器(保存引导驱动器),并以CS:IP=0x0000:0x8200跳转执行,这里正是kernel.img所在内存地址。
BIOS读中断过程(LBA/CHS)参考boot.S中的注释,此处不再重复。



深入理解 GNU GRUB - 03 diskboot.S 3.3 diskboot.S详细注释

分类: Bootloader   224人阅读  评论(1)  收藏  举报

转载注明出处(cppgp: http://blog.youkuaiyun.com/cppgp )

 

diskboot.S位于grub-1.98/boot/i386/pc/目录,采用AT&T汇编语法编写。详细注释如下:

 struct BlockListNode{

LONGLONG StartSectorNumber;

WORD Length;//有多少个连续扇区属于这个结点

WORD TargetCs;//本node将被读到的内存cs位置

}

[cpp]  view plain copy
  1. /* 
  2.  *  GRUB  --  GRand Unified Bootloader 
  3.  *  Copyright (C) 1999,2000,2001,2002,2006,2007,2009,2010   Free Software Foundation, Inc. 
  4.  * 
  5.  *  GRUB is free software: you can redistribute it and/or modify 
  6.  *  it under the terms of the GNU General Public License as published by 
  7.  *  the Free Software Foundation, either version 3 of the License, or 
  8.  *  (at your option) any later version. 
  9.  * 
  10.  *  GRUB is distributed in the hope that it will be useful, 
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of 
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  13.  *  GNU General Public License for more details. 
  14.  * 
  15.  *  You should have received a copy of the GNU General Public License 
  16.  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>. 
  17.  */  
  18. /* 
  19.  * cppgp 注释 
  20.  * 
  21.  * 转载请注明原作者 
  22.  * 
  23.  * 日期: 2011-04-22 
  24.  * 
  25.  * Email 
  26.  *    cppgp@qq.com, 
  27.  *    yanyg02@163.com 
  28.  * 
  29.  * GRUB version: 
  30.  *    gnu grub-1.98 
  31.  */  
  32.  /* 
  33.  * diskboot.S 
  34.  * 
  35.  * diskboot.S生成diskboot.img, 共512字节 
  36.  * 
  37.  * 安装程序根据实际情况, 改写blocklist数据集. 最多支持 
  38.  * 15个数据集, 每个数据集占用12字节, 0~7字节表示起始 
  39.  * 扇区, 8~9字节表示该数据集扇区数, 10~11表示目的 
  40.  * 缓冲区起始段地址. 必须有一个数据集的扇区数字段 
  41.  * 为0, 程序根据此判断读取结束. 
  42.  *  
  43.  * 
  44.  * 安装在硬盘上时,DPT部分(0x1BE~0x1FD)保留不变,   
  45.  * 
  46.  * 安装在软盘上时, DPT部分(0x1BE~0x1FD)是软盘复位和 
  47.  * 扇区探测代码. 扇区末尾两字节 
  48.  * 
  49.  * 扇区最后两字节 写入0xAA55 (小端表示, 0x1FE位置为0x55, 
  50.  * 0x1FF位置为0xAA). 
  51.  * 
  52.  * diskboot.img开机时加载到0x8000~0x81FF, 并以CS:IP=0x0000:0x8000 
  53.  * 跳转执行, 它将加载kernel.img到内存0x8200开始位置,并以 
  54.  * CS:IP=0x0000:0x8200跳转执行. kernel.img扇区数可能有多个, 
  55.  * 在生成影像(grub-mkinage)时确定. 
  56.  * 
  57.  * diskboot.img可以使用boot.img设置的堆栈和寄存器值,但是在 
  58.  * 跳转到0x8200之前,要确保没有更改这些设置, 因为kernel.img 
  59.  * 还会用到这些寄存器. 
  60.  * 
  61.  * diskboot.img当前只用到一个数据集. 在我的机器上, 反解 
  62.  * 安装以后的diskboot.img, 得到的值如下: 
  63.  * 
  64.  *  起始扇区: 0x0000 0000 0000 0002 
  65.  *  扇区数      : 0x002e 
  66.  *  段地址      : 0x0820 
  67.  */  
  68. #include <grub/symbol.h>  
  69. #include <grub/machine/boot.h>  
  70. /* 
  71.  *  defines for the code go here 
  72.  */  
  73. #define MSG(x)  movw $x, %si; call LOCAL(message)  
  74.     .file   "diskboot.S"  
  75.     .text  
  76.     /* Tell GAS to generate 16-bit instructions so that this code works 
  77.        in real mode. */  
  78.     /* 
  79.      * 告诉汇编器产生16位代码 
  80.      */  
  81.     .code16  
  82.     /* 
  83.      * 如同在boot.S所指明的, 
  84.      * 此处的代码被加载在内存0x8000处 
  85.      * 并且以CS:IP=0x0000:0x8000跳转执行 
  86.      */  
  87.     .globl  start, _start  
  88. start:  
  89. _start:  
  90.     /* 
  91.      * _start is loaded at 0x2000 and is jumped to with 
  92.      * CS:IP 0:0x2000 in kernel. 
  93.      */  
  94.     /* 
  95.      * we continue to use the stack for boot.img and assume that 
  96.      * some registers are set to correct values. See boot.S 
  97.      * for more information. 
  98.      */  
  99.     /* 
  100.      * boot.img中已设置堆栈(SS:SP=0x0000:0x2000) 
  101.      * 并且假定一些寄存器被设置为正确值 
  102.      * 其中包括: 
  103.      *  DL: 引导驱动器 
  104.      *  SI: DAP地址(BPB数据块, 
  105.      *       -1(%si)可获取读取模式LBA/CHS) 
  106.      *       (%si)LBA读的DAP参数起始地址 
  107.      *       或CHS参数存放地址 
  108.      *  DS=SS=0: 数据段/堆栈段地址 
  109.      */  
  110.     /* save drive reference first thing! */  
  111.     /* 驱动器压栈 */  
  112.     pushw   %dx  
  113.     /* print a notification message on the screen */  
  114.     /* 
  115.      * 向终端输出提示信息"loading" 
  116.      * notification_string="loading" 
  117.      */  
  118.     pushw   %si  
  119.     MSG(notification_string)  
  120.     popw    %si  
  121.     /* this sets up for the first run through "bootloop" */  
  122.     /* 
  123.      * GRUB_BOOT_MACHINE_LIST_SIZE=12 
  124.      * (fitstlist-12) ~ firstlist共12字节空间, 指定GRUB内核起始扇区,扇区数,拷贝时的代码段 
  125.      * 起始扇区8字节, 扇区数2字节,代码段2字节 
  126.      * 代码中的标签分别是:blocklist_default_start, blocklist_default_len, blocklist_default_seg 
  127.      *  blocklist_default_start默认值2,在安装时候指定(grub-install), 决定GRUB内核起始扇区的LBA地址 
  128.      *  blocklist_default_len默认值0, 在制作引导镜像时候生成 (grub-mkimage), 设定为正确的GRUB内核长度 
  129.      *  blocklist_default_seg跳转到GRUB内核时的默认代码段值, 默认值CS=0x820,  
  130.      *     它仅仅在LOCAL(copy_buffer)中用到, 最终跳转时, 使用CS:IP=0x0000:0x8200 (blocklist_default_seg<<4) 
  131.      */  
  132.     movw    $(firstlist - GRUB_BOOT_MACHINE_LIST_SIZE), %di  
  133.     /* save the sector number of the second sector in %ebp */  
  134.     /* 
  135.      * 8字节起始扇区的低地址(%si)保存到ESP寄存器 
  136.      *   LBA寻址用到高4字节. 
  137.      *   CHS寻址,如果高4字节不为0生成错误,因为CHS寻址不可达(CHS寻址范围7.88GiB, 参考2.1节) 
  138.      */  
  139.     movl    (%di), %ebp  
  140.         /*ebp是起启扇区, this is the loop for reading the rest of the kernel in */  
  141. /* 加载所有数据集, 当前只使用一个数据集*/  
  142. LOCAL(bootloop):  
  143.     /* check the number of sectors to read */  
  144.     /* 
  145.      * 8(%di)确定GRUB内核扇区数 
  146.      * grub-mkimage生成镜像时改写为正确的内核长度 
  147.      * 每次循环加载减去已读取的扇区 
  148.      * 为0时表示已经加载完毕, 跳转到LOCAL(bootit) 
  149.      */  
  150.     cmpw    $0, 8(%di)  
  151.     /* if zero, go to the start function */  
  152.     /* 所有数据集加载完毕跳转到LOCAL(bootit) */  
  153.     je  LOCAL(bootit)  
  154. /* LOCAL(setup_sectors)只加载当前数据集 */  
  155. LOCAL(setup_sectors):  
  156.     /* check if we use LBA or CHS */  
  157.     /* 
  158.      * boot.img中已经设置读取模式: 1表示LBA, 0表示CHS 
  159.      */  
  160.     cmpb    $0, -1(%si)  
  161.     /* use CHS if zero, LBA otherwise */  
  162.     /* CHS模式读 */  
  163.     je  LOCAL(chs_mode)  
  164.     /* load logical sector start,因为起始扇区号是8字节,所以用两个寄存器ecx:ebx */  
  165.     movl    (%di), %ebx  
  166.     movl    4(%di), %ecx  
  167.     /* the maximum is limited to 0x7f because of Phoenix EDD */  
  168.     /* Phoenix EDD限制单次读不能超过0x7F扇区,如果超过7f个扇区,则只读7f个,剩下的下次再读 */  
  169.     xorl    %eax, %eax  
  170.     movb    $0x7f, %al  
  171.     /* how many do we really want to read? */  
  172.     cmpw    %ax, 8(%di) /* compare against total number of sectors */  
  173.     /* which is greater? */  
  174.     jg  1f  
  175.     /* if less than, set to total */  
  176.     /* 如果到达这里,表示剩余扇区不足0x7F扇区,这次就可以加载完毕了 */  
  177.     movw    8(%di), %ax  
  178. 1:  
  179.     /* subtract from total */  
  180.     /* 修改内存中变量字段,减去这次要读取的扇区数, 代码用8(%di) 是否为0来判断有否加载完毕,len-此次要读的扇区个数 */  
  181.     subw    %ax, 8(%di)  
  182.     /* add into logical sector start */  
  183.     /* 
  184.      * 起始扇区要加上这次将要读取的扇区数 
  185.      * 注意是8字节的起始扇区 
  186.      * 高4字节的加要注意进位 
  187.      */  
  188.     addl    %eax, (%di)  
  189.     adcl    $0, 4(%di)  
  190.     /* set up disk address packet */  
  191.     /* 
  192.      * 设置LBA读参数并调用BIOS中断 
  193.      * 参考boot.S LBA读注释 
  194.      */  
  195.     /* 以下是设置中断DAP参数,同boot中一样,the size and the reserved byte */  
  196.     movw    $0x0010, (%si)  
  197.     /* the number of sectors */  
  198.     movw    %ax, 2(%si)  
  199.     /* the absolute address */  
  200.     movl    %ebx, 8(%si)  
  201.     movl    %ecx, 12(%si)  
  202.     /* the segment of buffer address */  
  203.     movw    $GRUB_BOOT_MACHINE_BUFFER_SEG, 6(%si)  
  204.     /* save %ax from destruction! */  
  205.     /* 保存这次要读取的扇区数 */  
  206.     pushw   %ax  
  207.     /* the offset of buffer address */  
  208.     movw    $0, 4(%si)  
  209. /* 
  210.  * BIOS call "INT 0x13 Function 0x42" to read sectors from disk into memory 
  211.  *  Call with   %ah = 0x42 
  212.  *          %dl = drive number 
  213.  *          %ds:%si = segment:offset of disk address packet 
  214.  *  Return: 
  215.  *          %al = 0x0 on success; err code on failure 
  216.  */  
  217.     movb    $0x42, %ah  
  218.     int $0x13  
  219.     jc  LOCAL(read_error)  
  220.     movw    $GRUB_BOOT_MACHINE_BUFFER_SEG, %bx  
  221.     jmp LOCAL(copy_buffer)  
  222. LOCAL(chs_mode):  
  223.     /* 
  224.      * CHS读 
  225.      * 判断C/H/S参数是否越界 
  226.      * 调用CHS读的BIOS中断 
  227.      * 参考boot.S CHS读注释 
  228.      */  
  229.     /* load logical sector start (top half) */  
  230.     movl    4(%di), %eax  
  231.     orl %eax, %eax  
  232.     jnz LOCAL(geometry_error)  
  233.     /* load logical sector start (bottom half) */  
  234.     movl    (%di), %eax  
  235.     /* zero %edx */  
  236.     xorl    %edx, %edx  
  237.     /* divide by number of sectors */  
  238.     divl    (%si)  
  239.     /* save sector start */  
  240.     movb    %dl, 10(%si)  
  241.     xorl    %edx, %edx  /* zero %edx */  
  242.     divl    4(%si)      /* divide by number of heads */  
  243.     /* save head start */  
  244.     movb    %dl, 11(%si)  
  245.     /* save cylinder start */  
  246.     movw    %ax, 12(%si)  
  247.     /* do we need too many cylinders? */  
  248.     cmpw    8(%si), %ax  
  249.     jge LOCAL(geometry_error)  
  250.     /* determine the maximum sector length of this read */  
  251.     movw    (%si), %ax  /* get number of sectors per track/head */  
  252.     /* subtract sector start */  
  253.     subb    10(%si), %al  
  254.     /* how many do we really want to read? */  
  255.     cmpw    %ax, 8(%di) /* compare against total number of sectors */  
  256.     /* which is greater? */  
  257.     jg  2f  
  258.     /* if less than, set to total */  
  259.     movw    8(%di), %ax  
  260. 2:  
  261.     /* subtract from total */  
  262.     subw    %ax, 8(%di)  
  263.     /* add into logical sector start */  
  264.     addl    %eax, (%di)  
  265.     adcl    $0, 4(%di)  
  266. /* 
  267.  *  This is the loop for taking care of BIOS geometry translation (ugh!) 
  268.  */  
  269.     /* get high bits of cylinder */  
  270.     movb    13(%si), %dl  
  271.     shlb    $6, %dl     /* shift left by 6 bits */  
  272.     movb    10(%si), %cl    /* get sector */  
  273.     incb    %cl     /* normalize sector (sectors go 
  274.                     from 1-N, not 0-(N-1) ) */  
  275.     orb %dl, %cl    /* composite together */  
  276.     movb    12(%si), %ch    /* sector+hcyl in cl, cylinder in ch */  
  277.     /* restore %dx */  
  278.     popw    %dx  
  279.     pushw   %dx  
  280.     /* head number */  
  281.     movb    11(%si), %dh  
  282.     pushw   %ax /* save %ax from destruction! */  
  283. /* 
  284.  * BIOS call "INT 0x13 Function 0x2" to read sectors from disk into memory 
  285.  *  Call with   %ah = 0x2 
  286.  *          %al = number of sectors 
  287.  *          %ch = cylinder 
  288.  *          %cl = sector (bits 6-7 are high bits of "cylinder") 
  289.  *          %dh = head 
  290.  *          %dl = drive (0x80 for hard disk, 0x0 for floppy disk) 
  291.  *          %es:%bx = segment:offset of buffer 
  292.  *  Return: 
  293.  *          %al = 0x0 on success; err code on failure 
  294.  */  
  295.     movw    $GRUB_BOOT_MACHINE_BUFFER_SEG, %bx  
  296.     movw    %bx, %es    /* load %es segment with disk buffer */  
  297.     xorw    %bx, %bx    /* %bx = 0, put it at 0 in the segment */  
  298.     movb    $0x2, %ah   /* function 2 */  
  299.     int $0x13  
  300.     jc  LOCAL(read_error)  
  301.     /* save source segment */  
  302.     movw    %es, %bx  
  303. LOCAL(copy_buffer):  
  304.     /* 
  305.      * 无论CHS/LBA, 缓冲区地址为segment:offset=%bx:0x0=0x7000:0x0处 
  306.      */  
  307.     /* load addresses for copy from disk buffer to destination */  
  308.     /* 设置目的段 */  
  309.     movw    10(%di), %es    /* load destination segment */  
  310.     /* restore %ax */  
  311.     /* 
  312.      * 调用BIOS中断前已经把这次要读取的扇区数压栈 
  313.      * 每个扇区512字节即2^9 
  314.      *   然后%ax左移5位并加到段地址上, 
  315.      *   段地址要左移4位放到地址线上, 
  316.      *   因此,等价于%ax左移9位放到地址线上 
  317.      *   这正好是一个扇区数据占用的内存空间 
  318.      */  
  319.     popw    %ax  
  320.     /* determine the next possible destination address (presuming 
  321.         512 byte sectors!) */  
  322.     /* 
  323.      * 下一次可能的目的段地址(强制要求512字节扇区) 
  324.      * 本次使用的目的段在此之前已经保存到%es了 
  325.      */  
  326.     shlw    $5, %ax     /* shift %ax five bits to the left */  
  327.     addw    %ax, 10(%di)    /* add the corrected value to the destination 
  328.                    address for next time */  
  329.     /* save addressing regs */  
  330.     pusha  
  331.     pushw   %ds  
  332.     /* get the copy length */  
  333.     /* 
  334.      * %ax左移3位, 共左移8位 
  335.      * 因此%ax中是这次读取的字数(word, 1-word=2-byte) 
  336.      * 设置%cx为需要拷贝的字数,rep使用%cx作为循环计数器 
  337.      */  
  338.     shlw    $3, %ax  
  339.     movw    %ax, %cx  
  340.     /* 
  341.      * 以扇区为单位,源/目的串偏移量都是0 
  342.      */  
  343.     xorw    %di, %di    /* zero offset of destination addresses */  
  344.     xorw    %si, %si    /* zero offset of source addresses */  
  345.     /* 进入LOCAL(copy_buffer)之前, %bx持有缓冲区段地址 */  
  346.     movw    %bx, %ds    /* restore the source segment */  
  347.     /* 字符串操作指针移动方向为前向 */  
  348.     cld     /* sets the copy direction to forward */  
  349.     /* perform copy */  
  350.     /* 完成拷贝 */  
  351.     rep     /* sets a repeat */  
  352.     movsw       /* this runs the actual copy */  
  353.     /* restore addressing regs and print a dot with correct DS 
  354.        (MSG modifies SI, which is saved, and unused AX and BX) */  
  355.     /* MSG不用到DS, 
  356.     /* 
  357.      * 设置正确的数据段地址%ds 
  358.      * 调用MSG显示"." 
  359.      * 对于慢速存储设备, 
  360.      * 提供用户反馈, 以免被当做死机 
  361.      */  
  362.     popw    %ds  
  363.     MSG(notification_step)  
  364.     popa  
  365.     /* check if finished with this dataset */  
  366.     /* 检测是否读取完毕, 8(%di)持有需要读取的剩余扇区数 */  
  367.     cmpw    $0, 8(%di)  
  368.     jne LOCAL(setup_sectors)  
  369.     /* update position to load from */  
  370.     /* 
  371.      * 更新为上一个数据集 
  372.      * 意指(firstlist-(x+1)*12)~(firstlist-x*12)位置, x从0开始递增 
  373.      * 可以有多个数据集 
  374.      * 但是不能和LOCAL(message)重叠 
  375.      * 多个数据集数据最终是否连续, 依赖于该数据集合上一个数据集 
  376.      * 缓冲区段地址 
  377.      * 
  378.      * 否则diskboot会出错 
  379.      * 反汇编显示LOCAL(message)结束处地址0x8147 
  380.      * 因此0x148~0x1FF可全部用作数据集 
  381.      * 每个数据集12字节,最多可有(0x200-0x148)/12=15个数据集 
  382.      * 最开始处数据集扇区数必须为0 (否则重叠到LOCAL(message)去啦) 
  383.      * ==> 最多可有14个有效数据集 
  384.      * 反汇编安装后的diskboot.img的结果, 显示只用了一个数据集 
  385.      * 
  386.      * 推导: 
  387.      *   每个数据集采用2字节描述扇区数,因此不能超过0xFFFF个扇区 
  388.      *   14个有效数据集位置, 共计扇区数0xFFFF*14 
  389.      *   共计字节数= 0xFFFF*14*512=469754880bytes=447MB远超实模式下的寻址空间了 
  390.      */  
  391.     subw    $GRUB_BOOT_MACHINE_LIST_SIZE, %di  
  392.     /* jump to bootloop */  
  393.     /* 跳转到bootloop处理下一数据集 */  
  394.     jmp LOCAL(bootloop)  
  395. /* END OF MAIN LOOP */  
  396. /* 
  397.  * 所有数据读取完毕 
  398.  * 单个数据集内的数据总是连续放置在内存中 
  399.  * 当前只使用一个数据集,放置在0x8200起始的内存中 
  400.  * LOCAL(bootit)打印提示信息并跳转执行 
  401.  * GRUB_BOOT_MACHINE_KERNEL_ADDR=0x8000 
  402.  * CS:IP=0x0000:0x8200 
  403.  * startup.S生成的指令开始执行 
  404.  */  
  405. LOCAL(bootit):  
  406.     /* print a newline */  
  407.     MSG(notification_done)  
  408.     popw    %dx /* this makes sure %dl is our "boot" drive */  
  409.     ljmp    $0, $(GRUB_BOOT_MACHINE_KERNEL_ADDR + 0x200)  
  410. /* 
  411.  * 错误提示字符串和输出函数 
  412.  * 参考boot.S注释 
  413.  */  
  414. /* 
  415.  * BIOS Geometry translation error (past the end of the disk geometry!). 
  416.  */  
  417. LOCAL(geometry_error):  
  418.     MSG(geometry_error_string)  
  419.     jmp LOCAL(general_error)  
  420. /* 
  421.  * Read error on the disk. 
  422.  */  
  423. LOCAL(read_error):  
  424.     MSG(read_error_string)  
  425. LOCAL(general_error):  
  426.     MSG(general_error_string)  
  427. /* go here when you need to stop the machine hard after an error condition */  
  428. LOCAL(stop):    jmp LOCAL(stop)  
  429. notification_string:    .asciz "loading"  
  430. notification_step:  .asciz "."  
  431. notification_done:  .asciz "/r/n"  
  432. geometry_error_string:  .asciz "Geom"  
  433. read_error_string:  .asciz "Read"  
  434. general_error_string:   .asciz " Error"  
  435. /* 
  436.  * message: write the string pointed to by %si 
  437.  * 
  438.  *   WARNING: trashes %si, %ax, and %bx 
  439.  */  
  440.     /* 
  441.      * Use BIOS "int 10H Function 0Eh" to write character in teletype mode 
  442.      *  %ah = 0xe   %al = character 
  443.      *  %bh = page  %bl = foreground color (graphics modes) 
  444.      */  
  445. 1:  
  446.     movw    $0x0001, %bx  
  447.     movb    $0xe, %ah  
  448.     int $0x10       /* display a byte */  
  449.     incw    %si  
  450. LOCAL(message):  
  451.     movb    (%si), %al  
  452.     cmpb    $0, %al  
  453.     jne 1b  /* if not end of string, jmp to display */  
  454.     ret  
  455. /* 
  456.  * 反汇编结果显示, 此处地址是0x8148 
  457.  * 可在此处添加. = _start + 0x148 测试 
  458.  * 
  459.  * 0x148~0x1FF共计184字节,可存放15个12字节的数据集 
  460.  * 按照从下到上的顺序存放数据集 
  461.  * 最后一个有效数据集的扇区数(数据集内偏移量8)必须为0 
  462.  */  
  463.    
  464. /* 
  465.  *  This area is an empty space between the main body of code below which 
  466.  *  grows up (fixed after compilation, but between releases it may change 
  467.  *  in size easily), and the lists of sectors to read, which grows down 
  468.  *  from a fixed top location. 
  469.  */  
  470.     .word 0  
  471.     .word 0  
  472.     . = _start + 0x200 - GRUB_BOOT_MACHINE_LIST_SIZE  
  473.         /* fill the first data listing with the default */  
  474. blocklist_default_start:  
  475.     /* this is the sector start parameter, in logical sectors from 
  476.        the start of the disk, sector 0 */  
  477.     .long 2, 0  
  478. blocklist_default_len:  
  479.     /* this is the number of sectors to read.  grub-mkimage 
  480.        will fill this up */  
  481.     .word 0  
  482. blocklist_default_seg:  
  483.     /* this is the segment of the starting address to load the data into */  
  484.     .word (GRUB_BOOT_MACHINE_KERNEL_SEG + 0x20)  
  485. firstlist:  /* this label has to be after the list data!!! */  




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值