我的引导加载程序可以工作,但没有将我的内核加载到内存中

问题描述

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

  • 我正在像这样处理我的内核和引导加载程序:cat boot.bin kernel > img.bin
  • 我正在像这样组装引导加载程序:nasm -f bin boot.s -o boot.bin
  • i686-elf-ld -o kernel -Ttext=0x1000 kernel_entry.bin kernel.bin --oformat binary
  • 我正在像这样编译我的内核:i686-elf-gcc *.o -Ttext=0x1000 -o kernel.bin -ffreestanding -O2 -nostdlib -lgcc

(*.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
mov ss,ax
mov sp,0x7c00
jmp 0:skip ; far jump

skip:
; load kernel
mov bx,0x1000
mov dh,17 ; reading 20 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:
        set_up_stack:
            mov esp,stack_end

        mov ax,DATA_SEG
        mov ds,ax
        mov ss,ax
        mov es,ax
        mov fs,ax
        mov gs,ax
        jmp 0x1000 ; jump to kernel_entry.s

    ; 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,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 "------ bootloader ------",0x0d,0xa,0
    disK_READ_FAIL db "An error occurred while loading the kernel! Please restart your computer.",0

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

    section .bss
    stack_begin:
        resb 4096 ; 4kib stack
    stack_end:

; 9 sectors

位于 0x1000代码是这样的:

; kernel_entry.s

[bits 32]
[extern kmain]

call kmain
jmp $

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

; 1 sectors

我的引导加载程序没有崩溃,但它没有加载我的内核,它应该会在屏幕上打印一些内容

这是 kmain 函数

void kmain(void)
{
    /* Initialize terminal */
    tty_init();
    tty_puts("Hello kernel!",VGA_COLOR_LIGHT_CYAN);
}

假设 tty 函数正在工作,因为在使用 grub 而不是我自己的引导加载程序进行测试时,它们运行良好。有谁知道发生了什么? (在 bochs 中测试显示没有错误

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)