Linux中console初始化流程
在init/main.c文件
asmlinkage void __init start_kernel(void)
函数中调用
console_init()函数 (该函数位于driver/char/tty_io.c文件中)
/*
* Initialize the console device. This is called *early*, so
* we can't necessarily depend on lots of kernel help here.
* Just do some early initializations, and do the complex setup
* later.
*/
void __init console_init(void)
{
initcall_t *call;
/* Setup the default TTY line discipline. */
tty_ldisc_begin();
/*
* 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++;
}
}
从上面的源码可以看出,这个函数设置默认的TTY线性规划,调用console的初始化代码。下面着重分析是如何调用console初始化代码的。
在arch/arm/kernel/vmlinux.lds文件中有
__con_initcall_start = .;
*(.con_initcall.init)
__con_initcall_end = .;
源码是将虚拟地址 __con_initcall_start 赋值给指针call,然后去执行*(.con_initcall.init) 。
我的串口驱动里有这样的代码:
static int __init duart_console_init(void)
{
register_console(&duart_console);
return 0;
}
console_initcall(duart_console_init);
发现console_initcall是一个宏,定义在include/linux/init.h文件中
#define console_initcall(fn) \
static initcall_t __initcall_##fn \
__used __section(.con_initcall.init) = fn
将console_initcall(duart_console_init)宏展开得到
static initcall_t __initcall_duart_console_init \
__attribute_used __attribute__((__section__(“.con_initcall.init”))) = duart_console_init
这样就构建了一个.con_initcall.init节的指向初始化函数的指针,执行duart_console_init函数最终初始化console。
(若理解有误还请大侠指出)