mtk preloader流程简介

## mtk preloader流程简介
**一、preloader流程简介
1、启动流程
(1)设备上电起来后,跳转到Boot ROM(不是flash)中的bootcode中执行把pre-loader加载起到ISRAM, 因为当前DRAM(RAM分SRAM跟DRAM,简单来说SRAM就是cache,DRAM就是普通内存)还没有准备好,所以要先把pre-loaderload到芯片内部的ISRAM(Internal SRAM)中。
(2)preloder的主要工作是初始化环境,包括c环境,timer,gpio,pmic,uart,i2c等以及装载LK镜像至DRAM中。
(3)如果实现了ATF,preloader加载完lk分区后,还会加载tee分区,在设置好环境后,会先跳转到EL3。
(4)EL3回到lk,执行lk流程,preloader流程结束。
2、下载流程
preloader除了具有启动功能之外,还具有下载功能。首先还是需要明确的是mtk芯片都的有个boot rom,如果没有这个rom那么,那么程序是无法被下载到nandflash中的,然后此时的flash上是为空的,没有任何数据的。系统在上电之后它会检测是启动模式还是下载模式,如果是下载模式,它会初始化一个usb的串口,将preloader加载到内部的SRAM中,跳转到preloader中去执行,初始化好flash和外部RAM之后,依次将preloader、lk、kernel、android下载到nand flash中去。
二、主要流程**

    void main(u32 *arg)
    
    {…..
    
    mtk_uart_init(UART_SRC_CLK_FRQ,CFG_LOG_BAUDRATE);
    
    /*初始化平台环境,比如Timer、PLL、UART、PMIC、Memory、BootableStorage等。*/
    
    bldr_pre_process();
    
    /*和外部工具通过UART或者USB方式握手,确定启动模式。*/
    
    bldr_handshake(&handler);
    
    /*安全相关的初始化*/
    
    #if CFG_ATF_SUPPORT
    
       trustzone_pre_init();
    
    #endif
    
    /*加载LK镜像到DRAM中(SecureBoot)*/
    
       if (0 != bldr_load_images(&jump_addr)){
    
           print("%s Second Bootloader Load Failed\n", MOD);
    
           goto error;
    
    }
    
    /*初始化所有的环境。*/
    
    bldr_post_process();
    
    /*初始化所有的安全相关环境。*/
    
    #if CFG_ATF_SUPPORT
    
       trustzone_post_init();
    
    #endif
    
    /*设置向lk传递参数的地址*/
    
    #if CFG_BOOT_ARGUMENT_BY_ATAG
    
       jump_arg = (u32)&(g_dram_buf->boottag);
    
    #else
    
       jump_arg = (u32)&bootarg;
    
    #endif
    
    #if CFG_ATF_SUPPORT
    
      ……
    
    /*支持ATF,跳转到EL3,然后再跳转到lk*/
    
           bldr_jump64(jump_addr,jump_arg, sizeof(boot_arg_t));
    
    #else
    
    /*跳转到lk*/
    
       bldr_jump(jump_addr,jump_arg, sizeof(boot_arg_t));
    
    #endif
    
    error:
    
       platform_error_handler();
    
    }

**三、详细流程
1、初始化**

**(1)link_descriptor.ld
文件路径:/vendor/mediatek/proprietary/bootable/bootloader/preloader/platform/mt6735**

**在该文件中定义了入口,会跳转到_start中执行:**

    ENTRY(_start)

**2)init.s
文件路径:
vendor/mediatek/proprietary/bootable/bootloader/preloader/platform/mt6735/src/init
在该文件中会执行_start,然后跳转到resethandler执行,主要作用是配置c运行环境(寄存器、堆栈、BSS等)   BSS静态内存段(未初始化)、数据段(初始化)、堆段、栈段
以及设置cpu为管理模式,关中断。**

    .globl _start
    _start:
        b resethandler
    
    结束后会跳转到main开始执行: 
    entry :
        LDR r0, =bldr_args_addr
        B   main


**(3)main.c
文件路径:
/vendor/mediatek/proprietary/bootable/bootloader/preloader/platform/mt6735/src/core
初始化外部DRAM的timer、时钟、UART、EMI(DRAM防静电干扰)。
 bldr_pre_process()完成各种的平台硬件(timer,pmic,gpio,wdt...)初始化工作。**

    static void bldr_pre_process(void)
    
    { …..
    
        /* 重要的硬件初始化timer,pll, uart... */
    
        platform_pre_init();
    
        /* 平台初始化*/
    
     platform_init();
    
     /* 分区初始化*/
    
     part_init();  
    
     part_dump();
    
        /* 初始化安全库*/
    
     sec_lib_init();
    
     /* 将log输出到dram*/
    
     log_buf_ctrl(1);
    
     …..
    
    }
    
     
    
    void platform_pre_init(void)
    
    {
    
         /* 初始化计时器*/
    
         mtk_timer_init();
    
         /* init boot time */
    
         g_boot_time = get_timer(0);
    
         /* 初始化串口*/
    
         mtk_uart_init(UART_SRC_CLK_FRQ,CFG_LOG_BAUDRATE);
    
         /*初始化GPIO*/
    
         mt_gpio_init();
    
         clk_buf_all_on();
    
         //初始化PMICwrap
    
         pwrap_init_preloader();
    
         //初始化i2c
    
         i2c_hw_init();
    
           check_charger_boost_status();
    
         //打开长按重启功能
    
         PMIC_enable_long_press_reboot();
    
         platform_core_handler();
    
    }
    
    void platform_init(void)
    
    {
    
         /* check DDR-reserve mode */
    
         check_ddr_reserve_status();
    
         /* init watch dog, will enable AP watch dog*/
    
         mtk_wdt_init();
    
         /*init kpd PMIC mode support*/
    
         set_kpd_pmic_mode();
    
         enable_PMIC_kpd_clock();
    
     /*初始化boot参数:  memset((void *)&(g_dram_buf->bootarg),0, sizeof(boot_arg_t));*/
    
          init_dram_buffer();
    
            ram_console_init();
    
            ram_console_reboot_reason_save(g_rgu_status);
    
        /*初始化devicestoreage */
    
     ret =boot_device_init();
    
     #ifCFG_REBOOT_TEST
    
         mtk_wdt_sw_reset();
    
         while(1);
    
     #endif
    
     /* 传递默认dram信息给LK*/  
    
    }

 

    (4)bldr_handshake(&handler): UART、USB握手测试(保证可以通信)。

