OSDev:为什么我的内存分配功能突然在AHCI初始化功能中停止工作?

时间:2019-04-14 01:08:34

标签: c osdev kernel-mode

我的内核在ArchInit()函数内部调用了AHCIInit()函数后,我在MemAllocate()调用之一中遇到了页面错误,这仅在真实的机器上发生,因为我尝试在VirtualBox上复制它, VMWare和QEMU。

我尝试调试代码,对内存分配器进行单元测试,并从内核中删除所有内容,但内存管理器和AHCI驱动程序本身除外,我发现的唯一发现是某些东西破坏了分配块,使得MemAllocate()页面错误。

整个内核源代码位于https://github.com/CHOSTeam/CHicago-Kernel,但是可能出现问题的主要文件是:
https://github.com/CHOSTeam/CHicago-Kernel/blob/master/mm/alloc.c
https://github.com/CHOSTeam/CHicago-Kernel/blob/master/arch/x86/io/ahci.c

我希望AHCIInit()能够检测并初始化所有AHCI设备,并且引导继续进行到到达会话管理器或内核外壳为止,但是在实际计算机中,它甚至在初始化调度程序之前也会出现页面错误(因此,问题不是我的调度程序)。

1 个答案:

答案 0 :(得分:0)

如果它可以在仿真器中运行,但不能在实际硬件上运行;那么我会怀疑的第一件事是:

  • 物理内存管理中的错误。例如,物理内存管理器初始化未将“可用RAM区域的起始地址”四舍五入到页面边界,或者未将“可用RAM区域的结束地址”四舍五入到页面边界,从而导致“一半的可用RAM和一半的不可用RAM”。 ”页面,稍后由堆分配(该页面可在模拟器上运行,因为固件提供的内存映射恰好描述了无论如何对齐的区域)。

  • 一个假定RAM包含零但可能不是的bug(在模拟器上工作,因为它们倾向于使几乎所有RAM都充满零)。

  • 竞争条件(不同的计时导致不同的行为)。

但是;这是一个整体式内核,这意味着您将不断面对“内核空间中的任何代码段所做的事情都会导致其他任何地方的代码段出现问题”;而且还有很多与内存使用有关的常见错误(例如,意外地在分配的内容写完之后)。因此,我希望有更好的工具来帮助诊断问题,尤其是对于堆。

具体来说,对于堆,我将从金丝雀开始(例如,在堆中的每个内存块之前放置一个魔术数字,例如0xFEEDFACE,在堆中的每个内存块之后放置另一个不同的数字;然后检查魔术数字仍然存在,并且在方便时正确(例如,释放或调整块大小时)。然后,我将编写一个“ check_heap()”函数,该函数将尽可能多地检查所有内容(金丝雀,如果“空闲块数”之类的统计信息实际上是正确的,等等)。这样的想法是(无论何时您怀疑某个东西可能破坏了堆),您都可以插入对“ check_heap()”函数的调用,并移动该调用,直到找出导致堆损坏的代码。我还建议您在您的“ kmalloc()或等效名称中使用一个“ what”参数(例如,这样您就可以进行myFooStructure = kmalloc("Foo Structure", sizeof(struct foo));之类的操作),其中所提供的“ what string”存储在分配的块的元数据,以便以后(当您发现堆已损坏时)可以显示与损坏之前的块关联的“字符串”,以便您(例如)列出每种事物的数量当前有帮助确定什么正在泄漏内存(例如,“ Foo Structure”块的数量是否持续增加)。当然,可以通过编译时选项(例如#ifdef DEBUG_HEAP)启用/禁用这些功能。

我建议的另一件事是自测。这些就像单元测试一样,但是直接内置在内核本身中并且始终存在。例如,您可以编写代码以消除堆中的日光(例如,分配随机大小的内存,并用一些东西填充它们,直到耗尽内存,然后释放其中一半,然后分配更多,直到内存耗尽再次等;在每个步骤之间调用“ check_heap()”函数时);该代码可以/应该采用“多少磅”参数的位置(因此您可以花费少量时间进行自检,也可以花费大量时间进行自检)。您还可以编写代码以消除虚拟内存管理器和物理内存管理器(以及调度程序等)的日光。然后,您可以决定每次启动内核时总是进行少量的自测试,并且/或者提供一个特殊的内核参数/选项以启用“极端彻底的自测试模式”。

不要忘记,最终(如果/当发布操作系统时)您可能不得不求助于“通过电子邮件进行远程调试”(例如,没有任何编程经验的人,可能不太懂英语,向您发送一封电子邮件,指出“操作系统不起作用”;您必须设法弄清楚出了什么问题,然后最终用户的“放弃且不再关心的麻烦数量”计数器将耗尽。