# 3.2.2 初始化

内存管理模块本身也需要使用内存，例如页表、page、zone、node等数据结构的创建过程本身就需要分配内存，但此时系统的内存管理模块还没有完成初始化，又如何完成内存分配呢？这是一个鸡生蛋、蛋生鸡的问题。内存的初始化流程就是用来解决该问题的，本节我们简单介绍一下该议题，但这部分内容对我们理解内存管理模块的设计思想帮助不大，因此不做深入讲解，我们会给出一些相关的思路、涉及到的代码及参考资料，有兴趣的同学可以自行探索。

从总体思路上来讲，内存的初始化流程可以归纳为如下几个阶段：

1. 探测物理内存 - E820 OS要管理内存，首先需要知道系统有多少可用的物理内存，该部分信息通过一个叫着[E820](https://en.wikipedia.org/wiki/E820)的机制来获取，在系统加电时， [BIOS](https://en.wikipedia.org/wiki/BIOS)通过E820这种方式获取到物理内存的大小与布局信息，以供后续的 boot loader 和操作系统使用。

   内和中涉及到E820 的文件有：

   * arch/x86/include/asm/e820/types.h
   * arch/x86/include/asm/e820/api.h
   * arch/x86/kernel/e820.c

   E820探测到的物理内存信息会打印在启动日志中，可以通过命令 `dmesg ｜ grep 'e820'` 查看。有关E820的详细实现可以参考如下资料：

   * <https://biscuitos.github.io/blog/MMU-E820/>
   * <https://wiki.osdev.org/Detecting_Memory_(x86)#BIOS_Function:_INT_0x15.2C_EAX_.3D_0xE820>
2. 初始化时内存管理 - bootmem/memblock 在系统启动阶段，Buddy System并没有初始化，系统使用的是专门的内存管理器来管理物理内存的分配与释放，Linux 早期使用的是 bootmem, 后来逐渐演化成了现在使用的 memblock. 内核中与 memblock 相关的代码集中在如下文件中：

   * include/linux/memblock.h
   * mm/memblock.c

   内存的 boot allocator 的实现逻辑并不会对系统正常运行时的内存管理有太大影响，因此我们在这里不对其做深入讨论，感兴趣的读者可以参见如下资料：

   * <https://lwn.net/Articles/761215/>
   * <https://www.kernel.org/doc/gorman/html/understand/understand008.html>
   * <https://www.kernel.org/doc/html/v4.19/core-api/boot-time-mm.html>
   * <https://biscuitos.github.io/blog/HISTORY-bootmem/>
   * <https://biscuitos.github.io/blog/MMU-ARM32-MEMBLOCK-index/>
3. 运行时内存管理 - Buddy System 系统正常运行起来之后，负责物理内存页面的分配与释放的子系统叫 Buddy System, 我们将在后面详细介绍；另外内核还通过 slab/slob/slub 系统来提供对象缓存机制。