**2、加载Lk到DRAM
bldr_load_images(&jump_addr):将各个分区加载进入DRAM,主要是lk分区。**

    (1)static int bldr_load_images(u32 *jump_addr){
    
     /*获取启动设备,为得到分区在ROM中的地址做准备*/
    
     if (NULL == (bootdev = blkdev_get(CFG_BOOT_DEV))) {
    
             print("%scan't find boot device(%d)\n", MOD, CFG_BOOT_DEV);
    
             /* FIXME, shouldchange to global error code */
    
             return -1;
    
         }
    
    ………
    
     #elifCFG_LOAD_UBOOT
    
     /* 这个值是一个固定值,确定了lk加载的目的地址,定义在default.mak中CFG_UBOOT_MEMADDR  :=0x41E00000 */
    
          addr = CFG_UBOOT_MEMADDR;
    
      /*在ROM中找到lk分区,并加载到DRAM中addr位置*/
    
          ret = bldr_load_part("lk", bootdev, &addr,&size);
    
         if (ret)
    
             return ret;
    
         *jump_addr = addr;
    
     #endif
    
     /*如果支持ATF,在加载lk后还会加载tee分区*/
    
     #if CFG_ATF_SUPPORT
    
          addr = CFG_ATF_ROM_MEMADDR;
    
          ret = bldr_load_tee_part("tee1", bootdev, &addr,0, &size);
    
       ……
    
         bldr_load_bootimg_header("boot",bootdev, &addr, 0, &size);
    
     #endif
    
         return ret;
    
    }

**(2)bldr_load_part最终会执行:part_load(bdev, part, addr, 0, size);指定读取的偏移量,检索分区头是否正确,如果正确则开始加载分区,加载分区的代码:**

    intpart_load(blkdev_t *bdev, part_t *part, u32 *addr, u32 offset, u32 *size)
    
    {
    
        /*检索分区头. */
    
        if (blkdev_read(bdev, src,sizeof(img_hdr_t), (u8*)hdr, part->part_id) != 0) {
    
            //print("[%s] bdev(%d) read error(%s)\n", MOD, bdev->type, part->name);
    
            return -1;
    
        }
    
        if (part_hdr->info.magic == PART_MAGIC){
    
            /* 加载带分区头的image*/
    
            part_hdr->info.name[31] = '\0';
    
    ……
    
            maddr = part_hdr->info.maddr;
    
            dsize = part_hdr->info.dsize;
    
            mode = part_hdr->info.mode;
    
            src += sizeof(part_hdr_t);
    
           memcpy(part_info + part_num, part_hdr, sizeof(part_hdr_t));
    
           part_num++;
    
        } else {
    
            //print("[%s] %s image doesn'texist\n", MOD, part->name);
    
            return -1;
    
        }
    
    /*设置
    
        if (maddr == PART_HEADER_DEFAULT_ADDR) {
    
            maddr = *addr;
    
    #ifCFG_ATF_SUPPORT
    
        } else if (mode == LOAD_ADDR_MODE_BACKWARD){
    
            maddr = tee_get_load_addr(maddr);
    
    #endif
    
    }

**3、跳转到LK
(1)bldr_post_process():内部其实是执行platform_post_init(),其主要作用是检查电池是否存在,确定要传给lk的参数。**

    voidplatform_post_init(void)
    
    {
    
    #ifCFG_BATTERY_DETECT
    
    /*检查电池是否存在,不存在就一直等待 */
    
    …..
    
    #endif
    
    platform_parse_bootopt();
    
    /*设置要传递给lk的参数,在platform.c中定义*/
    
        platform_set_boot_args();
    
    }
    
    (2) bldr_jump(jump_addr,jump_arg, sizeof(boot_arg_t)):执行init.s中定义的jump,实现跳转到lk执行,跳转地址即为0x41E00000。
    
    .globl jump
    jump:
        MOV r4, r1   /* r4 argument */
        MOV r5, r2   /* r5 argument */
        MOV pc, r0    /* jump to addr */
    
    如果支持ATF就执行bldr_jump64(jump_addr,jump_arg, sizeof(boot_arg_t)):
    
    bldr_jump64最主要是执行:trustzone_jump(addr, arg1, arg2)
    
    void trustzone_jump(u32 addr, u32 arg1,u32 arg2)
    
    {/*初始化tee模块*/
    
    tee_sec_config();
    
    ……
    
    /*执行init.s中定义的jumparch64*/
    
       jumparch64(addr, arg1, arg2, trustzone_get_atf_boot_param_addr());
    
    }
    
    jumparch64: 先jump到el3,然后再回到lk。

你可能感兴趣的:(嵌入式)