Assembly LGDT指令后重新启动并跳转到保护模式

Assembly LGDT指令后重新启动并跳转到保护模式,assembly,x86,bootloader,protected-mode,gdt,Assembly,X86,Bootloader,Protected Mode,Gdt,因此,我遇到了一个问题,我现在一直被困在这个问题上,似乎是永恒的,大约3天没有睡觉,现在我试图自己解决这个问题,这对我来说有点沮丧,因为我觉得加载一个简单的表并执行跳远到32位模式并发出隆隆声应该是一个相对简单的任务!让它与我的数字快照一起工作。问题是每次我加载GDT并执行跳远操作时,我的计算机都会重新启动,正如我在处理相同问题的许多其他帖子和人员中看到的那样。我使用“INT 0x13,AX=0x20A”和“ES:BX=0x1000:0”从引导加载程序加载。就在'CLI LGDT[GDT_END

因此,我遇到了一个问题,我现在一直被困在这个问题上,似乎是永恒的,大约3天没有睡觉,现在我试图自己解决这个问题,这对我来说有点沮丧,因为我觉得加载一个简单的表并执行跳远到32位模式并发出隆隆声应该是一个相对简单的任务!让它与我的数字快照一起工作。问题是每次我加载GDT并执行跳远操作时,我的计算机都会重新启动,正如我在处理相同问题的许多其他帖子和人员中看到的那样。我使用“INT 0x13,AX=0x20A”和“ES:BX=0x1000:0”从引导加载程序加载。就在'CLI LGDT[GDT_END]'指令之前,如果我执行'JMP$'指令,它将成功打印关于已将其写入内核的字符串。然而,第二次我加载GDT时,无论是通过%include加载还是直接在内核内部粘贴include的内容,错误都会持续不断地重新启动

任何关于我做错了什么的建议都会很好!我花了好几天的时间,似乎在任何地方都找不到解决问题的答案,尽管有大量的帖子看起来都类似于同一个问题。这是我反复输入的内核代码,可能已经输入了几千次了。。。我试着让它看起来尽可能清晰,并尝试了所有我能找到的似乎有助于他人的解决方案。这似乎是我最后的办法。。如果需要引导加载程序,我也可以将其发布,但是,正如我所说的,它实际上会将其发送到在段0x1000偏移量0处加载的内核中。我通常从不使用ORG,老实说,我不知道它实际上在做什么,也不知道它在做什么,我也找不到关于它的明确解释,但不管有没有它,无论如何,它都不起作用。使用“NASM-okernel.bin kernel.asm”在windows命令行中与NASM组装

    BITS 16
    ORG 0x10000
    JMP FLOW_KERNEL_START
    NOP

;----------------------------
;  GLOBAL DESCRIPTOR TABLE
;----------------------------
GDT_START:
    dq 0

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

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

GDT_END:
    dw GDT_END - GDT_START - 1
    dd GDT_START

;----------------------------
;       INCLUDES
;----------------------------
;%INCLUDE 'BIO_Land\gdt.asm'
;----------------------------

FLOW_KERNEL_START:
            ; SET SEGMENTS AND BOOT DEVICE VARIABLES
    XOR AX, AX
    CLI
    MOV SS, AX
    MOV SP, 0x9000
    STI

    MOV AX, 0x1000
    MOV DS, AX
    MOV ES, AX
    MOV FS, AX
    MOV GS, AX
    MOV byte [VAR_BOOTDEV], DL
    CALL FUNC_GOOD
    MOV AX, 0
    INT 0x16

            ; LOAD GDT TABLE AND MASK 32-BIT PROTECTED MODE FLAG
    CLI
    LGDT [GDT_END]
    MOV EAX, 0x10
    MOV DS, EAX
    MOV ES, EAX
    MOV FS, EAX
    MOV GS, EAX
    MOV SS, EAX
    MOV EAX, CR0
    OR EAX, 1
    MOV CR0, EAX
    JMP dword 0x8:FLOW_PROTECTED_MODE
    NOP

BITS 32
FLOW_PROTECTED_MODE:
    STI
    MOV byte [0xB8000], 'O'
    MOV byte [0xB8001], 0x0F
    MOV byte [0xB8002], 'O'
    MOV byte [0xB8003], 0x0F
    MOV byte [0xB8004], 'O'
    MOV byte [0xB8005], 0x0F
    MOV byte [0xB8006], 'O'
    MOV byte [0xB8007], 0x0F
    MOV byte [0xB8008], 'O'
    MOV byte [0xB8009], 0x0F
    JMP $

