我的主引导记录代码:;bit16 ; 16bit by default org 0x7c00 jmp short start nopbsOEM db "OS423 v.0.1" ; OEM Stringstart:;;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 $-msgpadding times 510-($-$$) db 0 ;to make MBR 512 bytesbootSig db 0x55, 0xaa ;signature (optional)我的用于nasm编译并将二进制文件放入.img软盘的终端命令:line1:定义一个名为boot.img的软盘,块大小为512字节,共2880字节第2行:使用nasm编译器,将mbr.asm文件编译为二进制格式,并将其存储在名为mbr.bin的文件中(这是我的主引导记录)第3行:在dt.bin上将dt.asm编译为二进制第4行:将mbr.bin的内容放入boot.img中,块大小为512,总共放入1个块第5行:将dt.bin的内容放入boot.img,块大小为512,位于物理扇区2(逻辑扇区1)dd if=/dev/zero of=boot.img bs=512 count=2880nasm -f bin mbr.asm -o mbr.binnasm -f bin dt.asm -o dt.bindd if=mbr.bin of=boot.img bs=512 count=1 conv=notruncdd if=dt.bin of=boot.img bs=512 seek=1 count=1 conv=notruncdt.asm中的代码:[BITS 16] ;Set code generation to 16 bit modeORG 0x5647:0x1234 ;set addressing to begin at 579b4Hstartdt: ;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) retdspmsg: 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 retwelcom: db 'jiansong Hes first Operating System :D',10,13,'$'mlen2 equ $-welcom;date:;Get date from the systemmov ah,04h ;function 04h (get RTC date)int 1Ah ;BIOS Interrupt 1Ah (Read Real Time Clock)ret;CH - Century;CL - Year;DH - Month;DL - Daycvtmo:;Converts the system date from BCD to ASCIImov bh,dh ;copy contents of month (dh) to bhshr bh,1shr bh,1shr bh,1shr bh,1add bh,30h ;add 30h to convert to asciimov [dtfld],bhmov bh,dhand bh,0fhadd bh,30hmov [dtfld + 1],bhretcvtday:mov bh,dl ;copy contents of day (dl) to bhshr bh,1shr bh,1shr bh,1shr bh,1add bh,30h ;add 30h to convert to asciimov [dtfld + 3],bhmov bh,dland bh,0fhadd bh,30hmov [dtfld + 4],bhretcvtcent:mov bh,ch ;copy contents of century (ch) to bhshr bh,1shr bh,1shr bh,1shr bh,1add bh,30h ;add 30h to convert to asciimov [dtfld + 6],bhmov bh,chand bh,0fhadd bh,30hmov [dtfld + 7],bhretcvtyear:mov bh,cl ;copy contents of year (cl) to bhshr bh,1shr bh,1shr bh,1shr bh,1add bh,30h ;add 30h to convert to asciimov [dtfld + 8],bhmov bh,cland bh,0fhadd bh,30hmov [dtfld + 9],bhretdtfld: db '00/00/0000'dspdate:;Display the system datemov ah,13h ;function 13h (Display String)mov al,0 ;Write mode is zeromov bh,0 ;Use video page of zeromov bl,0x0f ;Attributemov cx,10 ;Character string is 10 longmov dh,4 ;position on row 4mov dl,0 ;and column 28push ds ;put ds register on stackpop es ;pop it into es registerlea bp,[dtfld] ;load the offset address of string into BPint 10Hrettime:;Get time from the systemmov ah,02hint 1Ahret;CH - Hours;CL - Minutes;DH - Secondscvthrs:;Converts the system time from BCD to ASCIImov bh,ch ;copy contents of hours (ch) to bhshr bh,1shr bh,1shr bh,1shr bh,1add bh,30h ;add 30h to convert to asciimov [tmfld],bhmov bh,chand bh,0fhadd bh,30hmov [tmfld + 1],bhretcvtmin:mov bh,cl ;copy contents of minutes (cl) to bhshr bh,1shr bh,1shr bh,1shr bh,1add bh,30h ;add 30h to convert to asciimov [tmfld + 3],bhmov bh,cland bh,0fhadd bh,30hmov [tmfld + 4],bhretcvtsec:mov bh,dh ;copy contents of seconds (dh) to bhshr bh,1shr bh,1shr bh,1shr bh,1add bh,30h ;add 30h to convert to asciimov [tmfld + 6],bhmov bh,dhand bh,0fhadd bh,30hmov [tmfld + 7],bhrettmfld: db '00:00:00'dsptime:;Display the system timemov ah,13h ;function 13h (Display String)mov al,0 ;Write mode is zeromov bh,0 ;Use video page of zeromov bl,0x0f;Attributemov cx,8 ;Character string is 8 longmov dh,5 ;position on row 5mov dl,0;and column 0push ds ;put ds register on stackpop es ;pop it into es registerlea bp,[tmfld] ;load the offset address of string into BPint 10Hretint 20H我的测试环境是dosbox,我可以在屏幕上成功显示欢迎消息,但是无法将另一个扇区从0x5647:0x1234开始加载到内存中谢谢 最佳答案 由于其他答案中未涵盖许多问题,因此我将提供一个新答案。我建议在其他Stackoverflow answer中查看我的General Bootloader提示。特别是前几个技巧在这里适用: 在代码中, bootstrap 应在SS:SP中设置堆栈指针。将其放置在引导加载程序的正下方是合理的,即0x0000:0x7c00。您应该在销毁DL寄存器之前保存它,因为它包含启动驱动器号。您可以在开始时将其压入堆栈,并在设置与磁盘相关的例程 int 13h 时将其还原。您不应假定ES或DS(尤其是DS)的值设置为0。由于您使用的ORG为0x7c00,因此分段需要为0x0000。 (0x0000 要解决这些问题,您可以在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拥有bootdrv后,您需要添加一个msg变量bootdrv: db 0在使用int 13h磁盘读取功能之前,现在可以在发出中断调用之前使用bootdrv中的值并将其放入DL中。此行应替换为:mov dl, 00 ;drive number带有:mov dl,[bootdrv];Get the boot drive saved at start of bootloader在 bootstrap 中,在int 20之后有jmp 0x5678:0x1234。我相信您的意思是int 20h。 JMP将永远不会返回,因此在它后面放置代码将无济于事。但是,int 20h是DOS中断,仅在MS-DOS系统从磁盘加载到内存后才可用。您的磁盘上当然没有MS-DOS。在引导加载程序(裸机)环境中,根本不使用DOS中断。在dt.asm中,您遇到了一些问题。您将JMP FAR到新加载的代码0x5678:0x1234。这样做,CS设置为0x5678。您需要手动设置ES和DS,可以通过将CS中的值复制到DS和ES来实现。您还需要设置适当的ORG。在这种情况下,原点是从片段开头(0x5678)开始的0x1234,因此您必须使用org 0x1234。 dt.asm的顶部可以修改为:BITS 16 ;Set code generation to 16 bit modeORG 0x1234 ;set origin point to 0x1234mov ax, cs ;copy CS to DS and ES ;alternatively could have used mov ax, 0x5678mov ds, axmov es, axstartdt:前面讨论的int 20h问题是dt.asm中的问题。删除所有出现的事件。相反,您可以将处理器置于无限循环中。在dt.asm返回之后,在call dsptime中执行的最后一个代码。调用之后,您可以使用以下内容进行无限循环: jmp $更可取的,可能需要较少处理能力的无限循环是使用CLI关闭中断,使用HLT指令,然后为了安全起见,如果HLT返回JMP并再次执行HLT(如果存在NMI不可屏蔽中断,则可能发生)。 HLT等待直到下一个中断发生。这是您经常看到的: cliendloop: hlt jmp endloop其他观察它出现在您发布到INT 13h/AH=2磁盘读取功能的参数不正确的代码的第一版中。扇区号从1开始,磁头和磁柱从零开始。中断信息的最佳来源是Ralph Brown's Interrupt List,它涵盖了BIOS和MS-DOS中断。如果您需要有关中断参数的信息,这是一个很好的引用。我建议使用BOCHS调试引导加载程序。它具有一个命令行调试器,该调试器了解实模式寻址,可用于在执行指令时观察指令,设置断点,显示寄存器,检查内存等。关于linux - 加载引导加载程序的第二阶段和/或将控制转移到第二阶段时出现问题,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/41795817/ 10-12 19:57