parse_early_param() 함수는 커널 부트업 타임에 사용하는 early parameter를 파싱해 오는 함수로 boot command line을 파싱해오는 역할을 합니다.
parse_early_param()
init/main.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /* Arch code calls this early on, or if not, just before other parsing. */ void __init parse_early_param(void) { static int done __initdata; static char tmp_cmdline[COMMAND_LINE_SIZE] __initdata; if (done) return; /* All fall through to do_early_param. */ strlcpy(tmp_cmdline, boot_command_line, COMMAND_LINE_SIZE); parse_early_options(tmp_cmdline); done = 1; } | cs |
__initdata 메모리 영역에 tmp_cmdline 문자 배열을 선언하고, boot_command_line (dt /chosen node의 bootargs 값) 을 복사해 옵니다. parse_early_options() 함수를 호출하여 option을 파싱해 옵니다.
parse_early_param()
-> parse_early_options()
init/main.c
1 2 3 4 5 | void __init parse_early_options(char *cmdline) { parse_args("early options", cmdline, NULL, 0, 0, 0, NULL, do_early_param); } | cs |
인자 마지막에 do_early_param 이란 함수포인터를 전달한다. 해당 함수포인터를 어떤 용도로 사용하는지는 parse_args() 함수 분석 시 설명한다.
parse_early_param()
-> parse_early_options()
-> parse_args();
kernel/params.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | /* Args looks like "foo=bar,bar2 baz=fuz wiz". */ char *parse_args(const char *doing, char *args, const struct kernel_param *params, unsigned num, s16 min_level, s16 max_level, void *arg, int (*unknown)(char *param, char *val, const char *doing, void *arg)) { char *param, *val, *err = NULL; /* Chew leading spaces */ args = skip_spaces(args); if (*args) pr_debug("doing %s, parsing ARGS: '%s'\n", doing, args); while (*args) { int ret; int irq_was_disabled; args = next_arg(args, ¶m, &val); /* Stop at -- */ if (!val && strcmp(param, "--") == 0) return err ?: args; irq_was_disabled = irqs_disabled(); ret = parse_one(param, val, doing, params, num, min_level, max_level, arg, unknown); if (irq_was_disabled && !irqs_disabled()) pr_warn("%s: option '%s' enabled irq's!\n", doing, param); switch (ret) { case 0: continue; case -ENOENT: pr_err("%s: Unknown parameter `%s'\n", doing, param); break; case -ENOSPC: pr_err("%s: `%s' too large for parameter `%s'\n", doing, val ?: "", param); break; default: pr_err("%s: `%s' invalid for parameter `%s'\n", doing, val ?: "", param); break; } err = ERR_PTR(ret); } return err; } | cs |
args = next_arg(args, ¶m, &val);
args로 bootargs 속성 값인 cmdline을 전달하고 그 내부에 param과 val를 output으로 전달하게 됩니다. 내부는 "A=B, C=D"와 같은 형식에서 A, C는 param이고, B, D는 value로서 output으로 전달됩니다. 스페이스를 기준으로 전달되며 while문에서 args가 null일 때까지 반복해서 param과 val을 얻어옵니다.
irq_was_disabled = irqs_disabled();
System control register의 인터럽트가 disable 상태인지 확인합니다.
ret = parse_one(param, val, doing, params, num, min_level, max_level, arg, unknown);
param, val, doing 등의 파라미터와 마지막으로 함수포인터 unknown이 전달됩니다. 위 unknown은 parse_early_options()내에서 전달하는 do_early_param 함수포인터입니다. next_arg로 가져온 param, val를 전달하여 do_early_param() 함수에서 뭔가 처리하는 것 같습니다. 해당 함수는 아래 설명하겠습니다.
parse_one() 함수 이후는 에러 핸들링을 위한 로직입니다. 위에서 설명한대로 최종적으로 arg가 NULL이 될 때까지 위 과정을 반복하게 됩니다.
parse_early_param()
-> parse_early_options()
-> parse_args();
-> do_ealrly_param(); (parse_early_options() 함수에서 전달된 함수포인터)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | static int __init do_early_param(char *param, char *val, const char *unused, void *arg) { 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; } | cs |
do_early_param() 함수는 while() 내에서 param과 val를 하나씩 전달받아 실행이 됩니다. 이 때 obs_kernel_param에 등록된 모든 setup_func() 들을 호출해주며 val 값을 전달해주고 있습니다. setup_func() 함수는 early_param() 함수를 통해 등록된 함수포인터입니다. obs_kernel_param은 컴파일 타임에 .init.setup 섹션에 메모리 할당되는 녀석들입니다.
'Linux > Kernel Analysis' 카테고리의 다른 글
[커널분석] arm64_memblock_init() (1) | 2018.09.15 |
---|---|
[ARMv8] aarch64 프로세서 상태 레지스터(PSTATE) (0) | 2018.09.08 |
[커널분석] static void __init setup_machine_fdt(phys_addr_t dt_phys) (0) | 2018.08.25 |
void __init early_fixmap_init(void) (작성중...) (0) | 2018.08.21 |
[Linux] Writing udev rules, udev 규칙 작성법에 관하여.. (1) | 2015.10.31 |