arm linux 内核 c=,Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3.0 ARMv7)...

发布时间:2024-01-21 13:30

/*

* 使用大量bootmem分配,且必须先于

* kmem_cache_init()

*/

点击(此处)折叠或打开

以上注释的含义在于bootmem是内核启动时使用的临时内存分配器。之后由slab接替。

kmem_cache_init()初始化了内核高速缓存分配器(slab分配器),这个函数标标志着bootmem的终结,同时内核的内存管理系统正式启用了。

所以在kmem_cache_init()之后,bootmem的API不再可用,所以bootmem分配必须先于kmem_cache_init()。

setup_log_buf(0);

点击(此处)折叠或打开

使用bootmem分配一个记录启动信息的缓存区

pidhash_init();

点击(此处)折叠或打开

使用bootmem分配并初始化PID散列表,由PID分配器管理空闲和已指派的PID

vfs_caches_init_early();

点击(此处)折叠或打开

前期VFS缓存初始化

sort_main_extable();

点击(此处)折叠或打开

对内核异常表( exception table )按照异常向量号大小进行排序。

trap_init();

点击(此处)折叠或打开

对内核陷阱异常进行初始化,在ARM构架中为空函数。

mm_init();

点击(此处)折叠或打开

初始化内核内存分配器,其包含6个子函数,作用如下:

1、page_cgroup_init_flatmem(); 获取page_cgroup 所需内存

2、mem_init(); 关闭并释放bootmem分配器,打印内存信息。在内核启动时看到的类似如下信息,就是其子函数mem_init输出的:

点击(此处)折叠或打开

Memory: 86MB 39MB = 125MB total

Memory: 120768k/120768k available, 99392k reserved, 0K highmem

Virtual kernel memory layout:

vector : 0xffff0000 - 0xffff1000 ( 4 kB)

fixmap : 0xfff00000 - 0xfffe0000 ( 896 kB)

DMA : 0xffc00000 - 0xffe00000 ( 2 MB)

vmalloc : 0xde800000 - 0xf8000000 ( 408 MB)

lowmem : 0xc0000000 - 0xde400000 ( 484 MB)

pkmap : 0xbfe00000 - 0xc0000000 ( 2 MB)

modules : 0xbf000000 - 0xbfe00000 ( 14 MB)

.init : 0xc0008000 - 0xc003b000 ( 204 kB)

.text : 0xc003b000 - 0xc04c0000 (4628 kB)

.data : 0xc04c0000 - 0xc0501a80 ( 263 kB)

3、kmem_cache_init(); 初始化slab分配器

4、percpu_init_late(); PerCPU变量系统后期初始化

5、pgtable_cache_init();页表缓存初始化,对于ARM,“介是一个空函数”

6、vmalloc_init();初始化虚拟内存分配器

/*

* 在开启任何中断(比如定时器中断)前设置调度器。

* 完整的拓扑设置发生在smp_init()中

*-但与此同时,我们仍然有一个正常运作的调度器。

*/

sched_init();

点击(此处)折叠或打开

初始化调度器数据结构,并创建运行队列

/*

* 禁用强占 - 早期启动时的调度是极为脆弱的,

*直到cpu_idle()的首次运行。

*/

preempt_disable();

if (!irqs_disabled()) {

printk(KERN_WARNING "start_kernel(): bug: interrupts were "

"enabled *very* early, fixing it\n");

local_irq_disable();

}

点击(此处)折叠或打开

在启动的初期关闭抢占和中断。

idr_init_cache();

点击(此处)折叠或打开

为IDR机制分配缓存,主要是为struct idr_layer结构体分配空间

perf_event_init();

点击(此处)折叠或打开

CPU性能监视机制初始化

此机制包括CPU同一时间执行指令数,cache miss数,分支预测失败次数等性能参数

rcu_init();

点击(此处)折叠或打开

内核RCU(Read-Copy Update:读取-复制-更新)机制初始化

