从后期引导加载程序加载GDT

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

我目前正在开发一个操作系统,并制作一个名为 early bootloader (DfltBoot) 和 late bootloader (AdvBoot) 的 2 阶段引导加载程序,早期的引导加载程序完成其工作并加载后期的引导加载程序并跳转到它的条目,然后从那里开始执行代码。现在后期引导加载程序已加载,我想切换到 32 位保护模式(稍后切换到 64 位,但这现在并不重要),这里是早期和后期引导加载程序的一些代码。我不会放入大部分早期引导加载程序的代码,因为它只是执行 FAT12 加载内容并将后期引导加载程序加载到内存中,然后开始执行它,但我仍然会将跳转部分放入后期引导加载程序。

DfltBoot.asm (早期引导加载程序/引导扇区)

.ReadFinish: ; Gets jumped to whenever ADVBOOT.BIN get's loaded into memory
    mov [EBR_DriveNumber], dl ; Save the boot drive

    ; Set the segments again
    mov ax, ADVBOOT_LoadSegment
    mov ds, ax
    mov es, ax

    jmp ADVBOOT_LoadSegment:ADVBOOT_LoadOffset ; Segment = 0x2000 Offset=0x0
    jmp WaitKeyAndReboot ; Shouldn't get executed, late bootloader won't return.

早期引导加载程序的上述代码工作得很好,后期引导加载程序确实会跳转到,因为我仍处于 16 位实模式,我可以打印字符,所以我在后期引导加载程序中执行了这些操作,并且它确实打印了字符,所以早期引导加载程序中的读取和跳转部分应该工作得很好。

问题出现在后期引导加载程序中的一些后期代码中,这里是后期引导加载程序的完整代码:

AdvBoot.asm (后期引导加载程序/实际引导加载程序)

org 0x0
bits 16

Start:
    cli
    lgdt [GDT_Descriptor]

    ; Set the 32-bit flag in control register 0
    mov eax, cr0
    or al, 1
    mov cr0, eax

    ;;; Problematic part
    jmp GDT_CodeSegment:ProtectedModeStart ; Far jump to flush the pipeline

bits 32

ProtectedModeStart:
    ; NOTE: This label doesn't get jumped to, I tried putting a jmp $ here
    ; and QEMU just crashed on me. If I put it before the far jump, it does
    ; actually stop and not crash, so I'd assume the far jump is the problem.
    mov ax, GDT_DataSegment
    mov ds, ax
    mov ss, ax
    mov es, ax
    mov fs, ax
    mov gs, ax

    mov ebp, 0x90000
    mov esp, ebp

    mov edx, 0xb8000
    mov ah, 0x0f
    mov al, 'B'
    mov [edx], ax
    jmp $
    
    %include "Boot/GDT.asm"

正如评论中所说,远跳部分在执行时会导致整个计算机崩溃并重新启动并重复循环。我不确定它在这种情况下是否相关,但如果是的话,这是我的 GDT:

GDT.asm

GDT_Start:

GDT_Null:
    dd 0x0
    dd 0x0

GDT_Code:
    dw 0xFFFF
    dw 0
    db 0
    db 10011010b
    db 11001111b
    db 0

GDT_Data:
    dw 0xFFFF
    dw 0
    db 0
    db 10010010b
    db 11001111b
    db 0

GDT_End:

GDT_Descriptor:
    dw GDT_End - GDT_Start - 1
    dd GDT_Start

GDT_CodeSegment equ GDT_Code - GDT_Start
GDT_DataSegment equ GDT_Data - GDT_Start

我什至不明白问题是什么,是段、GDT 还是其他什么。

assembly operating-system nasm bootloader
1个回答
0
投票

有三个关键部分需要使用正确的地址。

  1. lgdt [GDT_Descriptor]
    。由于您使用
    ds
    加载
    ADVBOOT_LoadSegment
    并且您拥有
    org 0x0
    ,这实际上很好。
  2. jmp GDT_CodeSegment:ProtectedModeStart
    。这需要相对于保护模式段基址的偏移量为零。因此,您需要通过负载段(如
    jmp dword GDT_CodeSegment:ADVBOOT_LoadSegment*16+ProtectedModeStart
    )来调整它。请注意,您需要
    dword
    ,因为偏移量不适合 16 位。您还可以设置段的基地址,但不建议这样做。
  3. dd GDT_Start
    。这需要是一个线性地址。与上一点类似,您应该像
    dd GDT_Start+ADVBOOT_LoadSegment*16
  4. 那样调整它

通过这些更改,您的代码似乎可以正常工作(在我填写了缺失的部分之后,因为您没有提供可重现的示例)。

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