DIY Bootloader 没有做它应该做的事情

问题描述 投票:0回答:1

不久前,我在教程的帮助下编写了一个引导加载程序。但它太复杂了,我几乎什么都听不懂。所以今天我开始利用我的知识和谷歌来制作我自己的引导加载程序。没什么大不了的,只是一个引导加载程序,它激活我能找到的东西并进行编程,然后将电源传递给内核。

我的目标是稍微玩一下视频缓冲区,所以我一开始就激活了它。然后我被告知,在将权力传递给内核之前,我应该切换到保护模式,这就是问题开始的地方,因为我不知道到底该怎么做。出于调试原因,我制作了 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

软盘加载成功。

在这里也许可以发现我的其他错误: 内核文件夹中的linker.ld:

ENTRY(kernel_main)
SECTIONS {
    . = 0x1000;

    .text : {
        *(.text)
    }
    .data : {
        *(.data)
    }
    .bss : {
        *(.bss)
    }
}

内核文件夹中的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 字节大小的二进制文件

assembly x86 qemu bootloader low-level
1个回答
0
投票

这是切换到保护模式的程序:

[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 字节的限制。在加载能够直接与硬盘驱动器通信的驱动程序之前,无论您是否喜欢,都必须使用

int 0x13
(并且,由于它是 BIOS 调用,因此仅在实模式下可用)。在实模式下还需要完成其他事情,例如使用
int 0x15, eax=0xE820
获取内存映射,但这只是一个起点。

© www.soinside.com 2019 - 2024. All rights reserved.