嵌入式Linux内核启动顺序【简析】
看了点代码,就我了解的kernel启动的顺序,说说情况:
从initmain.c中的start_kernel()开始:
该函数中,主要做了下列事情:
(1)先是
boot_cpu_init();
初始化了启动相关的内容后
然后
printk(KERN_NOTICE);
printk(linux_banner);
打印内核信息,比如我这里的:
Linux version 2.6.22.2 ([email protected]) (gcc version 4.3.2 (GCC) ) #89 Fri May 15 11:25:09 CST 2009
(2)
其后主要初始化了中断,时钟等:
init_IRQ();
init_timers();
softirq_init();
(3)
再打印出命令行:
printk(KERN_NOTICE "Kernel command line: %sn", boot_command_line);
如此处的:
Kernel command line: root=/dev/mtdblock2 rw init=/linuxrc console=ttyS0,115200 mem=64M rootfstype=jffs2
(4)
后来才是调用
console_init();
去初始化Uart的,就是调用uart的probe函数。
(5)
先预初始化:
cpuset_init_early();
(6)
初始化内存:
mem_init();
(7)
初始化buffer:
buffer_init();
再初始化cpu(组):
cpuset_init();
(8)
用check_bugs();
去测试CPU的相关情况:
CPU: Testing write buffer coherency: ok
(9)
最后调用:
rest_init();
去启动线程
kernel_init
{
。。。
do_basic_setup();
。。。
init_post();
}
其中调用
do_basic_setup();
{
。。。
driver_init();
。。。
do_initcalls();
。。。
}
去初始化Linux kernel相关的内容
其中
driver_init()
{
/* These are the core pieces */
devices_init();
buses_init();
classes_init();
firmware_init();
hypervisor_init();
/* These are also core pieces, but must come after the
* core core pieces.
*/
platform_bus_init();
system_bus_init();
cpu_dev_init();
memory_dev_init();
attribute_container_init();
}
初始化真正的系统的
device,bus,class等等内容,
然后的
do_initcalls()
{
//从__Start 开始 到 __End 结束,
//以此调用之前内核中相关的__init前缀的那些初始化函数
}
其中,这些用__init标明的函数,可以在system.map中看到对应的信息,
包括对应的变量和其对应的地址
c001d164 t __initcall_ptrace_break_init1
c001d164 T __initcall_start
c001d168 t __initcall_consistent_init1
c001d16c t __initcall_sysctl_init1
c001d170 t __initcall_init_jiffies_clocksource1
c001d174 t __initcall_pm_init1
c001d178 t __initcall_ksysfs_init1
。。。。。。。。。。。。。。。
c001d194 t __initcall_sock_init1
c001d198 t __initcall_netlink_proto_init1
c001d19c t __initcall_kobject_uevent_init2
c001d1a0 t __initcall_amba_init2
c001d1a4 t __initcall_tty_class_init2
c001d1a8 t __initcall_vtconsole_class_init2
c001d1ac t __initcall_customize_machine3
。。。。。。。。。。。
c001d1b0 t __initcall_clk_init3
c001d1b4 t __initcall_dma_init3
c001d1bc t __initcall_topology_init4
c001d1c0 t __initcall_param_sysfs_init4
。。。。。。。。。。。。。
c001d200 t __initcall_init_pipe_fs5
c001d204 t __initcall_eventpoll_init5
。。。。。。。。。。。。。。
c001d24c t __initcall_init6
c001d250 t __initcall_kallsyms_init6
c001d254 t __initcall_utsname_sysctl_init6
c001d258 t __initcall_init_per_zone_pages_min6
c001d25c t __initcall_pdflush_init6
。。。。。。。。。。
c001d2e8 t __initcall_loop_init6
c001d2ec t __initcall_net_olddevs_init6
c001d2f0 t __initcall_loopback_init6
c001d2f4 t __initcall_init_mtd6
c001d2f8 t __initcall_afs_parser_init6
c001d2fc t __initcall_init_mtdchar6
c001d300 t __initcall_init_mtdblock6
c001d304 t __initcall_init_nftl6
。。。。。。。。。。。。
c001d388 t __initcall_ip_auto_config7
。。。。。。。。。。。
可以看出,这些函数经过系统处理后,
加了前缀__initcall_和后缀的数字,看起来是表示启动的阶段。
也就是加了和函数对应的一个个变量(标示)。
当然,也可以找到函数对应的首地址,比如
变量
c001d1b0 t __initcall_clk_init3
对应的函数clk_init放在c000e624 :
c000e624 t clk_init
然后,调用
init_post()
{
1.打开console:
sys_open("/dev/console", O_RDWR, 0)
2.运行命令:
run_init_process(ramdisk_execute_command);
和
run_init_process(execute_command);
3.运行系统初始化文件:
run_init_process("/sbin/init");
run_init_process("/etc/init");
run_init_process("/bin/init");
run_init_process("/bin/sh");
}
最后,我们才进入我们熟悉的嵌入式Linux环境,
才能输入用户名和密码(如果有的话),比如:
Welcome to Embedded Linux
(none) login: root
Dec 31 17:00:11 login[704]: root login on ‘ttyS0’
# cd /
。。。
【附录】
关于系统架构中,如何把函数和系统联系起来
注:我这里是arm架构的板子
在archarmkernelsetup.c 的
void __init setup_arch(char **cmdline_p)
{
init_arch_irq = mdesc->init_irq;
system_timer = mdesc->timer;
init_machine = mdesc->init_machine;
}
而mdesc即使machine description,
对应的是你在archarmmach-XXXXXXX_pb.c
中定义的,类似于如下的内容:
MACHINE_START(XXXX, "XXXX PB")
/* Maintainer: Austriamicrosystems Ltd */
.phys_io = XXXX,
.io_pg_offst = XXXX,
.boot_params = XXXX,
.map_io = XXXX_map_io,
.init_irq = XXXX_init_irq,
.timer = &XXXX_timer,
.init_machine = XXXX_init,
MACHINE_END
其中XXX代表你的板子(架构)名字。
而XXXX_init就赋值给上面的init_machine了,对应的这些函数放在
archarmmach-XXXcore.c
转载请注明:在路上 » 嵌入式Linux内核启动顺序【简析】