assembly 我的 Boot 扇区试图从另一个扇区加载代码并执行它,但它却锁定了,发生了什么问题?

qoefvg9y  于 7个月前  发布在  其他
关注(0)|答案(2)|浏览(71)

为了学习,我已经考虑制作一个小型操作系统,现在正在使用引导装载程序。我希望能够使用int 0x13从软盘驱动器读取扇区,将它们放入内存,然后跳转到该代码。以下是我到目前为止所做的:

org 0x7c00
bits 16

main:
    call setup_segments

    mov ah, 2      ; function
    mov al, 1      ; num of sectors
    mov ch, 1      ; cylinder
    mov cl, 2      ; sector
    mov dh, 0      ; head
    mov dl, 0      ; drive
    mov bx, 0x1000 ;
    mov es, bx     ; dest (segment)
    mov bx, 0      ; dest (offset)
    int 0x13       ; BIOS Drive Interrupt

    jmp 0x1000:0   ; jump to loaded code

times 510 - ($-$$) db 0 ; fluff up program to 510 B
dw 0xAA55               ; boot loader signature



LoadTarget: ; Print Message, Get Key Press, Reboot

jmp new_main

Greeting: db "Hello, welcome to the bestest bootloader there ever was!", 0
Prompt:   db "Press any key to reboot...", 0

Println:
    lodsb ; al <-- [ds:si], si++

    or al, al    ; needed for jump ?
    jz PrintNwl  ; if null is found print '\r\n'
    mov ah, 0x0e ; function
    mov bh, 0    ; page number ?
    mov bl, 7    ; text attribute ?
    int 0x10     ; BIOS Interrupt
    jmp Println

PrintNwl: ; print \r\n
    ; print \r
    mov ah, 0x0e ; function
    mov al, 13   ; char (carriage return)
    mov bh, 0    ; page number ?
    mov bl, 7    ; text attribute ?
    int 0x10

    ; print \n
    mov ah, 0x0e ; function
    mov al, 20   ; char (line feed)
    mov bh, 0    ; page number ?
    mov bl, 7    ; text attribute ?
    int 0x10

    ret          ; return

GetKeyPress:
    mov si, Prompt ; load prompt
    call Println   ; print prompt

    xor ah, ah     ; clear ah
    int 0x16       ; BIOS Keyboard Service

    ret            ; return

setup_segments:
    cli ;Clear interrupts
    ;Setup stack segments
    mov ax,cs
    mov ds,ax
    mov es,ax
    mov ss,ax
    sti ;Enable interrupts

    ret

new_main:
    call setup_segments

    mov si, Greeting ; load greeting
    call Println     ; print greeting

    call GetKeyPress ; wait for key press

    jmp 0xffff:0     ; jump to reboot address

times 1024 - ($-$$) db 0 ; fluff up sector

字符串
我想加载LoadTarget后的扇区到地址0x1000:0,然后跳转到它.到目前为止,我只是得到一个空白的屏幕.我觉得这个错误是在main和线times 510 - ($-$$) db 0之间的某个地方.也许我只是没有得到寄存器的值的权利?请帮助!谢谢

fruv7luv

fruv7luv1#

你应该把第一个call setup_segments替换为实际的指令,同样,Jester指出,在改变SS寄存器的时候,总是更新SP寄存器。
当前您正在从1号气缸阅读。它应该是0号气缸。
Linefeed的代码是10(不是你写的20)。
PrintNwl 中的两个BIOS调用都不需要BL寄存器,因为CR和LF都是不可显示的asynchrons。

rmbxnbpk

rmbxnbpk2#

使用ORG 0x7C00意味着您希望CS:IP对或寄存器保存0000 h:7 C 00 h。请记住,BIOS已经将1024字节长的程序的前512字节放在线性地址00007 C 00 h。
设置其他段寄存器只是把CS复制到DS、ES和SS中的问题。但非常重要的是,每次更改SS时,您都必须同时更改SP,以保持一对连贯的SS:SP寄存器。在您的程序中,堆栈的一个方便位置应该在程序下方,因此我用7 C 00 h设置SP寄存器。您不能在子程序中摆弄SS:SP(就像您所做的那样),因为最后的RET不知道返回到哪里!
当你从软盘加载第二个扇区时,它必须来自柱面0。在CHS表示中,柱面和磁头从0开始,扇区从1开始。
如果你检查CF以确保手术成功,那就太好了。
通过jmp 0x1000:0不能跳转到加载的代码,因为现在在那里的代码是用ORG 0x7C00指令编译的程序的一部分。你需要对此进行补偿!
1.补偿ORG 0x7C00指令。从段部分减去07 C 0 h,在偏移部分加上7 C 00 h。=> jmp 0840h:7C00h
1.补偿 LoadTarget 标签在 * 程序内偏移512 * 的事实。从段部分减去0020 h,向偏移部分添加0200 h。=> jmp 0820h:7E00h
下面是初始代码的样子

org 7C00h
 bits 16
main:
 mov ax,cs
 mov ds,ax  <-- Not necessary at this stage in this program
 mov es,ax  <-- (keep them should you display a message on error)
 cli
 mov ss,ax
 mov sp,7C00h
 sti
 mov ax,0201h
 mov cx,0002h
 mov dx,0000h
 mov bx,1000h
 mov es,bx
 mov bx,0000h
 int 13h
 jc  Error
 jmp 0820h:7E00h
Error:
 hlt

字符串
一旦第二阶段运行,您只需要设置DS和ES寄存器。CS:IP通过JMP设置,SS:SP继续。

...
new_main:
 push cs
 pop  ds
 push cs
 pop  es
 mov  si,Greeting
 call Println
 ...

相关问题