今天研究init/main.c文件中的代码,发现了一个问题:
本来我的代码是ok的,我的linux内核在开发版上是可以正常起来的。我将init/main.c文件里start_kernel()函数里边的console_init()函数注释掉,大家猜怎么样?居然还可以启动!查看console_init()函数的代码,实现在drivers/char/tty_io.c文件里边,核心代码如下:
initcall_t *call;
call = __con_initcall_start;/*zswan*/
while (call < __con_initcall_end) {
(*call)();
call++;
}
注:
__con_initcall_start和__con_initcall_end的虚拟地址arch/arm/kernel/vmlinux.lds.S文件里定义.这段代码其实就是去执行在 __con_initcall_start和__con_initcall_end之间的initcall_t,而这个虚拟地址范围里边的initcall_t是什么怎么添加进来的呢?通过console_init()函数!你调用了几次console_init(),那么此处(*call)()就调用几次.大家可以看到,我们的console驱动程序就是通过console_init()函数而非module_init()来注册的.所以说整个console_init函数的作用就是初始化系统中注册的所有的console口驱动.
但为什么我把console_init()注释掉以后,内核还能起来呢?希望知道的朋友可以告诉我.
另外,即使此处调用了console_init(),假如把后边的do_basic_setup()函数注释掉,那么内核也是启不来的.
不知道这又是何原因?
革命尚未成功,同志还需努力.
今天为了测试,将以下代码放在了rest_init()的前面(reset_init()为start_kernel()所执行的最后一个函数)。按我的理解来说,执行到rest_init的前面,系统体系相关的初始化已经完成了,应该可以使用ioremap了,但是依然出错。加了如下代码以后,系统刮起在Uncompressing Linux.......................阶段),所加代码如下:
/*这短代码的功能是驱动buzzer,其实很简单,就是写寄存器*/
void *paddr;
paddr = ioremap(0x51000000, 0x10);
if (!paddr) {
printk(KERN_ERR "Buzzer: Failed to ioremap region\n");
}
paddr += 2;
*((u8 volatile *)paddr) = 0x8;
只有将此段代码加在do_initcalls()函数的最后执行才可以,靠前放则不可以执行。因为do_initcalls()所完成的是对驱动部分的初始化工作。感觉buzzer依赖于某个驱动,所以,放在do_initcalls的最后,当其他驱动初始化完成以后,它才可以工作。但不太清楚它需要依赖哪个驱动?最有可能的就是ioremap可能需要某个东东初始化以后才可以用(例如,内存初始化?),但是内存的初始化早在rest_init以前就应该完成了阿。
不知道这又是何原因?
革命尚未成功,同志还需努力.
阅读(984) | 评论(0) | 转发(0) |