lk启动流程

1、链接脚本:

路径:/bootable/bootloader/lk/arch/arm/system-onesegment.ld

 

1 OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm","elf32-littlearm")

      2 OUTPUT_ARCH(arm)

      3

     4 ENTRY(_start)                                //代码从_start开始

      5 SECTIONS

      6 {

      7        . = %MEMBASE%;

      8

  9   /* text/read-only data */

  10  .text.boot : { *(.text.boot) }

  11  .text :   { *(.text .text.* .glue_7* .gnu.linkonce.t.*) } =0x9090

     

2_start汇编入口:

路径:/bootable/bootloader/lk/arch/arm/crt0.S

 

27 .section ".text.boot"

    28 .globl _start

     29_start:

     30        b       reset

     31        b       arm_undefined

     32        b       arm_syscall

     33        b       arm_prefetch_abort

     34        b       arm_data_abort

     35        b       arm_reserved

     36        b       arm_irq

     37        b       arm_fiq

     38

……………………

     158         blt             .L__copy_loop        //copy bootloader到内存

     159

     160 .L__do_bss:

     161        /* clear out the bss */

     162        ldr             r0, =__bss_start

     163        ldr             r1, =_end

    164        mov             r2, #0

    165  .L__bss_loop:

    166        cmp             r0, r1

    167        strlt   r2, [r0], #4

    168        blt             .L__bss_loop

    169

    170 #ifdef ARM_CPU_CORTEX_A8

    171        DSB

    172        ISB

    173 #endif

    174

   175      bl     kmain        //跳到kmain出执行

    176         b              .

2kmain函数:

路径:/bootable/bootloader/lk/kernel/main.c

启动bootstrap2线程初始化系统:

voidkmain(void)

{

// get us into some sort of thread context

thread_init_early();

 

// early arch stuff

arch_early_init();

 

// do any super early platform initialization

platform_early_init();

 

// do any super early target initialization

target_early_init();

 

dprintf(INFO, "welcome to lk\n\n");

bs_set_timestamp(BS_BL_START);

 

// 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();

 

#if(!ENABLE_NANDWRITE)

// create a thread tocomplete system initialization

dprintf(SPEW, "creating bootstrap completion thread\n");

thread_resume(thread_create("bootstrap2",&bootstrap2, NULL,

DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));

 

// enable interrupts

exit_critical_section();

 

// become the idle thread

thread_become_idle();

#else

        bootstrap_nandwrite();

#endif

}

3bootstrap2线程:

 路径:/bootable/bootloader/lk/kernel/main.c

staticint bootstrap2(void *arg)

{

dprintf(SPEW, "top of bootstrap2()\n");

 

arch_init();

 

// XXX put this somewhere else

#ifWITH_LIB_BIO

bio_init();

#endif

#ifWITH_LIB_FS

fs_init();

#endif

 

// 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;

}

 

其中,target_init函数:

voidtarget_init(void)

{

uint32_t base_addr;

uint8_t slot;

 

dprintf(INFO, "target_init()\n");

   //初始化SPMI控制器

spmi_init(PMIC_ARB_CHANNEL_NUM, PMIC_ARB_OWNER_ID);

   //按键初始化,设置音量上下键

target_keystatus();

   //初始化MMC

/* Trying Slot 1*/

slot = 1;

base_addr = mmc_sdc_base[slot - 1];

if (mmc_boot_main(slot, base_addr))

{

 

/* Trying Slot 2 next*/

slot = 2;

base_addr = mmc_sdc_base[slot - 1];

if (mmc_boot_main(slot, base_addr)) {

dprintf(CRITICAL, "mmc init failed!");

ASSERT(0);

}

}

 

if (target_use_signed_kernel())

target_crypto_init_params();

}

 

其中,apps_init()函数:

路径:/bootable/bootloader/lk/app/app.c

voidapps_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);

}

}

}

 

APP_START(aboot)

.init = aboot_init,

APP_END

通过.init = aboot_init,可以看出,app->init(app);”会调用aboot_init函数。

 

4aboot_init函数:

路径:/bootable/bootloader/lk/app/aboot/aboot.c

aboot_init函数分析:

1)设置page size

/* Setuppage size information for nand/emmc reads */

if (target_is_emmc_boot())

{

    //eMMCpage size=2k

page_size = 2048;

page_mask = page_size - 1;

}

else

{

page_size = flash_page_size();

page_mask = page_size - 1;

}

 

