Assembly 加载引导加载程序的第二阶段

Assembly 加载引导加载程序的第二阶段,assembly,x86,nasm,bootloader,real-mode,Assembly,X86,Nasm,Bootloader,Real Mode,我正在尝试为x86机器创建一个小型操作系统,并开始为一个相当小的引导加载程序编写代码。我创建的引导加载程序非常简单,它从主引导记录后面的扇区加载一个小的第二个引导加载程序,并跳转到该代码。主引导记录中的引导加载程序代码似乎运行正常,当它尝试跳转到第二阶段引导加载程序时,问题就会出现。这个第二阶段引导加载程序应该输出一个表示成功的字母(字母S),这样我就可以知道代码正在执行。问题是屏幕上没有显示任何内容,因此我怀疑第二阶段引导加载程序从未执行过。我使用的代码如下: 主引导记录中的引导加载程序: [

我正在尝试为x86机器创建一个小型操作系统,并开始为一个相当小的引导加载程序编写代码。我创建的引导加载程序非常简单,它从主引导记录后面的扇区加载一个小的第二个引导加载程序,并跳转到该代码。主引导记录中的引导加载程序代码似乎运行正常,当它尝试跳转到第二阶段引导加载程序时,问题就会出现。这个第二阶段引导加载程序应该输出一个表示成功的字母(字母S),这样我就可以知道代码正在执行。问题是屏幕上没有显示任何内容,因此我怀疑第二阶段引导加载程序从未执行过。我使用的代码如下:

主引导记录中的引导加载程序:

[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
    ; Set the stack segment to 0xA000
    add ax, 0xA000
    mov ss, ax
    mov sp, 0x00
    ; Reset the drive, dl contains drive number
    mov ah, 0x00
    int 0x13
    ; 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
ReadDrive:
    mov ah, 0x02
    mov al, 0x01 ; Read 1 sector
    mov ch, 0x00 ; Read on cylinder 0
    mov cl, 0x02 ; Read sector 2
    mov dh, 0x00 ; Head number 0
    int 0x13

    jnc Success
    ; Print error (character F)
    mov al, 0x46
    call PrintChar
    jmp ReadDrive ; Retry

PrintChar: ; Prints a single character
    pusha
    mov ah, 0x09
    mov bh, 0x00
    mov bl, 0x0F
    mov cx, 0x01
    int 0x10
    popa
    ret

Success:
    jmp 0x7E00:0x00 ; Jump to 2nd stage bootloader

TIMES 510 - ($ - $$) db 0
DW 0xAA55 ; Boot signature
第二阶段引导加载程序的代码:

[BITS 16]
[ORG 0x7E00]

Boot2:
    ; Prints the character S to the screen
    mov al, 0x53
    mov ah, 0x09
    mov bh, 0x00
    mov bl, 0x0F
    mov cx, 0x01
    int 0x10
    jmp $ ; Loop forever

TIMES 512 - ($ - $$) db 0 ; Fill rest of block
此代码是使用以下代码编译并写入驱动器的:

nasm boot.asm -o boot.bin -f bin
nasm boot2.asm -o boot2.bin -f bin
dd if=boot.bin of=/dev/sd3 bs=512
dd if=boot2.bin of=/dev/sd3 bs=512 seek=1

写入此代码的设备是一个16GB的USB驱动器。我用来引导这段代码的计算机支持从USB引导,并像其他硬盘一样引导它们。代码似乎无法执行的原因是什么?

代码中似乎存在许多问题。我会尽力找出其中的一些。在我为Stackoveflow写的一些答案中可以找到一些有用的参考资料

  • 它给出了您不想在引导加载程序中进行的一般指导原则和假设
  • 在访问内存变量时没有正确设置DS和获取垃圾的陷阱。这在一定程度上适用于你的第二阶段
  • 一个与你的问题相似的问题的答案也可以提供一些有用的信息

堆栈 您确实设置了一个堆栈,但它可能与视频内存重叠。虽然这可能与您的问题无关,但这是一个潜在的问题。使用此代码:

add ax, 0xA000
mov ss, ax
mov sp, 0x00
jmp 0x7E00:0x00 ; Jump to 2nd stage bootloader
设置SS=0xa000,SP=0x0000。这将设置堆栈,但不幸的是,堆栈上推送的第一个值将位于0xa000:(0x0000-2)=0xa000:0xfffe。0xa000:0xfffe恰好位于视频内存中。也许您打算执行ss=0x9000,所以堆栈上的第一个值应该是0x9000:0xfffe。那里也有一个障碍。(EBDA)可以位于该区域。某些BIOSE错误地返回此区域的错误大小。在大多数情况下,它的大小为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位使用此计算映射到物理内存地址:(如果使用
[ORG 0x0000],会发生什么情况
在第二阶段的顶部和第一行代码使用
mov-ax,cs
mov-DS,ax
初始化DS?您如何知道引导扇区成功运行?其次也是最重要的一点是,您跳到
jmp 0x7E00:0x00
。这是物理地址(0x7E00您确定第一阶段运行正常吗?也许它应该输出一个字符来确保。在此环境中,您确定
dl
具有驱动器号吗?当您开始定义数据变量并尝试在第二阶段使用它们时,我的第一条注释的重要性将变得显而易见。如果没有正确设置的DS a所有对变量的引用将位于错误的偏移量。您的代码目前没有变量,因此您不会注意到问题。如果将jmp转移到第二个阶段,则ORG指令应等于跳转到的偏移量。如果您在上面进行建议的jmp更改(
jmp 0x07E0:0x00
)然后JMP将CS:IP更改为CS=0x07E0,IP=0x0000。您希望ORG等于IP。所以ORG应该是0x0000。
jmp 0x7E00:0x00 ; Jump to 2nd stage bootloader
jmp 0x07E0:0x00 ; Jump to 2nd stage bootloader  
[ORG 0x0000]
mov ax, cs 
mov ds, ax
[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
[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