console_init

来源:互联网 发布:网络复活赛 编辑:程序博客网 时间:2024/05/08 04:37
从start_kernel 会调用console_init 来初始化串口
void __init console_init(void)
{
    initcall_t *call;

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

    /*
     * set up the console device so that later boot sequences can
     * inform about problems etc..
     */
    call = __con_initcall_start;
    while (call < __con_initcall_end) {
        (*call)();
        call++;
    }
}
从console_init的实现可以看出会依次调用__con_initcall_start和__con_initcall_end的函数
从system.map 中可以看到在__con_initcall_start和__con_initcall_end 之间有四个函数
ffff0000090bc9a0 T __con_initcall_start
ffff0000090bc9a0 t __initcall_con_init
ffff0000090bc9a0 T __initcall_end
ffff0000090bc9a8 t __initcall_hvc_console_init
ffff0000090bc9b0 t __initcall_univ8250_console_init
ffff0000090bc9b8 t __initcall_mvebu_uart_console_init
ffff0000090bc9c0 T __con_initcall_end

其运行时的callstack如下:
[    0.021084] Hardware name: (null) (DT)
[    0.024865] Call trace:
[    0.027334] [<ffff00000808a470>] dump_backtrace+0x0/0x178
[    0.032787] [<ffff00000808a608>] show_stack+0x20/0x28
[    0.037888] [<ffff0000083f3a18>] dump_stack+0x8c/0xac
[    0.042989] [<ffff00000811d658>] register_console+0x28/0x354
[    0.048706] [<ffff000008d0c258>] con_init+0x240/0x264
[    0.053806] [<ffff000008d0b6e4>] console_init+0x30/0x40
[    0.059084] [<ffff000008cce8ac>] start_kernel+0x2e0/0x438
[    0.064535] [<ffff0000080811c8>] 0xffff0000080811c8
[    0.069466] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.4.63-10.g63e7b5f-default+ #1
[    0.077289] Hardware name: (null) (DT)
[    0.081069] Call trace:
[    0.083533] [<ffff00000808a470>] dump_backtrace+0x0/0x178
[    0.088984] [<ffff00000808a608>] show_stack+0x20/0x28
[    0.094084] [<ffff0000083f3a18>] dump_stack+0x8c/0xac
[    0.099184] [<ffff00000811d658>] register_console+0x28/0x354
[    0.104899] [<ffff000008d0c414>] hvc_console_init+0x18/0x24
[    0.110527] [<ffff000008d0b6e4>] console_init+0x30/0x40
[    0.115802] [<ffff000008cce8ac>] start_kernel+0x2e0/0x438
[    0.121253] [<ffff0000080811c8>] 0xffff0000080811c8
[    0.126181] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.4.63-10.g63e7b5f-default+ #1
[    0.134004] Hardware name: (null) (DT)
[    0.137785] Call trace:
[    0.140249] [<ffff00000808a470>] dump_backtrace+0x0/0x178
[    0.145700] [<ffff00000808a608>] show_stack+0x20/0x28
[    0.150800] [<ffff0000083f3a18>] dump_stack+0x8c/0xac
[    0.155899] [<ffff00000811d658>] register_console+0x28/0x354
[    0.161615] [<ffff000008d0cb64>] univ8250_console_init+0x2c/0x3c
[    0.167681] [<ffff000008d0b6e4>] console_init+0x30/0x40
[    0.172957] [<ffff000008cce8ac>] start_kernel+0x2e0/0x438
[    0.178408] [<ffff0000080811c8>] 0xffff0000080811c8
[    0.183335] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.4.63-10.g63e7b5f-default+ #1
[    0.191158] Hardware name: (null) (DT)
[    0.194938] Call trace:
[    0.197402] [<ffff00000808a470>] dump_backtrace+0x0/0x178
[    0.202853] [<ffff00000808a608>] show_stack+0x20/0x28
[    0.207953] [<ffff0000083f3a18>] dump_stack+0x8c/0xac
[    0.213052] [<ffff00000811d658>] register_console+0x28/0x354
[    0.218768] [<ffff000008d0d840>] cdns_uart_console_init+0x14/0x20
[    0.224923] [<ffff000008d0b6e4>] console_init+0x30/0x40
[    0.230198] [<ffff000008cce8ac>] start_kernel+0x2e0/0x438
[    0.235649] [<ffff0000080811c8>] 0xffff0000080811c8
我们以univ8250_console_init为例
static int __init univ8250_console_init(void)
{
    if (nr_uarts == 0)
        return -ENODEV;

    serial8250_isa_init_ports();
    register_console(&univ8250_console);
    return 0;
}
console_initcall(univ8250_console_init);
原来就是在univ8250_console_init 中直接调用register_console,这个函数是所有console driver 必须调用的
其次通过console_initcall将自己也就是univ8250_console_init 添加到__con_initcall_start和__con_initcall_end 之间
可以看到console_initcall 是放在con_initcall.init 这个section中
#define console_initcall(fn)                    \
    static initcall_t __initcall_##fn            \
    __used __section(.con_initcall.init) = fn


而con_initcall.init 是让在__con_initcall_start和__con_initcall_end 之间的.
#define CON_INITCALL                            \
        VMLINUX_SYMBOL(__con_initcall_start) = .;        \
        KEEP(*(.con_initcall.init))                \
        VMLINUX_SYMBOL(__con_initcall_end) = .;

所以要注册自己的console的driver的话,可以通过console_initcall 将自己添加到__con_initcall_start和__con_initcall_end,这样kernel初始化的时候就会自动调用init函数.
0 0
原创粉丝点击