本文简单介绍了mtk-lk阶段的启动流程。
1.crt0.S的_start跳转到kmain执行
.section ".text.boot" .globl _start _start: ...... bl kmain
2.kmain函数在kernel/main.c中定义
void kmain(void) { //初始化线程系统,初始化run_queue& thread链表,初始化bootstrap线程,并标记为当前线程 thread_init_early(); //设置异常向量表基地址,使能mmu和neon,neon为多媒体应用优化设计 arch_early_init(); //平台相关初始化,中断、uart、gpio、wdt、i2c、pmic等,很多在preloader阶段已经完成的无需重复初始化 platform_early_init(); //目标板子前期初始化,这里并未定义 target_early_init(); //调用构造函数,调用.ctors段中的函数,使用objdump反汇编lk文件,并不存在.ctors段,这里直接跳过 call_constructors(); //初始化堆空间,插入空闲堆空间,并进行整合,减少碎片化 heap_init(); //timer线程初始化,这里跳过这步 thread_init(); //初始化dpc线程,调用dpc_queue将callback函数加入线程中,有时间触发时,线程会顺序执行回调函数 dpc_init();
//初始化timer_queue,并设置每隔10ms产生中断调用timer_tick函数 timer_init(); #if (!ENABLE_NANDWRITE) //创建并执行bootstrap2线程 dprintf(SPEW, "creating bootstrap completion thread\n"); thread_resume(thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE)); //退出临界区,使能中断 exit_critical_section(); //标记当前线程为空闲状态,即bootstrap线程空闲 thread_become_idle(); #else bootstrap_nandwrite(); #endif }
- platform_early_init
void platform_early_init(void) {
//初始化gic controller platform_init_interrupts();
//timer前期初始化 platform_early_init_timer();
//gpio设置为default状态 mt_gpio_set_default();
//串口初始化,从bootarg中获取串口和波特率并进行设置 uart_init_early();
//wdt初始化 mtk_wdt_init();
//i2c初始化,preloader阶段已经完成,这里忽略 i2c_hw_init();
//pmic初始化,preloader阶段完成,这里忽略 pmic_init(); }
- call_constructors,遍历.ctors(__ctor_list到__ctor_end)段中所有的函数,并执行,通过objdump反编译lk并不存在.ctors段,这里直接忽略
static void call_constructors(void) { void **ctor; ctor = &__ctor_list; while(ctor != &__ctor_end) { void (*func)(void); func = (void (*)())*ctor; func(); ctor++; } }
- heap_init,堆初始化
void heap_init(void) { LTRACE_ENTRY; //设置堆空间范围 theheap.base = (void *)HEAP_START; theheap.len = HEAP_LEN; //初始化空闲堆链表 list_initialize(&theheap.free_list); //创建空闲堆块,并插入空闲堆链表中,并与前后相邻空闲堆合并,初始化阶段就一个空闲堆 heap_insert_free_chunk(heap_create_free_chunk(theheap.base, theheap.len)); #ifdef MTK_3LEVEL_PAGETABLE
//标记堆初始化标志位为1 extern ld_tt_l2_info_t ld_tt_l2_info; ld_tt_l2_info.heap_init_done = 1; #endif }
- dpc_init,初始化dpc线程,该线程负责顺序执行dpc链表中的cb函数,thread_exit函数调用dpc_queue,负责处理线程退出时的清理工作,包括从线程链表中删除节点并释放线程的栈空间
void dpc_init(void) { //初始化dpc_event event_init(&dpc_event, false, 0); //创建并启用dpc线程,调用dpc_thread_routine函数,等待dpc_event事件发生 thread_resume(thread_create("dpc", &dpc_thread_routine, NULL, DPC_PRIORITY, DEFAULT_STACK_SIZE)); } static int dpc_thread_routine(void *arg) { //循环等待dpc事件发生 for (;;) { event_wait(&dpc_event); //关闭中断,进入临界区 enter_critical_section(); //将该dpc从链表中删除 struct dpc *dpc = list_remove_head_type(&dpc_list, struct dpc, node); if (!dpc) //dpc信号触发标志清零 event_unsignal(&dpc_event); //打开中断,退出临界区 exit_critical_section(); if (dpc) { //执行dpc的callback函数 dpc->cb(dpc->arg); free(dpc); } } return 0; } //通过dpc_queue将需要执行的操作加入dpc链表中 status_t dpc_queue(dpc_callback cb, void *arg, uint flags) { struct dpc *dpc; dpc = malloc(sizeof(struct dpc)); dpc->cb = cb; dpc->arg = arg; enter_critical_section(); list_add_tail(&dpc_list, &dpc->node); event_signal(&dpc_event, (flags & DPC_FLAG_NORESCHED) ? false : true); exit_critical_section(); return NO_ERROR; }
- timer_init,初始化timer_queue,并且设置10ms的周期任务执行timer_tick来实现线程调度
void timer_init(void)
{
list_initialize(&timer_queue);
platform_set_periodic_timer(timer_tick, NULL, 10); /* 10ms */
}
3.bootstrap2代码分析
static int bootstrap2(void *arg) { //arch初始化,这里忽略直接返回 arch_init(); //平台其余部分初始化 platform_init(); //target初始化,这里忽略直接返回 target_init(); //调用app->init函数,加载并启动kernel apps_init(); return 0; }
- platform_init
void platform_init(void) {
//mmc初始化 mmc_legacy_init(1);
//led初始化 leds_init();
//env初始化 env_init();
//设置framebuffer的起始地址和大小 g_fb_size = mt_disp_get_vram_size(); g_fb_base = mblock_reserve(&g_boot_arg->mblock_info, g_fb_size, 0x10000, 0xa0000000, RANKMAX);
//display&lcm初始化 mt_disp_init((void *)g_fb_base);
//填充fb为黑画面 mt_disp_fill_rect(0, 0, CFG_DISPLAY_WIDTH, CFG_DISPLAY_HEIGHT, 0x0);
mt_disp_update(0, 0, CFG_DISPLAY_WIDTH, CFG_DISPLAY_HEIGHT);
//初始化console drv_video_init();
//这里直接返回 set_kpd_pmic_mode();
//启动模式 boot_mode_select();
//加载开机动画 mboot_common_load_logo((unsigned long)mt_get_logo_db_addr_pa(), "logo");
//安全相关 sec_func_init(pl_start_addr); seclib_set_oemkey(g_oemkey, OEM_PUBK_SZ);
//pll设置 mt_pll_turn_off();
//battery,charge相关 mt65xx_bat_init();
//rtc开机检测 rtc_boot_check(false); //关机充电启动则显示充电图标,否则显示正常开机画面 if (kernel_charging_boot() == 1) { mt_disp_power(TRUE); mt_disp_show_low_battery(); mt65xx_leds_brightness_set(6, 110); } else if (g_boot_mode != KERNEL_POWER_OFF_CHARGING_BOOT && g_boot_mode != LOW_POWER_OFF_CHARGING_BOOT) { if (g_boot_mode != ALARM_BOOT && (g_boot_mode != FASTBOOT)) { mt_disp_show_boot_logo(); } } //打开背光 mt65xx_backlight_on(); mt_disp_update(0, 0, CFG_DISPLAY_WIDTH, CFG_DISPLAY_HEIGHT);
//在LCM上显示开机模式文字,正常开机显示"=> NORMAL BOOT",user版本该文字不显示 sw_env(); }
- app_init
void apps_init(void) { const struct app_descriptor *app; //调用.apps段中的app_init函数 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); } } }
mt_boot.c文件中定义了app,调用mt_boot_init函数,APP_START宏定义的内容放入.apps段中
APP_START(mt_boot) .init = mt_boot_init, APP_END
#define APP_START(appname) struct app_descriptor _app_##appname __SECTION(".apps") = { .name = #appname, #define APP_END };
- mt_boot_init,主要调用boot_linux_from_storage函数加载并启动内核
boot_linux_from_storage();
- boot_linux_from_storage
int boot_linux_from_storage(void) {
//加载bootimage header ret = mboot_android_load_bootimg_hdr(PART_BOOTIMG, CFG_BOOTIMG_LOAD_ADDR);
//加载bootimage ret = mboot_android_load_bootimg(PART_BOOTIMG, kimg_load_addr); #ifndef SKIP_LOADING_RAMDISK if (g_rimg_sz == 0) { if (g_boot_hdr != NULL) { g_rimg_sz = g_boot_hdr->ramdisk_size; } } #ifdef MTK_3LEVEL_PAGETABLE /* rootfs addr */ if (g_boot_hdr != NULL) { arch_mmu_map((uint64_t)g_boot_hdr->ramdisk_addr, (uint32_t)g_boot_hdr->ramdisk_addr, MMU_MEMORY_TYPE_NORMAL_WRITE_BACK | MMU_MEMORY_AP_P_RW_U_NA, ROUNDUP(g_rimg_sz, PAGE_SIZE)); } #endif /* relocate rootfs (ignore rootfs header) */ memcpy((g_boot_hdr!=NULL) ? (char *)g_boot_hdr->ramdisk_addr : (char *)CFG_RAMDISK_LOAD_ADDR, (char *)(g_rmem_off), g_rimg_sz); g_rmem_off = (g_boot_hdr!=NULL) ? g_boot_hdr->ramdisk_addr : CFG_RAMDISK_LOAD_ADDR; #endif // preloader传递给lk的参数中获取uart口,并将其添加到cmdline中
custom_port_in_kernel(g_boot_mode, cmdline_get());
//boot_linux,tags_addr作为fdt的加载地址 boot_linux((void *)g_boot_hdr->kernel_addr, (unsigned *)g_boot_hdr->tags_addr, (char *)cmdline_get(), board_machtype(), (void *)g_boot_hdr->ramdisk_addr, g_rimg_sz); }
- boot_linux,启动dts文件
void boot_linux(void *kernel, unsigned *tags, char *cmdline, unsigned machtype, void *ramdisk, unsigned ramdisk_size) { #ifdef DEVICE_TREE_SUPPORT boot_linux_fdt((void *)kernel, (unsigned *)tags, (char *)cmdline, machtype, (void *)ramdisk, ramdisk_size); while (1) ; #endif }
- boot_linux_fdt,加载并解析fdt,关闭cache&mmu,最终跳转到kernel执行
int boot_linux_fdt(void *kernel, unsigned *tags, char *cmdline, unsigned machtype, void *ramdisk, unsigned ramdisk_size) { zimage_size = (g_boot_hdr->kernel_size); addr = (unsigned int)(zimage_addr + zimage_size);
//从zImage后的地址依次寻址,根据MAGIC匹配fdt for (dtb_size = 0; dtb_size < zimage_size; dtb_size++, addr--) { magic = (unsigned char *)addr;
//fdt MAGIC 0xd00dfeed if ( *(magic + 3) == 0xED && *(magic + 2) == 0xFE && *(magic + 1) == 0x0D && *(magic + 0) == 0xD0) { dtb_addr = addr; dtb_size = (dtb_size + 0x3) & (~0x3);
//copy fdt到tags_addr(fdt)地址中 memcpy_u8(fdt, (void *)dtb_addr, dtb_size); dtb_addr = (unsigned int)fdt; break; } } if (dtb_size != zimage_size) { zimage_size -= dtb_size; }
//解压zImage镜像 if (decompress_kernel((unsigned char *)zimage_addr, (void *)g_boot_hdr->kernel_addr, (int)zimage_size, (int)0x4000000)) { while (1); } if (fdt32_to_cpu(*(unsigned int *)dtb_addr) == FDT_MAGIC) { dtb_size = fdt32_to_cpu(*(unsigned int *)(dtb_addr+0x4)); }
//copy fdt memcpy(fdt, (void *)dtb_addr, dtb_size); strcpy(&buf[FDT_BUFF_SIZE], FDT_BUFF_PATTERN); setup_fdt(fdt, MIN(0x100000, (g_fb_base-(unsigned int)fdt)));
//加载modem镜像 extern void load_modem_image(void)__attribute__((weak)); if (load_modem_image) { load_modem_image(); }
//根据是否为user版本决定kernel阶段uart log是否打开
#ifdef USER_BUILD
sprintf(cmdline,"%s%s",cmdline," printk.disable_uart=1");
#else
sprintf(cmdline,"%s%s",cmdline," printk.disable_uart=0 ddebug_query=\"file *mediatek* +p ; file *gpu* =_\"");
#endif
//解析memory节点 offset = fdt_path_offset(fdt, "/memory"); extern int get_mblock_num(void) __attribute__((weak)); ret = fdt_setprop(fdt, offset, "reg", mem_reg_property, ((int)get_mblock_num? get_mblock_num(): g_nr_bank ) * sizeof(dt_dram_info));
//解析chosen节点 offset = fdt_path_offset(fdt, "/chosen"); ret = fdt_setprop_cell(fdt, offset, "linux,initrd-start",(unsigned int) ramdisk); ret = fdt_setprop_cell(fdt, offset, "linux,initrd-end", (unsigned int)ramdisk + ramdisk_size);
//关闭cache&mmu arch_disable_cache(UCACHE); arch_disable_mmu();
//跳转kernel执行,entry为kernel地址,tags为fdt地址 lk_jump64((u32)entry, (u32)tags, 0, KERNEL_64BITS); }