从软盘加载段int13h

时间:2015-12-09 12:22:00

标签: assembly nasm bootloader 16-bit osdev

我目前正在尝试编写16位实模式启动代码来打印一个字母,然后从软盘加载第二段并跳转到它,然后还会打印一封信。

但是,我对Read Sectors From Drive调用的工作方式感到有些困惑。到目前为止,这是我的代码:

[BITS 16]
org 0x7B00

start:
        mov ax, 0xB800 ; Video buffer
        mov es, ax     ; Copy address of video buffer to extra segment

        mov byte [es:0], 'A'    ; Move character A to first address
        mov byte [es:1], 0x17   ; Format for blue background, white foreground

        mov ah, 0x02 ; Read sectors from drive
        mov al, 1    ; Read 1 sector
        mov ch, 0    ; Cylinder 0
        mov cl, 0    ; Sector 0
        mov dh, 0    ; Head 0
        mov dl, 0    ; Drive 0 (Floppy)
        mov word [es:bx], sect2dest ; <- Completely unsure about this.

        int 0x13

        jmp sect2dest:0

data:
        sect2dest equ 0x0500

第二个汇编程序文件,我复制到软盘的第二个扇区,看起来像这样:

[BITS 16]
org 0x5000

sect2:

        mov ax, 0xB800
        mov es, ax

        mov byte [es:2], 'B'
        mov byte [es:3], 0x17

        jmp $

然而,我的光标只是变成紫色,而不是打印任何东西。我知道,这是一个奇怪的问题,很可能通过更好的ASM技能轻松解决,所以请原谅我

1 个答案:

答案 0 :(得分:5)

我强烈建议您查看我在之前的StackOverflow答案中写的General Bootloader Tips。您应该考虑在引导加载程序代码中设置堆栈,设置 DS (数据段),并且当您的 DL 寄存器中应使用BIOS提供的引导驱动器时bootloader已执行。这将允许您从可能不是第一张软盘的驱动器启动。我的第一个提示概述了:

  

当BIOS跳转到您的代码时,您不能依赖具有有效或预期值的CS,DS,ES,SS,SP寄存器。应在引导加载程序启动时正确设置它们。只能保证您的引导加载程序将从物理地址0x00007c00加载并运行,引导驱动器号将加载到 DL 寄存器中。

Bootloader问题

主引导记录(磁盘的第一个扇区)由BIOS加载到0x7c00。您的 ORG 指令使用0x7b00。你应该改变:

org 0x7B00

为:

org 0x7C00

我不确定您是否关闭了代码,但是在启动加载程序的最底层,您没有将 0xAA55 魔术值放在扇区的最后一个字中以标记您的引导扇区可引导。你应该在你的引导灯的底部添加这样的东西:

times 510-($-$$) db 0 
dw 0xaa55 

如果您使用的是链接描述文件(有迹象表明您没有),那么您可以使用它在第一个扇区的末尾插入 0xaa55 。您可能会以其他方式执行此操作,但未在您的问题中显示。如果您以其他方式插入0xAA55,则可以忽略此更改。

Ralph Brown的Interrupt List可能是中断文档的最佳来源(包括BIOS中断)。特别是int 13h/ah=02读取扇区记录为:

AH = 02h
AL = number of sectors to read (must be nonzero)
CH = low eight bits of cylinder number
**CL** = sector number 1-63 (bits 0-5)
high two bits of cylinder (bits 6-7, hard disk only)
DH = head number
**DL** = drive number (bit 7 set for hard disk)
**ES:BX** -> data buffer

因为 DL 包含BIOS传递的启动驱动器号,您可以删除此行,因为 DL 已经是我们想要的值:

mov dl, 0    ; Drive 0 (Floppy)

此更改允许我们从BIOS实际使用的启动驱动器中读取扇区,这意味着代码可用于从软盘B( DL = 0x01)或硬盘驱动器( DL = 0x80等)

