|
接上回
start_kernel在/init/main.c中定义
asmlinkage void __init start_kernel(void)
{
char * command_line;
extern struct kernel_param __start___param[], __stop___param[];
smp_setup_processor_id();
/*
* Need to run as early as possible, to initialize the
* lockdep hash:
*/
unwind_init(); //Convert the symbol addresses to absolute values
lockdep_init(); //锁定入口,初始化散列
/*
void lockdep_init(void)
{
int i;
/*
* Some architectures have their own start_kernel()
* code which calls lockdep_init(), while we also
* call lockdep_init() from the start_kernel() itself,
* and we want to initialize the hashes only once:
*/
if (lockdep_initialized)
return;
for (i = 0; i < CLASSHASH_SIZE; i++)
INIT_LIST_HEAD(classhash_table + i);
for (i = 0; i < CHAINHASH_SIZE; i++)
INIT_LIST_HEAD(chainhash_table + i);
lockdep_initialized = 1;
}
*/
cgroup_init_early(); //cgroup: 它的全称为control group.即一组进程的行为控制.该函数主要是做数据结构和其中链表的初始化
local_irq_disable(); //关闭系统总中断
early_boot_irqs_off(); //设置系统中断的关闭标志
early_init_irq_lock_class();
/*
* Interrupts are still disabled. Do necessary setups, then
* enable them
*/
lock_kernel();
tick_init(); //初始化内核时钟系统
boot_cpu_init(); //激活当前cpu
/*
static void __init boot_cpu_init(void)
{
int cpu = smp_processor_id();
/* Mark the boot cpu "present", "online" etc for SMP and UP case */
cpu_set(cpu, cpu_online_map);
cpu_set(cpu, cpu_present_map);
cpu_set(cpu, cpu_possible_map);
}
*/
page_address_init(); //高端内存相关,未定义高端内存的话为空函数
/*
void __init page_address_init(void)
{
int i;
INIT_LIST_HEAD(&page_address_pool);
for (i = 0; i < ARRAY_SIZE(page_address_maps); i++)
list_add(&page_address_maps.list, &page_address_pool);
for (i = 0; i < ARRAY_SIZE(page_address_htable); i++) {
INIT_LIST_HEAD(&page_address_htable.lh);
spin_lock_init(&page_address_htable.lock);
}
spin_lock_init(&pool_lock);
}
*/
printk(KERN_NOTICE);
printk(linux_banner); //将打印信息放在缓冲(4K),因为控制台还没初始化,系统起来后可以用dmesg查看
setup_arch(&command_line); //设置与体系结构相关的环境
/*在arch/arm/kernel/setup.c
void __init setup_arch(char **cmdline_p)
{
struct tag *tags = (struct tag *)&init_tags;
struct machine_desc *mdesc;
char *from = default_command_line;
setup_processor(); //进行处理器相关的设置,会调用引导阶段的lookup_processor_type函数
mdesc = setup_machine(machine_arch_type); //获得开发板的machine_desc结构
machine_name = mdesc->name;
if (mdesc->soft_reboot)
reboot_setup("s");
if (__atags_pointer) //tags列表的首地址,在arch/arm/mach-pxa/littleton.c中的MACHINE_START:.boot_params= 0xa0000100。
tags = phys_to_virt(__atags_pointer); //转换为虚拟地址
else if (mdesc->boot_params)
tags = phys_to_virt(mdesc->boot_params);
/*
* If we have the old style parameters, convert them to
* a tag list.
*/
if (tags->hdr.tag != ATAG_CORE)
convert_to_tag_list(tags);
if (tags->hdr.tag != ATAG_CORE)
tags = (struct tag *)&init_tags;
if (mdesc->fixup)
mdesc->fixup(mdesc, tags, &from, &meminfo);
if (tags->hdr.tag == ATAG_CORE) {
if (meminfo.nr_banks != 0)
squash_mem_tags(tags); //如果已经在内核中定义了meminfo结构,则忽略内存tag
save_atags(tags);
parse_tags(tags); //处理每个tag
//每个tag都定义了相对应的处理函数,比如内存tag,__tagtable(ATAG_MEM, parse_tag_mem32);
}
init_mm.start_code = (unsigned long) &_text; //内核代码段开始
init_mm.end_code = (unsigned long) &_etext; //内核代码段结束
init_mm.end_data = (unsigned long) &_edata; //内核数据段开始
init_mm.brk = (unsigned long) &_end; //内核数据段结束
memcpy(boot_command_line, from, COMMAND_LINE_SIZE);
boot_command_line[COMMAND_LINE_SIZE-1] = '\0';
parse_cmdline(cmdline_p, from); //对命令进行一些先期的处理,主要通过early_params结构体
paging_init(&meminfo, mdesc); //重新初始化页表,设置页表, 初始化内存映射,分配三页出来用于处理异常过程:零页面,坏页和坏页表。
//paging_init-->devicemaps_init-->map_io 也就是.map_io= pxa_map_io。这里设置晶振频率
request_standard_resources(&meminfo, mdesc);
#ifdef CONFIG_SMP
smp_init_cpus();
#endif
cpu_init(); //cpu初始化
/*
* Set up various architecture-specific pointers
*/
init_arch_irq = mdesc->init_irq;
system_timer = mdesc->timer;
init_machine = mdesc->init_machine;
#ifdef CONFIG_VT
#if defined(CONFIG_VGA_CONSOLE)
conswitchp = &vga_con;
#elif defined(CONFIG_DUMMY_CONSOLE)
conswitchp = &dummy_con;
#endif
#endif
}
*/
setup_command_line(command_line); //对cmdline进行备份和保存
unwind_setup();
setup_per_cpu_areas(); //为系统中每个处理器的per_cpu变量申请空间
smp_prepare_boot_cpu();/* arch-specific boot-cpu hooks */针对SMP处理器的内存初始化函数
/*
* 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.
*/
sched_init(); //初始化每个处理器的可运行进程队列,设置系统初始化进程即0号进程
/*
* Disable preemption - early bootup scheduling is extremely
* fragile until we cpu_idle() for the first time.
*/
preempt_disable();
build_all_zonelists(); //建立系统内存页区链表
page_alloc_init();
printk(KERN_NOTICE "Kernel command line: %s\n", boot_command_line);
parse_early_param(); //解析早期格式内核参数
parse_args("Booting kernel", static_command_line, __start___param,
__stop___param - __start___param, //解析新格式内核参数
&unknown_bootoption); //命令行的后续处理,在kernel\include\asm-generic\vmlinux.lds.h有关kernel_param的结构体
if (!irqs_disabled()) {
printk(KERN_WARNING "start_kernel(): bug: interrupts were "
"enabled *very* early, fixing it\n");
local_irq_disable();
}
sort_main_extable();
//将放在__start__ex_table到__stop__ex_table之间的*(__ex_table)区中的struct exception_table_entry型全局结构变量按insn成员变量值从小到大排序,即将可能导致缺页异常的指令按其指令二进制代码值从小到大排序
trap_init(); //异常入口地址搬到高端中断向量
rcu_init(); //Read-Copy Update,RCU锁机制初始化
init_IRQ();
pidhash_init(); //根据内存大小设置pid hash列表
init_timers();
hrtimers_init();
softirq_init();
timekeeping_init();
time_init();
profile_init(); //对体统剖析做相关初始化
if (!irqs_disabled())
printk("start_kernel(): bug: interrupts were enabled early\n");
early_boot_irqs_on();
local_irq_enable();
/*
* 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.
*/
console_init();
/*在drivers/char/tty_io.c中
void __init console_init(void)
{
initcall_t *call;
/* Setup the default TTY line discipline. */
(void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
/*
* set up the console device so that later boot sequences can
* inform about problems etc..
*/
call = __con_initcall_start;
while (call < __con_initcall_end) {
(*call)();
call++;
}
}
它调用的范围从con_initcall_start到con_initcall_end之间定义的每个函数,这些函数使用console_initcall宏来指定。
*/
if (panic_later)
panic(panic_later, panic_param);
lockdep_info(); //lockdep是一个内核调试模块,用来检测内核互斥机制潜在的死锁问题
/*
* 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 &&
initrd_start < min_low_pfn << PAGE_SHIFT) {
printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - "
"disabling it.\n",initrd_start,min_low_pfn << PAGE_SHIFT);
initrd_start = 0;
}
#endif
vfs_caches_init_early();
cpuset_init_early();
mem_init(); //初始化内存,调节内存申请限制
enable_debug_pagealloc();
cpu_hotplug_init();
kmem_cache_init(); //执行高速缓存内存管理,即slab分配器相关初始化
setup_per_cpu_pageset();
numa_policy_init();
if (late_time_init)
late_time_init();
calibrate_delay(); //计算bogoMIPS值,一个衡量cpu性能的标志
pidmap_init(); //PID分配映射初始化
pgtable_cache_init();
prio_tree_init();
anon_vma_init(); //匿名虚拟内存域初始化
#ifdef CONFIG_X86
if (efi_enabled)
efi_enter_virtual_mode();
#endif
fork_init(num_physpages); //进程创建机制初始化,为内核“task_struct”分配空间,计算最大任务数
proc_caches_init(); //初始化进程创建机制所需的其他数据结构,为其申请空间
buffer_init(); //缓存系统初始化,创建缓存头空间,并检查其大小
unnamed_dev_init();
key_init(); //内核密钥管理体统初始化
security_init(); //内核安全框架初始化
vfs_caches_init(num_physpages); //虚拟文件系统缓存初始化
radix_tree_init();
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函数
acpi_early_init(); /* before LAPIC and SMP init */
/* Do the rest non-__init'ed, we're now alive */
rest_init(); //剩余的初始化
}
小结:
1.内核启动参数的获取和处理
2.内存管理的初始化
|
|