雖說前文分析記憶體管理框架構建的實現,提到了find_zone_movable_pfns_for_nodes(),但這裡不准備覆述什麼,僅針對required_movablecore和required_kernelcore做一個補充。 以required_movablecore為例,代碼中沒有很清晰地 ...
雖說前文分析記憶體管理框架構建的實現,提到了find_zone_movable_pfns_for_nodes(),但這裡不准備覆述什麼,僅針對required_movablecore和required_kernelcore做一個補充。
以required_movablecore為例,代碼中沒有很清晰地表明該值從何而來,僅有一處cmdline_parse_movablecore()疑似賦值的實現:
【file:/mm/page_alloc.c】
/*
* movablecore=size sets the amount of memory for use for allocations that
* can be reclaimed or migrated.
*/
static int __init cmdline_parse_movablecore(char *p)
{
return cmdline_parse_core(p, &required_movablecore);
}
而其中cmdline_parse_core()實現:
【file:/mm/page_alloc.c】
static int __init cmdline_parse_core(char *p, unsigned long *core)
{
unsigned long long coremem;
if (!p)
return -EINVAL;
coremem = memparse(p, &p);
*core = coremem >> PAGE_SHIFT;
/* Paranoid check that UL is enough for the coremem value */
WARN_ON((coremem >> PAGE_SHIFT) > ULONG_MAX);
return 0;
}
可以推測其值是由此而來,繼而可以找到:
【file:/mm/page_alloc.c】
early_param("movablecore", cmdline_parse_movablecore);
這是一個函數註冊巨集,該巨集展開後:
static const char __setup_str_cmdline_parse_movablecore[] __attribute__ ((__section__(".init.rodata"))) __attribute__((aligned(1))) = "movablecore"; static struct obs_kernel_param __setup_cmdline_parse_movablecore __attribute__((__used__)) __attribute__ ((__section__(".init.setup"))) __attribute__((aligned((sizeof(long))))) = { __setup_str_cmdline_parse_movablecore, cmdline_parse_movablecore, 1 }
由此借用於__section__屬性定義,編譯器通過arch/x86/kernel/vmlinux.lds鏈接腳本把__setup_cmdline_parse_movablecore放置在.init.setup段中。
註冊的函數將會在do_early_param()中調用,相關代碼:
【file:/init/main.c】
/* Check for early params. */
static int __init do_early_param(char *param, char *val, const char *unused)
{
const struct obs_kernel_param *p;
for (p = __setup_start; p < __setup_end; p++) {
if ((p->early && parameq(param, p->str)) ||
(strcmp(param, "console") == 0 &&
strcmp(p->str, "earlycon") == 0)
) {
if (p->setup_func(val) != 0)
pr_warn("Malformed early option '%s'\n", param);
}
}
/* We accept everything at this stage. */
return 0;
}
可以看到藉助於__setup_start和__setup_end的範圍標記,將遍歷.init.setup段中的排布的obs_kernel_param結構體,找到匹配的字元串及early成員為true的情況下,將會調用其中的setup_func鉤子函數,由此將對應數據初始化。
do_early_param()函數在初始化時的調用關係:
do_early_param()函數在初始化時的調用關係:
start_kernel()
->setup_arch()
->parse_early_param()
->parse_early_options()
->parse_args()
->parse_one()
->do_early_param()
這裡只能說明required_movablecore和required_kernelcore在何處初始化的,而其值的由來呢?其值通過入參傳遞,在parse_early_param()函數中通過strlcpy()來自於boot_command_line全局變數。而boot_command_line早期則是在/arch/x86/kernel/head_32.s的初始化中來自於boot_params。具體 do_early_param()處理的數據來自於grub.cfg,也就是說required_movablecore和required_kernelcore也是來自於此。
好了,暫且分析至此,避免走偏了,該文也是一時好奇鑽研了一下,記之以作備忘。