首页 > 解决方案 > 为什么这个引导加载程序会崩溃?

问题描述

我更多地研究了创建自己的引导加载程序,而不是使用 grub。我很快想到了这个:它负责切换到 32 位 pm,它从磁盘加载我的内核并跳转到它执行它。

*.o都是我这样编译的编译C文件:i686-elf-gcc -c file.c -o file.o -std=gnu99 -ffreestanding -O2 -Wall -Wextra

这是我的引导加载程序代码:

[org 0x7c00]
[bits 16]

xor ax, ax
mov ds, ax
mov es, ax

; load kernel
mov bx, 0x1000
mov dh, 10 ; reading 15 sectors should be enough ._.
mov dl, [BOOT_DRIVE]
call dsk_load
call load_kernel

dsk_load:
    mov [SECTORS], dh
    mov ch, 0x00 ; C = 0
    mov dh, 0x00 ; H = 0
    mov cl, 0x02 ; S = 2

    next_group:
        mov di, 5 ; retry 5 times

    again: 
        mov ah, 0x02
        mov al, [SECTORS]
        int 0x13
        jc maybe_retry
        sub [SECTORS], al ; set remaining sectors
        jz done
        mov cl, 0x01 ; read sector 1
        xor dh, 1 ; next head
        jnz next_group
        inc ch ; next cylinder
        jmp next_group

    maybe_retry:
        mov ah, 0x00 ; reset drive
        int 0x13
        dec di
        jnz again
        jmp dsk_err ; we've tried too many times, give up

    dsk_err:
        mov bx, BOOTLOADER_SIG
        call print
        mov bx, DISK_READ_FAIL
        call print
        jmp $

    done:
        ret

; print string
print:
    ; print loop
    print_loop:
        mov ah, 0x0e
        mov al, [bx] ; load current character
        cmp al, 0
        je print_return ; return when finished
        int 0x10 ; print character
        inc bx ; next character
        jmp print_loop

    print_return:
        ret

load_kernel:
    ; If all that went well, we can switch to protected mode
    cli
    lgdt [gdt_descriptor]
    mov eax, cr0
    or eax, 0x1
    mov cr0 , eax
    jmp CODE_SEG:init_32_pm ; make a far jump

    [bits 32]
    init_32_pm:
        mov ax, DATA_SEG
        mov ds, ax
        mov ss, ax
        mov es, ax
        mov fs, ax
        mov gs, ax
        jmp 0x1000 ; call kernel
        jmp $

    ; our beloved gdt
    gdt_start:
        gdt_null: ; null descriptor
            dd 0x0
            dd 0x0
        gdt_code: ; code segment descriptor
            dw 0xffff ; limit (bits 0-15)
            dw 0x0 ; base (bits 0-15)
            db 0x0 ; base (bits 16 -23)
            db 10011010b ; 1st flags, type flags
            db 11001111b ; 2nd flags, Limit (bits 16-19)
            db 0x0 ; base (bits 24 - 31)
        gdt_data: ; data segment descriptor
            dw 0xffff ; limit (bits 0-15)
            dw 0x0 ; base (bits 0-15)
            db 0x0 ; base (bits 16 -23)
            db 10010010b ; 1st flags, type flags
            db 11001111b ; 2nd flags, Limit (bits 16-19)
            db 0x0 ; base (bits 24 - 31)
    gdt_end:
        gdt_descriptor:
            dw gdt_end - gdt_start - 1 ; gdt size
            dd gdt_start ; gdt start address

            ; some handy constants
            CODE_SEG equ gdt_code - gdt_start
            DATA_SEG equ gdt_data - gdt_start

    BOOT_DRIVE db 0
    SECTORS db 0
    BOOTLOADER_SIG db "------ NubelaOS bootloader ------", 0x0d, 0xa, 0
    DISK_READ_FAIL db "An error occurred while loading the kernel! Please restart your computer.", 0x0d, 0xa, 0

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


将其引导到 Qemu 会使其进入“引导循环”,通过不断重启

标签: cassemblyx86bootloaderosdev

解决方案


推荐阅读