Bootloader执行失败

时间:2015-09-02 18:42:34

标签: assembly nasm bootloader

我正在尝试编写加载下一个扇区的bootloader,并在启用a20后跳转执行它并进入保护模式。我创建了这段代码:

;NOTE: Im assuming that dl is hard drive number when executing bootloader
org 0x7C00    
bits 16
jmp 0:kernel_load
;setup gdt
gdt_start:

gdt_null:
    dd 0x0
    dd 0x0

gdt_code:
    dw 0xffff
    dw 0x0
    db 0x0
    db 10011010b
    db 11001111b
    db 0x0

gdt_data:
    dw 0xffff
    dw 0x0
    db 0x0
    db 10010010b
    db 11001111b
    db 0x0

gdt_end:

gdt_descriptor:
    dw gdt_end - gdt_start
    dd gdt_start

CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start
kernel_load:
;load kernel
reset:
    mov ah,0
    int 0x13
    jc reset
    mov ax,0x7E00
    mov es,ax
    xor bx,bx
read:
    mov ah,0x02
    mov al, 1
    mov ch, 1
    mov cl, 2
    mov dh, 0
    int 0x13
    jc read

check_a20:
    pushf
    push ds
    push es
    push di
    push si

    cli

    xor ax,ax
    mov es,ax

    not ax; ax = 0xFFFF
    mov ds,ax

    mov di,0x0500
    mov si,0x0510

    mov al, byte [es:di]
    push ax

    mov al, byte [ds:si]
    push ax

    mov byte[es:di], 0x00
    mov byte[ds:si], 0xFF

    cmp byte[es:di], 0xFF

    pop ax
    mov byte[ds:si], al

    pop ax
    mov byte[es:di], al

    mov ax, 0
    je check_a20_end

    mov ax,1
check_a20_end:
    pop si
    pop di
    pop es
    pop ds
    popf
    ret

a20_enable:
inc bx
call check_a20
cmp ax,1
je a20_enable_end

mov ax,0x2401
int 0x15

call check_a20
cmp ax,1
je a20_enable_end

in al, 0x92
or al, 2
out 0x92, al

call check_a20
cmp ax,1
je a20_enable_end
jnz a20_enable

cmp bx,0x3
je boot_error

a20_enable_end:
;a20 enabled

;set gdt
lgdt[gdt_descriptor]

;clear registers
reload:
    jmp 0x08:.reload_cs
    .reload_cs:
        mov ax,0x10
        mov ds,ax
        mov es,ax
        mov fs,ax
        mov gs,ax
        mov ss,ax
        ret

;go to Pmode
mov eax, cr0
or al, 1
mov cr0, eax


;jump to kernel
jmp 0x7E00

boot_error:
    mov bx,ErrorMSG
    .print:
        pusha
        jmp .print1
    .print1:
        lodsb
        or al,al
        jz .print2
        mov ah,0x0e
        int 0x10
        jmp .print1
    .print2:
        popa
        ret
    hlt

ErrorMSG db "Bootloader failure"
times 510-($-$$) db 0x0
db 0x55
db 0xAA
;==========
;Sector 2
;==========
bits 32

VIDEO_MEMORY equ 0xb8000
WHITE_ON_BLACK equ 0x0f
MSG db "working", 0

print:
    pusha
    mov edx, VIDEO_MEMORY
    .loop:
        mov al, [ebx]
        mov ah, WHITE_ON_BLACK
        cmp al, 0
        je .done
        mov [edx], ax
        add ebx, 1
        add edx, 2
        jmp .loop
    .done:
        popa
        ret

mov ebx,MSG
call print

hlt

当我试图在Bochs上打开这个代码时,它说“使用不存在的段寄存器7”。当我尝试在真实计算机上运行此代码时,计算机会生成三重故障并重新启动。

我将此代码基于以下来源:
启用A20 - http://wiki.osdev.org/A20
从磁盘加载扇区 - http://www.brokenthorn.com/Resources/OSDev5.html
转到保护模式 - http://wiki.osdev.org/Pmode

我不是真正的汇编程序员,所以如果有人能指出我生成Truple Fault的错误,我会非常感激,并解释为什么这段代码不起作用。

我还读到了在启用A20后我需要跳转到执行32位代码的地方,我试图交换加载内核,A20并进入保护模式但没有成功。

<小时/> 更新:

我对Jester评论做了一些改进。代码已经更新,但我仍然遇到问题。

现在只检查我是否使用过Jester的linked代码中的gdt

我还使用此来源来帮助GDT:http://wiki.osdev.org/GDT_Tutorial

Bochs现在可以开启,但它一直在说“使用不存在的段寄存器7”。在调试器模式下,它停留在mov bp, ??

1 个答案:

答案 0 :(得分:0)

你的程序早期已经存在一些缺陷。

  • 你不应该从气缸0而不是1来读第二个扇区吗?
  • 您忘了跳过 check_a20 例行程序。现在你失败了,ret无处可去!
  • 以下代码存在问题

    call check_a20
    cmp ax,1
    je a20_enable_end
    jnz a20_enable
    cmp bx,0x3
    je boot_error
    

    它不会根据设置的最大重试次数重试! cmp bx,0x3永远不会被执行。

  • 为什么下一个代码块以ret结尾?它不是一个子程序。

    mov ax,0x10
    mov ds,ax
    mov es,ax
    mov fs,ax
    mov gs,ax
    mov ss,ax
    ret
    
  • 尝试显示您编写的mov bx,ErrorMSG错误消息时,代码使用lodsb来检索字符。您必须使用SI寄存器。