提问人:Fabboy 提问时间:9/14/2023 最后编辑:phuclvFabboy 更新时间:9/14/2023 访问量:51
DIY Bootloader 没有做它应该做的事情
DIY Bootloader isn't doing what it should do
问:
不久前,我在教程的帮助下编写了一个引导加载程序。但它太复杂了,我几乎什么都不懂。所以今天我开始用我的知识和谷歌来制作我自己的引导加载程序。没什么大不了的,只是一个引导加载程序,它激活了我能找到和编程的东西,然后将电源传递给内核。
我的目标是稍微玩一下视频缓冲区,所以我一开始就激活了它。然后我被告知,在将电源传递给内核之前,我应该切换到保护模式,这就是问题开始的地方,因为我不知道该怎么做。出于调试原因,我制作了 2 个标签,这些标签只是在屏幕上画点,但有时我只有一个,在当前状态下我只有一个黑屏。
我目前的代码:
[bits 16]
[org 0x7c00]
start:
cli
; Initialize stack
mov ax, 0x8000
mov ss, ax
xor sp, sp
; Initialize data segments
xor ax, ax
mov ds, ax
mov es, ax
; Switch to Video Mode
mov ax, 0x0013
int 0x10
call debug
lgdt [gdtr]
jmp 0x08:skip
[bits 32]
skip:
mov eax, cr0
or al, 1
mov cr0, eax
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
jmp 0x08:0x1000
debug:
mov ax, 0xA000
mov es, ax
mov di, 320*100 + 100
mov al, 0x0F
stosb
debug2:
mov ax, 0xA000
mov es, ax
mov di, 320*100 + 300
mov al, 0x0F
stosb
section .gdtr
gdtr:
dw 0x17FF
gdt:
dd 0x00000000, 0x00000000
dd 0x00FFFFFF, 0x00CF9A00
; Boot signature
times 422-($-$$) db 0
dw 0xAA55
软盘加载成功。
在这里也许可以发现我的其他错误: kernel 文件夹中的 linker.ld:
ENTRY(kernel_main)
SECTIONS {
. = 0x1000;
.text : {
*(.text)
}
.data : {
*(.data)
}
.bss : {
*(.bss)
}
}
kernel 文件夹中的 entry.asm:
section .text
global _start
extern kernel_main
_start:
; Initialize stack
mov esp, mainFnStack + 4096 ; Point to the top of the stack space
; Draw dot for debugging
mov ax, 0xA000
mov es, ax
mov di, 320*100 + 200
mov al, 0x0F
stosb
; Call main kernel function
call kernel_main
; Infinite loop to halt execution
jmp $
section .bss
mainFnStack resb 4096 ; Allocate 4096 bytes for the stack
如果你能帮助我,我将不胜感激。
我正在使用 QEMU,但我无法将 GDB 与 QEMU 结合使用。
编辑:
以下是引导加载程序的 Makefile:
ASMC = nasm
FLAGS = -f bin -O3
SRC = boot.asm
DEST = ../../bin/boot.bin
all: $(DEST)
$(DEST): $(SRC)
$(ASMC) $(FLAGS) $< -o $@
clean:
rm -f $(DEST)
内核的 makefile:
CC = gcc
LD = ld
ASMC = nasm
CFLAGS = -ffreestanding -c
ASMFLAGS = -f elf64
LDFLAGS = -o ../../bin/kernel.bin -T linker.ld
SRC_C = $(wildcard *.c */*.c)
SRC_ASM = $(wildcard *.asm */*.asm)
OBJ_C = $(patsubst %.c, obj/%.o, $(SRC_C))
OBJ_ASM = $(patsubst %.asm, obj/%.o, $(SRC_ASM))
all: ../../bin/kernel.bin
../../bin/kernel.bin: $(OBJ_C) $(OBJ_ASM)
$(LD) $(LDFLAGS) $(OBJ_ASM) $(OBJ_C)
obj/%.o: %.c
@mkdir -p $(@D)
$(CC) $(CFLAGS) $< -o $@
obj/%.o: %.asm
@mkdir -p $(@D)
$(ASMC) $(ASMFLAGS) $< -o $@
clean:
rm -rf obj ../../bin/kernel.bin
项目根目录中的 Makefile:
all:
$(MAKE) -C src/kernel
$(MAKE) -C src/bootloader
dd if=/dev/zero of=bin/floppy.img bs=1k count=1440
dd if=bin/boot.bin of=bin/floppy.img conv=notrunc seek=0
dd if=bin/kernel.bin of=bin/floppy.img bs=512 seek=1 conv=notrunc
clean:
$(MAKE) -C src/kernel clean
$(MAKE) -C src/bootloader clean
rm -f bin/floppy.img
如果我填充到 510,我会得到一个大约 550 字节的二进制文件,或多或少
答:
0赞
DarkAtom
9/14/2023
#1
这是切换到保护模式的程序:
[bits 16]
[org 0x7c00]
start:
cli
; Initialize stack
mov ax, 0x8000
mov ss, ax
xor sp, sp
; Initialize data segments
xor ax, ax
mov ds, ax
mov es, ax
; Switch to Video Mode
mov ax, 0x0013
int 0x10
;; call debug ;; not needed
lgdt [gdtr]
;; jmp 0x08:skip ;; not this early
mov ax, 0x2401 ; enable A20 (might already be done but who knows)
int 0x15
cli ; I noticed that some virtual machines set FLAGS.IF after that BIOS call
mov eax, cr0
or al, 1
mov cr0, eax
jmp 0x8:skip
[bits 32]
skip:
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
jmp 0x08:0x1000 ; I assume you want your code to continue here, but if this code is the only one loaded, it will jump to nothing (a.k.a. junk bytes)
debug: ; these are designed to run in Protected Mode
mov byte [0xA0000 + 32100], 0x0F
ret
debug2:
mov byte [0xA0000 + 32300], 0x0F
ret
gdtr:
dw 23
dd gdt
gdt:
dd 0x00000000, 0x00000000
dd 0x0000FFFF, 0x00CF9A00 ; code segment 0x08
dd 0x0000FFFF, 0x00CF9200 ; data segment 0x10
; Boot signature
times 510-($-$$) db 0
dw 0xAA55
但是,我应该提一下,如果您这么早切换到保护模式,您将不会走得太远,因为您受到引导扇区 512 字节的限制。在加载能够直接与硬盘驱动器通信的驱动程序之前,无论您喜欢与否,都必须使用它(并且,由于它是BIOS调用,因此仅在实模式下可用)。在实模式下还需要做其他事情,例如使用获取内存映射,但这只是一个起点。int 0x13
int 0x15, eax=0xE820
评论
0赞
Fabboy
9/14/2023
这对你有用吗?看起来它崩溃了,QEMU 尝试重新启动它。但谢谢,我试着让它运行
0赞
DarkAtom
9/14/2023
当然,它崩溃了。它跳转到 ,它不包含任何内容。正如我最后所说,您将不得不从Real Mode的硬盘驱动器加载更多内容。0x8:0x1000
0赞
Fabboy
9/14/2023
我错过了这个。这是这个块还是需要更多? 看起来很糟糕,我不知道该怎么做asm ; Read Kernel from the disk mov ah, 0x02 ; read sectors from drive function mov al, 0x01 ; number of sectors to read mov ch, 0x00 ; cylinder number mov cl, 0x02 ; sector number, start from the second sector mov dh, 0x00 ; head number mov dl, 0x80 ; drive number, 0x80 for the first disk mov bx, 0x1000 ; destination address in memory mov es, bx xor bx, bx ; offset 0 int 0x13
0赞
DarkAtom
9/14/2023
不要复制粘贴代码块。试着理解它们。是的,您想用来从硬盘驱动器加载内容。但是您需要计算要读取的扇区的 CHS 地址(为此,您需要知道您的文件在驱动器上的位置)。此外,指定硬盘驱动器,但在您提到的问题中您使用的是软盘,这需要 .这是一个很好的资源。int 0x13, ah=2
dl=0x80
dl=0
0赞
Fabboy
9/14/2023
我正在尽力理解它。是的,我使用 Floppy,我刚刚看到并更改了它。但我不知道如何“计算扇区的 CHS 地址”。
评论
debug
times
call debug
mov ax, 0xA000
mov eax, 0xC08EA000
mov edi, 0x0FB07D64
stosb
#UD
FF FF
FF FF
FF 17
call near [bx]
bx
0x1800
int 6