CL 中开始读取的扇区号是1到63之间的值。扇区号(CHS格式)不常见,因为它们是1而不是0。扇区上的扇区1 0头0是引导扇区。磁道0上的扇区2磁头0是引导记录之后的扇区。鉴于你的问题,似乎你的意思是这条线:

mov cl, 0    ; Sector 0

成为:

mov cl, 2    ; Sector 2

您将此代码标记为可能的问题,并且您是正确的:

mov word [es:bx], sect2dest

这将常量 sect2dest 移动到内存中从 ES:BX 开始的字。 BX 可能在其中为零(它从未被初始化,因此可能是任何东西),并且由于 ES 仍然指向视频内存,您​​可能会将0x0500写入第一个单元格视频显示。什么 ES:BX 在文档中表示 ES BX 应该是您要将磁盘扇区读入内存的段和偏移量。由于您似乎打算在0x0500:0x0000加载第二阶段,因此需要设置ES = 0x0500和BX = 0x0000。删除此代码:

mov word [es:bx], sect2dest ; <- Completely unsure about this.

并将其替换为:

mov bx, sect2dest
mov es, bx          ; ES = 0x0500
xor bx, bx          ; BX = 0. So ES:BX=0x0500:0x0000

第二阶段问题

在第二阶段,org 0x5000应为org 0x0000。原因是jmp 0x0500:0x0000将设置段:偏移CS:IP到CS = 0x0500和IP = 0x0000。您需要 ORG 指令来匹配跳转到的偏移量。您应该使用ORG 0x0000,因为您将获得远程跳转jmp sect2dest:0的IP(偏移)= 0x0000。

变化:

org 0x5000

org 0x0000

您应该在第二阶段通过将 CS (0x0500)复制到 DS 来设置 DS 数据段。您可以在第二阶段将其添加到代码顶部:

mov ax, cs 
mov ds, ax

这有效地使DS = CS。您不需要为显示的示例代码执行此操作,但如果添加.data部分,则需要它来正确访问变量。

更改后的代码

bootloader汇编代码:

[BITS 16]
org 0x7C00

start:
        ; This section of code is added based on Michael Petch's bootloader tips
        xor ax,ax      ; We want a segment of 0 for DS for this question
        mov ds,ax      ;     Set AX to appropriate segment value for your situation
        mov bx,0x8000  ; Stack segment can be any usable memory

        cli            ; Disable interrupts to circumvent bug on early 8088 CPUs
        mov ss,bx      ; Top of the stack @ 0x80000.
        mov sp,ax      ; Set SP=0 so the bottom of stack will be just below 0x90000
        sti            ; Re-enable interrupts
        cld            ; Set the direction flag to be positive direction

        mov ax, 0xB800 ; Video buffer
        mov es, ax     ; Copy address of video buffer to extra segment

        mov byte [es:0], 'A'    ; Move character A to first address
        mov byte [es:1], 0x17   ; Format for blue background, white foreground

        mov ah, 0x02 ; Read sectors from drive
        mov al, 1    ; Read 1 sector
        mov ch, 0    ; Cylinder 0
        mov cl, 2    ; Sector 2
        mov dh, 0    ; Head 0
        mov bx, sect2dest 
        mov es, bx   ; ES = sect2dest
        xor bx, bx   ; BX = 0
        int 0x13

        jmp sect2dest:0

data:
        sect2dest equ 0x0500

times   510-($-$$) db 0     ; Create padding to fill out to 510 bytes
dw      0xaa55              ; Magic number in the trailer of a boot sector

第二阶段汇编代码:

[BITS 16]
org 0x0000

sect2:
        mov ax, cs
        mov ds, ax    ; Set CS=DS. CS=0x0500, therefore DS=0x500
                      ; If variables are added to this code then this
                      ; will be required to properly reference them
                      ; in memory

        mov ax, 0xB800
        mov es, ax

        mov byte [es:2], 'B'
        mov byte [es:3], 0x17

        jmp $