radix_tree_init();

点击(此处)折叠或打开

内核radix树算法初始化

/* 在init_ISA_irqs()之前初始化一些链接 */

early_irq_init();

init_IRQ();

点击(此处)折叠或打开

硬件中断系统初始化:

early_irq_init();前期外部中断描述符初始化,主要初始化数据结构。

init_IRQ;对应构架特定的中断初始化函数,在ARM构架中:

点击(此处)折叠或打开

void __init init_IRQ(void)

{

machine_desc->init_irq();

}

也就是运行设备描述结构体中的init_irq函数,此函数一般在板级初始化文件(arch/*/mach-*/board-*.c)中定义。

prio_tree_init();

点击(此处)折叠或打开

初始化内核基于radix数的优先级搜索树(PST),主要是对其结构体进行初始化。

init_timers();

hrtimers_init();

softirq_init();

timekeeping_init();

time_init();

点击(此处)折叠或打开

以上几个函数主要是初始化内核的软中断及时钟机制:

前面几个函数主要是注册一些内核通知函数到cpu和hotcpu通知链,并开启部分软中断(tasklet等)。

最后的time_init是构架相关的,旨在开启一个硬件定时器,开始产生系统时钟。对于ARM构架:

点击(此处)折叠或打开

void __init time_init(void)

{

system_timer = machine_desc->timer;

system_timer->init();

#ifdef CONFIG_HAVE_SCHED_CLOCK

sched_clock_postinit();

#endif

}

其实就是调用板级初始化文件(arch/arm/mach-*/board-*.c)中定义“设备描述结构体”中的timer成员的初始化函数。

profile_init();

点击(此处)折叠或打开

初始化内核profile子系统,她是内核的性能调试工具。

call_function_init();

点击(此处)折叠或打开

初始化所有CPU的call_single_queue(具体作用还没搞明白),并注册CPU热插拔通知函数到CPU通知链中。

if (!irqs_disabled())

printk(KERN_CRIT "start_kernel(): bug: interrupts were "

"enabled early\n");

early_boot_irqs_disabled = false;

local_irq_enable();

点击(此处)折叠或打开

检测硬件中断是否开启,如果开启了就打印出警告。

设置启动早期IRQ使能标志,允许IRQ使能。

最后开启总中断(ARM构架是这样,其他构架可能也是这个意思)。

/* 中断已经开启,因此所有GFP分配是安全的. */

gfp_allowed_mask = __GFP_BITS_MASK;

点击(此处)折叠或打开

开启所有GFP分配允许标志

GFP(get free page)

kmem_cache_init_late();

点击(此处)折叠或打开

slab分配器的后期初始化。如果使用的是slob或slub,则为空函数。

/*

* HACK ALERT! hack警告!这个是早期的。我们在完成PCI设置等工作前

* 使能控制台,且console_init()必须意识到这个。

* 但是我们的确想要早点输出信息,以防某些错误的发生。

*/

console_init();

点击(此处)折叠或打开

初始化控制台,这样可以早点看到启动信息,避免出错时无法查找原因。

if (panic_later)

panic(panic_later, panic_param);

点击(此处)折叠或打开

检查内核恐慌标志。如果出了问题,就打印信息。

lockdep_info();

点击(此处)折叠或打开

打印lockdep调试模块的信息。

/*

* 当irq使能的时候必须运行这个函数,因为它也要自检

* [hard/soft]-irqs 开/关 锁反转的bug:

*

*/

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

点击(此处)折叠或打开

检查initrd的位置是否符合要求。

min_low_pfn是系统可用的最小的pfn(页帧号)。

也就是判断传递进来initrd_start对应的物理地址是否正常。如果有误就打印错误信息,并清零initrd_start。

page_cgroup_init();

点击(此处)折叠或打开

mem_cgroup是cgroup体系中提供的用于memory隔离的功能,此处对此功能进行初始化。

enable_debug_pagealloc();

点击(此处)折叠或打开

