当前位置:  开发笔记 > 编程语言 > 正文

使用int13h从软盘加载段

如何解决《使用int13h从软盘加载段》经验,为你挑选了1个好方法。

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

但是,我对“从云端硬盘读取扇区”呼叫的工作方式有些困惑。到目前为止,这是我的代码:

[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> Michael Petc..:

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

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


引导程序问题


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

org 0x7B00

至:

org 0x7C00

我不确定是否要切断代码,但是在引导加载程序的最底部,您没有将0xAA55 magic值放在扇区的最后一个字中,以将引导扇区标记为可引导。您应该在引导程序的底部添加以下内容:

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

如果您使用的是链接程序脚本(有迹象表明您不是),则可以使用该脚本在第一个扇区的末尾插入0xaa55。您可能以其他方式(问题中未显示)执行此操作。如果以其他方式插入0xAA55,则可以忽略此更改。


Ralph Brown的中断列表可能是中断文档(包括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开始的。圆柱0上的扇区1磁头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手段在文档中是ESBX应该是段和你想读磁盘扇区成内存偏移。由于您似乎打算将第二阶段加载到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将segment:offset CS:IP设置为CS = 0x0500和IP = 0x0000。您需要您的ORG指令以匹配您要跳转到的偏移量。您应该使用它,ORG 0x0000因为随着远跳将获得IP(偏移)= 0x0000 jmp sect2dest:0

更改:

org 0x5000

org 0x0000

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

mov ax, cs 
mov ds, ax

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


更改后的代码

引导程序汇编代码:

[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 $


非常感谢。您的上述解释确实帮助我更深入地了解了我的代码。我希望我可以不止一次投票!您会发现,我们老师的策略是“ Google it”,因此,我很感谢我能获得的每一个帮助
推荐阅读
小妖694_807
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有