2015년 7월 4일 토요일

[Linux Kernel] 108주차(2015.07.04)

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(-)

댓글 없음:

댓글 쓰기