使能页分配的调试标志。

debug_objects_mem_init();

点击(此处)折叠或打开

debug objects机制的内存分配初始化

kmemleak_init();

点击(此处)折叠或打开

内核内存泄漏检测机制初始化;

setup_per_cpu_pageset();

点击(此处)折叠或打开

设置每个CPU的页组,并初始化。此前只有启动页组。

numa_policy_init();

点击(此处)折叠或打开

非一致性内存访问(NUMA)初始化

if (late_time_init)

late_time_init();

点击(此处)折叠或打开

如果构架存在此函数,就调用后期时间初始化。

sched_clock_init();

点击(此处)折叠或打开

对每个CPU,初始化调度时钟。

calibrate_delay();

点击(此处)折叠或打开

计算BogoMIPS值,他是衡量一个CPU性能的标志。

pidmap_init();

点击(此处)折叠或打开

PID分配映射初始化。

anon_vma_init();

点击(此处)折叠或打开

匿名虚拟内存域( anonymous VMA)初始化

#ifdef CONFIG_X86

if (efi_enabled)

efi_enter_virtual_mode();

#endif

thread_info_cache_init();

点击(此处)折叠或打开

获取thread_info缓存空间,大部分构架为空函数(包括ARM)

cred_init();

点击(此处)折叠或打开

任务信用系统初始化。详见:Documentation/credentials.txt

fork_init(totalram_pages);

点击(此处)折叠或打开

进程创建机制初始化。为内核"task_struct"分配空间,计算最大任务数。

proc_caches_init();

点击(此处)折叠或打开

初始化进程创建机制所需的其他数据结构,为其申请空间。

buffer_init();

点击(此处)折叠或打开

缓存系统初始化,创建缓存头空间,并检查其大小限时。

key_init();

点击(此处)折叠或打开

内核密匙管理系统初始化。

security_init();

点击(此处)折叠或打开

内核安全框架初始化

dbg_late_init();

点击(此处)折叠或打开

内核调试系统后期初始化

vfs_caches_init(totalram_pages);

点击(此处)折叠或打开

虚拟文件系统(VFS)缓存初始化

signals_init();

点击(此处)折叠或打开

信号管理系统初始化

/* 根文件系统的填充可能需要也回写机制 */

page_writeback_init();

点击(此处)折叠或打开

页回写机制初始化

#ifdef CONFIG_PROC_FS

proc_root_init();

#endif

点击(此处)折叠或打开

proc文件系统初始化

cgroup_init();

点击(此处)折叠或打开

control group的正式初始化

cpuset_init();

点击(此处)折叠或打开

CPUSET初始化。

参考资料:

taskstats_init_early();

点击(此处)折叠或打开

任务状态早期初始化函数:为结构体获取高速缓存,并初始化互斥机制。

delayacct_init();

点击(此处)折叠或打开

任务延迟机制初始化

check_bugs();

点击(此处)折叠或打开

检查CPU BUG的函数,通过软件规避BUG

acpi_early_init(); /* 在 LAPIC 和 SMP 前初始化 */

点击(此处)折叠或打开

ACPI早期初始化函数。

ACPI - Advanced Configuration and Power Interface高级配置及电源接口

sfi_init_late();

点击(此处)折叠或打开

SFI 初始程序晚期设置函数,

SFI - SIMPLE FIRMWARE INTERFACE。

ftrace_init();

点击(此处)折叠或打开

功能跟踪调试机制初始化,ftrace 是 function trace 的简称。

/* 所剩下的非-__init的初始化, 内核现在已经启动了 */

rest_init();

点击(此处)折叠或打开

虽然从名字上来说是剩余的初始化。

但是这个函数中的初始化包含了很多的内容,后面我回单独写一篇来分析。

}

ItVuer - 免责声明 - 关于我们 - 联系我们

本网站信息来源于互联网,如有侵权请联系:561261067@qq.com

桂ICP备16001015号