;----------------------------
;       FUNCTIONS
;----------------------------
FUNC_GOOD:
    MOV SI, VAR_STRING
    CALL FUNC_PRINT
    RET

FUNC_PRINT:
    MOV AH, 0x0E
    FUNC_PRINT_LOOP:
        LODSB
        CMP AL, 0
        JE FUNC_PRINT_DONE
        INT 0x10
        JMP FUNC_PRINT_LOOP
    FUNC_PRINT_DONE:
        RET
;----------------------------
;       VARIABLES
;----------------------------
VAR_BOOTDEV db 0

;----------------------------
;       STRINGS
;----------------------------
VAR_STRING db 'Hello world! You made it to the kernel!', 0

编辑:我已经将JMP$更改为INT 0x16,以使事情更简单。它引导到它刚刚好,正如前面提到的,但在按键是一个重新启动。我已将组织更改为0x1000以及0x10000。我不确定在不将地址0x7C00附加到引导加载程序本身内部的情况下如何在地址0x7C00处加载,但尽管如此,我也尝试在引导加载程序的末尾放置一个缓冲区标签并在其处加载内核,假设引导加载程序后的地址为0x7E00并将其用作组织。我还尝试完全省略组织(因为它已经通过DS设置了,不是吗?),然后将0x8:FLOW\u PROTECTED\u模式更改为0x8:FLOW\u PROTECTED\u模式+0x10000。我还尝试过使用JMP 0x8:$$+$和其他许多东西。BOSHC所说的正是我所期望的,即JMPF 0x8:0x00001065无法解析。我假设内核实际上加载在内存中的某个地方,因为它确实在说Hello world!,但我一辈子都搞不清楚如何正确找到位置或问题出在哪里。

在BOCHS这样的模拟器下运行代码,该模拟器将向您显示三重故障重置的原因,并具有理解分段/GDT的内置调试器。
Org 0x10000
16位代码不会执行您认为会执行的操作。对于16位地址,NASM将其包装为0x0000。在所有段寄存器设置为0x1000的组合中,代码将显示为在0x1000:0x0000处运行。如果您要加载GDT并跳转到prot模式,我强烈建议使用
org 0x7c00
并使用0x0000加载段寄存器。这将解决GDT(和IDT)地址不是段:偏移量而是线性的其他问题。通过设置
org 0x7c00
并使用0x0000段,将为您提供恰好与线性addrese匹配的地址,它们不需要调整。我创建了一个1.44MB的映像文件。我的引导加载程序有一个fat12文件系统,读取内核文件的扇区35并加载它。我创建了一个包含所有0的img文件,并通过十六进制编辑器将我的usb驱动器复制到文件位置,并引导到bochs中,但它也在重复一条消息“从软盘引导”?编辑:我想我必须搞乱波什设置。谢谢你的建议。我会搞砸它,希望我能弄明白。起初我以为它是一个引导加载程序,所以我说0x7c00。您可以在引导加载程序之后从0x0000:0x7e00开始加载内核(并将堆栈放在引导加载程序下面的0x0000:0x7c00处。或者您可以将内核放在0x0000:0x1000处。所有这些示例都使用0x0000段,这样您就不必通过更改GDT地址或FAR JMP来胡乱处理。在类似BOCHS的模拟器下运行代码,该模拟器将向您显示三重故障重置的原因,并具有内置的d理解分段/GDT的ebugger。
Org 0x10000
在16位代码中不会做你认为会做的事。NASM会将16位地址的值包装为0x0000。在所有分段寄存器被设置为0x1000的组合中,代码将以0x1000:0x0000的速度运行。如果你要加载GDT并跳转到prot模式,我强烈建议你使用
org 0x7c00
并用0x0000加载段寄存器。这将修复其他问题GDT(和IDT)地址不是段:偏移量,而是线性的。通过设置
org 0x7c00
并使用0x0000段,将为您提供与线性addrese匹配的地址,它们不需要调整。我创建了一个1.44MB的映像文件。我的引导加载程序有一个fat12文件系统,读取内核文件的扇区35并加载它。我创建了一个img文件由所有0组成,通过一个十六进制编辑器将我的usb驱动器复制到文件位置并引导到bochs中,但它也在重复一条消息“从软盘引导”?编辑:我想我必须搞乱bochs设置。不过谢谢你的建议。我会搞乱它,希望我能弄明白。起初我以为这是一个引导加载程序o我说的是0x7c00。您可以在引导加载之后从0x0000:0x7e00开始加载内核