MTK fastboot代码流程

一、进fastboot之前
bootloader入口文件为vendor\mediatek\proprietary\bootable\bootloader\lk\arch\arm arch\arm\crt0.S,前面的是一些环境和硬件的初始化,我们直接从kmain:”bl Kmain“开始,该函数位于main.c文件中。
kmain()—>bootstrap2()—>apps_init()

void kmain(void)
{
	…
	初始化环境的一系列的init
	thread_t *thread_bs2 = thread_create("bootstrap2", &bootstrap2, NULL,
		DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
	…
}

static int bootstrap2(void *arg)
{
	…
	平台相关的init
	apps_init();
	return 0;
}

这里apps_init 是关键,对 LK 中所有的app 初始化并将其运行起来,而 aboot_init 就将在这里开始被运行,android linux 内核的加载工作就在 aboot_init 中完成的 。该函数中包含两个for函数,且循环条件一致:作用就是初始化app,并运行起来。

/* one time setup */
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);
	}
	/* 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_start这个宏:
在这里插入图片描述
vendor\mediatek\proprietary\bootable\bootloader\lk\include\app.h中
APP_START和APP_END定义如下:
在这里插入图片描述

这个需要结合对应的连接脚本去理解:

vendor\mediatek\proprietary\bootable\bootloader\lk\arch\arm\system-onesegment.ld
.rodata : { 
		*(.rodata .rodata.* .gnu.linkonce.r.*)
		. = ALIGN(4);
		__commands_start = .;
		KEEP (*(.commands))
		__commands_end = .;
		. = ALIGN(4);
		__apps_start = .;
		KEEP (*(.apps))
		__apps_end = .;
		. = ALIGN(4); 
		__rodata_end = . ;		
	}

这里的意思是将需要启动的apps括在了SECTIONS下的.rodata段中,且以__apps_start为开头,以__apps_end标志结束,指定的app就会在 bootloader bootup 时放入 thread section 中被执行,结合aboot_init()的定义就明确很多了 :
vendor\mediatek\proprietary\bootable\bootloader\lk\app\aboot\aboot.c最后
在这里插入图片描述

这里定义的aboot_init()就会在bootloader bootup是和其他的init app一样放入thread section中被执行。
再看aboot_init (const struct app_descriptor *app);

  1. 设置NAND/EMMC读取信息页面大小:
    在这里插入图片描述

  2. 读取按键信息,判断是正常开机,还是进入 fastboot ,还是进入recovery 模式:
    在函数体内,除了上半部分对按键进行判断以确定模式走向外,还有对BCB区域中command指令的读取来判断是否进入recovery 模式:
    在这里插入图片描述
    在这里插入图片描述

  3. 加载内核:如果是启动main system则执行boot_linux_from_mmc()进行加载,如果是启动Recovery模式则通过boot_linux_from_flash()加载。

  4. 启动内核:

boot_linux((void *)hdr->kernel_addr, (unsigned *) hdr->tags_addr,
		   (const char *)cmdline, board_machtype(),
		   (void *)hdr->ramdisk_addr, hdr->ramdisk_size);

二、fastboot分支
这里我们走fastboot分支,goto fastboot;
在这里插入图片描述

void aboot_init(const struct app_descriptor *app)
{
	…
	udc_init(&surf_udc_device);
	…
	udc_start();
}

调用usb初始化,并注册fastboot的boot/erase/flash/continue/product/kernel等命令,并fastboot_init,新建thread来接受pc发过来的命令

int fastboot_init(void *base, unsigned size)
{
	…
	/\*LXO: Download related command\*/
	fastboot_register("download:", cmd_download, TRUE, FALSE);
	fastboot_publish("max-download-size", dl_max_str);
	/\*LXO: END!Download related command\*/
	…
	event_init(&usb_online, 0, EVENT_FLAG_AUTOUNSIGNAL);
	event_init(&txn_done, 0, EVENT_FLAG_AUTOUNSIGNAL);

	in = udc_endpoint_alloc(UDC_TYPE_BULK_IN, 512);
	if (!in) {
		ret = -1;
		goto fail_alloc_in;
	}

	out = udc_endpoint_alloc(UDC_TYPE_BULK_OUT, 512);
	if (!out) {
		ret = -2;
		goto fail_alloc_out;
	}

	fastboot_endpoints[0] = in;
	fastboot_endpoints[1] = out;

	req = udc_request_alloc();
	if (!req) {
		ret = -3;
		goto fail_alloc_req;
	}
	if (udc_register_gadget(&fastboot_gadget)) {
		ret = -4;
		goto fail_udc_register;
	}

	thr = thread_create("fastboot", fastboot_handler, 0, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
	if (!thr) {
		ret = -1;
		goto fail_alloc_in;
	}
	thread_resume(thr);
	return 0;
	…
}

这个函数又注册download命令,并建立thread接受pc发过来的执行,thread的callback函数是

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

这个函数是循环,如果usb接收到命令,就调用fastboot_command_loop来解析命令并调用命令的执行函数

static void fastboot_command_loop(void)
{
	struct fastboot_cmd *cmd;
	int r;
	dprintf(INFO,"fastboot: processing commands\n");
	
	again:
	while (fastboot_state != STATE_ERROR) {
		r = usb_read(buffer, 64);
		if (r < 0) break;
		buffer[r] = 0;
		dprintf(INFO,"fastboot: %s\n", buffer);
		
		for (cmd = cmdlist; cmd; cmd = cmd->next) {
			if (memcmp(buffer, cmd->prefix, cmd->prefix_len))
			continue;
			fastboot_state = STATE_COMMAND;
			cmd->handle((const char*) buffer + cmd->prefix_len,
			   (void*) download_base, download_size);
			if (fastboot_state == STATE_COMMAND)
				fastboot_fail("unknown reason");
				goto again;
		}
		
		fastboot_fail("unknown command");
		
	}
	fastboot_state = STATE_OFFLINE;
	dprintf(INFO,"fastboot: oops!\n");
}

所有的命令都在cmdlist 这个列表中,调用memcmp来比较pc发的命令和fastboot的命令是否相等,如果相等就调用handle处理。
cmdlist:在调用fastboot_register 注册时会先通过malloc 申请一个fastboot_cmd,然后分配给prefix赋值命令的名称,然后将这个新建的cmd加到cmdlist中,这样在fastboot 处理函数中fastboot_command_loop,会比较buffer中接收到的命令和cmdlist->prefix 相比较是否相等(if (memcmp(buffer, cmd->prefix, cmd->prefix_len))),
如果相等就调用handle函数。

cmd->handle((const char*) buffer + cmd->prefix_len,
 (void*) download_base, download_size);

我们会调用fastboot_publish 来注册常量,例如下例中定义version=0.5
fastboot_publish(“version”, “0.5”);
又是通过fastboot_register(“getvar:”, cmd_getvar)来注册如果获取常量的
所以如果发过来的命令是getvar,就调用cmd_getvar。
而cmd_getvar 就是将varlist中的所有产量通过fastboot_okay 发送给pc,显示出来.

static void cmd_getvar(const char *arg, void *data, unsigned sz)
{
	struct fastboot_var *var;
	for (var = varlist; var; var = var->next) {
		if (!strcmp(var->name, arg)) {
		fastboot_okay(var->value);
			return;
		}
	}
	fastboot_okay("");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值