Linux启动流程_LK流程(源码层面)_作废

此博客是刚刚开始学习LK的时候写的,现在看来十分粗糙,重新写了一个LK系列(大多数参考了网上资料),故此篇作废。

此篇博客有很多参考其他文章的内容,由于参考内容繁杂,不一一标注角标了,在末尾会贴上所有参考博客的link,如有侵权,请联系本人处理,谢谢。

深入,并且广泛
					 -沉默犀牛

step1 从哪里开始执行,目前还不清楚,不作分析了。
step2 Bootloader(LK)

LK的代码在bootable/bootloader/lk目录下

在 bootable/bootloadler/lk/arch/arm/ssystem-onesegment.ld 连接文件中ENTRY(_start)指定 LK 从_start 函数开始,_start 在 lk/arch/crt0.S中,下面我们来看一下这个文件中的内容:

    .globl _start

    _start:  //这里就是ENTRY(_start)中的_start

    ...

    /*启动CPU*/

    这里的指令都是有关CPU初始化的一些指令,不展开了

    /* we are relocated, jump to the right address */

    ldrr0, =.Lstack_setup

    ...

    .Lstack_setup:

    /*为irq、fiq、abort、undefined、system/user和last supervisor模式设置堆栈*/

    /* 清除BSS *

    bl    kmain  //注意这里!

上文说过bootloader分为stage1和stage2,从这个汇编文件来看,应该已经包含了stage1,和stage2。只是stage2还没有结束,kmain也算是stage2里面的一部分。如果这里理解有误,请留言告知,感激不尽。

汇编中的最后一个有注释的指令bl kmain,跳转到了如下的代码中,代码路径为 lk/kernel/main.c

 void kmain(void) __NO_RETURN __EXTERNALLY_VISIBLE;

    void kmain(void) {

    thread_t *thr;

    thread_init_early();   //初始化thread(lk 中的简单进程)相关结构体。

    arch_early_init();     //做一些如 关闭 cache,使能 mmu 的 arm 相关工作。

    platform_early_init();  // 相关平台的早期初始化

    target_early_init();   // 现在就一个函数跳转,初始化UART(板子相关)

    dprintf(INFO, "welcome to lk\n\n");

    bs_set_timestamp(BS_BL_START);

    dprintf(SPEW, "calling constructors\n"); 

    call_constructors();

    dprintf(SPEW, "initializing heap\n");

    heap_init();       // lk系统相关的堆栈初始化

    __stack_chk_guard_setup();

    dprintf(SPEW, "initializing threads\n");

    thread_init();   // 线程初始化

    dprintf(SPEW, "initializing dpc\n");

    dpc_init();   // lk系统控制器初始化(相关事件初始化)

    dprintf(SPEW, "initializing timers\n");

    timer_init();   // 初始化lk中的定时器

    #if (!ENABLE_NANDWRITE)

    dprintf(SPEW, "creating bootstrap completion thread\n");

    thr = thread_create("bootstrap2",&bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);   // 新建线程入口函数

    if (!thr) {

    panic("failed to create thread bootstrap2\n");

    }thread_resume(thr);

    exit_critical_section();   // 使能中断

    thread_become_idle();  // 使自己成为idle进程

    #else    //对应上面的#if (!ENABLE_NANDWRITE) ,我们一般走if,不会走else

            bootstrap_nandwrite();

    #endif

    }

这里可以看到,kmain主要做了两件事:1.本身lk的初始化 2.boot启动初始化

以上与 boot 启动初始化相关函数是arch_early_init、platform_early_init 、bootstrap2,这些是启动的重点,我们下面慢慢来看。

arch_early_init

void arch_early_init(void)
{
	/* turn off the cache */
	arch_disable_cache(UCACHE);    // 关闭 cache 

	/* set the vector base to our exception vectors so we dont need to double map at 0 */
#if ARM_CPU_CORTEX_A8
	set_vector_base(MEMBASE);     //设置异常向量基地址
#endif

#if ARM_WITH_MMU
	arm_mmu_init();     //初始化MMU

#endif

	/* turn the cache back on */
	arch_enable_cache(UCACHE);   /*开启cache */

#if ARM_WITH_NEON
	/* enable cp10 and cp11 */
	/* 使能 cp10 和 cp11*/
	uint32_t val;
	__asm__ volatile("mrc	p15, 0, %0, c1, c0, 2" : "=r" (val));
	val |= (3<<22)|(3<<20);
	__asm__ volatile("mcr	p15, 0, %0, c1, c0, 2" :: "r" (val));

	isb();

	/* set enable bit in fpexc */
	/*设置使能 fpexc 位(中断相关)*/
	__asm__ volatile("mrc  p10, 7, %0, c8, c0, 0" : "=r" (val));
	val |= (1<<30);
	__asm__ volatile("mcr  p10, 7, %0, c8, c0, 0" :: "r" (val));
#endif

#if ARM_CPU_CORTEX_A8
	/* enable the cycle count register */
	/* 使能循环计数寄存器 */
	uint32_t en;
	__asm__ volatile("mrc	p15, 0, %0, c9, c12, 0" : "=r" (en));
	en &= ~(1<<3);   /*循环计算每个周期*/
	en |= 1; /* 启动所有的 performance 计数器  */
	__asm__ volatile("mcr	p15, 0, %0, c9, c12, 0" :: "r" (en));

	/* enable cycle counter */
	en = (1<<31);
	__asm__ volatile("mcr	p15, 0, %0, c9, c12, 1" :: "r" (en));
#endif
}

platform_early_init

void platform_early_init(void)
{
	/* initialize the interrupt controller */
	/*1.初始化中断*/
	platform_init_interrupts();

	/* initialize the timer block */
	/*初始化定时器*/
	platform_init_timer();
}

bootstrap2

static int bootstrap2(void *arg)
{
	dprintf(SPEW, "top of bootstrap2()\n");

	arch_init();  //此函数为空

	// XXX put this somewhere else
#if WITH_LIB_BIO
	bio_init();
#endif
#if WITH_LIB_FS
	fs_init();
#endif

	// initialize the rest of the platform
	dprintf(SPEW, "initializing platform\n");
	platform_init();  // 平台初始化,不同的平台要做的事情不一样,可以是初始化系统时钟,超频等

	// initialize the target
	dprintf(SPEW, "initializing target\n");
	target_init();   //目标设备初始化,主要初始化Flash,整合分区表等

	dprintf(SPEW, "calling apps_init()\n");
	apps_init();//应用功能初始化,主要调用aboot_init,启动kernel,加载boot/recovery镜像等

	return 0;
}

platform_init 中主要是函数 acpu_clock_init,在 acpu_clock_init 对 arm11 进行系统时钟设置,超频 。

target_init 针对硬件平台进行设置。主要对 arm9 和 arm11 的分区表进行整合,初始化flash和读取FLASH信息。

apps_init 是关键,对 LK 中所有 app 初始化并运行起来,而 aboot_init 就将在这里开始被运行,android linux 内核的加载工作就在 aboot_init 中完成的 。

void apps_init(void)
{
	const struct app_descriptor *app;

	/* call all the init routines */
	for (app = &__apps_start; app != &__apps_end; app++) {
		if (app->init)   //如果app有init成员,就执行app->init
			app->init(app);
	}

	/* start any that want to start on boot */
	for (app = &__apps_start; app != &__apps_end; app++) {
		if (app->entry && (app->flags & APP_FLAG_DONT_START_ON_BOOT) == 0) { 
			start_app(app);
		}
	}
}

apps_init()的逻辑很简单,可以猜测aboot_init一定是aboot->init,for循环轮到aboot的时候,就自然调用了aboot_init。

以下代码也证实了我们的猜测:

APP_START(aboot)           // 增加一个name为aboot的app
	.init = aboot_init,    //该app的ini赋值为ab
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值