Linux内核启动流程-第二阶段start_kernel 函数

一.  Linux内核启动

上一篇文章简单介绍了 Linux内核启动的第一阶段,即执行汇编流程。

本文简单了解一下,Linux内核启动的第二阶段:start_kernel函数,这是一个 C 函数。

本文续上一篇文章的学习,地址如下:

Linux内核启动流程-第一阶段汇编流程简介_凌肖战的博客-CSDN博客

二.  Linux内核启动-start_kernel函数

start_kernel 通过调用众多的子函数来完成 Linux 启动之前的一些初始化工作,由于 start_kernel 函数里面调用的子函数太多,而这些子函数又很复杂,因此我们简单的来看一下一 些重要的子函数。

精简并添加注释后的 start_kernel 函数内容如下:

asmlinkage __visible void __init start_kernel ( void )
{
char * command_line ;
char * after_dashes ;
lockdep_init ();       /* lockdep 是死锁检测模块,此函数会初始化
                              * 两个 hash 表。此函数要求尽可能早的执行!
                              */
set_task_stack_end_magic (& init_task );  /* 设置任务栈结束魔术数,
                                                                  *用于栈溢出检测
                                                                  */
smp_setup_processor_id ();    /* SMP 有关 ( 多核处理器 ) ,设置处理器 ID
                                                * 有很多资料说 ARM 架构下此函数为空函数,那是因
                                                * 为他们用的老版本 Linux,而那时候 ARM 还没有多
                                                * 核处理器。
                                                */
debug_objects_early_init ();     /* 做一些和 debug 有关的初始化 */
boot_init_stack_canary ();        /* 栈溢出检测初始化 */
cgroup_init_early ();                 /* cgroup 初始化, cgroup 用于控制 Linux 系统资源 */
local_irq_disable ();                  /* 关闭当前 CPU 中断 */
early_boot_irqs_disabled = true ;
/*
* 中断关闭期间,做一些重要的操作,然后打开中断
*/
boot_cpu_init ();                          /* 跟 CPU 有关的初始化 */
page_address_init ();                  /* 页地址相关的初始化 */
pr_notice ( "%s" , linux_banner );   /* 打印 Linux 版本号、编译时间等信息 */
setup_arch (& command_line );    /* 架构相关的初始化,此函数会解析传递进来的
                                                    * ATAGS 或者设备树(DTB)文件。会根据设备树里面
                                                    * 的 model 和 compatible 这两个属性值来查找
                                                    * Linux 是否支持这个单板。此函数也会获取设备树
                                                    * 中 chosen 节点下的 bootargs 属性值来得到命令
                                                    * 行参数,也就是 uboot 中的 bootargs 环境变量的
                                                    * 值,获取到的命令行参数会保存到
                                                    *command_line 中。
                                                     */
mm_init_cpumask (& init_mm );                 /* 看名字,应该是和内存有关的初始化 */
setup_command_line ( command_line );    /* 好像是存储命令行参数 */
setup_nr_cpu_ids ();                          /* 如果只是 SMP( 多核 CPU) 的话,此函数用于获取
                                                           * CPU 核心数量,CPU 数量保存在变量
                                                           * nr_cpu_ids 中。
                                                           */
setup_per_cpu_areas ();         /* SMP 系统中有用,设置每个 CPU per-cpu 数据 */
smp_prepare_boot_cpu ();
build_all_zonelists ( NULL , NULL );     /* 建立系统内存页区 (zone) 链表 */
page_alloc_init ();                                /* 处理用于热插拔 CPU 的页 */
pr_notice ( "Kernel command line: %s\n" , boot_command_line );    /* 打印命令行信息 */
parse_early_param ();                                   /* 解析命令行中的 console 参数 */
after_dashes = parse_args ( "Booting kernel" ,
static_command_line , __start___param ,
__stop___param - __start___param ,
- 1 , - 1 , & unknown_bootoption );
if (! IS_ERR_OR_NULL ( after_dashes ))
parse_args ( "Setting init args" , after_dashes , NULL , 0 , - 1 , - 1 ,
set_init_arg );
jump_label_init ();
setup_log_buf ( 0 );   /* 设置 log 使用的缓冲区 */
pidhash_init ();       /* 构建 PID 哈希表, Linux 中每个进程都有一个 ID,
                               * 这个 ID 叫做 PID 。通过构建哈希表可以快速搜索进程
                               * 信息结构体。
                               */
vfs_caches_init_early ();    /* 预先初始化 vfs(虚拟文件系统) 的目录项和
                                           * 索引节点缓存
                                           */
sort_main_extable ();    /* 定义内核异常列表 */
trap_init ();                     /* 完成对系统保留中断向量的初始化 */
mm_init ();                     /* 内存管理初始化 */
 
sched_init ();                         /* 初始化调度器,主要是初始化一些结构体 */
preempt_disable ();               /* 关闭优先级抢占 */
if ( WARN (! irqs_disabled (),   /* 检查中断是否关闭,如果没有的话就关闭中断 */
"Interrupts were enabled *very* early, fixing it\n" ))
local_irq_disable ();
idr_init_cache ();             /* IDR 初始化, IDR Linux 内核的整数管理机
                                        * 制,也就是将一个整数 ID 与一个指针关联起来。
                                        */
rcu_init ();                   /* 初始化 RCU, RCU 全称为 Read Copy Update( - 拷贝修改 ) */
trace_init ();                /* 跟踪调试相关初始化 */
context_tracking_init ();
radix_tree_init ();
                                  /* 基数树相关数据结构初始化 */
early_irq_init ();         /* 初始中断相关初始化 , 主要是注册 irq_desc 结构体变
                                 * 量,因为 Linux 内核使用 irq_desc 来描述一个中断。
                                 */
init_IRQ ();                /* 中断初始化 */
tick_init ();                  /* tick 初始化 */
rcu_init_nohz ();
init_timers ();             /* 初始化定时器 */
hrtimers_init ();          /* 初始化高精度定时器 */
softirq_init ();              /* 软中断初始化 */
timekeeping_init ();
time_init ();                 /* 初始化系统时间 */
sched_clock_postinit ();
perf_event_init ();
profile_init ();
call_function_init ();
WARN (! irqs_disabled (), "Interrupts were enabled early\n" );
early_boot_irqs_disabled = false ;
local_irq_enable ();                 /* 使能中断 */
kmem_cache_init_late ();          /* slab 初始化, slab Linux 内存分配器 */
console_init ();                         /* 初始化控制台,之前 printk 打印的信息都存放
                                                * 缓冲区中,并没有打印出来。只有调用此函数
                                                * 初始化控制台以后才能在控制台上打印信息。
                                                */
if ( panic_later )
panic ( "Too many boot %s vars at `%s'" , panic_later ,
panic_param );
lockdep_info ();         /* 如果定义了宏 CONFIG_LOCKDEP ,那么此函数打印一些信息。 */
locking_selftest ()    /* 锁自测 */
......
page_ext_init ();
debug_objects_mem_init ();
kmemleak_init ();         /* kmemleak 初始化, kmemleak 用于检查内存泄漏 */
setup_per_cpu_pageset ();
numa_policy_init ();
if ( late_time_init )
late_time_init ();
sched_clock_init ();
calibrate_delay ();         /* 测定 BogoMIPS 值,可以通过 BogoMIPS 来判断 CPU 的性能
                                      * BogoMIPS 设置越大,说明 CPU 性能越好。
                                       */
pidmap_init ();    /* PID 位图初始化 */
anon_vma_init ();         /* 生成 anon_vma slab 缓存 */
acpi_early_init ();
......
thread_info_cache_init ();
cred_init ();                         /* 为对象的每个用于赋予资格( 凭证 ) */
fork_init ();                          /* 初始化一些结构体以使用 fork 函数 */
proc_caches_init ();         /* 给各种资源管理结构分配缓存
*/
buffer_init ();              /* 初始化缓冲缓存 */
key_init ();                 /* 初始化密钥 */
security_init ();         /* 安全相关初始化 */
dbg_late_init ();
vfs_caches_init ( totalram_pages );  /* VFS 创建缓存 */
signals_init ();                                 /* 初始化信号 */
page_writeback_init ();                      /* 页回写初始化 */
proc_root_init ();                         /* 注册并挂载 proc 文件系统 */
nsfs_init ();
cpuset_init ();          /* 初始化 cpuset cpuset 是将 CPU 和内存资源以逻辑性
                               * 和层次性集成的一种机制,是 cgroup 使用的子系统之一
                               */
cgroup_init ();                      /* 初始化 cgroup */
taskstats_init_early ();        /* 进程状态初始化 */
delayacct_init ();
check_bugs ();                    /* 检查写缓冲一致性 */
acpi_subsystem_init ();
sfi_init_late ();
if ( efi_enabled ( EFI_RUNTIME_SERVICES )) {
efi_late_init ();
efi_free_boot_services ();
}
ftrace_init ();
rest_init (); /* rest_init 函数 */
}

start_kernel 里面调用了大量的函数,每一个函数都是一个庞大的知识点,如果想要学习 Linux 内核,那么这些函数就需要去详细的研究。本文简单介绍一下 Linux内核启动流程

猜你喜欢

转载自blog.csdn.net/wojiaxiaohuang2014/article/details/133283524