“内核版本:linux-2.6”
linux系统基本启动流程如下:
开机->BOOT引导->grub引导->加载内核->启动系统
本文重点分析加载内核过程及系统启动流程。
(1)内核入口
系统进入内核的入口是/init/main.c的start_kernel()函数,这个相当于系统执行的第一个进程:
/*
* Activate the first processor. 启动第一个进程。
*/
asmlinkage void __init start_kernel(void)
{
char * command_line;
extern char saved_command_line[];
extern struct kernel_param __start___param[], __stop___param[];
/*
* Interrupts are still disabled. Do necessary setups, then
* enable them
*/
lock_kernel();
printk(linux_banner);
setup_arch(&command_line);
setup_per_zone_pages_min();
setup_per_cpu_areas();
/*
* Mark the boot cpu "online" so that it can call console drivers in
* printk() and can access its per-cpu storage.
*/
smp_prepare_boot_cpu();
build_all_zonelists();
page_alloc_init();
/* linux内存管理初始化 ,建立初始化节点和内存域的数据结构,建立内核的内存分配器,见下文1介绍 */
rcu_init();
/* 初始化 RCU同步机制 */
pidhash_init();
/* PID hash链表初始化,见下文2 */
sched_init();
/* 进程调度相关初始化 */
radix_tree_init();
/* 基数树初始化,与文件系统内存管理相关 */
rest_init();
/* 初始化 init进程并启动 */
}
(2)init进程
init 进程通过kernel_thread建立,并传递CLONE_KERNEL标志继承了内核进程属性,这是内核下第一个进程,我们先看这个函数实现:
这里重点关注run_init_process("/sbin/init"),
内核init进程通过execve调用/sbin/init程序启动了用户第一个进程/sbin/init(1号进程),并开始执行系统初始化流程。
然后内核进入cpu_idle进程,如下:
无休止运行直到有进程需要调度。
关于2号进程kthreadd,高级版本内核在rest_init中创建启动:
该进程始终运行在内核空间,负责所有内核线程的调度和管理
(3)系统初始化阶段
当init启动后,它通过执行各种启动事务来完成引导进程(检查监视文件系统,启动后台程序daemons等),直至完成用户操作环境的配置工作。
这里主要涉及4个程序:init、getty、login和shell程序。
init进程根据/etc/rc文件进行配置信息的设置;
附录:
1. linux内存管理层次
(1)存储节点(node):CPU被划分为多个节点(node),内存则被分簇,每个CPU对应一个本地物理内存,即一个CPU-node对应一个内存簇bank,每个内存簇被认为是一个节点。
(2)管理区(zone):每个物理内存节点node被划分为多个内存管理区域,用于表示不同范围的内存,内核可以使用不同的映射方式映射物理内存;低端16M被描述为ZONE_DMA,可直接映射内核的普通内存域ZONE_NORMAL,超出内核段的物理地址域ZONE_HIGHMEM。
(3)页面(page):内存被细分为多个页面帧,页面是最基本的内存分配单位
2. pid hash链表
内核通过pid hash链表从进程的PID导出对应的进程描述符指针,这样快速访问进程。