日期:2014-05-16  浏览次数:20634 次

linux logo启动的大概顺序

start_kernel(main.c)->console_init->tty_init


con_init(vt.c)->update_screen
complete_change_console(vt_ioctl.c)->switch_screen


#define update_screen(x) redraw_screen(x, 0)
#define switch_screen(x) redraw_screen(x, 1)


redraw_screen->vc->vc_sw->con_switch
/fbcon_switch(fbcon.c)->fb_prepare_logo(fbmem.c)->fb_find_logo(logo.c)



在linux初始化过程中,除非启用了early console,否则直到console_init调用之前是没有任何输出的,它们的输出都放在__log_buf这个缓冲内的,在console_init调用时再将这个缓冲区内的数据一次性输出。

void __init console_init(void)
{
initcall_t *call;

/* Setup the default TTY line discipline. */
(void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);

/*
* set up the console device so that later boot sequences can
* inform about problems etc..
*/
#ifdef CONFIG_EARLY_PRINTK
disable_early_printk();
#endif
call = __con_initcall_start;/*zswan*/
while (call < __con_initcall_end) {
(*call)();
call++;
}
}

说实话这段代码比2.4里面的代码简单多了,linux进步不少啊 。

/*****************************************************************************/

void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);这段code主要的用途就是

注册tty线路规程的,大家研究tty的驱动就会发现了在用户和硬件之间tty的驱动是分了三层的

最底层当然是tty驱动程序了,主要负责从硬件接受数据,和格式化上层发下来的数据后给硬件。

在驱动程序之上就是线路规程了,他负责把从tty核心层或者tty驱动层接受的数据进行特殊的按着某个协议的格式化,就像是

ppp或者蓝牙协议,然后在分发出去的。

在tty线路规程之上就是tty核心层了。大家可参考ldd3学习一下。

/*****************************************************************8/

call = __con_initcall_start;/*zswan*/
while (call < __con_initcall_end) {
(*call)();
call++;
}

这段代码写得的确高深,比2.4的好,2.4的一看就知道干啥了,这个我看了半天,原来就是初始化个终端啊,晕!

看看这段代码吧:

在vmlinux.lds.S中连接脚本汇编中有这段代码

__con_initcall_start = .;
*(.con_initcall.init)
__con_initcall_end = .;

原来的call = __con_initcall_start;/*zswan*/就是把__con_initcall_start的虚拟地址给call

去执行在 __con_initcall_start = .;和__con_initcall_end = .;之间的con_initcall.init,设想一下吧linux惯用做法肯定是把某个

实际初始化函数的指针数据是放到了con_initcall.init的节,那么是怎么放的呢?

那么再看下面的code吧,

在init.h里面有这么一句宏定义啊

#define console_initcall(fn) /
static initcall_t __initcall_##fn /
__attribute_used__ __attribute__((__section__(".con_initcall.init")))=fn

这句的含义就是构建一个.con_initcall.init节的指向初始函数的指针。

在我的串口程序里面有这么一句:

console_initcall(serial_pxa_console_init);

大家这回就看出来了,通过#define console_initcall(fn) /宏,我的这段serial_pxa_console_init函数代码

就被节的指针所指向了。

总结大致的流程就很简单了start_kernel===>console_init===>serial_pxa_console_init

达到初始化控制台的目的了。说得比较乱了,大家知道这个意思自己在研究一下吧!

未完待续。。