Linux 添加 memory block

需求

现在是这么一个情况,手头的一块开发板,在增加了内存后,需要在 Linux 系统里识别到、并能使用起来。

正常情况下,一般是重新配置 devicetree 即可。比如,按 内核文档 以及 devicetree 文档,可以这样配置若干片内存区域(当然这里的字段个数,取决于 #address-cells#size-cells):

memory@0 {
    device_type = "memory";

    /* 第一行,起始地址 0x0,内存大小 2GB
     * 第二行,起始地址 0x100000000,内存大小 4GB
     */
    reg = <0x000000000 0x00000000 0x00000000 0x80000000
           0x000000001 0x00000000 0x00000001 0x00000000>;
};

这样在重新加载后即可生效,并可以通过查看 /proc/meminfo/proc/iomem 等方式来确认。

问题

现在碰到的问题是,在对 devicetree 进行修改并重新加载后,发现没有生效。

经过调试,目前猜测是 u-boot 里的一个开关 CONFIG_NR_DRAM_BANKS,它限制了 u-boot 向 kernel 传递 devicetree 里对应 memory 字段的内容。但考虑到并没有提供 u-boot 源码,没办法重新编译,也就没办法确认问题原因,所以只能选择其他办法。

解决办法

对于 memory 字段,查找到 kernel 里的函数 early_init_dt_scan_memory() 是用来负责搜索和解析对应的内存区域:

/**
 * early_init_dt_scan_memory - Look for and parse memory nodes
 */
int __init early_init_dt_scan_memory(unsigned long node, const char *uname,
                                     int depth, void *data)
{
    ...

    while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
        u64 base, size;

        base = dt_mem_next_cell(dt_root_addr_cells, &reg);
        size = dt_mem_next_cell(dt_root_size_cells, &reg);

        early_init_dt_add_memory_arch(base, size);
    }

    ...
}

所以目前的解决办法是,在这个函数里,在某个时机主动调用一下 early_init_dt_add_memory_arch(base, size) 来添加内存,从而实现最开始的需求。修改大概是这样的:

 /**
  * early_init_dt_scan_memory - Look for and parse memory nodes
  */
 int __init early_init_dt_scan_memory(unsigned long node, const char *uname,
                                      int depth, void *data)
 {
     ...

     while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
         u64 base, size;

         base = dt_mem_next_cell(dt_root_addr_cells, &reg);
         size = dt_mem_next_cell(dt_root_size_cells, &reg);

+        if (size == 0) {
+            pr_err("**HACK**:\n");
+            base = 0x100000000ull;
+            size = 0x100000000ull;
+            early_init_dt_add_memory_arch(base, size);
+            continue;
+        }
+
         early_init_dt_add_memory_arch(base, size);
     }

     ...
 }

Read More: