Aboot启动流程分析

位置:
bootloader/lk/app/aboot/aboot.c
在文件结尾有如下代码:

APP_START(aboot)
	.init = aboot_init,
APP_END

看一下宏APP_START的定义

#define APP_START(appname) struct app_descriptor _app_##appname __SECTION(".apps") = { .name = #appname,
#define APP_END };

将上面的展开结果为:

struct app_descriptor _app_aboot = {
.name = aboot,
.init = aboot_init,
}

那么aboot_init是在什么地方调用的呢?
bootable/bootloader/lk/kernel/main.c

static int bootstrap2(void *arg){
···
apps_init();
···
}

这里主要看一下调用的顺序,详细过程查看代码:bootable/bootloader/lk/app/app.c

void apps_init(void)
{
	/* call all the init routines */
	for (app = &__apps_start; app != &__apps_end; app++) {
		if (app->init)
			app->init(app);//此处运行aboot_init函数。
	}
}

简单介绍一下aboot_init这个函数

void aboot_init(const struct app_descriptor *app)
{
	/* Setup page size information for nv storage */
	//读取寄存器,查看是从emmc中启动设备
	if (target_is_emmc_boot())
	{
		page_size = mmc_page_size();
		page_mask = page_size - 1;
		dprintf(CRITICAL,"liyang emmc boot\n");
	}
	//从devinfo/aboot分区中读取设备的属性
	read_device_info(&device);
	read_allow_oem_unlock(&device);

	/* Display splash screen if enabled */
#if DISPLAY_SPLASH_SCREEN
#if NO_ALARM_DISPLAY
	if (!check_alarm_boot()) {
#endif
		//初始化显示模块,在这里面读取splash分区中的数据并且显示。
		//这个地方还没有打开display,所以没有显示出来
		dprintf(CRITICAL, "Display Init: liyang Start %s\n", device.display_panel);
		target_display_init(device.display_panel);
		dprintf(CRITICAL, "Display Init: liyang Done\n");
#if NO_ALARM_DISPLAY
	}
#endif
#endif
	//读取设备的序列号
	target_serialno((unsigned char *) sn_buf);
	//此处打开设备的显示,就能看到上面从splash读取出来的开机logo
	qpnp_wled_set_level(gwled, QPNP_WLED_MAX_BR_LEVEL);
	memset(display_panel_buf, '\0', MAX_PANEL_BUF_SIZE);

	/*
	 * Check power off reason if user force reset,
	 * if yes phone will do normal boot.
	 */
	if (is_user_force_reset())
		goto normal_boot;
	//接下来就是检测按键,根据不同的组合方式进入升级或者ELoad模式(变砖)
	/* Check if we should do something other than booting up */
	if (keys_get_state(KEY_VOLUMEUP) && keys_get_state(KEY_BACK))
	{
    //Add by Skysoft start 
    }else if (keys_get_state(KEY_VOLUMEDOWN) && keys_get_state(KEY_BACK))
    {
    //Add by Skysoft end
	}else{
	}
normal_boot:
	if (!boot_into_fastboot)//进入正常的开机流程
	{
		if (target_is_emmc_boot())
		{
			if(emmc_recovery_init())
				dprintf(CRITICAL," liyang error in emmc_recovery_init\n");
			if(target_use_signed_kernel())
			{
				if((device.is_unlocked) || (device.is_tampered))
				{
				#ifdef TZ_TAMPER_FUSE
					set_tamper_fuse_cmd();
				#endif
				#if USE_PCOM_SECBOOT
					set_tamper_flag(device.is_tampered);
				#endif
				}
			}
			boot_linux_from_mmc();
			dprintf(CRITICAL, "liyang after boot_linux_from_mmc\n");
		}
		else//如果是升级过程失败会进入这个分支。
		{
			dprintf(CRITICAL, "liyang recovery_init\n");
			recovery_init();//获取升级状态从而决定是进入recovery/boot
	#if USE_PCOM_SECBOOT
		if((device.is_unlocked) || (device.is_tampered))
			set_tamper_flag(device.is_tampered);
	#endif
			boot_linux_from_flash();//根据recovery_init进入recovery/boot
		}
	}else//进入fastboot模式
	/* We are here means regular boot did not happen. Start fastboot. */
	/* register aboot specific fastboot commands */
	aboot_fastboot_register_commands();//将fastboot中的命令注册进去。也可以从这里添加fastboot命令。也就是将命令存入到类型为struct fastboot_var的链表中。
	/* dump partition table for debug info */
	partition_dump();//将设备的分区信息读取出来

	/* initialize and start fastboot */
	fastboot_init(target_get_scratch_address(), target_get_max_flash_size());//初始化fastboot。包括usb的初始化。
#if FBCON_DISPLAY_MSG
	display_fastboot_menu();//显示fastboot的菜单
#endif
}

下面看一下fastboot_init这个函数,这个函数主要就是注册一些事件,初始化USB,以及开启一个Thread去检测这些事件。

int fastboot_init(void *base, unsigned size){
	thr = thread_create("fastboot", fastboot_handler, 0, DEFAULT_PRIORITY, 4096);
}

static int fastboot_handler(void *arg)
{
	for (;;) {
		event_wait(&usb_online);
		fastboot_command_loop();
	}
	return 0;
}

static void fastboot_command_loop(void)
{
	//申请一块cache
	uint8_t *buffer = (uint8_t *)memalign(CACHE_LINE, ROUNDUP(4096, CACHE_LINE));

again:
	while (fastboot_state != STATE_ERROR) {//开始读取USB中的数据,并且调用前面注册进来的处理函数。

		r = usb_if.usb_read(buffer, MAX_RSP_SIZE);

		fastboot_state = STATE_COMMAND;

		for (cmd = cmdlist; cmd; cmd = cmd->next) {
			if (memcmp(buffer, cmd->prefix, cmd->prefix_len))
				continue;
			cmd->handle((const char*) buffer + cmd->prefix_len,
				    (void*) download_base, download_size);//前面介绍中已经将cmd注册到链表中了。这里调用注册进来的函数。
			if (fastboot_state == STATE_COMMAND)
				fastboot_fail("unknown reason");
			goto again;
		}

		fastboot_fail("unknown command");

	}
	fastboot_state = STATE_OFFLINE;
	dprintf(INFO,"fastboot: oops!\n");
	free(buffer);
}

这就是boot的启动流程。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
运行 清除fastboot进磁盘操作.bat 接着电脑自动安装驱动(不会自动安装的驱动路径在MiFlash安装目录下) 这时就进入磁盘模式了,接着就可以用DiskGenius,分区助手专业版和MiFlash进行操作了(还可以用DiskGenius做数据备份) 用MiFlash刷机(目的是为了还原删除的aboot也可以用我提供的备份还原)刷完后关MiFlash,可别拔掉手机哦 呵呵 补充:没用miflash刷机的一定要要还原aboot分区要不后面改好了启动不来(一定要刷机要不你自己备份的也是清除的分区里面没数据是没用的) 3. 打开DiskGenius要操作的磁盘是QualcommMMCStorage(里面有27个分区的就是) 认为有必要的备份好整个分区表和分区(极力推荐备份)。 也可以用我提供的备份(有些分区是各手机私有的不能用我的备份分别是ssd dbi bk1 bk2 modemst1 modemst2 fsc bk3 fsg bk4 bk5 这11个分区同时也是不可动的)。 以下是两种分区方法 选其中一种即可 1。 用分区助手无损移动分区 2。 用DiskGenius删分区再重建 第一种: 方法删除 system1 boot1 modem1 userdata四个分区就可以了。(认为有必要的懂得可以删其他分区) 用分区助手移动分区把未分配空间集合在右边也就是userdata分区那一边保存修改(提交)然后用DiskGenius新建分区userdata把剩下的空间都给它 文件系统类型linux data partion 勾上对齐到下列扇区数的整数倍数值是8 详细里面的分区名userdata 再点上无盘符。 分区建好保存更改(分区名一定要是userdata)。 换到分区助手格式化userdata分区 格式ext3其他默认(可以开机后进fastboot用命令格式化此分区命令是fastboot format userdata)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值