添加此行后,为什么我的bootloader会崩溃?

时间:2016-09-01 21:51:33

标签: assembly x86 bootloader osdev

我正在关注Nick Blundell的启动扇区编程教程(https://www.cs.bham.ac.uk/~exr/lectures/opsys/10_11/lectures/os-dev.pdfhttps://www.youtube.com/watch?v=YvZhgRO7hL4)。我的代码在我的qemu模拟器中运行得很好,但是当我在物理机器上运行它时,每当我开始引用段寄存器时它都会崩溃。    我在学校的老师不熟悉低级编程,无法帮助我。这是我的bootloader,在这里我注释了导致它崩溃的字符串CRASH(注意:当我说崩溃时,它实际上只是从下一个磁盘加载我的操作系统。我从外部加载此代码硬盘):

[bits 16]
[org 0x7c00]        

mov bp, 0xffff
mov sp, bp
mov ax, 0x0000
mov ds, ax
;; mov es, ax ;; CRASH
;; mov ss, ax ;; CRASH

mov si, BOOT_MSG
call print_string
call print_newline

mov si, INIT_SEG_MSG
call print_string
call print_newline

;; mov dx, ds ;; CRASH
;; call print_hex
;; call print_newline

;;mov dx, cs ;; CRASH
;;call print_hex
;;call print_newline

;;mov dx, es ;; CRASH
;;call print_hex
;;call print_newline

;;mov dx, ss ;; CRASH
;;call print_hex
;;call print_newline

;; mov dl, 0x80         ;; disk where kernel is
;; mov cl, 3            ;; start sect
;; mov al, 1            ;; num sect
;; mov bx, 0x7ef0       ;; RAM addr
;; call load_kernel

;; mov si, KERN_MSG
;; call print_string
;; call print_newline

;;  call switch_to_pm

jmp $

%include "print.asm"
%include "print_hex.asm"
%include "disk.asm"
%include "pm.asm"

[bits 32]
pm :
    mov esi, PM_MSG
    call print_string_pm
    jmp 0x7ef0
    jmp $
[bits 16]

BOOT_MSG : db 'booted 16-bit to 0x7c00',0
KERN_MSG : db 'loaded kernel to es 0x7ef0',0
PM_MSG : db 'switched to 32-bit mode',0
INIT_SEG_MSG : db 'init segment registers',0

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

我确信我有一个根本的误解,任何帮助将不胜感激。这是我的打印例程:

print_string :
    push ax
    _loop :
        lodsb
        cmp al, 0
        je _end

        mov ah, 0x0e
        int 0x10
        jmp _loop
    _end :
        pop ax
        ret

print_hex :
    mov si, HEX_TEMPLATE

    mov bx, dx
    shr bx, 12
    mov bx, [bx+HEXABET]
    mov [HEX_TEMPLATE+2], bl

    mov bx, dx      ;; bx -> 0x1234
    shr bx, 8       ;; bx -> 0x0012
    and bx, 0x000f  ;; bx -> 0x0002
    mov bx, [bx+HEXABET]
    mov [HEX_TEMPLATE+3], bl

    mov bx, dx      
    shr bx, 4
    and bx, 0x00f   
    mov bx, [bx+HEXABET]
    mov [HEX_TEMPLATE+4], bl

    mov bx, dx      
    and bx, 0x0f    
    mov bx, [bx+HEXABET]
    mov [HEX_TEMPLATE+5], bl

    call print_string
    ret 

    HEX_TEMPLATE : db '0x???? ',0
    HEXABET : db '0123456789abcdef'

print_newline :
    pusha
    mov ah, 0x0e
    mov al, 0x0d
    int 0x10
    mov al, 0x0a
    int 0x10
    popa
    ret

2 个答案:

答案 0 :(得分:1)

BIOS的特点是CS的状态未知。在Bochs中,可能Qemu CS = 0,因此原点为0x7C00的代码将起作用。实际硬件可能会传递CS = 0x7C0,因此在代码调用开始时没有适当的远程跳转到接近绝对函数的调用将被0x7C00字节偏移,并且原点设置为0x7C00。

解决方案:

    org    0x7C00

    jmp    0:Begin                   ; Far jump so CS = 0
Begin:
    mov    ax, cs
    mov    ds, ax
    mov    es, ax

    org    0
    jmp    0x7C0:0                   ; Far jump so CS = 0x7C0

这可能是正在发生的事情,崩溃即将来临@ call print_string,它实际上正在寻找代码@ 0xF8 ??。

答案 1 :(得分:1)

所以在许多硬重置之后,我找到了解决方案。问题是,我认为是问题,不是问题。所以我决定把我的闪存驱动器从我父亲的电脑上启动。它工作得很好。所以我继续在我自己的电脑上写我的bootloader。我写了代码进入PM模式,运行它,完美,没有问题。然后我做了另一个改变。使用dd将字节复制到闪存驱动器,然后在我爸爸的电脑上运行它。可是等等。这个改变没有出现......所以我跑了几次dd,将驱动器归零,但仍然没有。所以我重新启动了我的计算机,RAN DD再次,并且它工作了。 问题似乎是我的操作系统(Ubuntu 16,不确定它是否相关)发布dd命令的方式。似乎/ dev / sdb是一种实际上没有写入磁盘的缓冲区,至少在我第一次移除闪存驱动器之后。也许这是操作系统中的一个错误。也许这是dd中的一个bug。也许我错过了什么。谁知道呢。问题(如评论中所述)是我不知道Linux块设备如何工作。见:sync。显然,我所做的更改是CACHED而不是写入。无论哪种方式,我将从现在开始使用模拟器。谢谢大家!