CPU在访问全局变量时重置自定义C内核的执行

CPU在访问全局变量时重置自定义C内核的执行,c,assembly,kernel,x86-64,bootloader,C,Assembly,Kernel,X86 64,Bootloader,希望你在面试中表现良好 作为一个简短的介绍:我写这个问题并不是作为特里特,而是作为来自西班牙的计算机科学学生协会ASOC的成员。我们试图通过自己开发一个内核来学习内核是如何工作的。我们已经将所有代码(与问题相关)发布在 由于我们是大约30名学生,我们已经将工作分为:文件系统、内存、用户空间软件(仅仅是shell)、进程管理和引导加载程序 当我们开发一个月后,我们在最后一部分遇到了一些真正的麻烦,所以在这里我请求您对这个主题提供一些帮助 从BIOS将我们设置为0x7c00开始,我们遵循的步骤是:

希望你在面试中表现良好

作为一个简短的介绍:我写这个问题并不是作为特里特,而是作为来自西班牙的计算机科学学生协会ASOC的成员。我们试图通过自己开发一个内核来学习内核是如何工作的。我们已经将所有代码(与问题相关)发布在

由于我们是大约30名学生,我们已经将工作分为:文件系统、内存、用户空间软件(仅仅是shell)、进程管理和引导加载程序

当我们开发一个月后,我们在最后一部分遇到了一些真正的麻烦,所以在这里我请求您对这个主题提供一些帮助

从BIOS将我们设置为
0x7c00
开始,我们遵循的步骤是:

  • 通过跳远设置CS(谢谢佩奇先生!)
  • 保存主磁盘
  • 设置16位堆栈
  • 从磁盘加载8个扇区(第二阶段)
  • 加载32位GDT
  • 负载IDT
  • 启用保护模式(CR0)
  • 执行跳远以冲洗管道并设置CS
  • 将所有分段设置为相同(平面分段)
  • 将新堆栈设置为
    0x90000
  • 通过CPUID检测LM是否存在
  • 禁用旧分页(我们没有在PM中设置分页)
  • 设置页面表
  • 激活PAE
  • 激活LM
  • 启用分页
  • 加载GDT(与32位相同,可能在兼容模式下?)
  • 跳远的原因与上述相同
  • 更新段
  • 重置堆栈
  • 通过
    extern kmain Call kmain调用C kmain
我们的链接器脚本是:

OUTPUT_FORMAT("binary");
ENTRY(boot);
SECTIONS
{
    . = 0x7C00;
    .text : {
        *(.boot);
        *(.text);
    }

    .rodata : SUBALIGN(4) {
        *(.rodata);
    }

    .data : SUBALIGN(4) {
        *(.data);
    }

    .bss : SUBALIGN(4) {
        *(.bss)
    }

    /DISCARD/ : {
        *(.eh_frame);
        *(.comment);
        *(.note.gnu.build-id);
    }
}
我们使用以下工具进行编译:

nasm -f elf64 boot.asm -o boot.o 
gcc -ffreestanding -nostdlib -mno-red-zone -fno-exceptions -m64 kernel.c boot.o -o kernel.bin -T link.ld
并通过以下方式进行测试:

qemu-system-x86_64 -fda kernel.bin
如果我们像这样设置函数,我们的kmain会写入VGA:

void kmain() {

    char * vga_ptr = (char*)0xb8000;
    *(vga_ptr++) = 0x0f;
    *(vga_ptr++) = 'H';

    while (1){}
}
但是,如果我声明
vga_ptr
超出
kmain
边界,cpu将重置执行

我在这里所做的假设是,鉴于IDT不完整的事实,CPU是三重故障(对此的任何帮助都将不胜感激)。问题更多的是,是什么触发了导致双故障、三故障、复位底座的异常。我只是猜测,但可能与不正确的分页或构建过程有关(friend
link.ld过去给我们带来了很多麻烦)

任何关于这个问题的说明,或者指出我们代码中检测到的任何混乱,都将不胜感激。如果问题太长或不准确,我很抱歉。记住,我们确实是学生

祝你度过愉快的一天,保持安全

另外,引导加载程序的完整代码链接在github的上面,分支引导测试中。我试图让问题尽可能简短,但根据请求,我可以编辑文本以包含您需要的任何代码片段


[编辑]另一个失败,可能与此无关,就是当我分解.bin文件时,它显示了
.data
部分下的所有内容。

试着做一个修改,该repo中有很多文件(有些模棱两可:
boot.asm
vs
boot2.asm
并且没有反映您发布的代码),以及大量的意大利面编码。您的CPU显然存在三重故障,bochs在调试此问题方面优于qemu,因为它可以输出一个非常详细的日志,其中包括导致TF的原因。如果您盲目地从OSDEV复制代码,那么它可能无法工作。我会仔细检查PML4设置,特别是您使用的映射是什么?为什么您是否重新加载了与PM中使用的完全相同的GDT(即,没有设置L位,然后执行64位代码)?如果您将目标分解为:1)从启动时输入PM,并检查一切是否正常(执行32位代码,设置了段),可能会更好。2) 启用PAE并检查每个页面是否可正确访问(访问页面的预期地址)3)启用LM并检查64位汇编代码是否正确运行(包括访问上述页面)。4) 编译内核,检查链接器脚本是否正常工作,访问的地址是否正确。检查内核是否加载到正确的地址并执行它。非常感谢@MargaretBloom。给我一些时间来整理一下分支机构的混乱,(你说得绝对正确)并在第二条评论中遵循你的建议,我将编辑这个问题。祝你有一个愉快的一天。试着做一个简单的回复,回复中有很多文件(有些模棱两可:
boot.asm
vs
boot2.asm
,没有反映你发布的代码),还有很多意大利面编码。您的CPU显然是三重故障,bochs在调试这个问题上比qemu更好,因为它可以输出一个非常详细的日志,其中包括导致TF的原因。如果您盲目地从OSDEV复制代码,那么它可能不会工作。我会仔细检查PML4设置,特别是您使用的映射是什么?为什么您要重新加载与PM中使用的完全相同的GDT(即,没有设置L位,然后执行64位代码)?也可能更好的是,您可以分解您的目标:1)从启动时输入PM,并检查一切是否正常(执行32位代码,设置段)。2) 启用PAE并检查每个页面是否可正确访问(访问页面的预期地址)3)启用LM并检查64位汇编代码是否正确运行(包括访问上述页面)。4) 编译内核,检查链接器脚本是否正常工作,访问的地址是否正确。检查内核是否加载到正确的地址并执行它。非常感谢@MargaretBloom。给我一些时间来整理一下分支机构的混乱,(你说得绝对正确)并在第二条评论中遵循你的建议,我将编辑这个问题。祝您有个美好的一天。