A4. MTK开机流程
preloader流程:
路径: vendor/mediatek/proprietary/bootable/bootloader/preloader/platform/mt6761/src/core/main.c
入口函数: main()
void main(u32 *arg)
{
struct bldr_command_handler handler;
u32 jump_addr, jump_arg;
/* get the bldr argument */
p_bldr_param = &bldr_param;
memcpy((void *)p_bldr_param, (void *)*arg, sizeof(bl_param_t));
/* 初始化uart*/
mtk_uart_init(UART_SRC_CLK_FRQ, CFG_LOG_BAUDRATE);
/* 平台硬件初始化platform_init()
* 设置g_boot_mode初值NORMAL_BOOT
*/
bldr_pre_process();
handler.priv = NULL;
handler.attr = 0;
handler.cb = bldr_cmd_handler;
#if MT6370_PMU
BOOTING_TIME_PROFILING_LOG("mtk db_pos discharge");
mtk_dbpos_discharge();
#endif
//代码与平台设计相关
BOOTING_TIME_PROFILING_LOG("before bldr_handshake");
bldr_handshake(&handler);
BOOTING_TIME_PROFILING_LOG("bldr_handshake");
#if BOOTROM_INTEGRITY_CHECK
/* if rom integrity check fails, device halts, so don't put it before bootloader
handshake, this could make device bricked */
rom_integrity_check();
#endif
#if !CFG_FPGA_PLATFORM
/* security check */
device_APC_dom_setup();
#endif
BOOTING_TIME_PROFILING_LOG("sec_boot_check");
#if CFG_ATF_SUPPORT
trustzone_pre_init();
BOOTING_TIME_PROFILING_LOG("trustzone pre init");
#endif
#if (defined(MTK_AB_OTA_UPDATER) && !CFG_DRAM_CALIB_OPTIMIZATION)
ab_ota_boot_check();
#endif
#if !(CFG_BYPASS_LOAD_IMG_FORCE_ATF)
/* Do not load ATF, lk, load by JTAG */
if (0 != bldr_load_images(&jump_addr)) {
pal_log_err("%s Second Bootloader Load Failed\n", MOD);
#if !CFG_BYPASS_EMI
goto error;
#endif
}
#else
jump_addr = CFG_UBOOT_MEMADDR;
#endif
BOOTING_TIME_PROFILING_LOG("load images");
bldr_post_process();
#ifdef SLT
mt_usb_phy_recover();
//mu3d_hal_rst_dev();
#endif
#if CFG_ATF_SUPPORT
trustzone_post_init();
BOOTING_TIME_PROFILING_LOG("trustzone post init");
#endif
//获取lk地址,跳转到lk
#if CFG_BOOT_ARGUMENT_BY_ATAG
jump_arg = (u32)&(g_dram_buf->boottag);
#else
jump_arg = (u32)&bootarg;
#endif
/* 64S3,32S1,32S1 (MTK_ATF_BOOT_OPTION = 0)
* re-loader jump to LK directly and then LK jump to kernel directly */
#if CFG_ATF_SUPPORT
pal_log_info("%s Others, jump to ATF\n", MOD);
bldr_jump64(jump_addr, jump_arg, sizeof(boot_arg_t));
#else
bldr_jump(jump_addr, jump_arg, sizeof(boot_arg_t));
#endif
}
总结preloader的功能:
① 硬件属性初始化
② 相关配置参数初始化
③ 安全检测
④ lk运行地址获取
⑤ 跳转到lk
lk流程分析
路径:vendor/mediatek/proprietary/bootable/bootloader/lk/kernel/main.c
入口函数: kmain()
void kmain(void)
{
#if !defined(MACH_FPGA) && !defined(SB_LK_BRINGUP)
boot_time = get_timer(0);
#endif
/* 早起初始化线程池: 运行队列、线程链表建立等
* lk架构支持多线程,当前仅有一个cpu运行,所以仅有一条代码执行顺序
*/
thread_init_early();
// early arch stuff
arch_early_init();
/* 平台初始化,包括irq,timer,wdt,uart,led,pmic等硬件平台*/
platform_early_init();
#if defined(MACH_FPGA) || defined(SB_LK_BRINGUP)
boot_time = get_timer(0);
#endif
// do any super early target initialization
target_early_init();
dprintf(INFO, "welcome to lk\n\n");
// deal with any static constructors
dprintf(SPEW, "calling constructors\n");
call_constructors();
// bring up the kernel heap
dprintf(SPEW, "initializing heap\n");
heap_init();
// initialize the threading system
dprintf(SPEW, "initializing threads\n");
thread_init();
// initialize the dpc system
dprintf(SPEW, "initializing dpc\n");
dpc_init();
// initialize kernel timers
dprintf(SPEW, "initializing timers\n");
timer_init();
#ifdef MTK_LK_IRRX_SUPPORT
mtk_ir_init(0);
#endif
#if (!ENABLE_NANDWRITE)
// create a thread to complete system initialization
dprintf(SPEW, "creating bootstrap completion thread\n");
/* 重新创建一个bootstrap2线程
* 并执行bootstrap2线程
*/
thread_t *thread_bs2 = thread_create("bootstrap2", &bootstrap2, NULL,
DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
if (thread_bs2)
thread_resume(thread_bs2);
else {
dprintf(CRITICAL, "Error: Cannot create bootstrap2 thread!\n");
assert(0);
}
thread_t *thread_io = thread_create("iothread", &iothread, NULL,
IO_THREAD_PRIORITY, DEFAULT_STACK_SIZE);
if (thread_io)
thread_resume(thread_io);
else {
dprintf(CRITICAL, "Error: Cannot create I/O thread!\n");
assert(0);
}
// enable interrupts
exit_critical_section();
/* 当前线程跑完便置于空闲状态 */
// become the idle thread
thread_become_idle();
#else
bootstrap_nandwrite();
#endif
}
kmain:
① 初始化系统任务所需的线程、链表和相关队列。
② 初始化硬件平台,搭建lk基本运行环境
③ 初始化定时器等
④ 创建一个新线程bootstrap2,并执行。当前线程置于空闲状态
bootstrap2():
static int bootstrap2(void *arg)
{
dprintf(SPEW, "top of bootstrap2()\n");
print_stack_of_current_thread();
arch_init();
// XXX put this somewhere else
#if WITH_LIB_BIO
bio_init();
#endif
#if WITH_LIB_FS
fs_init();
#endif
// Allocate LK memory from mb, free before jump to kernel
mboot_allocate_lk_scratch_from_mblock();
// initialize the rest of the platform
dprintf(SPEW, "initializing platform\n");
platform_init();
// initialize the target
dprintf(SPEW, "initializing target\n");
target_init();
dprintf(SPEW, "calling apps_init()\n");
apps_init();
return 0;
}
bootstrap2():
① 初始化硬件
② 跳转到app_init()
③ 运行platform_init后,会更新g_boot_mode
app_init:
路径: vendor/mediatek/proprietary/bootable/bootloader/lk/app/app.c
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);
}
}
}
这里start_app()会跳转到mt_boot_init
APP_START(mt_boot)
.init = mt_boot_init,
APP_END
mt_boot_init:
路径: vendor/mediatek/proprietary/bootable/bootloader/lk/app/mt_boot/mt_boot.c
void mt_boot_init(const struct app_descriptor *app)
{
unsigned usb_init = 0;
unsigned sz = 0;
#ifdef MTK_AB_OTA_UPDATER
int ret;
#endif
set_serial_num();
if (g_boot_mode == FASTBOOT)
goto fastboot;
#ifdef MTK_SECURITY_SW_SUPPORT
#if MTK_FORCE_VERIFIED_BOOT_SIG_VFY
/* verify oem image with android verified boot signature instead of mediatek proprietary signature */
/* verification is postponed to boot image loading stage */
/* note in this case, boot/recovery image will be verified even when secure boot is disabled */
g_boot_state = BOOT_STATE_RED;
#else
if (0 != sec_boot_check(0))
g_boot_state = BOOT_STATE_RED;
#endif
#endif
/* Will not return */
boot_linux_from_storage();
fastboot:
target_fastboot_init();
if (!usb_init)
udc_init(&surf_udc_device);
mt_part_dump();
sz = target_get_max_flash_size();
fastboot_init(target_get_scratch_address(), sz);
udc_start();
}
再次跳转到boot_linux_from_storage
boot_linux_from_storage:
路径: vendor/mediatek/proprietary/bootable/bootloader/lk/app/mt_boot/mt_boot.c
int boot_linux_from_storage(void)
{
int ret = 0;
uint32_t kernel_target_addr = 0;
uint32_t ramdisk_target_addr = 0;
uint32_t tags_target_addr = 0;
uint32_t ramdisk_addr = 0;
int32_t ramdisk_sz = 0;
uint32_t ramdisk_real_sz = 0;
#define CMDLINE_TMP_CONCAT_SIZE 110
char cmdline_tmpbuf[CMDLINE_TMP_CONCAT_SIZE];
switch (g_boot_mode) {
case NORMAL_BOOT:
case META_BOOT:
case ADVMETA_BOOT:
case SW_REBOOT:
case ALARM_BOOT:
#ifdef MTK_KERNEL_POWER_OFF_CHARGING
case KERNEL_POWER_OFF_CHARGING_BOOT:
case LOW_POWER_OFF_CHARGING_BOOT:
#endif
PROFILING_START("load boot image");
#if defined(CFG_NAND_BOOT)
snprintf(cmdline_tmpbuf, CMDLINE_TMP_CONCAT_SIZE, "%s%x%s%x",
NAND_MANF_CMDLINE, nand_flash_man_code, NAND_DEV_CMDLINE, nand_flash_dev_id);
cmdline_append(cmdline_tmpbuf);
#endif
ret = load_vfy_boot(BOOTIMG_TYPE_BOOT, CFG_BOOTIMG_LOAD_ADDR);
PROFILING_END();
break;
case RECOVERY_BOOT:
/* it's boot.img when system as root is enabled, and is *
* recovery.img when system as root is disabled. *
*/
PROFILING_START("load recovery image");
ret = load_vfy_boot(BOOTIMG_TYPE_RECOVERY, CFG_BOOTIMG_LOAD_ADDR);
PROFILING_END();
break;
case FACTORY_BOOT:
case ATE_FACTORY_BOOT:
/* it's boot.img, we don't have standalone factory image now */
PROFILING_START("load factory image");
#if defined(CFG_NAND_BOOT)
snprintf(cmdline_tmpbuf, CMDLINE_TMP_CONCAT_SIZE, "%s%x%s%x",
NAND_MANF_CMDLINE, nand_flash_man_code, NAND_DEV_CMDLINE, nand_flash_dev_id);
cmdline_append(cmdline_tmpbuf);
#endif
ret = load_vfy_boot(BOOTIMG_TYPE_BOOT, CFG_BOOTIMG_LOAD_ADDR);
PROFILING_END();
break;
case FASTBOOT:
case DOWNLOAD_BOOT:
case UNKNOWN_BOOT:
break;
}
kernel_target_addr = get_kernel_target_addr();
ramdisk_target_addr = get_ramdisk_target_addr();
ramdisk_addr = get_ramdisk_addr();
ramdisk_sz = get_ramdisk_sz();
ramdisk_real_sz = get_ramdisk_real_sz();
tags_target_addr = get_tags_addr();
PAL_ASSERT(kernel_target_addr != 0);
PAL_ASSERT(ramdisk_target_addr != 0);
PAL_ASSERT(ramdisk_addr != 0);
#ifndef SYSTEM_AS_ROOT
PAL_ASSERT(ramdisk_sz != 0);
PAL_ASSERT(ramdisk_real_sz != 0);
#endif
#ifdef MTK_3LEVEL_PAGETABLE
/* rootfs addr */
arch_mmu_map((uint64_t)ramdisk_target_addr,
(uint32_t)ramdisk_target_addr,
MMU_MEMORY_TYPE_NORMAL_WRITE_BACK | MMU_MEMORY_AP_P_RW_U_NA,
ROUNDUP(ramdisk_sz, PAGE_SIZE));
#endif
/* relocate rootfs */
memcpy((void *)ramdisk_target_addr,
(void *)ramdisk_addr,
(size_t)ramdisk_real_sz);
// 2 weak function for mt6572 memory preserved mode
platform_mem_preserved_load_img();
platform_mem_preserved_dump_mem();
custom_port_in_kernel(g_boot_mode, cmdline_get());
snprintf(cmdline_tmpbuf, CMDLINE_TMP_CONCAT_SIZE, "%s", get_cmdline());
cmdline_append(cmdline_tmpbuf);
#ifdef SELINUX_STATUS
#if SELINUX_STATUS == 1
cmdline_append("androidboot.selinux=disabled");
#elif SELINUX_STATUS == 2
cmdline_append("androidboot.selinux=permissive");
#endif
#endif
/* This is patch for Android Test Mode(ATM). */
/* 1. Sets kernel cmdline for ATM only in normal mode
* 2. Bypass write protect in boot mode "normal" when ATM is enabled.
* Background:
* "proinfo" partition is write protected in boot mode "normal". When ATM is enabled,
* we bypass write protection since we needs to write to proinfo. Whether device is in ATM
* should also be passed to kernel through cmdline, only seen in normal mode
*/
if (g_boot_mode == NORMAL_BOOT) {
if (true == get_atm_enable_status()) {
cmdline_append("androidboot.atm=enable");
} else if (false == get_atm_enable_status()) {
write_protect_flow();
cmdline_append("androidboot.atm=disabled");
}
}
/* pass the meta_log_disable to user space logger, default is enable */
if (is_meta_log_disable && (is_meta_log_disable() == 1)) {
cmdline_append("androidboot.meta_log_disable=1");
} else {
cmdline_append("androidboot.meta_log_disable=0");
}
/* pass related root of trust info via SMC call */
if (send_root_of_trust_info != NULL)
send_root_of_trust_info();
boot_linux((void *)kernel_target_addr,
(unsigned *)tags_target_addr,
board_machtype(),
(void *)ramdisk_target_addr,
ramdisk_real_sz);
while (1);
return 0;
}
boot_linux_from_storage主要功能:
① 根据g_boot_mode值加载相应的模式地址运行。例如g_boot_mode为FACTORY_BOOT、 ATE_FACTORY_BOOT跳转到Factory代码地址,为RECOVERY_BOOT则加载recovery代码地址。
② 如果没有检测到需要进入其他模式,则正常运行。
注:所以需要更换进入factory模式,或者recovery模式,只需要在之前代码位置添加一个条件,然后将g_boot_mode值置为RECOVERY_BOOT。例:
if(SOS键被按下){
g_boot_mode = RECOVERY_BOOT; //覆盖掉之前的值
}
boot_linux:
路径:vendor/mediatek/proprietary/bootable/bootloader/lk/app/mt_boot/mt_boot.c
void boot_linux(void *kernel, unsigned *tags,
unsigned machtype,
void *ramdisk, unsigned ramdisk_sz)
{
int i;
……
boot_linux_fdt((void *)kernel, (unsigned *)tags,
machtype,
(void *)ramdisk, ramdisk_sz);
while (1) ;
……
}
boot_linux_fdt:
路径:vendor/mediatek/proprietary/bootable/bootloader/lk/app/mt_boot/mt_boot.c
进入内核的最后一道工序。
boot_linux_fdt((void *)kernel, (unsigned *)tags,
machtype,
(void *)ramdisk, ramdisk_sz)
{
//1.解析dtb设备树
//2.搭建内核运行环境
//3.检测一些进入内核条件
}
正式进入kernel!