mtk-lk代码分析

本文简单介绍了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); }

 

posted @ 2018-05-29 20:05  sh驱动小蚂蚁  阅读(2621)  评论(0编辑  收藏  举报