Linux内核初始化步骤(⼀)
本⽂参考了blog.csdn/qing_ping/article/details/17351017博主的内容。
内核的初始化过程由start_kernel函数(\init\main.c)开始,⾄第⼀个⽤户进程init结束,调⽤了⼀系列的初始化函数对所有的内核组件进⾏初始化。其中,start_kernel、rest_init、kernel_init、init_post4个函数构成了整个初始化过程的主线。下⾯先来分析start_kernel函数。
asmlinkage void __init start_kernel(void)
{
char * command_line;
extern const struct kernel_param __start___param[], __stop___param[];
/*这两个变量为地址指针,指向内核启动该参数处理相关结构体段在内存中位置(虚拟地址)。
声明传⼊参数的外部参数对于arm平台,位于\include\asm-generic\vmlinux.lds.h*/
/*
* Need to run as early as possible, to initialize the
* lockdep hash:
*/
/*函数中初始化了两个哈希链表,分别是classhash_table和chainhash_table,
主要是⽤来调试内核锁的,⽐如检测加锁的顺序看是否有发⽣死锁的可能,
具体的作⽤要看后⾯怎么使⽤这两个哈希链表。*/
lockdep_init();
/*当只有⼀个CPU的时候,这个函数什么都不做,但是如果有多个CPU的
时候,那么它就返回在启动的时候那个CPU的代号*/
smp_setup_processor_id();
/*该函数的作⽤是初始化obj_hash、obj_static_pool这2个全局变量*/
debug_objects_early_init();
/* Set up the the initial canary ASAP:
*/
/*该函数主要⽤于初始化“⾦丝雀“——canary的值。⽤于防⽌栈溢出攻击。*/
boot_init_stack_canary();
/*1.cgroup:它的全称为control group。即⼀组进程的⾏为控制。
2.该函数主要是做数据结构和其中链表的初始化
*/
cgroup_init_early();
/*关闭当前CPU的中断,即系统总中断(底层调⽤汇编指令)*/
local_irq_disable();
early_boot_irqs_disabled = true;
/*
* Interrupts are still disabled. Do necessary setups, then
* enable them
*/
/*注册clockevents框架*/
tick_init();
/*激活当前CPU(在内核全局变量中将当前CPU的状态设为激活状态*/
boot_cpu_init();
/*初始化页地址,使⽤链表将其链接起来*/
page_address_init();
/
*显⽰内核的版本信息*/
printk(KERN_NOTICE "%s", linux_banner);
/*内核构架相关初始化函数,可以说是⾮常重要的⼀个初始化步骤。其中包含了
处理器相关参数的初始化、内核启动参数(tagged list)的获取和前期处理、
内存⼦系统的早期的初始化(bootmem分配器)。主要完成了4个⽅⾯的⼯作,
⼀个就是取得MACHINE和PROCESSOR的信息然或将他们赋值给kernel相应的全
局变量,然后呢是对boot_command_line和tags接⾏解析,再然后就是
局变量,然后呢是对boot_command_line和tags接⾏解析,再然后就是
memory、cache的初始化,最后是为kernel的后续运⾏请求资源*/
setup_arch(&command_line);
/*1.初始化代表内核本⾝内存使⽤的管理结构体init_mm。
2.每⼀个任务都有⼀个mm_struct结构以管理内存空间,init_mm是内核的mm_struct
3.设置成员变量*mmap指向⾃⼰,意味着内核只有⼀个内存管理结构
4.设置*pgd=swapper_pg_dir,swapper_pg_dir是内核的页⽬录(在arm体系结构有16K,
所以init_mm定义了整个kernel的内存空间)
5.这些内容涉及到内存管理⼦系统
mm_init_owner(&init_mm, &init_task);
/*初始化CPU屏蔽字*/
mm_init_cpumask(&init_mm);
/*对cmdline进⾏备份和保存:保存未改变的command_line到字符数组static_command_line[]中,保存boot_command_line到字符数组saved_command_line[]中*/
setup_command_line(command_line);
/*下⾯三段式针对SMP处理器的内存初始化函数,对arm来说是空*/
setup_nr_cpu_ids();
setup_per_cpu_areas();
smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */
/*建⽴系统内存页区(zone)链表*/
build_all_zonelists(NULL);
/*内存页初始化*/
page_alloc_init();
/*打印Linux启动命令⾏参数*/
printk(KERN_NOTICE "Kernel command line: %s\n", boot_command_line);
/*Kernel command line: console=ttyS1,115200n8 //调试串⼝为UART1,波特率为115200n8
mem=32M@0xc0000000 mem=192M@0xc4000000 //DDR内存分配,为arm分配了224M
eth=02:02:30:30:97:81//mac地址
da850-panel=TL070A //显⽰设备
da850-emac=mii //⽹络模式为MII
root=ubi0_d=4,2048 //⽂件系统节点、分区及分区偏移量
rootfstype=ubifs//⽂件系统类型为ubifs
*/
/*解析早期格式的内核参数*/
parse_early_param();
parse_args("Booting kernel", static_command_line, __start___param,
__stop___param - __start___param,
&unknown_bootoption);
jump_label_init();
/*
* These use large bootmem allocations and must precede
* kmem_cache_init()
*/
/*初始化hash表,以便于从进程的PID获得相应的进程描述指针,按照开发板上的物理
内存初始化pid hash表*/
setup_log_buf(0);
pidhash_init();
/*建⽴节点哈希表和数据缓冲哈希表*/
vfs_caches_init_early();
/
*对异常处理函数进⾏排序*/
sort_main_extable();
/*完成对系统保留中断向量(异常、⾮屏蔽中断以及系统调⽤)的初始化*/
trap_init();
trap_init();
/*建⽴内核的内存分配器*/
mm_init();
/*
* Set up the scheduler prior starting any interrupts (such as the
* timer interrupt). Full topology setup happens at smp_init()
* time - but meanwhile we still have a functioning scheduler.
*/linux内核文件放在哪
/*先初始化0进程,包括段选择符,描述符GDT,LDT等。然后将其他63个进程的段选择符
描述符置空,设置好后,将任务0的段选择符,描述符GDT,LDT等加载仅某个寄存器中。接着设置系统中断定时器,中断函数判断是否要切换,意思就是当进程时间⽚已经消耗完时,调⽤定时器中断函数判断是否要切换,最后定义系统调⽤*/
sched_init();
/*
* Disable preemption - early bootup scheduling is extremely
* fragile until we cpu_idle() for the first time.
*/
/*禁⽌内核抢占*/
preempt_disable();
/*检查中断是否已经打开,如果已经打开,则关闭中断*/
if (!irqs_disabled()) {
printk(KERN_WARNING "start_kernel(): bug: interrupts were "
"enabled *very* early, fixing it\n");
local_irq_disable();
}
/*创建idr缓冲区*/
idr_init_cache();
perf_event_init();
/*互斥访问机制*/
rcu_init();
radix_tree_init();
/* init some links before init_ISA_irqs() */
early_irq_init();
/*中断向量初始化*/
init_IRQ();
/*初始化优先级数组*/
prio_tree_init();
/*定时器初始化*/
init_timers();
/*⾼精度时钟初始化*/
hrtimers_init();
/
*软中断初始化*/
softirq_init();
/*初始化资源和普通计时器*/
timekeeping_init();
/*初始化系统时钟源*/
time_init();
/*对内核的⼀个性能测试⼯具profile进⾏初始化*/
profile_init();
call_function_init();
if (!irqs_disabled())
printk(KERN_CRIT "start_kernel(): bug: interrupts were "
"enabled early\n");
"enabled early\n");
early_boot_irqs_disabled = false;
/*使能中断*/
local_irq_enable();
/* Interrupts are enabled now so all GFP allocations are safe. */
gfp_allowed_mask = __GFP_BITS_MASK;
/*kmem_cache_init_late的⽬的在于完善slab分配器的缓存机制*/
kmem_cache_init_late();
/*
* HACK ALERT! This is early. We're enabling the console before
* we've done PCI setups etc, and console_init() must be aware of
* this. But we do want output early, in case something goes wrong.
*/
/*初始化控制台以显⽰printk的内容,在此之前调⽤的printk只是把数据存到缓冲区*/
console_init();
if (panic_later)
panic(panic_later, panic_param);
/*如果定义了CONFIG_LOCKDEP宏,那么就打印锁依赖信息,否则什么也不做*/
lockdep_info();
/*
* Need to run this when irqs are enabled, because it wants
* to self-test [hard/soft]-irqs on/off lock inversion bugs
* too:
*/
locking_selftest();
#ifdef CONFIG_BLK_DEV_INITRD
if (initrd_start && !initrd_below_start_ok &&
page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) {
printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - "
"disabling it.\n",
page_to_pfn(virt_to_page((void *)initrd_start)),
min_low_pfn);
initrd_start = 0;
}
#endif
page_cgroup_init();
debug_objects_mem_init();
kmemleak_init();
setup_per_cpu_pageset();
numa_policy_init();
if (late_time_init)
late_time_init();
sched_clock_init();
/
*校准延时函数的精确度*/
calibrate_delay();
pidmap_init();
/*匿名虚拟内存域(anonymous VMA)初始化*/
anon_vma_init();
#ifdef CONFIG_X86
if (efi_enabled)
efi_enter_virtual_mode();
#endif
thread_info_cache_init();//获取thread_info缓存空间,⼤部分架构为空函数(包括arm) cred_init();//任务信⽤系统初始化
fork_init(totalram_pages);//进程创建机制初始化
proc_caches_init();//初始化进程创建机制所需的其他数据结构,为其申请空间
buffer_init();//缓存系统初始化,创建缓存头空间,并检查其⼤⼩限时
key_init();//内核密钥管理系统初始化
security_init();//内核安全框架初始化
security_init();//内核安全框架初始化
dbg_late_init();
vfs_caches_init(totalram_pages);//虚拟⽂件系统缓存初始化
signals_init();//信号管理系统初始化
/* rootfs populating might need page-writeback */
page_writeback_init();//页写回机制初始化
#ifdef CONFIG_PROC_FS
proc_root_init();//proc⽂件系统初始化
#endif
cgroup_init();//control group正式初始化
cpuset_init();//CPUSET初始化
taskstats_init_early();//任务状态早期初始化函数,为结构体获取⾼速缓存,并初始化互斥机制 delayacct_init();//任务延迟初始化
check_bugs();//检查CPU BUG的函数,通过软件规避BUG
/*ACPI-Advanced Configuration and Power Interface ⾼级配置及电源接⼝*/
acpi_early_init(); /* before LAPIC and SMP init */
sfi_init_late();
ftrace_init();
/* Do the rest non-__init'ed, we're now alive */
rest_init();//虽然从名字来说是剩余的初始化,但是这个函数中的初始化包括了很多的内容
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论