问题描述
我更多地考虑创建自己的引导加载程序,而不是使用 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 (将#修改为@)