[Boot]Kernel启动
2020-02-25 本文已影响0人
Letcos
platform:RK3399
OS:Android 7.1
Kernel:4.4
参考:
1.Younix 《Android启动流程分析》
概述
Uboot最后阶段通过do_bootm_linux跳转到内核,此时内核开始运行,uboot任务完成。之后内核会完成一系列的初始化和注册,最终启动init进程(pid=1)和kthreadd(pid=2),并进入idle.
整体介绍
在这里插入图片描述start_kernel
函数名 | 定义目录 | 简介 |
---|---|---|
lockdep_init() | kernel/locking/lockdep.c | 初始化运行时锁校验器 |
set_task_stack_end_magic | kernel/fork.c | |
smp_setup_processor_id() | arch/arm64/kernel/setup.c | |
debug_objects_early_init() | lib/debugobjects.c | 初始化哈希桶并将静态对象池对象链接到轮询列表中 |
boot_init_stack_canary() | arch/arm64/include/asm/stackprotector.h | |
cgroup_init_early() | kernel/cgroup.c | |
local_irq_disable() | include/linux/irqflags.h | |
boot_cpu_init() | init/main.c | |
page_address_init() | mm/highmem.c | 初始化页地址hash链表 |
setup_arch(&command_line) | arch/arm64/kernel/setup.c | |
mm_init_cpumask(&init_mm) | include/linux/mm_types.h | |
setup_command_line | init/main.c | 保存command line |
setup_nr_cpu_ids() | kernel/smp.c | |
setup_per_cpu_areas() | mm/percpu.c | |
smp_prepare_boot_cpu() | arch/arm64/kernel/smp.c | |
build_all_zonelists | mm/page_alloc.c | 初始化所有build_zonelists |
page_alloc_init() | mm/page_alloc.c | 注册page_alloc_cpu_notify |
parse_early_param() | init/main.c | |
jump_label_init() | kernel/jump_label.c | |
setup_log_buf(0) | kernel/printk/printk.c | |
pidhash_init() | kernel/pid.c | 初始化pid hash表(16~4096) |
vfs_caches_init_early() | fs/dcache.c | dchche/inode init |
sort_main_extable() | kernel/extable.c | exception table |
trap_init() | arch/arm64/kernel/traps.c | register_break_hook |
mm_init() | init/main.c | 内核内存分配器 |
sched_init() | kernel/sched/core.c | 初始化任务调度器 |
preempt_disable() | include/linux/preempt.h | barrier() |
idr_init_cache() | lib/idr.c | |
rcu_init() | kernel/rcu/tree.c | |
trace_init() | kernel/trace/trace.c | |
context_tracking_init() | kernel/context_tracking.c | |
radix_tree_init() | lib/radix-tree.c | |
early_irq_init() | kernel/irq/irqdesc.c | |
init_IRQ() | arch/arm64/kernel/irq.c | irqchip_init() |
tick_init() | kernel/time/tick-common.c | |
rcu_init_nohz() | kernel/rcu/tree_plugin.h | |
init_timers() | kernel/time/timer.c | |
hrtimers_init() | kernel/time/hrtimer.c | 初始化高精度定时器 |
softirq_init() | kernel/softirq.c | |
timekeeping_init() | kernel/time/timekeeping.c | 初始化时钟源和公共时效值 |
time_init() | arch/arm64/kernel/time.c | |
sched_clock_postinit() | kernel/time/sched_clock.c | |
perf_event_init() | kernel/events/core.c | |
profile_init() | kernel/profile.c | |
call_function_init() | kernel/smp.c | 初始化call_single_queue队列;注册hotplug_cfd_notifier |
local_irq_enable() | include/linux/irqflags.h | |
kmem_cache_init_late() | mm/slob.c slab.c slub.c | |
console_init() | drivers/tty/tty_io.c | 注册控制台设备 |
lockdep_info() | kernel/locking/lockdep.c | 打印信息 |
locking_selftest() | lib/locking-selftest.c | |
page_ext_init() | mm/page_ext.c | |
debug_objects_mem_init() | lib/debugobjects.c | 初始化专用缓冲池 |
kmemleak_init() | mm/kmemleak.c | |
setup_per_cpu_pageset() | mm/page_alloc.c | 为每个cpu分配pagesets |
numa_policy_init() | mm/mempolicy.c | |
late_time_init() | init_main.c | |
sched_clock_init() | kernel/sched/clock.c | |
calibrate_delay() | init/calibrate.c | 默认延时校准 |
pidmap_init() | kernel/pid.c | |
anon_vma_init() | mm/rmap.c | |
acpi_early_init() | drivers/acpi/bus.c | |
thread_stack_cache_init() | kernel/fork.c | |
cred_init() | kernel/cred.c | 分配一个cred_jar cache |
fork_init() | kernel/fork.c | |
proc_caches_init() | kernel/fork.c | |
buffer_init() | fs/buffer.c | |
key_init() | security/keys/key.c | 初始化秘钥管理状态 |
security_init() | security/security.c | 初始化安全框架 |
dbg_late_init() | kernel/debug/debug_core.c | |
vfs_caches_init() | fs/dcache.c | |
signals_init() | kernel/signal.c | |
page_writeback_init() | mm/page-writeback.c | |
proc_root_init() | fs/proc/root.c | 初始化proc文件系统 |
nsfs_init() | fs/nsfs.c | |
cpuset_init() | kernel/cpuset.c | |
cgroup_init() | kernel/cgroup.c | |
taskstats_init_early() | kernel/taskstats.c | |
delayacct_init() | kernel/delayacct.c | |
check_bugs() | arch/arm/mm/fault-armv.c | |
acpi_subsystem_init() | drivers/acpi/bus.c | 初始化acpi子系统 |
sfi_init_late() | drivers/sfi/sfi_core.c | |
ftrace_init() | kernel/trace/ftrace.c | |
rest_init() | init/main.c | 执行非__init结尾的初始化 |
执行了非常多的初始化_init函数,为整个系统运行做好准备,最后调用rest_init。
rest_init
初始化项
函数名 | 定义目录 | 简介 |
---|---|---|
rcu_scheduler_starting() | kernel/rcu/tree.c | rcu_scheduler_active = 1 |
smpboot_thread_init() | kernel/cpu.c | 注册smpboot_thread_notifier |
kernel_thread(kernel_init) | init/main.c | 在Kernel_init线程中创建init进程并执行init中的命令 |
numa_default_policy() | mm/mempolicy.c | |
pid = kernel_thread(kthreadd) | kernel/kthread.c | 创建2号进程Kthreadd |
init_idle_bootup_task(current) | kernel/sched/core.c | |
schedule_preempt_disabled() | kernel/sched/core.c | |
cpu_startup_entry(CPUHP_ONLINE) | kernel/sched/idle.c | 执行idle_loop,空闲循环等待 |
kernel_init
static int __ref kernel_init(void *unused)
{
int ret;
kernel_init_freeable();
/* need to finish all async __init code before freeing the memory */
async_synchronize_full();
free_initmem();
mark_readonly();
system_state = SYSTEM_RUNNING;
numa_default_policy();
flush_delayed_fput();
if (ramdisk_execute_command) {
ret = run_init_process(ramdisk_execute_command);
if (!ret)
return 0;
pr_err("Failed to execute %s (error %d)\n",
ramdisk_execute_command, ret);
}
/*
* We try each of these until one succeeds.
*
* The Bourne shell can be used instead of init if we are
* trying to recover a really broken machine.
*/
/*执行init*/
if (execute_command) {
ret = run_init_process(execute_command);
if (!ret)
return 0;
panic("Requested init %s failed (error %d).",
execute_command, ret);
}
if (!try_to_run_init_process("/sbin/init") ||
!try_to_run_init_process("/etc/init") ||
!try_to_run_init_process("/bin/init") ||
!try_to_run_init_process("/bin/sh"))
return 0;
}
kernel_init_freeable()
static noinline void __init kernel_init_freeable(void)
{
....
//真正开始初始化
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)
pr_err("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();
}
...
}
do_basic_setup()
static void __init do_basic_setup(void)
{
cpuset_init_smp();
shmem_init();
driver_init();
init_irq_proc();
do_ctors();
usermodehelper_enable();
//加载并注册所有的module
do_initcalls();
random_int_secret_init();
}
总结:在rest_init中真正让整个内核跑了起来,并创建了两个非常重要的进程:Kthreadd(pid=2)负责内核空间线程的创建。init(pid=1),该进程是所有用户空间进程的鼻祖。另外一边完成了初始化的内核进入idle_loop状态。