tatic noinline void __init_refok rest_init(void)
{
int pid;
rcu_scheduler_starting();
/*
* We need to spawn init first so that it obtains pid 1, however
* the init task will end up wanting to create kthreads, which, if
* we schedule it before we create kthreadd, will OOPS.
*/
/***********创建kernel_init进程**进程号为1********************************/
kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
numa_default_policy();
pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
rcu_read_lock();
kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
创建kthreadd内核线程,它的作用是管理和调度其它内核线程。
它循环运行一个叫做kthreadd的函数,该函数的作用是运行kthread_create_list全局链表中维护的内核线程。
调用kthread_create创建一个kthread,它会被加入到kthread_create_list 链表中;
被执行过的kthread会从kthread_create_list链表中删除;
且kthreadd会不断调用scheduler函数让出CPU。此线程不可关闭。
rcu_read_unlock();
complete(&kthreadd_done);
/*
* The boot idle thread must execute schedule()
* at least once to get things moving:
*/
init_idle_bootup_task(current);
preempt_enable_no_resched();
schedule();
preempt_disable();
/* Call into cpu_idle with preempt disabled */
cpu_idle();
}
进入kernel_init进程
-
tatic int __init kernel_init(void * unused)
-
{
-
/*
-
* Wait until kthreadd is all set-up.
-
*/
-
wait_for_completion(&kthreadd_done);
-
/*
-
* init can allocate pages on any node
-
*/
-
set_mems_allowed(node_states[N_HIGH_MEMORY]);
-
/*
-
* init can run on any cpu.
-
*/
-
set_cpus_allowed_ptr(current, cpu_all_mask);
-
/*
-
* Tell the world that we're going to be the grim
-
* reaper of innocent orphaned children.
-
*
-
* We don't want people to have to make incorrect
-
* assumptions about where in the task array this
-
* can be found.
-
*/
-
init_pid_ns.child_reaper = current;
-
-
cad_pid = task_pid(current);
-
-
smp_prepare_cpus(setup_max_cpus);
-
-
do_pre_smp_initcalls();
-
lockup_detector_init();
-
-
smp_init();
-
sched_init_smp();
-
/*初始化设备驱动,完成其他驱动程序(直接编译进内核的模块)的初始化。
内核中部分的启动数据输出出自这里。
*/
-
do_basic_setup();
-
-
-
/* Open the /dev/console on the rootfs, this should never fail */
-
if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
-
printk(KERN_WARNING "Warning: unable to open an initial console.\n");
-
/*复制两次标准输入 一次作为输出 一次作为出错 */
-
(void) sys_dup(0);
-
(void) sys_dup(0);
-
/*
-
* check if there is an early userspace init. If yes, let it do all
-
* the work
-
*/
-
-
if (!ramdisk_execute_command)
-
ramdisk_execute_command = "/init";
-
-
if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {
-
ramdisk_execute_command = NULL;
-
prepare_namespace();
-
}
-
-
/*
-
* Ok, we have completed the initial bootup, and
-
* we're essentially up and running. Get rid of the
-
* initmem segments and start the user-mode stuff..
-
*/
-
-
init_post();
-
return 0;
-
}
内核初始化过程中,通过do_base_setup来完成驱动的初始化 注册加载进内核
-
/*
-
* Ok, the machine is now initialized. None of the devices
-
* have been touched yet, but the CPU subsystem is up and
-
* running, and memory and process management works.
-
-
* Now we can finally start doing some real work..
-
*/
-
static void __init do_basic_setup(void)
-
{
-
cpuset_init_smp();
-
usermodehelper_init();
-
init_tmpfs();
-
driver_init();
-
init_irq_proc();
-
do_ctors();
-
do_initcalls();
-
}
driver_init()函数分析:
-
/**
-
* driver_init - initialize driver model.
-
*
-
* Call the driver model init functions to initialize their
-
* subsystems. Called early from init/main.c.
-
*/
-
void __init driver_init(void)
-
{
-
/* These are the core pieces */
-
初始化devtmpfs文件系统,驱动核心设备将在这个文件系统中添加它们的设备节点。
这个文件系统可以由内核在挂载根文件系统之后自动挂载到/dev下,
-
也可以在文件系统的启动脚本中手动挂载
-
devtmpfs_init();
-
创建一些设备 char Blok 结点
-
devices_init();
-
初始化驱动模型中的bus子系统
-
buses_init();
-
classes_init();
-
firmware_init();
-
-
hypervisor_init();
-
-
/* These are also core pieces, but must come after the
-
* core core pieces.
-
*/
-
bus/platform子系统
-
platform_bus_init();
-
初始化驱动模型中的system子系统
-
system_bus_init();
-
初始化驱动模型中的devices cpu子系统
-
cpu_dev_init();
-
memory_dev_init();
-
}
do_initcalls()函数:
调用所有编译内核的驱动模块中的初始化函数。
其中按照各个内核模块初始化函数所自定义的启动级别(1~7),按顺序调用器初始化函数。
对于同一级别的初始化函数,安装编译是链接的顺序调用,也就是和内核Makefile的编写有关。
在编写内核模块的时候需要知道这方面的知识,
如果编写的模块必须和依赖的模块在同一级,那就必须注意内核Makefile的修改了。
-
static void __init do_initcalls(void)
-
{
-
initcall_t *fn;
-
-
for (fn = __early_initcall_end; fn < __initcall_end; fn++)
-
do_one_initcall(*fn);
-
}
-
比如:board中初始化函数的调用
-
static int __init customize_machine(void)
{
/* customizes platform devices, or adds new ones */
if (machine_desc->init_machine)
machine_desc->init_machine();
return 0;
}
arch_initcall(customize_machine);
-
#define pure_initcall(fn) __define_initcall("0",fn,0)
#define core_initcall(fn) __define_initcall("1",fn,1)
#define core_initcall_sync(fn) __define_initcall("1s",fn,1s)
#define postcore_initcall(fn) __define_initcall("2",fn,2)
#define postcore_initcall_sync(fn) __define_initcall("2s",fn,2s)
-
#define arch_initcall(fn) __define_initcall("3",fn,3)
-
#define arch_initcall_sync(fn) __define_initcall("3s",fn,3s)
#define subsys_initcall(fn) __define_initcall("4",fn,4)
#define subsys_initcall_sync(fn) __define_initcall("4s",fn,4s)
#define fs_initcall(fn) __define_initcall("5",fn,5)
#define fs_initcall_sync(fn) __define_initcall("5s",fn,5s)
#define rootfs_initcall(fn) __define_initcall("rootfs",fn,rootfs)
#define device_initcall(fn) __define_initcall("6",fn,6)
#define device_initcall_sync(fn) __define_initcall("6s",fn,6s)
#define late_initcall(fn) __define_initcall("7",fn,7)
#define late_initcall_sync(fn) __define_initcall("7s",fn,7s)
-
-
#define INITCALLS \
-
*(.initcallearly.init) \
-
VMLINUX_SYMBOL(__early_initcall_end) = .; \
-
*(.initcall0.init) \
-
*(.initcall0s.init) \
-
*(.initcall1.init) \
-
*(.initcall1s.init) \
-
*(.initcall2.init) \
-
*(.initcall2s.init) \
-
*(.initcall3.init) \
-
*(.initcall3s.init) \
-
*(.initcall4.init) \
-
*(.initcall4s.init) \
-
*(.initcall5.init) \
-
*(.initcall5s.init) \
-
*(.initcallrootfs.init) \
-
*(.initcall6.init) \
-
*(.initcall6s.init) \
-
*(.initcall7.init) \
-
*(.initcall7s.init)
-
-
#define INIT_CALLS \
-
VMLINUX_SYMBOL(__initcall_start) = .; \
-
INITCALLS \
-
VMLINUX_SYMBOL(__initcall_end) = .;
阅读(1764) | 评论(0) | 转发(0) |