转自:http://blog.chinaunix.net/uid-7332782-id-3268801.html
1. Version2.6内核启动过程
start_kernel( ) //板子上电启动后进入start_kernel( ),相当于程序的main入口
-->setup_arch(&command_line) //command_line由内核传入
-->mdesc = setup_machine(machine_arch_type);
-->list = lookup_machine_type(nr); //汇编实现查找机器码所定义的平台,找到后返回mdesc结构
-->init_machine = mdesc->init_machine; //struct machine_desc *mdesc;machine_desc结构很重要,
-->rest_init()
-->kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND); //定义进程kernel_init,pid=1,在kthreadd进程创建好后调度运行
-->kernel_init()
-->do_basic_setup()
-->driver_init()
-->devices_init()
-->buses_init()
-->classes_init()
-->platform_bus_init()
-->do_initcalls() //此函数很重要,执行了initcall表中所有的函数,包含了init_machine(saar_init())函数
-->saar_init()
-->init_post() //调度用户空间程序,比如bash,在用户空间死循环执行程序
-->pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES); //定义进程kthreadd
2. Version3.x内核启动过程和2.6版本在init_machine加载设备资源的差异对比
- 在2.6内核中, 在setup_arch()中,举个例子imx5,
-->init_machine=mdesc->init_machine; //init/main.c->start_kernel()->setup_arch(), 将init_machine指向mdesc结构体重的init_machine指针,而mdesc中该指针指向具体芯片对应的设备资源函数mxc_board_init.
-->.init_machine=mxc_board_init; //arch/arm/mach-mx5/mx50_arm2.c->MACHINE_START() ,宏即时初始化machine_desc结构体
-->mxc_register_device(&mxc_dma_device); //arch/arm/mach-mx5/mx50_arm2.c->mxc_board_init(), 在mxc_board_init完成这些设备注册
-->mxc_register_device(&mxc_wdt_device); //mxc_wdt_device这些设备资源也都申明在mach-mx50下面
-->mxc_register_device(&mxci2c_devices[0]);
-->..........
当然在setup_arch()中对init_machine进行初始化,这个时候并没有调用init_machine函数,init_machine是在代码中被定义为arch_initcall属性(arch/arm/kernel/setup.c), 然后在do_initcalls()中进行遍历调用,具体见上述的启动过程。
由上述可以看出,在系统启动时,device设备就已经register到总线上了,而3.x以后已经不在mach-**中申明设备资源了,那启动流程如何呢,见下一节。
- 在3.x内核中,在setup_arch()是这么处理的, 首先解析dtb
-->setup_arch() //init/main.c->start_kernel()->setup_arch()
-->mdesc=setup_machine_fdt();
-->unflatten_device_tree() //和2.6内核不同,在setup_arch()中并没有init_machine = mdesc->init_machine.那init_machine如何执行呢?
-->__unflatten_device_tree()
-->unflatten_dt_node() //到此基本完成dts中node到链表的操作
节点中的设备注册
-->DT_MACHINE_START //machine_desc结构体赋值,在2.6内核中宏伟MACHINE_START,文件位置:arch/arm/mach-***
-->.init_machine=imx6sx_init_machine
-->of_platform_populate(); //imx6sx_init_machine()调用,在setup_arch()中解析设备数,构造设备节点链表,然后在这里进行设备的注册,而init_machine为arch_initcall属性,当在setup_arch()后面代码调用到do_initcalls()函数时调用init_machine()函数完成设备注册。
-->of_platform_bus_create(); //由for_each_child_of_node()调用,遍历device tree中每个节点
-->of_platform_device_create_pdata()
-->of_device_alloc() //为每个device申请空间
-->platform_device_put()
-->of_platform_bus_create()
到此完成设备的注册。
在3.x的setup.c中关于init_machine的调用是这么定义的
1 static int __init customize_machine(void) 2 { 3 /* 4 * customizes platform devices, or adds new ones 5 * On DT based machines, we fall back to populating the 6 * machine from the device tree, if no callback is provided, 7 * otherwise we would always need an init_machine callback. 8 */ 9 if (machine_desc->init_machine) 10 machine_desc->init_machine(); 11 #ifdef CONFIG_OF 12 else 13 of_platform_populate(NULL, of_default_bus_match_table, 14 NULL, NULL); 15 #endif 16 return 0; 17 }
关于init_machine到底会不会被执行,在Documentation/Devicetree/usage-model.txt中有这么一段话
The most interesting hook in the DT context is .init_machine() which is primarily responsible for populating the Linux device model with data about the platform. Historically this has been implemented on embedded platforms by defining a set of static clock structures, platform_devices, and other data in the board support .c file, and registering it en-masse in .init_machine(). When DT is used, then instead of hard coding static devices for each platform, the list of devices can be obtained by parsing the DT, and allocating device structures dynamically. The simplest case is when .init_machine() is only responsible for registering a block of platform_devices. A platform_device is a concept used by Linux for memory or I/O mapped devices which cannot be detected by hardware, and for 'composite' or 'virtual' devices (more on those later). While there is no 'platform device' terminology for the DT, platform devices roughly correspond to device nodes at the root of the tree and children of simple memory mapped bus nodes.