您的位置:首页 > 运维架构 > Linux

lk启动流程

2016-11-08 15:01 176 查看
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
}
3、bootstrap2线程:
 路径:/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函数。
 
4、aboot_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();

}
 
5、boot_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
MAGIC和VERSION
//DEV_TREE_MAGIC:  0x54444351 /*"QCDT"
*/
//DEV_TREE_VERSION:1

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

6、boot_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.csdn.net/xichangbao/article/details/51484138
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux lk