c - 为什么这个引导加载程序会崩溃?
问题描述
我更多地研究了创建自己的引导加载程序,而不是使用 grub。我很快想到了这个:它负责切换到 32 位 pm,它从磁盘加载我的内核并跳转到它执行它。
- 我正在像这样对我的内核和引导加载程序进行处理:
cat boot.bin kernel.bin > img.bin
- 我正在像这样组装我的引导加载程序:
nasm -f bin kernel/arch/$ARCH_TARGET/boot/boot.s -o boot.bin
- 我正在像这样编译我的内核:
i686-elf-gcc *.o -Ttext=0x0 -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
; 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 会使其进入“引导循环”,通过不断重启
解决方案
推荐阅读
- swift - Firebase 新用户:身份工具包 API 错误
- java - 缺少锁和 ConcurrentHashMap 的更新
- opencv - OpenCV,我们如何将 Mat min 标准化为 max 并将 max 标准化为 min?
- java - 通过广播接收器每分钟检查一次时间
- jenkins-groovy - “如何修复:org.codehaus.groovy.control.MultipleCompilationErrorsException:启动失败
- mongodb - 查询子文档数组中的对象
- shell - 如何运行“docker exec -it
bash" 使用 Gradle 构建? - python - 将数据框中的选定元素从浮点数转换为整数不成功
- json - Google 表格:ImportJSON 与请求标头中的键/值对
- dropwizard - 在 dropwizard 中,访问应用程序中任何位置的配置对象的最佳方式是什么