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。
(若理解有误还请大侠指出)
本文详细解析了Linux系统中console初始化的过程,从start_kernel函数到console_init函数,再到具体初始化代码的执行路径。通过分析源码,揭示了如何通过构建特定节来调用初始化函数。
441

被折叠的 条评论
为什么被折叠?



