Skip to content

Latest commit

 

History

History
1499 lines (1283 loc) · 38.2 KB

a10c_108.md

File metadata and controls

1499 lines (1283 loc) · 38.2 KB
ARM10C : 108 주차
일시 : 2015.07.04 (108 주차 스터디 진행)
모임명 : NAVER개발자커뮤니티지원_10차ARM-C
장소 : 토즈 타워점
장소지원 : NAVER 개발자 커뮤니티 지원 프로그램
참여인원 : 3명

============

108 주차 진도

  • parse_args() 복습
  • console_init()->con_init()
  • console_init()->s3c24xx_serial_console_init()

__setup("console=", console_setup)을 복습

	// static_command_line: "console=ttySAC2,115200 init=/linuxrc"
	parse_args("Booting kernel", static_command_line, __start___param,
		   __stop___param - __start___param,
		   -1, -1, &unknown_bootoption);
/* Args looks like "foo=bar,bar2 baz=fuz wiz". */
// ARM10C 20131019
// parse_args("early options", cmdline, NULL, 0, 0, 0, do_early_param);
// ARM10C 20150627
// "Booting kernel", "console=ttySAC2,115200 init=/linuxrc",
// __start___param, 120, -1, -1, &unknown_bootoption
int parse_args(const char *doing,
	       char *args,
	       const struct kernel_param *params,
	       unsigned num,
	       s16 min_level,
	       s16 max_level,
	       int (*unknown)(char *param, char *val, const char *doing))
{
	char *param, *val;

	/* Chew leading spaces */
	// string의 앞 공백 제거
	// args: "console=ttySAC2,115200 init=/linuxrc"
	// args: "console=ttySAC2,115200 init=/linuxrc"
	args = skip_spaces(args);
	// args: "console=ttySAC2,115200 init=/linuxrc"
	// args: "console=ttySAC2,115200 init=/linuxrc"
// ARM10C 20150627
// "Booting kernel", "console=ttySAC2,115200 init=/linuxrc",
// __start___param, 120, -1, -1, &unknown_bootoption
int parse_args(const char *doing,
	       char *args,
	       const struct kernel_param *params,
	       unsigned num,
	       s16 min_level,
	       s16 max_level,
	       int (*unknown)(char *param, char *val, const char *doing))
{
...
	// args: "console=ttySAC2,115200 init=/linuxrc"
	args = skip_spaces(args);
	// args: "console=ttySAC2,115200 init=/linuxrc"

	// dtb 에서 복사된 값
	// "console=ttySAC2,115200 init=/linuxrc" 이 args 값임
	// args: "console=ttySAC2,115200 init=/linuxrc"
	if (*args)
		// doing: "Booting kernel", args: "console=ttySAC2,115200 init=/linuxrc"
		pr_debug("doing %s, parsing ARGS: '%s'\n", doing, args);
		// "doing Booting kernel, parsing ARGS: 'console=ttySAC2,115200 init=/linuxrc'\n"

	// args: "console=ttySAC2,115200 init=/linuxrc"
	while (*args) {
		int ret;
		int irq_was_disabled;

		// args: "console=ttySAC2,115200 init=/linuxrc"
		// next_arg("console=ttySAC2,115200 init=/linuxrc", &param, &val): "init=/linuxrc"
		args = next_arg(args, &param, &val);
		// args: "init=/linuxrc", param: "console", val: "ttySAC2,115200"
  • next_arg(args, &param, &val); 호출
// ARM10C 20150627
// args: "console=ttySAC2,115200 init=/linuxrc", &param, &val
static char *next_arg(char *args, char **param, char **val)
{
	unsigned int i, equals = 0;
	// equal: 0
	// equal: 0

	int in_quote = 0, quoted = 0;
	// in_quote: 0, quoted: 0
	// in_quote: 0, quoted: 0

	char *next;

	// *args: 'c'
	// *args: 'c'
	if (*args == '"') {
		args++;
		in_quote = 1;
		quoted = 1;
	}

	// equals 값은 "=" string index 값
	for (i = 0; args[i]; i++) {
		// i: 0, args[0]: 'c', isspace('c'): 0, in_quote: 0
		// i: 1, args[1]: 'o', isspace('o'): 0, in_quote: 0
		// i: 2, args[2]: 'n', isspace('n'): 0, in_quote: 0
		// i: 3, args[3]: 's', isspace('s'): 0, in_quote: 0
		// i: 4, args[4]: 'o', isspace('o'): 0, in_quote: 0
		// i: 5, args[5]: 'l', isspace('l'): 0, in_quote: 0
		// i: 6, args[6]: 'e', isspace('e'): 0, in_quote: 0
		// i: 7, args[7]: '=', isspace('='): 0, in_quote: 0
		// ...
		// i: 22, args[22]: ' ', isspace(' '): 1, in_quote: 0
		if (isspace(args[i]) && !in_quote)
			break;
			// break 수행

		// equals: 0
		// equals: 0
		// equals: 0
		// equals: 0
		// equals: 0
		// equals: 0
		// equals: 0
		// equals: 0
		// ...
		// equals: 0
		if (equals == 0) {
			// i: 0, args[0]: 'c'
			// i: 1, args[1]: 'o'
			// i: 2, args[2]: 'n'
			// i: 3, args[3]: 's'
			// i: 4, args[4]: 'o'
			// i: 5, args[5]: 'l'
			// i: 6, args[6]: 'e'
			// i: 7, args[7]: '='
			// ...
			// i: 21, args[21]: '0'
			if (args[i] == '=')
				// equals: 0, i: 7
				equals = i;
				// equals: 7
		}

		// i: 0, args[0]: 'c'
		// i: 1, args[1]: 'o'
		// i: 2, args[2]: 'n'
		// i: 3, args[3]: 's'
		// i: 4, args[4]: 'o'
		// i: 5, args[5]: 'l'
		// i: 6, args[6]: 'e'
		// i: 7, args[7]: '='
		// ...
		// i: 21, args[21]: '0'
		if (args[i] == '"')
			in_quote = !in_quote;

		// i: 7...22 까지 루프 수행
	}

	// *param: param, args: "console=ttySAC2,115200 init=/linuxrc"
	*param = args;
	// *param: param: "console=ttySAC2,115200 init=/linuxrc"

	// equals: 7
	if (!equals)
		*val = NULL;
	else {
		// equals: 7, args[7]: '='
		args[equals] = '\0';
		// args[7]: '\0'

		// *val: val, args: "console\0ttySAC2,115200 init=/linuxrc", equals: 7
		*val = args + equals + 1;
		// *val: val: "ttySAC2,115200 init=/linuxrc"

		/* Don't include quotes in value. */
		// **val: *val: 't'
		if (**val == '"') {
			(*val)++;
			if (args[i-1] == '"')
				args[i-1] = '\0';
		}

		// quoted: 0, i: 22, arg[21]: '0'
		if (quoted && args[i-1] == '"')
			args[i-1] = '\0';
	}

	// i: 22, arg[22]: ' '
	if (args[i]) {
		// i: 22, arg[22]: ' '
		args[i] = '\0';
		// arg[22]: '\0'

		// args: "console\0ttySAC2,115200\0init=/linuxrc", i: 22
		next = args + i + 1;
		// next: "init=/linuxrc"
	} else
		next = args + i;

	/* Chew up trailing spaces. */
	// next: "init=/linuxrc"
	return skip_spaces(next);
	// return "init=/linuxrc"
}
// ARM10C 20150627
// "Booting kernel", "console=ttySAC2,115200 init=/linuxrc",
// __start___param, 120, -1, -1, &unknown_bootoption
int parse_args(const char *doing,
	       char *args,
	       const struct kernel_param *params,
	       unsigned num,
	       s16 min_level,
	       s16 max_level,
	       int (*unknown)(char *param, char *val, const char *doing))
{
...

	// args: "console=ttySAC2,115200 init=/linuxrc"
	while (*args) {
		int ret;
		int irq_was_disabled;

		// args: "console=ttySAC2,115200 init=/linuxrc"
		// next_arg("console=ttySAC2,115200 init=/linuxrc", &param, &val): "init=/linuxrc"
		args = next_arg(args, &param, &val);
		// args: "init=/linuxrc", param: "console", val: "ttySAC2,115200"

		// irqs_disabled(): 1
		irq_was_disabled = irqs_disabled();
		// irq_was_disabled: 1

		// param: "console", val: "ttySAC2,115200", doing: "Booting kernel",
		// params: __start___param, num: 120, min_level, -1, max_level: -1, unknown: unknown_bootoption
		// parse_one("console", "ttySAC2,115200", "Booting kernel", __start___param, 120, -1, -1, unknown_bootoption): 0
		ret = parse_one(param, val, doing, params, num,
				min_level, max_level, unknown);
		// ret: 0
  • ret = parse_one(param, val, doing, params, num, min_level, max_level, unknown);호출
// ARM10C 20150627
// param: "console", val: "ttySAC2,115200", doing: "Booting kernel",
// params: __start___param, num: 120, min_level, -1, max_level: -1, unknown: unknown_bootoption
static int parse_one(char *param,
		     char *val,
		     const char *doing,
		     const struct kernel_param *params,
		     unsigned num_params,
		     s16 min_level,
		     s16 max_level,
		     int (*handle_unknown)(char *param, char *val,
				     const char *doing))
{
	unsigned int i;
	int err;

	/* Find parameter */
	// num_params: 120
	for (i = 0; i < num_params; i++) {
		// i: 0, param: "console", params[0].name
		if (parameq(param, params[i].name)) {
			if (params[i].level < min_level
			    || params[i].level > max_level)
				return 0;
			/* No one handled NULL, so do it here. */
			if (!val &&
			    !(params[i].ops->flags & KERNEL_PARAM_FL_NOARG))
				return -EINVAL;
			pr_debug("handling %s with %p\n", param,
				params[i].ops->set);
			mutex_lock(&param_lock);
			err = params[i].ops->set(val, &params[i]);
			mutex_unlock(&param_lock);
			return err;
		}
		// i: 1...120 루프 수행
	}
	// 위 루프 수행 결과 param: "console"과 동일한 param이 없음

	// handle_unknown: unknown_bootoption
	if (handle_unknown) {
		// doing: "Booting kernel", param: "console", val: "ttySAC2,115200"
		pr_debug("doing %s: %s='%s'\n", doing, param, val);
		// "doing Booting kernel: console=ttySAC2,115200\n"

		// handle_unknown: unknown_bootoption
		// param: "console", val: "ttySAC2,115200", doing: "Booting kernel"
		// unknown_bootoption("console", "ttySAC2,115200", "Booting kernel"): 0
		return handle_unknown(param, val, doing);
		// return 0
  • return handle_unknown(param, val, doing); 에서 unknown_bootoption() 호출
// ARM10C 20150627
// param: "console", val: "ttySAC2,115200", doing: "Booting kernel"
static int __init unknown_bootoption(char *param, char *val, const char *unused)
{
	// param: "console", val: "ttySAC2,115200", unused: "Booting kernel"
	repair_env_string(param, val, unused);

	// repair_env_string에서 한일:
	// param: "console=ttySAC2,115200"

	/* Handle obsolete-style parameters */
	// param: "console=ttySAC2,115200"
	// obsolete_checksetup("console=ttySAC2,115200"): 1
	if (obsolete_checksetup(param))
		return 0;
		// return 0
  • obsolete_checksetup(param) 에서 호출
// ARM10C 20150627
// param: "console=ttySAC2,115200"
static int __init obsolete_checksetup(char *line)
{
	const struct obs_kernel_param *p;
	int had_early_param = 0;
	// had_early_param: 0

	p = __setup_start;
	do {
		// p->str: __setup_console_setup.str: "console=", strlen("console="): 8
		int n = strlen(p->str);
		// n: 8

		// line: "console=ttySAC2,115200", p->str: __setup_console_setup.str: "console=", n: 8
		// parameqn("console=ttySAC2,115200", "console=", 8): true
		if (parameqn(line, p->str, n)) {
			// p->early: __setup_console_setup.early: 0,
			// p->setup_func: __setup_console_setup.setup_func: console_setup
			// line: "console=ttySAC2,115200", n: 8
			// console_setup("ttySAC2,115200"): 1
			if (p->early) {
				/* Already done in parse_early_param?
				 * (Needs exact match on param part).
				 * Keep iterating, as we can have early
				 * params and __setups of same names 8( */
				if (line[n] == '\0' || line[n] == '=')
					had_early_param = 1;
			} else if (!p->setup_func) {
				pr_warn("Parameter %s is obsolete, ignored\n",
					p->str);
				return 1;
			} else if (p->setup_func(line + n))
				return 1;
				// return 1
  • console_setup() 호출
// ARM10C 20150627
// "ttySAC2,115200"
static int __init console_setup(char *str)
{
	// sizeof(console_cmdline[0].name): 8
	char buf[sizeof(console_cmdline[0].name) + 4]; /* 4 for index */
	char *s, *options, *brl_options = NULL;
	// brl_options: NULL

	int idx;

	// &str: &"ttySAC2,115200", &brl_options: &NULL
	// _braille_console_setup(&"ttySAC2,115200", &NULL): NULL
	if (_braille_console_setup(&str, &brl_options))
		return 1;

	/*
	 * Decode str into name, index, options.
	 */
	// str[0]: 't'
	if (str[0] >= '0' && str[0] <= '9') {
		strcpy(buf, "ttyS");
		strncpy(buf + 4, str, sizeof(buf) - 5);
	} else {
		// str: "ttySAC2,115200", sizeof(buf): 12
		strncpy(buf, str, sizeof(buf) - 1);
		// buf: "ttySAC2,115"
	}
	// sizeof(buf): 12
	buf[sizeof(buf) - 1] = 0;
	// buf: "ttySAC2,11"

	// str: "ttySAC2,115200", strchr("ttySAC2,115200", ','): ",115200"
	if ((options = strchr(str, ',')) != NULL)
		// options: ",115200"
		*(options++) = 0;
		// options: "115200"
#ifdef __sparc__
	if (!strcmp(str, "ttya"))
		strcpy(buf, "ttyS0");
	if (!strcmp(str, "ttyb"))
		strcpy(buf, "ttyS1");
#endif
	// buf: "ttySAC2,11"
	for (s = buf; *s; s++)
		// *s: 't'
		// *s: 't'
		// *s: 'y'
		// *s: 'S'
		// *s: 'A'
		// *s: 'C'
		// *s: '2'
		if ((*s >= '0' && *s <= '9') || *s == ',')
			break;
			// break 수행

	// s: "2,11", simple_strtoul("2,11", NULL, 10): 2
	idx = simple_strtoul(s, NULL, 10);
	// idx: 2

	// *s: '2'
	*s = 0;
	// buf: "ttySAC"

	// buf: "ttySAC", idx: 2, options: "115200", brl_options: NULL
	__add_preferred_console(buf, idx, options, brl_options);

	// __add_preferred_console에서 한일:
	// selected_console: 0
	// console_cmdline[0].name: "ttySAC"
	// console_cmdline[0].options: "115200"
	// console_cmdline[0].index: 2

	console_set_on_cmdline = 1;
	// console_set_on_cmdline: 1

	return 1;
	// return 1
}
__setup("console=", console_setup);
  • console_setup에서 한일: // selected_console: 0 // console_cmdline[0].name: "ttySAC" // console_cmdline[0].options: "115200" // console_cmdline[0].index: 2 // console_set_on_cmdline: 1
// ARM10C 20150627
// param: "console=ttySAC2,115200"
static int __init obsolete_checksetup(char *line)
{
	const struct obs_kernel_param *p;
	int had_early_param = 0;
	// had_early_param: 0

	p = __setup_start;
	do {
		// p->str: __setup_console_setup.str: "console=", strlen("console="): 8
		int n = strlen(p->str);
		// n: 8

		// line: "console=ttySAC2,115200", p->str: __setup_console_setup.str: "console=", n: 8
		// parameqn("console=ttySAC2,115200", "console=", 8): true
		if (parameqn(line, p->str, n)) {
			// p->early: __setup_console_setup.early: 0,
			// p->setup_func: __setup_console_setup.setup_func: console_setup
			// line: "console=ttySAC2,115200", n: 8
			// console_setup("ttySAC2,115200"): 1
			if (p->early) {
				/* Already done in parse_early_param?
				 * (Needs exact match on param part).
				 * Keep iterating, as we can have early
				 * params and __setups of same names 8( */
				if (line[n] == '\0' || line[n] == '=')
					had_early_param = 1;
			} else if (!p->setup_func) {
				pr_warn("Parameter %s is obsolete, ignored\n",
					p->str);
				return 1;
			} else if (p->setup_func(line + n))
				return 1;
				// return 1

				// console_setup에서 한일:
				// selected_console: 0
				// console_cmdline[0].name: "ttySAC"
				// console_cmdline[0].options: "115200"
				// console_cmdline[0].index: 2
				// console_set_on_cmdline: 1
		}
		p++;
	} while (p < __setup_end);

	return had_early_param;
}
  • obsolete_checksetup에서 한일: // selected_console: 0 // console_cmdline[0].name: "ttySAC" // console_cmdline[0].options: "115200" // console_cmdline[0].index: 2 // console_set_on_cmdline: 1
// ARM10C 20150627
// param: "console", val: "ttySAC2,115200", doing: "Booting kernel"
static int __init unknown_bootoption(char *param, char *val, const char *unused)
{
	// param: "console", val: "ttySAC2,115200", unused: "Booting kernel"
	repair_env_string(param, val, unused);

	// repair_env_string에서 한일:
	// param: "console=ttySAC2,115200"

	/* Handle obsolete-style parameters */
	// param: "console=ttySAC2,115200"
	// obsolete_checksetup("console=ttySAC2,115200"): 1
	if (obsolete_checksetup(param))
		return 0;
		// return 0

	// obsolete_checksetup에서 한일:
	// selected_console: 0
	// console_cmdline[0].name: "ttySAC"
	// console_cmdline[0].options: "115200"
	// console_cmdline[0].index: 2
	// console_set_on_cmdline: 1

	/* Unused module parameter. */
	if (strchr(param, '.') && (!val || strchr(param, '.') < val))
		return 0;

	if (panic_later)
		return 0;

	if (val) {
		/* Environment option */
		unsigned int i;
		for (i = 0; envp_init[i]; i++) {
			if (i == MAX_INIT_ENVS) {
				panic_later = "Too many boot env vars at `%s'";
				panic_param = param;
			}
			if (!strncmp(param, envp_init[i], val - param))
				break;
		}
		envp_init[i] = param;
	} else {
		/* Command line option */
		unsigned int i;
		for (i = 0; argv_init[i]; i++) {
			if (i == MAX_INIT_ARGS) {
				panic_later = "Too many boot init vars at `%s'";
				panic_param = param;
			}
		}
		argv_init[i] = param;
	}
	return 0;
}
// ARM10C 20150627
// "Booting kernel", "console=ttySAC2,115200 init=/linuxrc",
// __start___param, 120, -1, -1, &unknown_bootoption
int parse_args(const char *doing,
	       char *args,
	       const struct kernel_param *params,
	       unsigned num,
	       s16 min_level,
	       s16 max_level,
	       int (*unknown)(char *param, char *val, const char *doing))
{
	char *param, *val;

	/* Chew leading spaces */
	// string의 앞 공백 제거
	// args: "console=ttySAC2,115200 init=/linuxrc"
	args = skip_spaces(args);
	// args: "console=ttySAC2,115200 init=/linuxrc"

	// dtb 에서 복사된 값
	// "console=ttySAC2,115200 init=/linuxrc" 이 args 값임
	// args: "console=ttySAC2,115200 init=/linuxrc"
	if (*args)
		// doing: "Booting kernel", args: "console=ttySAC2,115200 init=/linuxrc"
		pr_debug("doing %s, parsing ARGS: '%s'\n", doing, args);
		// "doing Booting kernel, parsing ARGS: 'console=ttySAC2,115200 init=/linuxrc'\n"

	// args: "console=ttySAC2,115200 init=/linuxrc"
	while (*args) {
		int ret;
		int irq_was_disabled;

		// args: "console=ttySAC2,115200 init=/linuxrc"
		// next_arg("console=ttySAC2,115200 init=/linuxrc", &param, &val): "init=/linuxrc"
		args = next_arg(args, &param, &val);
		// args: "init=/linuxrc", param: "console", val: "ttySAC2,115200"

		// irqs_disabled(): 1
		irq_was_disabled = irqs_disabled();
		// irq_was_disabled: 1

		// param: "console", val: "ttySAC2,115200", doing: "Booting kernel",
		// params: __start___param, num: 120, min_level, -1, max_level: -1, unknown: unknown_bootoption
		// parse_one("console", "ttySAC2,115200", "Booting kernel", __start___param, 120, -1, -1, unknown_bootoption): 0
		ret = parse_one(param, val, doing, params, num,
				min_level, max_level, unknown);
		// ret: 0

		// irq 값이 바뀌었는지 확인
		// irq_was_disabled: 1, irqs_disabled(): 1
		if (irq_was_disabled && !irqs_disabled())
			pr_warn("%s: option '%s' enabled irq's!\n",
				doing, param);

		// ret: 0
		switch (ret) {
		case -ENOENT:
			pr_err("%s: Unknown parameter `%s'\n", doing, param);
			return ret;
		case -ENOSPC:
			pr_err("%s: `%s' too large for parameter `%s'\n",
			       doing, val ?: "", param);
			return ret;
		case 0:
			break;
			// break 수행
		default:
			pr_err("%s: `%s' invalid for parameter `%s'\n",
			       doing, val ?: "", param);
			return ret;
		}
	}

	/* All parsed OK. */
	return 0;
	// return 0
}
  • 여기서 __setup()에서 foo(), bar() 함수를 동적할당해서 사용하는 것을 분석했다.
  • 다시 돌아가서 parse_args()에서는
  • DTB에서 넘어온 bootargs를 파싱하여 param, val을 뽑아내고 그에 대응되는
  • kernel_param 구조체에 값을 등록함.

main.c::main.c()

  • 그럼 다시 console_init()을 분석해 보자.

  • called: start_kernel()

asmlinkage void __init start_kernel(void)
{
...
	// irqs_disabled(): 1
	WARN(!irqs_disabled(), "Interrupts were enabled early\n");

	// early_boot_irqs_disabled: true
	early_boot_irqs_disabled = false;
	// early_boot_irqs_disabled: false

	local_irq_enable();
	// IRQ를 enable 함

	kmem_cache_init_late(); // null function

	/*
	 * HACK ALERT! This is early. We're enabling the console before
	 * we've done PCI setups etc, and console_init() must be aware of
	 * this. But we do want output early, in case something goes wrong.
	 */
	console_init();
  • call: start_kernel()->console_init()

tty_io.c::console_init()

  • called: start_kernel()->console_init()
// ARM10C 20150627
void __init console_init(void)
{
	initcall_t *call;

	/* Setup the default TTY line discipline. */
	tty_ldisc_begin();

	// tty_ldisc_begin에서 한일:
	// tty_ldiscs[0]: &tty_ldisc_N_TTY
	// (&tty_ldisc_N_TTY)->num: 0
	// (&tty_ldisc_N_TTY)->refcount: 0

	/*
	 * set up the console device so that later boot sequences can
	 * inform about problems etc..
	 */
	call = __con_initcall_start;
	// call: &__con_initcall_start

	// call: &__con_initcall_start
	while (call < __con_initcall_end) {
		// call:__initcall_s3c24xx_serial_console_init:
		// s3c24xx_serial_console_init
		(*call)();
		call++;
	}
  • call: start_kernel()->console_init()->s3c24xx_serial_console_init()

samsung.c::s3c24xx_serial_console_init()

  • called: start_kernel()->console_init()->s3c24xx_serial_console_init()
// ARM10C 20150627
static struct console s3c24xx_serial_console;

// ARM10C 20150627
static int __init s3c24xx_serial_console_init(void)
{
	register_console(&s3c24xx_serial_console);
	return 0;
}
console_initcall(s3c24xx_serial_console_init);
// ARM10C 20150627
static struct console s3c24xx_serial_console = {
	.name		= S3C24XX_SERIAL_NAME,
	.device		= uart_console_device,
	// CON_PRINTBUFFER: 1
	.flags		= CON_PRINTBUFFER,
	.index		= -1,
	.write		= s3c24xx_serial_console_write,
	.setup		= s3c24xx_serial_console_setup,
	.data		= &s3c24xx_uart_drv,
};
#endif /* CONFIG_SERIAL_SAMSUNG_CONSOLE */
  • call: start_kernel()->console_init()->s3c24xx_serial_console_init()
  • register_console(&s3c24xx_serial_console);

printk.c::register_console()

  • called: start_kernel()->console_init()->s3c24xx_serial_console_init()
  • register_console(&s3c24xx_serial_console);
// ARM10C 20150627
// &s3c24xx_serial_console
void register_console(struct console *newcon)
{
	int i;
	unsigned long flags;
	struct console *bcon = NULL;
	// bcon: NULL

	struct console_cmdline *c;

	// console_drivers: NULL
	if (console_drivers)
		for_each_console(bcon)
			if (WARN(bcon == newcon,
					"console '%s%d' already registered\n",
					bcon->name, bcon->index))
				return;

	/*
	 * before we register a new CON_BOOT console, make sure we don't
	 * already have a valid console
	 */
	// console_drivers: NULL, newcon->flags: (&s3c24xx_serial_console)->flags: 1, CON_BOOT: 8
	if (console_drivers && newcon->flags & CON_BOOT) {
		/* find the last or real console */
		for_each_console(bcon) {
			if (!(bcon->flags & CON_BOOT)) {
				pr_info("Too late to register bootconsole %s%d\n",
					newcon->name, newcon->index);
				return;
			}
		}
	}

	// console_drivers: NULL
	if (console_drivers && console_drivers->flags & CON_BOOT)
		bcon = console_drivers;

	// preferred_console: -1, bcon: NULL, console_drivers: NULL
	if (preferred_console < 0 || bcon || !console_drivers)
		// selected_console: 0
		preferred_console = selected_console;
		// preferred_console: 0

	// newcon->early_setup: (&s3c24xx_serial_console)->early_setup: NULL
	if (newcon->early_setup)
		newcon->early_setup();

	/*
	 *	See if we want to use this console driver. If we
	 *	didn't select a console we take the first one
	 *	that registers here.
	 */
	// preferred_console: 0
	if (preferred_console < 0) {
		if (newcon->index < 0)
			newcon->index = 0;

		if (newcon->setup == NULL ||
		    newcon->setup(newcon, NULL) == 0) {
			newcon->flags |= CON_ENABLED;
			if (newcon->device) {
				newcon->flags |= CON_CONSDEV;
				preferred_console = 0;
			}
		}
	}
	// MAX_CMDLINECONSOLES: 8, c->name[0]: console_cmdline[0].name[0]: 't'
	for (i = 0, c = console_cmdline;
	     i < MAX_CMDLINECONSOLES && c->name[0];
	     i++, c++) {
		// console_cmdline[0].name: 'ttySAC",
		// newcon->name (&s3c24xx_serial_console).name: 'ttySAC'
		// strcmp(c->name, newcon->name): 0
		if (strcmp(c->name, newcon->name) != 0)
			continue;
		if (newcon->index >= 0 &&
		    newcon->index != c->index)
			continue;
		if (newcon->index < 0)
			newcon->index = c->index;

		if (_braille_register_console(newcon, c))
			return;

		if (newcon->setup &&
		    newcon->setup(newcon, console_cmdline[i].options) != 0)
			break;
		newcon->flags |= CON_ENABLED;
		newcon->index = c->index;
		if (i == selected_console) {
			newcon->flags |= CON_CONSDEV;
			preferred_console = selected_console;
		}
		break;
	}

	// newcon->flags: (&s3c24xx_serial_console)->flags: 1, CON_ENABLED: 4
	if (!(newcon->flags & CON_ENABLED))
		return;
		// return 수행
  • called: start_kernel()->console_init()->s3c24xx_serial_console_init()
  • register_console(&s3c24xx_serial_console);
    • s3c24xx_serial_console_setup()

samsung.c::s3c24xx_serial_console_setup()

// ARM10C 20150627
// newcon: &s3c24xx_serial_console, NULL
static int __init
s3c24xx_serial_console_setup(struct console *co, char *options)
{
	struct uart_port *port;
	int baud = 9600;
	// baud: 9600

	int bits = 8;
	// bits: 8

	int parity = 'n';
	// parity: 'n'

	int flow = 'n';
	// flow: 'n'

	// co: &s3c24xx_serial_console, co->index: (&s3c24xx_serial_console)->index: 0,
	// options: NULL
	dbg("s3c24xx_serial_console_setup: co=%p (%d), %s\n",
	    co, co->index, options); // null function

	/* is this a valid port */

	// co->index: (&s3c24xx_serial_console)->index: 0, CONFIG_SERIAL_SAMSUNG_UARTS: 4
	if (co->index == -1 || co->index >= CONFIG_SERIAL_SAMSUNG_UARTS)
		co->index = 0;

	// co->index: (&s3c24xx_serial_console)->index: 0
	port = &s3c24xx_serial_ports[co->index].port;
	// port: &s3c24xx_serial_ports[0].port

	/* is the port configured? */

	// port->mapbase: (&s3c24xx_serial_ports[0].port)->mapbase: NULL
	if (port->mapbase == 0x0)
		// ENODEV: 19
		return -ENODEV;
		// return -19
  • return: start_kernel()->console_init()->s3c24xx_serial_console_init()
  • register_console(&s3c24xx_serial_console);
    • s3c24xx_serial_console_setup(): -19

printk.c::register_console()

  • return: start_kernel()->console_init()->s3c24xx_serial_console_init()
  • register_console(&s3c24xx_serial_console);
    • s3c24xx_serial_console_setup(): -19
// ARM10C 20150627
// &s3c24xx_serial_console
void register_console(struct console *newcon)
{
...
	// preferred_console: 0
	if (preferred_console < 0) {
		if (newcon->index < 0)
			newcon->index = 0;

		if (newcon->setup == NULL ||
		    newcon->setup(newcon, NULL) == 0) {
			newcon->flags |= CON_ENABLED;
			if (newcon->device) {
				newcon->flags |= CON_CONSDEV;
				preferred_console = 0;
			}
		}
	}
	/*
	 *	See if this console matches one we selected on
	 *	the command line.
	 */
	// MAX_CMDLINECONSOLES: 8, c->name[0]: console_cmdline[0].name[0]: NULL
	for (i = 0, c = console_cmdline;
	     i < MAX_CMDLINECONSOLES && c->name[0];
	     i++, c++) {
		if (strcmp(c->name, newcon->name) != 0)
			continue;
		if (newcon->index >= 0 &&
		    newcon->index != c->index)
			continue;
		if (newcon->index < 0)
			newcon->index = c->index;


		if (_braille_register_console(newcon, c))
			return;

		if (newcon->setup &&
		    newcon->setup(newcon, console_cmdline[i].options) != 0)
			// s3c24xx_serial_console_setup()
  • call: start_kernel()->console_init()->s3c24xx_serial_console_init()
  • register_console(&s3c24xx_serial_console);
    • s3c24xx_serial_console_setup()

samsung.c::s3c24xx_serial_console_setup()

  • called: start_kernel()->console_init()->s3c24xx_serial_console_init()
  • register_console(&s3c24xx_serial_console);
    • s3c24xx_serial_console_setup()
// ARM10C 20150627
// newcon: &s3c24xx_serial_console, NULL
static int __init
s3c24xx_serial_console_setup(struct console *co, char *options)
{
	struct uart_port *port;
	int baud = 9600;
	// baud: 9600

	int bits = 8;
	// bits: 8

	int parity = 'n';
	// parity: 'n'

	int flow = 'n';
	// flow: 'n'

	// co: &s3c24xx_serial_console, co->index: (&s3c24xx_serial_console)->index: 0,
	// options: NULL
	dbg("s3c24xx_serial_console_setup: co=%p (%d), %s\n",
	    co, co->index, options); // null function

	/* is this a valid port */

	// co->index: (&s3c24xx_serial_console)->index: 0, CONFIG_SERIAL_SAMSUNG_UARTS: 4
	if (co->index == -1 || co->index >= CONFIG_SERIAL_SAMSUNG_UARTS)
		co->index = 0;

	// co->index: (&s3c24xx_serial_console)->index: 0
	port = &s3c24xx_serial_ports[co->index].port;
	// port: &s3c24xx_serial_ports[0].port

	/* is the port configured? */

	// port->mapbase: (&s3c24xx_serial_ports[0].port)->mapbase: NULL
	if (port->mapbase == 0x0)
		// ENODEV: 19
		return -ENODEV;
		// return -19
  • called: start_kernel()->console_init()->s3c24xx_serial_console_init()
  • register_console(&s3c24xx_serial_console);
    • s3c24xx_serial_console_setup()
    • return -19

printk.c::register_console()

  • return: start_kernel()->console_init()->s3c24xx_serial_console_init()
  • register_console(&s3c24xx_serial_console);
    • s3c24xx_serial_console_setup()
    • return -19
// ARM10C 20150627
// &s3c24xx_serial_console
void register_console(struct console *newcon)
{
...
	// MAX_CMDLINECONSOLES: 8, c->name[0]: console_cmdline[0].name[0]: NULL
	for (i = 0, c = console_cmdline;
	     i < MAX_CMDLINECONSOLES && c->name[0];
	     i++, c++) {
		if (strcmp(c->name, newcon->name) != 0)
			continue;
		if (newcon->index >= 0 &&
		    newcon->index != c->index)
			continue;
		if (newcon->index < 0)
			newcon->index = c->index;

		if (_braille_register_console(newcon, c))
			return;

		if (newcon->setup &&
		    newcon->setup(newcon, console_cmdline[i].options) != 0)
			// s3c24xx_serial_console_setup(): -19
			break;
  • 여기서 -19리턴값이면 이상하다. 그래서 다시 살펴 보니.
  • console_init()에서 __con_initcall_con_init 이 먼저 호출되어야만 했다.
  • 따라서 다시 con_init()을 분석한다.

tty_io.c::console_init()

  • called: start_kernel()->console_init()
// ARM10C 20150627
void __init console_init(void)
{
	initcall_t *call;

	/* Setup the default TTY line discipline. */
	tty_ldisc_begin();

	// tty_ldisc_begin에서 한일:
	// tty_ldiscs[0]: &tty_ldisc_N_TTY
	// (&tty_ldisc_N_TTY)->num: 0
	// (&tty_ldisc_N_TTY)->refcount: 0

	/*
	 * set up the console device so that later boot sequences can
	 * inform about problems etc..
	 */
	call = __con_initcall_start;
	// call: &__con_initcall_start

	// call: &__con_initcall_start
	while (call < __con_initcall_end) {
	    // call: con_init()
		(*call)();
		call++;
	}
}
  • con_init()을 분석하자.
  • call: start_kernel()->console_init()->con_init()
  • while (call < __con_initcall_end) {
  • call: con_init()

vt.c::con_init()

  • called: start_kernel()->console_init()->con_init()
  • call: con_init()
static int __init con_init(void)
{
	const char *display_desc = NULL;
	struct vc_data *vc;
	unsigned int currcons = 0, i;

	console_lock();
  • call: start_kernel()->console_init()->con_init()
  • call: con_init()
  • console_lock()

printk.c::console_lock()

  • called: start_kernel()->console_init()->con_init()
  • call: con_init()
  • console_lock()
void console_lock(void)
{
	might_sleep();

	down(&console_sem);
	if (console_suspended)
		return;
	console_locked = 1;
	console_may_schedule = 1;
	mutex_acquire(&console_lock_dep_map, 0, 0, _RET_IP_);
}
EXPORT_SYMBOL(console_lock);
  • call: start_kernel()->console_init()->con_init()
  • call: con_init()
  • console_lock()
    • down()

printk.c::down()

  • call: start_kernel()->console_init()->con_init()
  • call: con_init()
  • console_lock()
    • down(&console_sem);
  • 선언문부터 알아보자.
#define DEFINE_SEMAPHORE(name)	\
	struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1)
#define __SEMAPHORE_INITIALIZER(name, n)				\
{									\
	.lock		= __RAW_SPIN_LOCK_UNLOCKED((name).lock),	\
	.count		= n,						\
	.wait_list	= LIST_HEAD_INIT((name).wait_list),		\
}
#define __RAW_SPIN_LOCK_UNLOCKED(lockname)	\
	(raw_spinlock_t) __RAW_SPIN_LOCK_INITIALIZER(lockname)
// ARM10C 20150411
// __RAW_SPIN_LOCK_INITIALIZER(clockevents_lock):
// {
//    .raw_lock = { { 0 } },
//    .magic = 0xdead4ead,
//    .owner_cpu = -1,
//    .owner = 0xffffffff,
// }
//
// #define __RAW_SPIN_LOCK_UNLOCKED(clockevents_lock):
// (raw_spinlock_t)
// {
//    .raw_lock = { { 0 } },
//    .magic = 0xdead4ead,
//    .owner_cpu = -1,
//    .owner = 0xffffffff,
// }
  • down() 함수 분석
void down(struct semaphore *sem)
{
	unsigned long flags;

	raw_spin_lock_irqsave(&sem->lock, flags);
	// (&console_sem)->count: 1
	if (likely(sem->count > 0))
	    // (&console_sem)->count: 1	
		sem->count--;
		// (&console_sem)->count: 0
	else
		__down(sem);
	raw_spin_unlock_irqrestore(&sem->lock, flags);
}
EXPORT_SYMBOL(down);
  • down()에서 한일
  • (&console_sem)->count: 1에서 0으로 바꿈.
  • return: start_kernel()->console_init()->con_init()
  • call: con_init()
  • console_lock()
    • down(&console_sem);

printk.c::console_lock()

  • return: start_kernel()->console_init()->con_init()
  • call: con_init()
  • console_lock()
    • down(&console_sem);
void console_lock(void)
{
	might_sleep();

	down(&console_sem);
	if (console_suspended)
		return;
	console_locked = 1;
	console_may_schedule = 1;
	mutex_acquire(&console_lock_dep_map, 0, 0, _RET_IP_);
}
EXPORT_SYMBOL(console_lock);
  • call: start_kernel()->console_init()->con_init()
  • call: con_init()
  • console_lock()
    • down(&console_sem);
  • mutex_acquire(&console_lock_dep_map, 0, 0, RET_IP);

lockdep.h::mutex_acquire()

  • called: start_kernel()->console_init()->con_init()
  • call: con_init()
  • console_lock()
    • down(&console_sem);
  • mutex_acquire(&console_lock_dep_map, 0, 0, RET_IP);
#define mutex_acquire(l, s, t, i)		lock_acquire_exclusive(l, s, t, NULL, i)
  • return: start_kernel()->console_init()->con_init()
  • call: con_init()
  • console_lock()
    • down(&console_sem);
  • mutex_acquire(&console_lock_dep_map, 0, 0, RET_IP);

vt.c::con_init()

  • return: start_kernel()->console_init()->con_init()
  • call: con_init()
  • console_lock()
    • down(&console_sem);
    • mutex_acquire(&console_lock_dep_map, 0, 0, RET_IP);
  • 리턴하여 진행.
static int __init con_init(void)
{
	const char *display_desc = NULL;
	struct vc_data *vc;
	unsigned int currcons = 0, i;

	console_lock();

    // conswitchp:: &dummy_con
	if (conswitchp)
	    // (&dummy_con)->con_startup()
		display_desc = conswitchp->con_startup();
  • (&dummy_con)->con_startup()을 찾아보면.
  • 여기서 dummycon_startup함수가 있다.
// ARM10C 20140215
// DUMMY: 0
const struct consw dummy_con = {
    .owner =		THIS_MODULE,
    .con_startup =	dummycon_startup,
    .con_init =		dummycon_init,
    .con_deinit =	DUMMY,
    .con_clear =	DUMMY,
    .con_putc =		DUMMY,
    .con_putcs =	DUMMY,
    .con_cursor =	DUMMY,
    .con_scroll =	DUMMY,
    .con_bmove =	DUMMY,
    .con_switch =	DUMMY,
    .con_blank =	DUMMY,
    .con_font_set =	DUMMY,
    .con_font_get =	DUMMY,
    .con_font_default =	DUMMY,
    .con_font_copy =	DUMMY,
    .con_set_palette =	DUMMY,
    .con_scrolldelta =	DUMMY,
};
  • (&dummy_con)->con_startup()을 찾아보면.
  • 여기서 dummycon_startup함수를 보면
static const char *dummycon_startup(void)
{
    return "dummy device";
}
  • dummycon_startup: "dummy device" 가 리턴된다.

vt.c::con_init()

  • ...

  • dummycon_startup: "dummy device" 가 리턴된다.

static int __init con_init(void)
{
...
	if (conswitchp)
		display_desc = conswitchp->con_startup();
	if (!display_desc) {
		fg_console = 0;
		console_unlock();
		return 0;
	}

    // MAX_NR_CON_DRIVER: 16
	for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
		struct con_driver *con_driver = &registered_con_driver[i];
		// con_driver: &registered_con_driver[0]

        // con_driver->con: &registered_con_driver[0]->con: NULL
		if (con_driver->con == NULL) {
			con_driver->con = conswitchp;
			// con_driver->con: &registered_con_driver[0]->con: :dummy device"
			con_driver->desc = display_desc;
			// con_driver->desc: &registered_con_driver[0]->desc: &"dummy device"
			con_driver->flag = CON_DRIVER_FLAG_INIT;
			// con_driver->flag: &registered_con_driver[0]->flag: CON_DRIVER_FLAG_INIT: 2
			con_driver->first = 0;
			// con_driver->first: &registered_con_driver[0]->first: 0
			con_driver->last = MAX_NR_CONSOLES - 1;
			// con_driver->last: &registered_con_driver[0]->last: -1			
			break;
		}
	}

    // MAX_NR_CON_DRIVER: 63
	for (i = 0; i < MAX_NR_CONSOLES; i++)
		con_driver_map[i] = conswitchp;
        // con_driver_map[0...63]: &dummy_con 을 loop 실행

    // blankinterval: 600
	if (blankinterval) {
		blank_state = blank_normal_wait;
		// blank_state: blank_normal_wait: 1

        // console_timer: 
		mod_timer(&console_timer, jiffies + (blankinterval * HZ));
	}

timer.c::mod_timer()

  • DEFINE_TIMER()
#define DEFINE_TIMER(_name, _function, _expires, _data)		\
	struct timer_list _name =				\
		TIMER_INITIALIZER(_function, _expires, _data)
  • TIMER_INITIALIZER
#define TIMER_INITIALIZER(_function, _expires, _data)		\
	__TIMER_INITIALIZER((_function), (_expires), (_data), 0)
  • __TIMER_INITIALIZER 을 알아보면.
#define __TIMER_INITIALIZER(_function, _expires, _data, _flags) { \
		.entry = { .prev = TIMER_ENTRY_STATIC },	\
		.function = (_function),			\
		.expires = (_expires),				\
		.data = (_data),				\
		.base = (void *)((unsigned long)&boot_tvec_bases + (_flags)), \
		.slack = -1,					\
		__TIMER_LOCKDEP_MAP_INITIALIZER(		\
			__FILE__ ":" __stringify(__LINE__))	\
	}
  • TIMER_ENTRY_STATIC 는
#define TIMER_ENTRY_STATIC	((void *) 0x74737461)
  • __TIMER_LOCKDEP_MAP_INITIALIZER 는
#define __TIMER_LOCKDEP_MAP_INITIALIZER(_kn)				\
	.lockdep_map = STATIC_LOCKDEP_MAP_INIT(_kn, &_kn),
  • timer_list 를 보면.
struct timer_list {
	/*
	 * All fields that change during normal runtime grouped to the
	 * same cacheline
	 */
	struct list_head entry;
	unsigned long expires;
	struct tvec_base *base;

	void (*function)(unsigned long);
	unsigned long data;

	int slack;

#ifdef CONFIG_TIMER_STATS // CONFIG_TIMER_STATS=n 
	int start_pid;
	void *start_site;
	char start_comm[16];
#endif
#ifdef CONFIG_LOCKDEP
	struct lockdep_map lockdep_map;
#endif
};
  • mod_timer()을 보자.
int mod_timer(struct timer_list *timer, unsigned long expires)
{
	expires = apply_slack(timer, expires);

	/*
	 * This is a common optimization triggered by the
	 * networking code - if the timer is re-modified
	 * to be the same thing then just return:
	 */
	if (timer_pending(timer) && timer->expires == expires)
		return 1;

	return __mod_timer(timer, expires, false, TIMER_NOT_PINNED);
}
EXPORT_SYMBOL(mod_timer);

log

  • 1st log
9b98f31..91641d4  master     -> origin/master
Updating 9b98f31..91641d4
Fast-forward
arch/arm/kernel/vmlinux.lds.S    |  1 +
drivers/tty/serial/samsung.c     | 20 ++++++----
drivers/tty/tty_io.c             |  3 +-
drivers/tty/vt/vt.c              | 79 ++++++++++++++++++++++++++++++++++++++++
drivers/video/console/dummycon.c |  3 ++
include/asm-generic/param.h      |  1 +
include/linux/console.h          |  1 +
include/linux/console_struct.h   |  1 +
include/linux/kernel.h           |  1 +
include/linux/list.h             |  1 +
include/linux/lockdep.h          |  6 +++
include/linux/poison.h           |  2 +
include/linux/semaphore.h        | 52 ++++++++++++++++++++++++++
include/linux/spinlock.h         |  2 +
include/linux/spinlock_types.h   | 10 +++++
include/linux/timer.h            | 63 ++++++++++++++++++++++++++++++--
include/uapi/linux/vt.h          |  2 +
init/main.c                      |  3 ++
kernel/locking/semaphore.c       | 15 ++++++++
kernel/printk/braille.h          |  2 +
kernel/printk/printk.c           | 67 +++++++++++++++++++++++++++-------
kernel/timer.c                   |  8 ++++
22 files changed, 318 insertions(+), 25 deletions(-)