转载:http://blog.chinaunix.net/uid-20543672-id-3157283.html
在分析start_kernel函数的时候,其中有构架相关的初始化函数setup_arch。
此函数根据构架而异,对于ARM构架的详细分析如下:
-
void __init setup_arch(char **cmdline_p)
-
{
-
struct machine_desc *mdesc;
-
-
-
unwind_init();
-
-
初始化基於ARM EABI的Backtrace Unwind機制(栈回退),此函数主要用于地址转换(arch/arm/kernel/unwind.c)
-
setup_processor();
-
再次检测处理器类型,并初始化处理器相关的底层变量。内核启动时的处理器信息(包括cache)就是通过这个函数打印的,例如:
-
CPU: ARMv7 Processor [413fc082] revision 2 (ARMv7), cr=10c53c7f
-
CPU: VIPT nonaliasing data cache, VIPT aliasing instruction cache
-
mdesc = setup_machine_fdt(__atags_pointer);
-
if (!mdesc)
-
mdesc = setup_machine_tags(machine_arch_type);
-
在此处通过bootloader传递过来的设备ID来匹配一个 struct machine_desc 结构体
-
(这个结构体就是在arch/arm/mach-*/mach-*.c中定义的结构体:MACHINE_START~MACHINE_END )
-
如果没有匹配上就死循环。
-
如果匹配上了就打印机器名 ,并处理bootloader传递过来的tagged_list,将所有的tag信息保存到相应的全局变量或结构体中。
-
内核启动时的机器信息就是这里打印的,例如:
-
-
最后返回结构体指针。
-
machine_desc = mdesc;
-
machine_name = mdesc->name;
-
通过匹配的struct machine_desc 结构体数据,初始化一些全局变量
-
-
if (mdesc->soft_reboot)
-
reboot_setup("s");
-
通过struct machine_desc 中的soft_reboot数据来设置重启类型:
-
如果存在就为“s”:softreset;如果不存在就为“h”:hardreset
-
-
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;
-
这里通过连接脚本中得到的Linux代码位置数据来初始化一个mm_struct结构体init_mm中的部分数据
-
ps:每一个任务都有一个mm_struct结构以管理内存空间,init_mm是内核自身的mm_struct
-
-
/* 同时填充cmd_line以备后用, 保护boot_command_line数据 */
-
strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
-
*cmdline_p = cmd_line;
-
将boot_command_line复制到cmd_line中。这里关键是要知道系统启动的时候的cmdline是如何传递的。
-
-
parse_early_param();
-
处理在 struct obs_kernel_param 中定义为early的启动参数(主要是内存配置部分的参数)
-
-
其中就分析了mem=size@start参数初始化了struct meminfo meminfo;
-
同时如果有vmalloc=size参数也会初始化 vmalloc_min
-
参考:《Linux内核高-低端内存设置代码跟踪(ARM构架)》
-
-
这里需要注意的是内核的cmdline中的参数按照其被需要的先后,分为early和非early的。
-
-
include/linux/init.h:
-
struct obs_kernel_param {
-
const char *str; //在cmdline中相应参数名。
-
int (*setup_func)(char *); //对于此参数的专用处理函数
-
int early; //是否为早期需要处理的参数
-
};
-
-
两种不同的参数在内核中用了不同的宏来定义:
-
early: #define early_param(str, fn) \
-
__setup_param(str, fn, fn, 1)
-
-
非early: #define __setup(str, fn) \
-
__setup_param(str, fn, fn, 0)
-
-
使用这两个宏定义的参数和构架相关,一些构架或者板子可以定义自己特定的参数和处理函数。对于比较重要的“men”参数就是early参数。
-
-
sanity_check_meminfo();
-
在此处设置struct meminfo meminfo中每个bank中的highmem变量,
-
通过vmalloc_min确定每个bank中的内存是否属于高端内存
-
arm_memblock_init(&meminfo, mdesc);
-
在此处按地址数据从小到大排序meminfo中的数据,并初始化全局的memblock数据。
-
-
paging_init(mdesc);
-
设置内核的参考页表。
-
此页表不仅用于物理内存映射,还用于管理vmalloc区。
-
此函数中非常重要的一点就是初始化了bootmem分配器!
-
-
request_standard_resources(mdesc);
-
-
通过获取设备描述结构体(struct machine_desc)中的数据和编译时产生的地址数据,初始化内存相关的全局结构体变量。
-
unflatten_device_tree();
-
通过启动参数中的“非平坦设备树”信息(如果有),获取内存相关信息
-
-
#ifdef CONFIG_SMP
-
if (is_smp())
-
smp_init_cpus();
-
#endif
-
针对SMP处理器,初始化可能存在的CPU映射 - 这描述了可能存在的CPU
-
reserve_crashkernel();
-
用于内核崩溃时的保留内核
-
此功能通过内核command line参数中的"crashkernel="保留下内存用于主内核崩溃时获取内核信息的导出。
-
-
cpu_init();
-
tcm_init();
-
-
#ifdef CONFIG_MULTI_IRQ_HANDLER
-
handle_arch_irq = mdesc->handle_irq;
-
#endif
-
-
调用设备描述结构体中的mdesc->handle_irq函数,目的未知。
-
#ifdef CONFIG_VT
-
#if defined(CONFIG_VGA_CONSOLE)
-
conswitchp = &vga_con;
-
#elif defined(CONFIG_DUMMY_CONSOLE)
-
conswitchp = &dummy_con;
-
#endif
-
#endif
-
early_trap_init();
-
-
if (mdesc->init_early)
-
mdesc->init_early();
-
如果设备描述结构体定义了init_early函数(应该是早期初始化之意),则在这里调用。
-
}
这个函数主要是检查处理器的类型是否匹配,并获取处理器信息来设置处理器的相关底层参数。
-
static void __init setup_processor(void)
-
{
-
struct proc_info_list *list;
-
-
/*
-
* 在支持处理器列表中定位处理器
-
* 连接器为我们创建这个列表,从 * arch/arm/mm/proc-*.S中的入口
-
*/
-
list = lookup_processor_type(read_cpuid_id());
-
if (!list) {
-
printk("CPU configuration botched (ID %08x), unable "
-
"to continue.\n", read_cpuid_id());
-
while (1);
-
}
-
这里再次核对处理器类型,虽然这个已经在汇编代码中执行过一遍了
-
-
cpu_name = list->cpu_name;
-
-
#ifdef MULTI_CPU
-
processor = *list->proc;
-
#endif
-
#ifdef MULTI_TLB
-
cpu_tlb = *list->tlb;
-
#endif
-
#ifdef MULTI_USER
-
cpu_user = *list->user;
-
#endif
-
#ifdef MULTI_CACHE
-
cpu_cache = *list->cache;
-
#endif
-
-
通过从struct proc_info_list获取的数据初始化CPU相关的全局变量
-
printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n",
-
cpu_name, read_cpuid_id(), read_cpuid_id() & 15,
-
proc_arch[cpu_architecture()], cr_alignment);
-
-
sprintf(init_utsname()->machine, "%s%c", list->arch_name, ENDIANNESS);
-
sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS);
-
elf_hwcap = list->elf_hwcap;
-
#ifndef CONFIG_ARM_THUMB
-
elf_hwcap &= ~HWCAP_THUMB;
-
#endif
-
-
feat_v6_fixup();
-
-
cacheid_init();
-
cpu_proc_init();
-
宏:
-
#define cpu_proc_init __glue(CPU_NAME,_proc_init)
-
意在调用处理器特定的初始化函数。
-
}
阅读(894) | 评论(0) | 转发(0) |