【问题标题】:Boot loader always messes up the first two bytes of Int 13h call to load kernel引导加载程序总是弄乱 Int 13h 调用以加载内核的前两个字节
【发布时间】:2012-06-29 06:07:41
【问题描述】:

Here's 我的引导加载程序代码,here's 显示寄存器图片的文档(以防我做错了什么很重要),内存中位置 0x10000 的内容(我告诉引导loader 来加载内核),我的内核的源程序集,以及 Qemu 运行时的屏幕输出。

kernelStub.bin 一开始就有EB 1B(右跳转命令)。 hda.img 在第二个扇区开始的 55 AA 之后有 EB 1B。进位标志在我的 load_mem 子例程中很清楚,表明它认为负载是好的。除了前两个总是 63 61 之外,所有字节都在内存中。

为什么 load_mem 例程总是错误地将扇区 2 的前两个字节加载到地址 0x10000 中,然后将其余部分正确?

引导加载程序代码:

更新:根据 Matthew Slattery 的更正,将 jmp SYSADDR:0000 更改为 jmp 0x1000:0x0000

;Very minimal boot loader 
BITS 16                ;Tell assembler to use 16-bit mode
jmp start              ;Jump over defines
SYSADDR  dw 0x1000     ;Load system at 0x10000
DRIVENUM db 0x80       ;Variable for drive number
HEADNUM  db 0
CYLNUM   db 0          ;Low bits of cylinder number
SECTNUM  db 2          ;Bits 6 and 7 high bits of cylinder number (0),
                       ;Bits 0-5 starting sector number (2)
NUMKERNELSECTS db 0x01 ;Will Probably Change! Number of sectors
                       ;to read from disk
load_msg    db 'Loading OS', 0
msg_2       db 'carry flag not clear', 0
load_worked db 'Load worked', 0

start:
    mov ax, 0x07C0     ;Set data segment to where BIOS loaded boot loader
    mov ds, ax
    mov si, load_msg   ;Simple text string to indicate loading
    call show_message
    call load_mem      ;Subroutine to load bytes from disk to location
                       ;pointed to by es
    jmp 0x1000:0x0000

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Subroutines

;;;Show Message;;;
show_message:
    mov ah, 0x0E       ;int 0x10 print character to screen function
.repeat:
    lodsb              ;Get char pointed to by si, puts in al
    cmp al, 0          ;see if char is 0 (null)
    je .done           ;null signifies done
    int 0x10           ;If not null, print to screen
    jmp .repeat        ;Get next char

.done:
    ret

;;;Load Memory;;;
load_mem:
    xor ah, ah         ;ah=0, reset drive
    int 0x13           ;Call drive reset

    mov ax, [SYSADDR]
    mov es, ax         ;Destination- es:bx
    mov bx, 0
    mov dl, [DRIVENUM]
    mov dh, [HEADNUM]
    mov al, [NUMKERNELSECTS]
    mov ch, [CYLNUM]
    mov cl, [SECTNUM]
    mov ah, 0x02       ;ah=2, read drive
    int 0x13           ;Call read interrupt
    jnc exit           ;If carry flag is clear, exit

exit:
    ret

times 510 - ($-$$) db 0;Pad sector with 0
dw 0xAA55              ;Boot signature

【问题讨论】:

  • 请在此处包含您的代码,以免将来更改或丢失。

标签: assembly bootloader bios


【解决方案1】:
SYSADDR  dw 0x1000    ;Load system at 0x10000
...
jmp SYSADDR:0000

没有做你想做的事。 SYSADDR 是您想要的值的位置(此处为0x0002),而不是值本身。

我认为执行0x0002:0000 的任何内容(甚至不是真正的代码;它是中断向量表的一部分)会导致您的数据被乱写。

(顺便说一句,至少还有一个问题:第二个链接文档中的内核存根代码没有重置ds。)


编辑:

我看到你现在已经完成了这项工作,但为了完整起见,我有一个 结果,对这两个字节中的神秘值的完整解释 jmp SYSADDR:0000 的错误:

0002:0000,即地址0x20,是INT 08h的向量。

INT 08h 处理程序的传统入口点地址是f000:fea5(BIOSes 倾向于保持传统,以便与使用 直接入口点)。所以这个地址的字节几乎肯定会 是a5 fe 00 f0 ...

如果您将这些字节中的第一个字节 a5 作为代码执行,则它是 movsw 指令,它将两个字节从ds:si复制到es:di

  • ds 仍然是引导加载程序的数据段
  • si 指向 msg_2 的开头(您的 show_message 例程在哪里 打印后留下load_msg)
  • es 仍然是 0x1000
  • di 大概包含 0

所以在jmp 0x0002:0000 之后发生的第一件事就是 camsg_2 开始被复制到前两个字节 加载的扇区。

【讨论】:

  • 我还尝试了 jmp 0x1000:0x0000 仍然无法正常工作,因为即使我跳到那里,EB 1B 的正确跳转也不在地址 0x10000 处。感谢ds的更正。
  • 非常整洁。现在我知道那些神秘价值是从哪里来的了。谢谢!
【解决方案2】:

我找到了关于获得内核第一次跳转的问题的关键细节here。我不知道用nop 跟随简短的jmp 是多么必要(至少有一些BIOS)。

一旦我将nops 放入并设置了我的ds 寄存器,它终于起作用了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-09-10
    • 1970-01-01
    • 2020-05-31
    • 2021-10-12
    • 2015-01-19
    • 2015-06-02
    • 2015-07-16
    • 1970-01-01
    相关资源
    最近更新 更多