加载引导加载程序的第二阶段时出现问题 and/or 将控制权转移给它
Problems loading second stage of a bootloader and/or transferring control to it
我的主引导记录代码:
;bit16 ; 16bit by default
org 0x7c00
jmp short start
nop
bsOEM db "OS423 v.0.1" ; OEM String
start:
;;cls
mov ah,06h ;Function 06h (scroll screen)
mov al,0 ;Scroll all lines
mov bh,0x0f ;Attribute (lightgreen on blue)
mov ch,0 ;Upper left row is zero
mov cl,0 ;Upper left column is zero
mov dh,24 ;Lower left row is 24
mov dl,79 ;Lower left column is 79
int 10h ;BIOS Interrupt 10h (video services)
;;print welcome msg
mov ah,13h ;Function 13h (display string), XT machine only
mov al,1 ;Write mode is zero: cursor stay after last char
mov bh,0 ;Use video page of zero
mov bl,0x0f ;Attribute (lightgreen on blue)
mov cx,mlen ;Character string length
mov dh,0 ;Position on row 0
mov dl,0 ;And column 0
lea bp,[msg] ;Load the offset address of string into BP, es:bp
;Same as mov bp, msg
int 10h
;;load sector into memory & 5678h:1234h
mov bx, 0x5678 ;segmented address
mov es, bx ;move segemented address to es
mov bx,0x1234 ;base address to bx
mov ah, 02 ;function read sectors
mov al, 01 ;# of sectors to load
mov ch, 00 ;track to read
mov cl, 02 ;sector to read
mov dh, 00 ;head to read
mov dl, 00 ;drive number
int 0x13 ;call interrupt 13
jmp 0x5678:0x1234 ;jump to memory address
int 20
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;variables;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
msg: db 'Welcome to Pradox OS 0.1! Authored by Jiansong he', 10, 13, '$'
mlen equ $-msg
padding times 510-($-$$) db 0 ;to make MBR 512 bytes
bootSig db 0x55, 0xaa ;signature (optional)
我的 nasm 编译二进制文件并将其放入我的 .img 软盘的终端命令:
line1: 定义一个软盘,名称为boot.img,块大小512字节,一共2880字节
line2: 使用nasm编译器,将mbr.asm文件编译成二进制格式,存放在名为mbr.bin的文件中(这是我的主引导记录)
第 3 行:在 dt.bin
将 dt.asm 编译成二进制文件
line4:将mbr.bin的内容放入boot.img,块大小512,共放入1个块
第 5 行:将 dt.bin 的内容放入 boot.img,块大小 512,物理扇区 #2(逻辑扇区 #1)
dd if=/dev/zero of=boot.img bs=512 count=2880
nasm -f bin mbr.asm -o mbr.bin
nasm -f bin dt.asm -o dt.bin
dd if=mbr.bin of=boot.img bs=512 count=1 conv=notrunc
dd if=dt.bin of=boot.img bs=512 seek=1 count=1 conv=notrunc
dt.asm中的代码:
[BITS 16] ;Set code generation to 16 bit mode
ORG 0x5647:0x1234 ;set addressing to begin at 579b4H
startdt:
;call cls ;call routine to clear screen
;call dspmsg ;call routine to display message
call date
call cvtmo
call cvtday
call cvtcent
call cvtyear
call dspdate
call time
call cvthrs
call cvtmin
call cvtsec
call dsptime
int 20h ;halt operation (VERY IMPORTANT!!!)
cls:
mov ah,06h ;function 06h (Scroll Screen)
mov al,0 ;scroll all lines
mov bh,0x0f ;Attribute (bright white on blue)
mov ch,0 ;Upper left row is zero
mov cl,0 ;Upper left column is zero
mov dh,24 ;Lower left row is 24
mov dl,79 ;Lower left column is 79
int 10H ;BIOS Interrupt 10h (video services)
ret
dspmsg:
mov ah,13h ;function 13h (Display String)
mov al,1 ;Write mode is zero
mov bh,0 ;Use video page of zero
mov bl,0x0a ;Attribute (bright white on bright blue)
mov cx,mlen2 ;Character length
mov dh,0 ;position on row 0
mov dl,0 ;and column 0
lea bp,[welcom] ;load the offset address of string into BP
int 10H
ret
welcom: db 'jiansong Hes first Operating System :D',10,13,'$'
mlen2 equ $-welcom;
date:
;Get date from the system
mov ah,04h ;function 04h (get RTC date)
int 1Ah ;BIOS Interrupt 1Ah (Read Real Time Clock)
ret
;CH - Century
;CL - Year
;DH - Month
;DL - Day
cvtmo:
;Converts the system date from BCD to ASCII
mov bh,dh ;copy contents of month (dh) to bh
shr bh,1
shr bh,1
shr bh,1
shr bh,1
add bh,30h ;add 30h to convert to ascii
mov [dtfld],bh
mov bh,dh
and bh,0fh
add bh,30h
mov [dtfld + 1],bh
ret
cvtday:
mov bh,dl ;copy contents of day (dl) to bh
shr bh,1
shr bh,1
shr bh,1
shr bh,1
add bh,30h ;add 30h to convert to ascii
mov [dtfld + 3],bh
mov bh,dl
and bh,0fh
add bh,30h
mov [dtfld + 4],bh
ret
cvtcent:
mov bh,ch ;copy contents of century (ch) to bh
shr bh,1
shr bh,1
shr bh,1
shr bh,1
add bh,30h ;add 30h to convert to ascii
mov [dtfld + 6],bh
mov bh,ch
and bh,0fh
add bh,30h
mov [dtfld + 7],bh
ret
cvtyear:
mov bh,cl ;copy contents of year (cl) to bh
shr bh,1
shr bh,1
shr bh,1
shr bh,1
add bh,30h ;add 30h to convert to ascii
mov [dtfld + 8],bh
mov bh,cl
and bh,0fh
add bh,30h
mov [dtfld + 9],bh
ret
dtfld: db '00/00/0000'
dspdate:
;Display the system date
mov ah,13h ;function 13h (Display String)
mov al,0 ;Write mode is zero
mov bh,0 ;Use video page of zero
mov bl,0x0f ;Attribute
mov cx,10 ;Character string is 10 long
mov dh,4 ;position on row 4
mov dl,0 ;and column 28
push ds ;put ds register on stack
pop es ;pop it into es register
lea bp,[dtfld] ;load the offset address of string into BP
int 10H
ret
time:
;Get time from the system
mov ah,02h
int 1Ah
ret
;CH - Hours
;CL - Minutes
;DH - Seconds
cvthrs:
;Converts the system time from BCD to ASCII
mov bh,ch ;copy contents of hours (ch) to bh
shr bh,1
shr bh,1
shr bh,1
shr bh,1
add bh,30h ;add 30h to convert to ascii
mov [tmfld],bh
mov bh,ch
and bh,0fh
add bh,30h
mov [tmfld + 1],bh
ret
cvtmin:
mov bh,cl ;copy contents of minutes (cl) to bh
shr bh,1
shr bh,1
shr bh,1
shr bh,1
add bh,30h ;add 30h to convert to ascii
mov [tmfld + 3],bh
mov bh,cl
and bh,0fh
add bh,30h
mov [tmfld + 4],bh
ret
cvtsec:
mov bh,dh ;copy contents of seconds (dh) to bh
shr bh,1
shr bh,1
shr bh,1
shr bh,1
add bh,30h ;add 30h to convert to ascii
mov [tmfld + 6],bh
mov bh,dh
and bh,0fh
add bh,30h
mov [tmfld + 7],bh
ret
tmfld: db '00:00:00'
dsptime:
;Display the system time
mov ah,13h ;function 13h (Display String)
mov al,0 ;Write mode is zero
mov bh,0 ;Use video page of zero
mov bl,0x0f;Attribute
mov cx,8 ;Character string is 8 long
mov dh,5 ;position on row 5
mov dl,0;and column 0
push ds ;put ds register on stack
pop es ;pop it into es register
lea bp,[tmfld] ;load the offset address of string into BP
int 10H
ret
int 20H
我的测试环境是 dosbox,我可以在屏幕上成功显示欢迎消息,但无法将另一个扇区加载到从 0x5647:0x1234 开始的内存中
谢谢
足够简单。
您不能仅使用 OEM 字符串启动引导扇区!
你必须跳过这个文本到真正的起点。
要么使用:
- 3 字节近跳转
- 一个 2 字节的短跳转后跟一个
nop
指令。
mov ch, 01 ;track to read
mov cl, 02 ;sector to read
mov dh, 01 ;head to read
如果要读取驱动器的第 2 个扇区,需要指定 Cylinder=0、Head=0 和 Sector=2
mov ch, 0 ;track to read
mov cl, 2 ;sector to read
mov dh, 0 ;head to read
您的引导消息可能不会显示,因为您没有设置 ES
段寄存器。鉴于 org 0x7C00
您需要设置 ES=0。你不能相信 BIOS 会为你做这件事。
您可能希望从程序中删除 int 20
指令。帮不了你。
与其使用 mov dl, 0
指定要加载的磁盘,不如使用 BIOS 首次调用引导扇区时获得的 DL
寄存器的内容。 像 DOSBOX 这样的模拟器可能会在这里使用一些特定的值!
由于其他答案中有很多问题没有涉及,我会提供一个新的答案。
我建议在另一个 中查看我的一般引导加载程序提示。特别是前几个技巧适用于此:
When the BIOS jumps to your code you can't rely on CS,DS,ES,SS,SP registers having valid or expected values. They should be set up appropriately when your bootloader starts. You can only be guaranteed that your bootloader will be loaded and run from physical address 0x00007c00 and that the boot drive number is loaded into the DL register.
The direction flag used by lodsb
, movsb
etc could be either set or cleared. If the direction flag is set improperly SI/DI registers may be adjusted in the wrong direction. Use STD
/CLD
to set it to the direction you wish (CLD=forward/STD=backwards). In this case the code assumes forward movement so one should use CLD
. More on this can be found in an instruction set reference
When jumping to a kernel it is generally a good idea to FAR JMP to it so that it properly sets CS:IP to expected values. This can avoid problems with kernel code that may do absolute near JMPs and CALLs within the same segment.
在您的代码中,您的引导加载程序应该在 SS:SP 中设置一个堆栈指针。将它放在引导加载程序下方是合理的 0x0000:0x7c00。你应该在销毁它之前保存 DL 寄存器,因为它包含引导驱动器号。您可以在开始时将其压入堆栈,并在设置访问的磁盘相关例程时恢复它 int 13h
。您不应该假设 ES 或 DS(特别是 DS)被设置为值0. 由于您使用 0x7c00 的 ORG,因此段需要 0x0000。 (0x0000<<4)+0x7c00 = 物理地址 0x07c00.
要解决这些问题,您可以在 start
标签后添加这些行:
start:
mov [bootdrv],dl;Save the boot drive passed in via DL to the bootloader
xor ax,ax ;Set ES and DS to zero since we use ORG 0x7c00
mov es,ax
mov ds,ax
mov ss,ax ;Set SS:SP to 0x0000:0x7c00 below bootloader
mov sp,0x7c00
cld ;Set direction flag forward
您需要在 msg
之后添加一个 bootdrv
变量
bootdrv: db 0
在使用 int 13h
磁盘读取功能之前,您现在可以使用 bootdrv
中的值并在发出中断调用之前将其放入 DL 中。此行应替换为:
mov dl, 00 ;drive number
有:
mov dl,[bootdrv];Get the boot drive saved at start of bootloader
在 jmp 0x5678:0x1234
之后,您的引导加载程序中有 int 20
。我相信你的意思是 int 20h。 JMP 永远不会 return 所以在它后面放置代码什么也做不了。但是,int 20h
是 DOS 中断,只有在 MS-DOS 系统从磁盘加载到内存后才可用。当然,您的磁盘上没有 MS-DOS。在引导加载程序(裸机)环境中根本不要使用 DOS 中断。
在 dt.asm
中,您遇到了一些问题。您 FAR JMP 到 0x5678:0x1234 处新加载的代码。在这样做时 CS 被设置为 0x5678。您需要手动设置 ES 和 DS,您可以通过复制 CS[=98= 中的值来完成此操作] 到 DS 和 ES。您还需要设置适当的 ORG。在这种情况下,原点是从段 (0x5678) 开始的 0x1234,因此您必须使用 org 0x1234
。 dt.asm
的顶部可以修改为:
BITS 16 ;Set code generation to 16 bit mode
ORG 0x1234 ;set origin point to 0x1234
mov ax, cs ;copy CS to DS and ES
;alternatively could have used mov ax, 0x5678
mov ds, ax
mov es, ax
startdt:
之前讨论的 int 20h
问题是 dt.asm
中的问题。删除它的所有匹配项。相反,您可以将处理器置于无限循环中。 dt.asm
中最后执行的代码是在 call dsptime
return 之后执行的。在那之后 CALL 你可以用这样的东西来无限循环:
jmp $
一个更可取的可以占用更少处理能力的无限循环是使用CLI, use a HLT指令关闭中断然后为了安全措施如果HLTreturns JMP 返回并再次执行 HLT(如果有 NMI Non-Maskable 中断可能会发生)。 HLT等待下一个中断发生。这是你经常看到的:
cli
endloop:
hlt
jmp endloop
其他观察结果
它出现在您将参数发布到 INT 13h/AH=2 disk read function were incorrect. Sector numbers start at 1 and heads and cylinders are zero based. The best source of interrupt information is Ralph Brown's Interrupt List 的代码的第一个版本中,其中涵盖了 BIOS 和 MS-DOS 中断。如果您需要有关中断参数的信息,这是一个很好的参考。
我建议 BOCHS 用于调试引导加载程序。它有一个命令行调试器,可以理解实模式寻址,可以用来观察指令的执行、设置断点、显示寄存器、检查内存等。
我的主引导记录代码:
;bit16 ; 16bit by default
org 0x7c00
jmp short start
nop
bsOEM db "OS423 v.0.1" ; OEM String
start:
;;cls
mov ah,06h ;Function 06h (scroll screen)
mov al,0 ;Scroll all lines
mov bh,0x0f ;Attribute (lightgreen on blue)
mov ch,0 ;Upper left row is zero
mov cl,0 ;Upper left column is zero
mov dh,24 ;Lower left row is 24
mov dl,79 ;Lower left column is 79
int 10h ;BIOS Interrupt 10h (video services)
;;print welcome msg
mov ah,13h ;Function 13h (display string), XT machine only
mov al,1 ;Write mode is zero: cursor stay after last char
mov bh,0 ;Use video page of zero
mov bl,0x0f ;Attribute (lightgreen on blue)
mov cx,mlen ;Character string length
mov dh,0 ;Position on row 0
mov dl,0 ;And column 0
lea bp,[msg] ;Load the offset address of string into BP, es:bp
;Same as mov bp, msg
int 10h
;;load sector into memory & 5678h:1234h
mov bx, 0x5678 ;segmented address
mov es, bx ;move segemented address to es
mov bx,0x1234 ;base address to bx
mov ah, 02 ;function read sectors
mov al, 01 ;# of sectors to load
mov ch, 00 ;track to read
mov cl, 02 ;sector to read
mov dh, 00 ;head to read
mov dl, 00 ;drive number
int 0x13 ;call interrupt 13
jmp 0x5678:0x1234 ;jump to memory address
int 20
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;variables;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
msg: db 'Welcome to Pradox OS 0.1! Authored by Jiansong he', 10, 13, '$'
mlen equ $-msg
padding times 510-($-$$) db 0 ;to make MBR 512 bytes
bootSig db 0x55, 0xaa ;signature (optional)
我的 nasm 编译二进制文件并将其放入我的 .img 软盘的终端命令:
line1: 定义一个软盘,名称为boot.img,块大小512字节,一共2880字节
line2: 使用nasm编译器,将mbr.asm文件编译成二进制格式,存放在名为mbr.bin的文件中(这是我的主引导记录)
第 3 行:在 dt.bin
将 dt.asm 编译成二进制文件line4:将mbr.bin的内容放入boot.img,块大小512,共放入1个块
第 5 行:将 dt.bin 的内容放入 boot.img,块大小 512,物理扇区 #2(逻辑扇区 #1)
dd if=/dev/zero of=boot.img bs=512 count=2880
nasm -f bin mbr.asm -o mbr.bin
nasm -f bin dt.asm -o dt.bin
dd if=mbr.bin of=boot.img bs=512 count=1 conv=notrunc
dd if=dt.bin of=boot.img bs=512 seek=1 count=1 conv=notrunc
dt.asm中的代码:
[BITS 16] ;Set code generation to 16 bit mode
ORG 0x5647:0x1234 ;set addressing to begin at 579b4H
startdt:
;call cls ;call routine to clear screen
;call dspmsg ;call routine to display message
call date
call cvtmo
call cvtday
call cvtcent
call cvtyear
call dspdate
call time
call cvthrs
call cvtmin
call cvtsec
call dsptime
int 20h ;halt operation (VERY IMPORTANT!!!)
cls:
mov ah,06h ;function 06h (Scroll Screen)
mov al,0 ;scroll all lines
mov bh,0x0f ;Attribute (bright white on blue)
mov ch,0 ;Upper left row is zero
mov cl,0 ;Upper left column is zero
mov dh,24 ;Lower left row is 24
mov dl,79 ;Lower left column is 79
int 10H ;BIOS Interrupt 10h (video services)
ret
dspmsg:
mov ah,13h ;function 13h (Display String)
mov al,1 ;Write mode is zero
mov bh,0 ;Use video page of zero
mov bl,0x0a ;Attribute (bright white on bright blue)
mov cx,mlen2 ;Character length
mov dh,0 ;position on row 0
mov dl,0 ;and column 0
lea bp,[welcom] ;load the offset address of string into BP
int 10H
ret
welcom: db 'jiansong Hes first Operating System :D',10,13,'$'
mlen2 equ $-welcom;
date:
;Get date from the system
mov ah,04h ;function 04h (get RTC date)
int 1Ah ;BIOS Interrupt 1Ah (Read Real Time Clock)
ret
;CH - Century
;CL - Year
;DH - Month
;DL - Day
cvtmo:
;Converts the system date from BCD to ASCII
mov bh,dh ;copy contents of month (dh) to bh
shr bh,1
shr bh,1
shr bh,1
shr bh,1
add bh,30h ;add 30h to convert to ascii
mov [dtfld],bh
mov bh,dh
and bh,0fh
add bh,30h
mov [dtfld + 1],bh
ret
cvtday:
mov bh,dl ;copy contents of day (dl) to bh
shr bh,1
shr bh,1
shr bh,1
shr bh,1
add bh,30h ;add 30h to convert to ascii
mov [dtfld + 3],bh
mov bh,dl
and bh,0fh
add bh,30h
mov [dtfld + 4],bh
ret
cvtcent:
mov bh,ch ;copy contents of century (ch) to bh
shr bh,1
shr bh,1
shr bh,1
shr bh,1
add bh,30h ;add 30h to convert to ascii
mov [dtfld + 6],bh
mov bh,ch
and bh,0fh
add bh,30h
mov [dtfld + 7],bh
ret
cvtyear:
mov bh,cl ;copy contents of year (cl) to bh
shr bh,1
shr bh,1
shr bh,1
shr bh,1
add bh,30h ;add 30h to convert to ascii
mov [dtfld + 8],bh
mov bh,cl
and bh,0fh
add bh,30h
mov [dtfld + 9],bh
ret
dtfld: db '00/00/0000'
dspdate:
;Display the system date
mov ah,13h ;function 13h (Display String)
mov al,0 ;Write mode is zero
mov bh,0 ;Use video page of zero
mov bl,0x0f ;Attribute
mov cx,10 ;Character string is 10 long
mov dh,4 ;position on row 4
mov dl,0 ;and column 28
push ds ;put ds register on stack
pop es ;pop it into es register
lea bp,[dtfld] ;load the offset address of string into BP
int 10H
ret
time:
;Get time from the system
mov ah,02h
int 1Ah
ret
;CH - Hours
;CL - Minutes
;DH - Seconds
cvthrs:
;Converts the system time from BCD to ASCII
mov bh,ch ;copy contents of hours (ch) to bh
shr bh,1
shr bh,1
shr bh,1
shr bh,1
add bh,30h ;add 30h to convert to ascii
mov [tmfld],bh
mov bh,ch
and bh,0fh
add bh,30h
mov [tmfld + 1],bh
ret
cvtmin:
mov bh,cl ;copy contents of minutes (cl) to bh
shr bh,1
shr bh,1
shr bh,1
shr bh,1
add bh,30h ;add 30h to convert to ascii
mov [tmfld + 3],bh
mov bh,cl
and bh,0fh
add bh,30h
mov [tmfld + 4],bh
ret
cvtsec:
mov bh,dh ;copy contents of seconds (dh) to bh
shr bh,1
shr bh,1
shr bh,1
shr bh,1
add bh,30h ;add 30h to convert to ascii
mov [tmfld + 6],bh
mov bh,dh
and bh,0fh
add bh,30h
mov [tmfld + 7],bh
ret
tmfld: db '00:00:00'
dsptime:
;Display the system time
mov ah,13h ;function 13h (Display String)
mov al,0 ;Write mode is zero
mov bh,0 ;Use video page of zero
mov bl,0x0f;Attribute
mov cx,8 ;Character string is 8 long
mov dh,5 ;position on row 5
mov dl,0;and column 0
push ds ;put ds register on stack
pop es ;pop it into es register
lea bp,[tmfld] ;load the offset address of string into BP
int 10H
ret
int 20H
我的测试环境是 dosbox,我可以在屏幕上成功显示欢迎消息,但无法将另一个扇区加载到从 0x5647:0x1234 开始的内存中 谢谢
足够简单。
您不能仅使用 OEM 字符串启动引导扇区!
你必须跳过这个文本到真正的起点。
要么使用:
- 3 字节近跳转
- 一个 2 字节的短跳转后跟一个
nop
指令。
mov ch, 01 ;track to read mov cl, 02 ;sector to read mov dh, 01 ;head to read
如果要读取驱动器的第 2 个扇区,需要指定 Cylinder=0、Head=0 和 Sector=2
mov ch, 0 ;track to read
mov cl, 2 ;sector to read
mov dh, 0 ;head to read
您的引导消息可能不会显示,因为您没有设置 ES
段寄存器。鉴于 org 0x7C00
您需要设置 ES=0。你不能相信 BIOS 会为你做这件事。
您可能希望从程序中删除 int 20
指令。帮不了你。
与其使用 mov dl, 0
指定要加载的磁盘,不如使用 BIOS 首次调用引导扇区时获得的 DL
寄存器的内容。 像 DOSBOX 这样的模拟器可能会在这里使用一些特定的值!
由于其他答案中有很多问题没有涉及,我会提供一个新的答案。
我建议在另一个
When the BIOS jumps to your code you can't rely on CS,DS,ES,SS,SP registers having valid or expected values. They should be set up appropriately when your bootloader starts. You can only be guaranteed that your bootloader will be loaded and run from physical address 0x00007c00 and that the boot drive number is loaded into the DL register.
The direction flag used by
lodsb
,movsb
etc could be either set or cleared. If the direction flag is set improperly SI/DI registers may be adjusted in the wrong direction. UseSTD
/CLD
to set it to the direction you wish (CLD=forward/STD=backwards). In this case the code assumes forward movement so one should useCLD
. More on this can be found in an instruction set referenceWhen jumping to a kernel it is generally a good idea to FAR JMP to it so that it properly sets CS:IP to expected values. This can avoid problems with kernel code that may do absolute near JMPs and CALLs within the same segment.
在您的代码中,您的引导加载程序应该在 SS:SP 中设置一个堆栈指针。将它放在引导加载程序下方是合理的 0x0000:0x7c00。你应该在销毁它之前保存 DL 寄存器,因为它包含引导驱动器号。您可以在开始时将其压入堆栈,并在设置访问的磁盘相关例程时恢复它 int 13h
。您不应该假设 ES 或 DS(特别是 DS)被设置为值0. 由于您使用 0x7c00 的 ORG,因此段需要 0x0000。 (0x0000<<4)+0x7c00 = 物理地址 0x07c00.
要解决这些问题,您可以在 start
标签后添加这些行:
start:
mov [bootdrv],dl;Save the boot drive passed in via DL to the bootloader
xor ax,ax ;Set ES and DS to zero since we use ORG 0x7c00
mov es,ax
mov ds,ax
mov ss,ax ;Set SS:SP to 0x0000:0x7c00 below bootloader
mov sp,0x7c00
cld ;Set direction flag forward
您需要在 msg
bootdrv
变量
bootdrv: db 0
在使用 int 13h
磁盘读取功能之前,您现在可以使用 bootdrv
中的值并在发出中断调用之前将其放入 DL 中。此行应替换为:
mov dl, 00 ;drive number
有:
mov dl,[bootdrv];Get the boot drive saved at start of bootloader
在 jmp 0x5678:0x1234
之后,您的引导加载程序中有 int 20
。我相信你的意思是 int 20h。 JMP 永远不会 return 所以在它后面放置代码什么也做不了。但是,int 20h
是 DOS 中断,只有在 MS-DOS 系统从磁盘加载到内存后才可用。当然,您的磁盘上没有 MS-DOS。在引导加载程序(裸机)环境中根本不要使用 DOS 中断。
在 dt.asm
中,您遇到了一些问题。您 FAR JMP 到 0x5678:0x1234 处新加载的代码。在这样做时 CS 被设置为 0x5678。您需要手动设置 ES 和 DS,您可以通过复制 CS[=98= 中的值来完成此操作] 到 DS 和 ES。您还需要设置适当的 ORG。在这种情况下,原点是从段 (0x5678) 开始的 0x1234,因此您必须使用 org 0x1234
。 dt.asm
的顶部可以修改为:
BITS 16 ;Set code generation to 16 bit mode
ORG 0x1234 ;set origin point to 0x1234
mov ax, cs ;copy CS to DS and ES
;alternatively could have used mov ax, 0x5678
mov ds, ax
mov es, ax
startdt:
之前讨论的 int 20h
问题是 dt.asm
中的问题。删除它的所有匹配项。相反,您可以将处理器置于无限循环中。 dt.asm
中最后执行的代码是在 call dsptime
return 之后执行的。在那之后 CALL 你可以用这样的东西来无限循环:
jmp $
一个更可取的可以占用更少处理能力的无限循环是使用CLI, use a HLT指令关闭中断然后为了安全措施如果HLTreturns JMP 返回并再次执行 HLT(如果有 NMI Non-Maskable 中断可能会发生)。 HLT等待下一个中断发生。这是你经常看到的:
cli
endloop:
hlt
jmp endloop
其他观察结果
它出现在您将参数发布到 INT 13h/AH=2 disk read function were incorrect. Sector numbers start at 1 and heads and cylinders are zero based. The best source of interrupt information is Ralph Brown's Interrupt List 的代码的第一个版本中,其中涵盖了 BIOS 和 MS-DOS 中断。如果您需要有关中断参数的信息,这是一个很好的参考。
我建议 BOCHS 用于调试引导加载程序。它有一个命令行调试器,可以理解实模式寻址,可以用来观察指令的执行、设置断点、显示寄存器、检查内存等。