前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >06.内核启动流程分析之内核启动

06.内核启动流程分析之内核启动

作者头像
嵌入式与Linux那些事
发布2021-05-20 15:04:58
8210
发布2021-05-20 15:04:58
举报
内核最终目的:运行根文件系统的应用程序
内核做的事情:
处理uboot传入的参数
代码语言:javascript
复制
arch\arm\kernel

/*启动内核:bi_arch_number机器ID。参数存放的地址 bd->bi_boot_params*/
theKernel (0, bd->bi_arch_number, bd->bi_boot_params);
判断是否支持单板(根据启动内核时传入的机器ID)
代码语言:javascript
复制
/**/
ENTRY(stext)
	msr	cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ ensure svc mode
						@ and irqs disabled
	mrc	p15, 0, r9, c0, c0		@ get processor id
	/*支持的处理器类型*/
	bl	__lookup_processor_type		@ r5=procinfo r9=cpuid
	movs	r10, r5				@ invalid processor (r5=0)?
	beq	__error_p			@ yes, error 'p'
	bl	__lookup_machine_type		@ r5=machinfo
	movs	r8, r5				@ invalid machine (r5=0)?
	beq	__error_a			@ yes, error 'a'
	bl	__create_page_tables

__lookup_machine_type:
	adr	r3, 3b              @ r3=3b的地址,物理地址
	/*	链接脚本
	__arch_info_begin = .;
			*(.arch.info.init)
		__arch_info_end = .;
	*/
	ldmia	r3, {r4, r5, r6}@ r4=“.”(.代表3b的虚拟地址) r5=__arch_info_begin r6=__arch_info_end
	sub	r3, r3, r4			@ get offset between virt&phys 虚拟地址物理地址的偏差
	add	r5, r5, r3			@ convert virt addresses to
	add	r6, r6, r3			@ physical address space
1:	ldr	r3, [r5, #MACHINFO_TYPE]	@ get machine type
	teq	r3, r1				@ matches loader number? 机器ID
	beq	2f				@ found
	add	r5, r5, #SIZEOF_MACHINE_DESC	@ next machine_desc
	cmp	r5, r6
	blo	1b
	mov	r5, #0				@ unknown machine
2:	mov	pc, lr

/*linux-2.6.22.6\linux-2.6.22.6\include\asm-arm\mach\arch.h*/
/*定义两个结构体,把段强制设置成.arch.info.init*/
#define MACHINE_START(_type,_name)			\
static const struct machine_desc __mach_desc_##_type	\
 __used							\
 __attribute__((__section__(".arch.info.init"))) = {	\
	.nr		= MACH_TYPE_##_type,		\
	.name		= _name,
	
/*linux-2.6.22.6\linux-2.6.22.6\arch\arm\mach-s3c2440\Mach-smdk2440.c*/
MACHINE_START(S3C2440, "SMDK2440")
	/* Maintainer: Ben Dooks <ben@fluff.org> */
	.phys_io	= S3C2410_PA_UART,
	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
	.boot_params	= S3C2410_SDRAM_PA + 0x100,

	.init_irq	= s3c24xx_init_irq,
	.map_io		= smdk2440_map_io,
	.init_machine	= smdk2440_machine_init,
	.timer		= &s3c24xx_timer,
MACHINE_END
创建页表
代码语言:javascript
复制
	bl	__create_page_tables
使能MMU
代码语言:javascript
复制
	adr	r4, __secondary_data
	ldmia	r4, {r5, r7, r13}		@ address to jump to after
	sub	r4, r4, r5			@ mmu has been enabled
	ldr	r4, [r7, r4]			@ get secondary_data.pgdir
	adr	lr, __enable_mmu		@ return address
	add	pc, r10, #PROCINFO_INITFUNC	@ initialise processor
						@ (return control reg)
跳转到start kernel(内核的第一个C函数,处理启动参数)
代码语言:javascript
复制
b	start_kernel
main.c(init)
代码语言:javascript
复制
/*启动流程
start_kernel
	setup_arch  解析UBOOT传入的启动参数
	setup_command_line   解析UBOOT传入的启动参数
	parse_early_param
		do_early_para
			从_setup_start到_setup_end,调用early函数
	unknown_bootoption
		obsolete_checksetup
			从_setup_start到_setup_end,调用early函数
	rest_init
		kernel_init
			prepare_namespace
				mount_root 挂载根文件系统
			init_post  执行应用程序
*/
	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();
	lockdep_init();

	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();
	page_address_init();
	printk(KERN_NOTICE);
	printk(linux_banner);
	setup_arch(&command_line);
	setup_command_line(command_line);
	unwind_setup();
	setup_per_cpu_areas();
	smp_prepare_boot_cpu();	/* arch-specific boot-cpu hooks */

	/*
	 * 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();
	/*
	 * 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);
	if (!irqs_disabled()) {
		printk(KERN_WARNING "start_kernel(): bug: interrupts were "
				"enabled *very* early, fixing it\n");
		local_irq_disable();
	}
	sort_main_extable();
	trap_init();
	rcu_init();
	init_IRQ();
	pidhash_init();
	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();
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-11-04 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 内核最终目的:运行根文件系统的应用程序
    • 内核做的事情:
      • 处理uboot传入的参数
      • 判断是否支持单板(根据启动内核时传入的机器ID)
      • 创建页表
      • 使能MMU
      • 跳转到start kernel(内核的第一个C函数,处理启动参数)
      • main.c(init)
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档