【Linux内存源码分析】构建内存管理框架(4)

虽说前文分析内存管理框架构建的实现,提到了find_zone_movable_pfns_for_nodes(),这里不准备复述什么,仅针对required_movablecorerequired_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()函数在初始化时的调用关系:

start_kernel()

->setup_arch()

->parse_early_param()

->parse_early_options()

->parse_args()

->parse_one()

->do_early_param()

这里只能说明required_movablecorerequired_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_movablecorerequired_kernelcore也是来自于此。

好了,暂且分析至此,避免走偏了,此文也是一时好奇钻研了一下,记之以作备忘。

发表评论

电子邮件地址不会被公开。 必填项已用*标注