内核启动过程中在memblock_double_array函数内调用了
new_array = addr ? __va(addr) : NULL;
然而再riscv64的情况下 kernel_map.va_pa_offset是在函数setup_bootmem内才设置的。
/*
* In 64-bit, any use of __va/__pa before this point is wrong as we
* did not know the start of DRAM before.
*/
if (IS_ENABLED(CONFIG_64BIT) && IS_ENABLED(CONFIG_MMU))
kernel_map.va_pa_offset = PAGE_OFFSET - phys_ram_base;
注释也写了在这之前不能用__va和__pa。memblock_double_array的第一次调用是在setup_bootmem之前。有人注意到这个地方了吗?这样没问题吗?
1 个赞
简单看了一下源码,因为memblock_double_array根本不会被调用
memblock_double_array这个函数前面有个
if (!memblock_can_resize)
panic("memblock: cannot resize %s array\n", type->name);
而memblock_can_resize又是在memblock_allow_resize被设置为1的
void __init memblock_allow_resize(void)
{
memblock_can_resize = 1;
}
在riscv上用gdb调试会发现setup_bootmem先于memblock_allow_resize
(gdb) b setup_bootmem
Breakpoint 1 at 0xffffffff80c07400: file arch/riscv/mm/init.c, line 222.
(gdb) b memblock_allow_resize
Breakpoint 2 at 0xffffffff80c19600: file mm/memblock.c, line 2107.
(gdb) c
Continuing.
Breakpoint 1, 0xffffffff80c07400 in setup_bootmem () at arch/riscv/mm/init.c:222
222 phys_addr_t vmlinux_end = __pa_symbol(&_end);
(gdb)
Continuing.
Breakpoint 2, memblock_allow_resize () at mm/memblock.c:2107
2107 memblock_can_resize = 1;
(gdb)
至于调用memblock_double_array的地方,无非就是memblock_add_range和memblock_isolate_range函数
前者初期会直接return掉
if (type->regions[0].size == 0) {
WARN_ON(type->cnt != 0 || type->total_size);
type->regions[0].base = base;
type->regions[0].size = size;
type->regions[0].flags = flags;
memblock_set_region_node(&type->regions[0], nid);
type->total_size = size;
type->cnt = 1;
return 0;
}
后者则是不满足while条件会被跳过
while (type->cnt + 2 > type->max)
if (memblock_double_array(type, base, size) < 0)
return -ENOMEM;
(gdb) print type->cnt
$3 = 1
(gdb) print type->max
$4 = 128
(gdb)
2 个赞