您的代码中似乎存在很多问题。我将尝试识别其中的一些。一些有用的参考资料可以在我为 Stackoveflow 撰写的一些答案中找到。
-
一般引导加载程序技巧其中给出了您不想在引导加载程序中做出的一般准则和假设
-
信息关于不设置的陷阱DS正确地访问内存变量并获取垃圾。这在某种程度上适用于你的第二阶段
- An answer对于与您的问题相似的问题也可以提供一些有用的信息。
Stack
您确实设置了一个堆栈,但它可能会与视频内存重叠。尽管这可能与您的问题无关,但它是一个潜在的问题。有了这个代码:
add ax, 0xA000
mov ss, ax
mov sp, 0x00
You set SS=0xa000,并且SP=0x0000。这会设置堆栈,但不幸的是,压入堆栈的第一个值将位于 0xa000:(0x0000-2)= 0xa000:0xfffe 。 0xa000:0xfffe 恰好可能落在视频内存中。也许您打算执行 ss=0x9000 ,因此堆栈上的第一个值将位于 0x9000:0xfffe 。那里也有一个障碍。这扩展 Bios 数据区(EBDA) 可以位于该区域。某些 BIOS 会错误地返回该区域的错误大小。在大多数情况下,其大小为 0k 到 4k,正好低于物理地址 0xa0000。如果考虑到最坏的情况,我会选择低于该值的堆栈。
add ax, 0x9000
mov ss, ax
mov sp, 0xF000 ; Bottom of stack at 0x9000:0xF000
内存地址0x7e00
这里有两个问题。在您的问题中,您建议您尝试将第二阶段读入引导加载程序上方的区域。那将位于物理地址 0x7e00。您的代码执行以下操作:
; Read from drive, dl contains drive number
; Set up output location to 0x7E00: 0x00
mov ax, 0x7E00
mov es, ax ; Load to 0x7E00 : 0x00
mov bx, 0x00
16-bit 段:偏移对使用此计算映射到物理内存地址:(segment
mov ax, 0x07E0
mov es, ax ; Load to 0x07E0:0x00
mov bx, 0x00
0x07E0:0x00 是物理内存地址 (0x07E0FAR JMP使用以下代码进入第二阶段:
jmp 0x7E00:0x00 ; Jump to 2nd stage bootloader
应该:
jmp 0x07E0:0x00 ; Jump to 2nd stage bootloader
第二阶段的潜在问题
如果您进行建议的更改(jmp 0x07E0:0x00
)前面提到过然后FAR JMP会改变CS:IP to CS=0x07E0(段),IP= 0x0000(offset) 并在那里继续执行。你需要你的ORG指令来匹配偏移量(IP)您从第一阶段跳转到的位置。由于偏移量 (IP) 是 0x0000 你的 ORG 指令应该匹配:
[ORG 0x0000]
您还需要确保当第二阶段开始加载时DS也被设置为匹配。实现此目的的一种方法是显式复制代码段CS到数据段DS。这可以通过第二阶段顶部的代码来完成,如下所示:
mov ax, cs
mov ds, ax
没有正确设置数据段DS对变量的所有引用都将使用错误的段,并且可能不会指向它们在内存中的实际位置。您的代码目前没有变量,因此您没有注意到该问题。
不要假设 BIOS 通过 CS:IP=0x0000:0x7c00 调用第一阶段
在这个答案的序言中提到的一般引导加载程序提示中,提示 #1 非常重要:
- 当 BIOS 跳转到您的代码时,您不能依赖 CS、DS、ES、SS、SP 寄存器具有有效或预期值。当引导加载程序启动时,应正确设置它们。您只能保证引导加载程序将从物理地址 0x00007c00 加载并运行,并且引导驱动器号加载到 DL 寄存器中。
在您的代码中,您的引导加载程序具有以下内容:
[BITS 16] ; 16 bit mode
[ORG 0x7C00] ; Boot loader start address
Boot:
; Initial, dl contains drive number
; Set data segment to code segment
mov ax, cs
mov ds, ax
mov es, ax
[ORG 0x7C00]
很好,但有一个假设是CS当它到达我们的引导加载程序时,该段被设置为 0x0000。然后我们设置DS=CS。对于简单的引导加载程序来说,传统观点是 BIOS 跳转到 0x0000:0x7c00 (CS:IP). ORG应与偏移量匹配(在本例中IP)。问题是,实际上 BIOS 跳转到物理地址 0x00007c00,但它可以通过多种方式来实现CS:IP pairs.
BIOS 可以对我们的代码进行 FAR JMP(或等效操作):jmp 0x07c0:0x0000
,一些模拟器和真实硬件就是这样做的。 0x07c0:0x0000 是 (0x07c0IP= 0x0000。我们已经设定了[ORG 0x7c00]
。那将是不匹配的!如果我们实际上不知道什么,我们如何解决这个问题CS:IP配对 BIOS 调用我们?很简单——不要复制CS to DS在引导加载程序的第一阶段。由于我们需要 0x7c00 的偏移量,DS需要为 0x0000 才能工作。我们应该明确地将 0x0000 放在我们的数据段中(DS)。代码可能如下所示:
[BITS 16] ; 16 bit mode
[ORG 0x7C00] ; Boot loader start address
Boot:
; Initial, dl contains drive number
; Set data segment to code segment
xor ax, ax ; AX=0
mov ds, ax ; DS=0
mov es, ax ; ES=0