2)如果kernel签名则读取device信息

if(target_use_signed_kernel())

{

read_device_info(&device);

 

}

 

3)读取UDC串号

target_serialno((unsignedchar *) sn_buf);

dprintf(SPEW,"serial number: %s\n",sn_buf);

surf_udc_device.serialno = sn_buf;

 

4)读取重启原因

reboot_mode=check_reboot_mode();

if (reboot_mode == RECOVERY_MODE) {

boot_into_recovery = 1;

} else if(reboot_mode == FASTBOOT_MODE) {

goto fastboot;

}

 

5)调用boot_linux_from_mmc函数启动kernel

if(target_is_emmc_boot())

{

if(emmc_recovery_init())

dprintf(ALWAYS,"error in emmc_recovery_init\n");

if(target_use_signed_kernel())

{

if((device.is_unlocked) || (device.is_tampered))

{

#ifdef TZ_TAMPER_FUSE

set_tamper_fuse_cmd();

#endif

#if USE_PCOM_SECBOOT

set_tamper_flag(device.is_tampered);

#endif

}

}

boot_linux_from_mmc();

}

else

{

recovery_init();

#ifUSE_PCOM_SECBOOT

if((device.is_unlocked) || (device.is_tampered))

set_tamper_flag(device.is_tampered);

#endif

boot_linux_from_flash();

}

 

5boot_linux_from_mmc函数:

1)验证是否为unified_boot

//boot image headeremmc中地址

uhdr = (struct boot_img_hdr *)EMMC_BOOT_IMG_HEADER_ADDR;

//验证uhdr->magic是否为"ANDROID!"

if (!memcmp(uhdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE))

   {

dprintf(INFO, "Unified boot method!\n");

hdr = uhdr;

goto unified_boot;

   }

 

2)验证bootrecovery分区是否存在

 

if (!boot_into_recovery) {

index =partition_get_index("boot");

ptn =partition_get_offset(index);

if(ptn == 0) {

dprintf(CRITICAL, "ERROR: No boot partition found\n");

                    return -1;

}

 }

else {

index =partition_get_index("recovery");

ptn =partition_get_offset(index);

if(ptn == 0) {

dprintf(CRITICAL, "ERROR: No recovery partition found\n");

                    return -1;

}

}

3)读取2K数据到buf

   //page_size=2048

if (mmc_read(ptn +offset, (unsigned int *)buf, page_size)) {

dprintf(CRITICAL, "ERROR: Cannot read boot imageheader\n");

                return -1;

}

 

 

4)验证boot.imgrecovery.imgBOOT_MAGIC是否为"ANDROID!"

example :

boot.img的头信息如下:



magic[BOOT_MAGIC_SIZE]="ANDROID!"

 

kernel_size       0x0052 3448

kernel_addr      0x0000 8000    2K

 

ramdisk_size     0x0005 9D64

ramdisk_addr:      0x0200 0000

 

second_size       0x0000 0000

second_addr      0xF000 0000

 

tags_addr        0x01E0 0000

page_size         0x0000 0800=2048=2K

dt_size           0x000CD000    820K

 

if(memcmp(hdr->magic, BOOT_MAGIC,BOOT_MAGIC_SIZE)) {

dprintf(CRITICAL, "ERROR: Invalid boot image header\n");

                return -1;

}

5)验证hdr->page_size是否为2K

//hdr->page_size==2048?

if (hdr->page_size && (hdr->page_size != page_size)) {

page_size = hdr->page_size;

page_mask = page_size - 1;

}

 

6)检查默认地址是否存在kernel/ramdisk/tags address

/*

 * Update thekernel/ramdisk/tags address if the boot image header

 * has default values, thesedefault values come from mkbootimg when

 * the boot image is flashedusing fastboot flash:raw

 */

update_ker_tags_rdisk_addr(hdr);

 

7)将物理kernel/ramdisk/tags address转换为虚拟地址

 

/* Get virtual addresses since the hdr saves physicaladdresses. */

hdr->kernel_addr = VA((addr_t)(hdr->kernel_addr));

hdr->ramdisk_addr = VA((addr_t)(hdr->ramdisk_addr));

hdr->tags_addr = VA((addr_t)(hdr->tags_addr));

 

8)加载kernel

 

if(target_use_signed_kernel() && (!device.is_unlocked)&& (!device.is_tampered))

{

   …………..

   …………..

}

else{

//获取kernel/ramdisk/second的长度

kernel_actual  =ROUND_TO_PAGE(hdr->kernel_size, page_mask);

ramdisk_actual = ROUND_TO_PAGE(hdr->ramdisk_size, page_mask);

second_actual  =ROUND_TO_PAGE(hdr->second_size, page_mask);

 

/* Load kernel */ //EMMC中读取实际kernel

if (mmc_read(ptn + offset, (void *)hdr->kernel_addr,kernel_actual)) {

dprintf(CRITICAL, "ERROR: Cannot read kernel image\n");

return -1;

}

 

 

//EMMC中读取实际RAMDISK

offset += kernel_actual;

/* Load ramdisk */

if(ramdisk_actual != 0)

{

if (mmc_read(ptn + offset, (void *)hdr->ramdisk_addr, ramdisk_actual))

{

dprintf(CRITICAL, "ERROR: Cannot read ramdisk image\n");

return -1;

}

}

offset += ramdisk_actual;

dprintf(INFO, "Loading boot image (%d): done\n",

      kernel_actual +ramdisk_actual);

 

//如果Second image存在则不加载

if(hdr->second_size != 0){

offset += second_actual;

/* Second image loading not implemented. */

ASSERT(0);

}

 

//读取page_size (2K)devicetree table数据到dt_buf

#if DEVICE_TREE

if(hdr->dt_size != 0) {

 

/* Read the device tree table into buffer */

if(mmc_read(ptn +offset,(unsigned int *) dt_buf, page_size))

{

  dprintf(CRITICAL,"ERROR: Cannot read the Device Tree Table\n");

return -1;

}

 

//device tree table指向dt_buf

table = (struct dt_table*)dt_buf;

 

 

/* Restriction that thedevice tree entry table should be less than a page*/

ASSERT(((table->num_entries * sizeof(struct dt_entry))+

DEV_TREE_HEADER_SIZE) < hdr->page_size);

 

 

 

 

//检查devicetree table MAGICVERSION

//DEV_TREE_MAGIC  0x54444351 /*"QCDT" */

//DEV_TREE_VERSION1

/*Validate the device tree table header */

if((table->magic!= DEV_TREE_MAGIC) && (table->version !=

DEV_TREE_VERSION)) {

dprintf(CRITICAL, "ERROR: Cannot validate Device Tree Table\n");

return -1;

}

 

 

boot.img镜像导出device tree table header如下:offset=0x57e000


table->magic=0x54444351

table->version=0x01

table->num_entries=0x15

 

//获取当前平台device tree table的入口点

/* Calculate the offset of device tree within device tree table */

if((dt_entry_ptr = dev_tree_get_entry_ptr(table))== NULL){

dprintf(CRITICAL, "ERROR: Getting device tree addressfailed\n");

return -1;

}

 

//eMMC中的devicetree读入hdr->tags_addr

/* Read device device tree in the "tags_add */

if(mmc_read(ptn + offset +dt_entry_ptr->offset,

 (void *)hdr->tags_addr, dt_entry_ptr->size)) {

dprintf(CRITICAL, "ERROR: Cannot read device tree\n");

return -1;

}

 

 

example

offset=0x57e000

dt_entry_ptr->offset=0x4c800

offset +dt_entry_ptr->offset=0x5ca800


6boot_linux函数:

1entry指向kernel内存的物理地址


2)获取tagsramdisk的物理地址


3)更新cmdline


4)更新device_tree


6update_device_tree函数:

1)检查device tree header: 4*10字节



串口读取数据如下:

[1170]fdt_magic(fdt)=0xd00dfeed....... 

[1170]fdt_version(fdt)=0x11....... 

[1180]fdt_last_comp_version(fdt)=0x10 .......

 

2为创建新节点和属性添加空间:


3获取/memory节点的offset:/memory_offset=0x11c


/memory:0x005ca958

/:0x005ca83c


4将RAM分区条目添加到devicetree中:


5获取/chosen节点的offset:/chosen_offset=0xa8


/chosen: 0x005ca8e4

/:0x005ca83c

6将cmdline添加到bootargs属性节点中:


7将ramdisk开始地址添加到linux,initrd-start属性节点中:


8将ramdisk结束地址添加到linux,initrd-end属性节点中:


7、启动kernel



http://blog.youkuaiyun.com/xichangbao/article/details/51484138


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值