Linux内核源码分析_setup_arch函数的主要作用

本文详细介绍了Linux内核启动过程中的关键函数setup_arch的作用与实现细节,包括处理器内核初始化、内存结构初始化及MMU的开启等步骤。通过具体代码分析,帮助读者理解Linux内核如何完成从启动到运行的基本过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

`一、setup_arch函数的主要作用

start_kernel 中,调用 setup_arch 函数,传给他的参数是那个未被初始化的内部变量 command_line 。这个 setup_arch() 函数是 start_kernel 阶段最重要的一个函数,每个体系都有自己的 setup_arch() 函数,是体系结构相关的,具体编译哪个体系的 setup_arch() 函数,由顶层 Makefile 中的 ARCH 变量决定:

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

  • start_kernel () --> setup_arch () --> paging_init () --> bootmem_init () --> alloc_bootmem_low_pages ()

具体代码分析如下:

void __init setup_arch(char **cmdline_p)
{
	struct tag *tags = (struct tag *)&init_tags; //定义了一个默认的内核参数列表
	struct machine_desc *mdesc;		//设备描述的结构体
	char *from = default_command_line;
	init_tags.mem.start = PHYS_OFFSET;
	unwind_init();
	setup_processor();   				//汇编的CPU初始化部分
	mdesc = setup_machine(machine_arch_type);
	machine_desc = mdesc;
	machine_name = mdesc->name;
	//下面一部分通过匹配struct machine_desc结构体数据,初始化一些全局变量
	//通过struct machine_desc 中的soft_reboot设置重启类型
	if (mdesc->soft_reboot) 
		reboot_setup("s");

	//检查bootloader是否传入参数,如果传入,则给tags赋值,若果没有传入则传递默认的启动参数地址
	if (__atags_pointer)	
		tags = phys_to_virt(__atags_pointer);
	else if (mdesc->boot_params) {
#ifdef CONFIG_MMU
		/*
		 * We still are executing with a minimal MMU mapping created
		 * with the presumption that the machine default for this
		 * is located in the first MB of RAM.  Anything else will
		 * fault and silently hang the kernel at this point.
		 */
		if (mdesc->boot_params < PHYS_OFFSET ||
		    mdesc->boot_params >= PHYS_OFFSET + SZ_1M) {
			printk(KERN_WARNING
			       "Default boot params at physical 0x%08lx out of reach\n",
			       mdesc->boot_params);
		} else
#endif
		{
			tags = phys_to_virt(mdesc->boot_params);
		}
	}

#if defined(CONFIG_DEPRECATED_PARAM_STRUCT)
	/*
	 * If we have the old style parameters, convert them to
	 * a tag list.
	 */
	if (tags->hdr.tag != ATAG_CORE)	//内核参数列表第一项为ATAG_CORE
		convert_to_tag_list(tags);
	//如果不是,这需要转换成新的内核参数类型,新的内核参数类型用下面的structtag结构表示
#endif
	if (tags->hdr.tag != ATAG_CORE)
		tags = (struct tag *)&init_tags;
	//如果没有内核参数,则选用默认的内核参数,在init_tags文件中有定义

	if (mdesc->fixup)
		mdesc->fixup(mdesc, tags, &from, &meminfo);
	//用选用的内核参数列表填充meminfo ,fixup函数出现在注册machine_desc中,即MACHINE_START、MACHINE_END定义中,这个函数,有些板子有,但在2410中没有定义这个函数。

	if (tags->hdr.tag == ATAG_CORE) {
		if (meminfo.nr_banks != 0)	//如果内存被初始化过
			squash_mem_tags(tags);	
		//如果是tag list,那么如果系统已经创建了默认的meminfo.nr_banks,清除tags中关于MEM的参数,以免再次被初始化	

		save_atags(tags);
		parse_tags(tags);	//做一些针对各个tags的处理
	}
	//解析内核参数列表,然后调用内核参数列表的处理函数对这些参数进行处理。比如,如果列表为命令行,则最终会用parse_tag_cmdlin函数进行解析,这个函数用_tagtable编译连接到了内核里

	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;
	//记录了内核代码的起始,结束虚拟地址

	/* parse_early_param needs a boot_command_line */
	strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);

	/* populate cmd_line too for later use, preserving boot_command_line */
	strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
	*cmdline_p = cmd_line;
	//将boot_command_line复制到cmd_line中

	parse_early_param();				//解释命令行参数

	arm_memblock_init(&meminfo, mdesc);	//将设备实体登记注册到总线空间链表中去

	paging_init(mdesc);
	request_standard_resources(mdesc);	

#ifdef CONFIG_SMP
	if (is_smp())
		smp_init_cpus();	//要配置CONFIG_KEXEC,否则为空函数,2410中没有配置
#endif
	reserve_crashkernel(); 

	cpu_init();	//初始化一个CPU,并设置一个per-CPU栈
	tcm_init();	//初始化ARM内部的TCM(紧耦合内存)

#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
	early_trap_init();		//对中断向量表进行早期的初始化
	//如果设备描述结构体定义了init_early函数(应该是早期初始化之意),则在这里调用 
	if (mdesc->init_early)			
		mdesc->init_early();
}

参考网址:

http://blog.youkuaiyun.com/boarmy/article/details/8652343

http://www.wesage.net/bbs/forum.php?mod=viewthread&tid=212&page=1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值