您的位置:首页 > 运维架构 > Linux

linux 3.6 启动源码分析(三) setup_arch

2013-12-16 14:05 549 查看
setup_arch()函数是start_kernel阶段最重要的一个函数,每个体系都有自己的setup_arch()函数,是体系结构相关的,具体编译哪个体系的setup_arch()函数,由顶层Makefile中的ARCH变量决定:

它首先通过检测出来的处理器类型进行处理器内核的初始化,然后通过 bootmem_init()函数根据系统定义的 meminfo
结构进行内存结构的初始化,最后调用paging_init()开启 MMU,创建内核页表,映射所有的物理内存和
IO空间。

void __init setup_arch(char **cmdline_p)
{
/*内核通过machine_desc结构体来控制系统体系架构相关部分的初始化。
machine_desc结构体通过MACHINE_START宏来初始化,在代码中,
通过在start_kernel->setup_arch中调用setup_machine_fdt来获取。*/
struct machine_desc *mdesc;
/*首先从arm寄存器里面取得cpu ID,然后调用lookup_processor_type来取得proc_info_list这个结构体。
取得proc_info_list以后,将里面的内容一个个赋值给相应的全局变量,
然后将CPU的信息打印出来。然后它会从arm寄存器里面获得cache的信息,
并将cache的信息打印出来(CPU: ARMv7 Processor [410fc051] revision 1 (ARMv7), cr=10c53c7d
CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache)。*/
setup_processor();
/*machine_desc结构体通过MACHINE_START宏来初始化,在代码中,调用setup_machine_fdt来获取。
对于samad5,它通过在arch/arm/mach-at91/board_dt.c中的DT_MACHINE_START宏初始化
输出CPU型号Machine: Atmel SAMA5 (Device Tree), model: Atmel SAMA5D34-EK*/
mdesc = setup_machine_fdt(__atags_pointer);
if (!mdesc)
mdesc = setup_machine_tags(machine_arch_type);
machine_desc = mdesc;
machine_name = mdesc->name;

setup_dma_zone(mdesc);

//通过struct machine_desc 中的soft_reboot数据来设置重启类型:
if (mdesc->restart_mode)
reboot_setup(&mdesc->restart_mode);

/*这里通过连接脚本中得到的Linux代码位置数据来初始化一个mm_struct结构体init_mm中的部分数据
ps:每一个任务都有一个mm_struct结构以管理内存空间,init_mm是内核自身的mm_struct
*/
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;

/* 同时填充cmd_line以备后用, 保护boot_command_line数据 populate cmd_line too for later use, preserving boot_command_line */
strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
*cmdline_p = cmd_line;
/*
处理在 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参数。
*/
parse_early_param();

sort(&meminfo.bank, meminfo.nr_banks, sizeof(meminfo.bank[0]), meminfo_cmp, NULL);
sanity_check_meminfo();//在此处设置struct meminfo meminfo中每个bank中的highmem变量2.通过vmalloc_min确定每个bank中的内存是否属于高端内存
arm_memblock_init(&meminfo, mdesc);//按地址数据从小到大排序meminfo中的数据,并初始化全局的memblock数据。

/*
设置内核的参考页表。
此页表不仅用于物理内存映射,还用于管理vmalloc区。
此函数中非常重要的一点就是初始化了bootmem分配器!
*/
paging_init(mdesc);
//通过获取设备描述结构体(struct machine_desc)中的数据和编译时产生的地址数据,初始化内存相关的全局结构体变量。
request_standard_resources(mdesc);

if (mdesc->restart)
arm_pm_restart = mdesc->restart;
//通过启动参数中的“非平坦设备树”信息(如果有),获取内存相关信息
unflatten_device_tree();

/*针对SMP处理器,初始化可能存在的CPU映射 - 这描述了可能存在的CPU*/
#ifdef CONFIG_SMP
if (is_smp())
smp_init_cpus();
#endif
/*1.用于内核崩溃时的保留内核此功能通过内核command line参数中的"crashkernel="保留下内存用于主内核崩溃时获取内核信息的导出*/
reserve_crashkernel();
/*
初始化ARM内部的TCM(紧耦合内存)。
参考资料:《对ARM紧致内存TCM的理解》
*/	tcm_init();

#ifdef CONFIG_MULTI_IRQ_HANDLER
handle_arch_irq = mdesc->handle_irq;
#endif

#ifdef CONFIG_VT
#if defined(CONFIG_VGA_CONSOLE)
conswitchp = &vga_con;
#elif defined(CONFIG_DUMMY_CONSOLE)
conswitchp = &dummy_con;
#endif
#endif
/*
1.如果设备描述结构体定义了init_early函数(应该是早期初始化之意),则在这里调用。
*/	if (mdesc->init_early)
mdesc->init_early();
}


主要完成了4个方面的工作,一个就是取得MACHINE和PROCESSOR的信息然或将他们赋值给kernel相应的全局变量,然后呢是对boot_command_line和tags接行解析,再然后呢就是memory、cach的初始化,最后是为kernel的后续运行请求资源。主要完成了4个方面的工作,

1.一个就是取得MACHINE和PROCESSOR的信息然或将他们赋值给kernel相应的全局变量.

2.对boot_command_line和tags接行解析.

3.memory、cach的初始化.

4.为kernel的后续运行请求资源.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: