安卓系统启动流程

1,Android启动概述

       Android系统启动基本可分为3个阶段:Bootloader启动,Linux启动,Android启动。

1.1,Bootloader启动     

       系统引导bootloader(bootable/bootloader/* u-boot/*),加电后,CPU先执行bootloader程序,正常启动系统,加载boot.img,中包含内核。

       源码:bootable/bootloader/* , 说明:加电后,CPU将先执行bootloader程序,此处有三种选择:
       a: 开机按Camera+Power启动到fastboot,即命令或SD卡烧写模式,不加载内核及文件系统,此处可以进行工厂模式的烧写
       b: 开机按Home+Power启动到recovery模式,加载recovery.img,recovery.img包含内核,基本的文件系统,用于工程模式的烧写
       c:开机按Power,正常启动系统,加载boot.img,boot.img包含内核,基本文件系统,用于正常启动手机(以下只分析正常启动的情况)

1.2,linux启动

         由bootloader加载kernel,kernel经自解压,初始化,载入built-in驱动程序,完成启动。kernel启动后会创建若干内核线程,之后装入并执行程序/sbin/init/,载入init process,切换至user-space。

1.3,Android启动

1.3.1,init进程启动

        源码:system/core/init/*
        配置文件:system/rootdir/init.rc
        说明:init是一个由内核启动的用户级进程,它按照init.rc中的设置执行:启动服务(这里的服务指linux底层服务,如adbd提供adb支持,vold提供SD卡挂载等),执行命令和按其中的配置语句执行相应功能。

1.3.2,zygote服务启动

       源码:frameworks/base/cmds/app_main.cpp等。
       说明:zygote是一个在init.rc中被指定启动的服务,该服务对应的命令是/system/bin/app_process。
       作用:建立Java Runtime,建立虚拟机;建立Socket接收ActivityManangerService的请求,用于Fork应用程序;启动System Server。

1.3.3,systemserver服务启动

       源码:frameworks/base/services/Java/com/android/server/SystemServer.java
       说明:被zygote启动,通过System Manager管理android的服务(这里的服务指frameworks/base/services下的服务,如卫星定位服务,剪切板服务等)。

1.3.4,launcher桌面启动

       源码:ActivityManagerService.java为入口,packages/apps/launcher*实现。
       说明:系统启动成功后SystemServer使用xxx.systemReady()通知各个服务,系统已经就绪,桌面程序Home就是在ActivityManagerService.systemReady()通知的过程中建立的,最终调用startHomeActivityLocked()启launcher。

1.3.5,lockscreen启动

       源码:frameworks/policies/base/phone/com/android/internal/policy/impl/*lock*
       说明:系统启动成功后SystemServer调用wm.systemReady()通知WindowManagerService,进而调用PhoneWindowManager,最终通过LockPatternKeyguardView显示解锁界面,跟踪代码可以看到解锁界面并不是一个Activity,这是只是向特定层上绘图,其代码了存放在特殊的位置。

1.3.6,othersapp启动

       源码:frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
       说明:系统启动成功后SystemServer调用ActivityManagerNative.getDefault().systemReady()通知ActivityManager启动成功,ActivityManager会通过置变量mBooting,通知它的另一线程,该线程会发送广播android.intent.action.BOOT_COMPLETED以告知已注册的第三方程序在开机时自动启动。

2,bootloader启动详细分析

2.1,Bootloader的定义和种类

        简单地说,BootLoader是在操作系统运行之前运行的一段程序,它可以将系统的软硬件环境带到一个合适状态,为运行操作系统做好准备。这样描述是比较抽象的,但是它的任务确实不多,终极目标就是把OS拉起来运行。在嵌入式系统世界里存在各种各样的Bootloader,种类划分也有多种方式。除了按照处理器体系结构不同划分以外,还有功能复杂程度的不同。
        先区分一下Bootloader和Monitor[l1] : 严格来说,Bootloader只是引导OS运行起来的代码;而Monitor另外还提供了很多的命令行接口,可以进行调试、读写内存、烧写Flash、配置环境变量等。在开发过程中Monitor提供了很好地调试功能,不过在开发结束之后,可以完全将其设置成一个Bootloader。所以习惯上将其叫做Bootloader。

Bootloader

 Monitor

描述

 X86

 ARM

 PowerPC

U-boot

通用引导程序

RedBoot

基于eCos的引导程序

BLOB 

LART(主板)等硬件平台的引导程序

LILO

Linux磁盘引导程序

GRUB

GNU的LILO替代程序

Loadlin

从DOS引导Linux

Vivi

韩国mizi 公司开发的bootloader

       更多bootloader还有:ROLO、Etherboot、ARMboot 、LinuxBIOS等。

       对于每种体系结构,都有一系列开放源码Bootloader可以选用:

       X86:X86的工作站和服务器上一般使用LILO和GRUB。

       ARM:最早有为ARM720处理器开发板所做的固件,又有了armboot,StrongARM平台的blob,还有S3C2410处理器开发板上的vivi等。现在armboot已经并入了U-Boot,所以U-Boot也支持ARM/XSCALE平台。U-Boot已经成为ARM平台事实上的标准Bootloader。

       PowerPC:最早使用于ppcboot,不过现在大多数直接使用U-boot。

       MIPS:最早都是MIPS开发商自己写的bootloader,不过现在U-boot也支持MIPS架构

       M68K:Redboot能够支持m68k系列的系统。

2.2,Arm特定平台的bootloader

        到目前为止,我们公司已经做过多个Arm平台的android方案,包括:marvell(pxa935)、informax(im9815)、mediatek(mt6516/6517)、broadcom(bcm2157)。由于不同处理器芯片厂商对arm core的封装差异比较大,所以不同的arm处理器,对于上电引导都是由特定处理器芯片厂商自己开发的程序,这个上电引导程序通常比较简单,会初始化硬件,提供下载模式等,然后才会加载通常的bootloader。

       下面是几个arm平台的bootloader方案:

        marvell(pxa935) :                bootROM + OBM [l4] + BLOB

        informax(im9815) :             bootROM + barbox + U-boot

        mediatek(mt6516/6517) :     bootROM + pre-loader[l5]  + U-boot

        broadcom(bcm2157) :          bootROM + boot1/boot2 + U-boot

       为了明确U-boot之前的两个loader的作用,下面以broadcom平台为例,看下在上电之后到U-boot的流程,如图1.2.1:

                                          图1.2.1 broadcom平台上电流程

2.3,uboot启动流程详解

        最常用的bootloader还是U-boot,可以引导多种操作系统,支持多种架构的CPU。它支持的操作系统有:Linux、NetBSD、VxWorks、QNX、RTEMS、ARTOS、LynxOS等,支持的CPU架构有:ARM、PowerPC、MISP、X86、NIOS、Xscale等。手机系统不像其他的嵌入式系统,它还需要在启动的过程中关心CP的启动,这个时候就涉及到CP的image和唤醒时刻,而一般的嵌入式系统的uboot只负责引导OS内核。所以这里我们也暂不关心CP的启动,而主要关心AP侧。

        从上面第二小节中可以看出,bootloader通常都包含有处理器厂商开发的上电引导程序,不过也不是所有的处理都是这样,比如三星的S3C24X0系列,它的bootROM直接跳到U-boot中执行,首先由bootROM将U-boot的前4KB拷贝到处理器ISRAM,接着在U-boot的前4KB中必须保证要完成的两项主要工作:初始化DDR,nand和nand控制器,接着将U-boot剩余的code拷贝到SDRAM中,然后跳到SDRAM的对应地址上去继续跑U-boot。

       所以U-boot的启动过程,大致上可以分成两个阶段:第一阶段,汇编代码;第二阶段,c代码。

2.3.1,汇编代码阶段

      U-boot的启动由u-boot/arch/arm/cpu/xxx/u-boot.lds开始,其引导调用u-boot/arch/arm/cpu/xxx/start.S。u-boot.lds:

[cpp]  view plain   copy
  1. OUTPUT_FORMAT("elf32-littlearm""elf32-littlearm""elf32-littlearm")  
  2. OUTPUT_ARCH(arm)  
  3. ENTRY(_start)  
  4. SECTIONS  
  5. {  
  6.     . = 0x00000000;  
  7.   
  8.     . = ALIGN(4);  
  9.     .text :  
  10.     {  
  11.         arch/arm/cpu/arm920t/start.o    (.text)//调用对应的start.S,start.o由start.S编译生成  
  12.         *(.text)  
  13.     }  
  14.   
  15.     . = ALIGN(4);  
  16.     .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }  
  17.   
  18.     . = ALIGN(4);  
  19.     .data : {  
  20.         *(.data)  
  21.     }  
  22.   
  23.     . = ALIGN(4);  
  24.   
  25.     . = .;  
  26.     __u_boot_cmd_start = .;  
  27.     .u_boot_cmd : { *(.u_boot_cmd) }  
  28.     __u_boot_cmd_end = .;  
  29.   
  30.     . = ALIGN(4);  
  31.   
  32.     .rel.dyn : {  
  33.         __rel_dyn_start = .;  
  34.         *(.rel*)  
  35.         __rel_dyn_end = .;  
  36.     }  
  37.   
  38.     .dynsym : {  
  39.         __dynsym_start = .;  
  40.         *(.dynsym)  
  41.     }  
  42.   
  43.     .bss __rel_dyn_start (OVERLAY) : {  
  44.         __bss_start = .;  
  45.         *(.bss)  
  46.          . = ALIGN(4);  
  47.         _end = .;  
  48.     }  
  49.   
  50.     /DISCARD/ : { *(.dynstr*) }  
  51.     /DISCARD/ : { *(.dynamic*) }  
  52.     /DISCARD/ : { *(.plt*) }  
  53.     /DISCARD/ : { *(.interp*) }  
  54.     /DISCARD/ : { *(.gnu*) }  
  55. }  

      对应的Makefile文件如下:

[cpp]  view plain   copy
  1. include $(TOPDIR)/config.mk  
  2.   
  3. LIB = $(obj)lib$(CPU).o  
  4.   
  5. START   = start.o  
  6.   
  7. COBJS-y += cpu.o  
  8. COBJS-$(CONFIG_USE_IRQ) += interrupts.o  
  9.   
  10. SRCS    := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS-y:.o=.c)  
  11. OBJS    := $(addprefix $(obj),$(COBJS-y) $(SOBJS))  
  12. START   := $(addprefix $(obj),$(START))  
  13.   
  14. all:    $(obj).depend $(START) $(LIB)  
  15.   
  16. $(LIB): $(OBJS)  
  17.     $(call cmd_link_o_target, $(OBJS))  
  18.   
  19. #########################################################################  
  20.   
  21. # defines $(obj).depend target  
  22. include $(SRCTREE)/rules.mk  
  23.   
  24. sinclude $(obj).depend  

      所以U-boot的第一条指令从u-boot/arch/arm/cpu/xxx/start.S文件开始,第一阶段主要做了如下事情:

      

       (1). 设置CPU进入SVC模式(系统管理模式),cpsr[4:0]=0xd3。

       (2). 关中断,INTMSK=0xFFFFFFFF, INTSUBMSK=0x3FF。

       (3). 关看门狗,WTCON=0x0。

      (4). 调用s3c2410_cache_flush_all函数,使TLBS,I、D Cache,WB中数据失效。

      (5). 时钟设置CLKDIVN=0x3 , FCLK:HCLK:PCLK = 1:2:4。

      (6). 读取mp15的c1寄存器,将最高两位改成11,表示选择了异步时钟模型。

      (7). 检查系统的复位状态,以确定是不是从睡眠唤醒。

[cpp]  view plain   copy
  1. #include <asm-offsets.h>  
  2. #include <common.h>  
  3. #include <config.h>  
  4.   
  5. .globl _start  
  6. _start: b   start_code  
  7.     ldr pc, _undefined_instruction  
  8.     ldr pc, _software_interrupt  
  9.     ldr pc, _prefetch_abort  
  10.     ldr pc, _data_abort  
  11.     ldr pc, _not_used  
  12.     ldr pc, _irq  
  13.     ldr pc, _fiq  
  14.   
  15. ......  
  16.   
  17. //开始的一些初始化操作  
  18. start_code:  
  19.     /* 
  20.      * set the cpu to SVC32 mode 
  21.      */  
  22.     mrs r0, cpsr  
  23.     bic r0, r0, #0x1f  
  24.     orr r0, r0, #0xd3  
  25.     msr cpsr, r0  
  26.   
  27.     bl  coloured_LED_init  
  28.     bl  red_LED_on  
  29.   
  30. ......  
  31.   
  32.     /* 
  33.      * we do sys-critical inits only at reboot, 
  34.      * not when booting from ram! 
  35.      */  
  36. #ifndef CONFIG_SKIP_LOWLEVEL_INIT  
  37.     bl  cpu_init_crit //重点函数  
  38. #endif  
  39.   
  40. /* Set stackpointer in internal RAM to call board_init_f */  
  41. /*board.c的board_init_f()函数*/  
  42. call_board_init_f:  
  43.     ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)  
  44.     bic sp, sp, #7 /* 8-byte alignment for ABI compliance */  
  45.     ldr r0,=0x00000000  
  46.     bl  board_init_f//board初始化  
  47.   
  48.   
  49.     .globl  relocate_code  
  50. relocate_code:  
  51.     mov r4, r0  /* save addr_sp */  
  52.     mov r5, r1  /* save addr of gd */  
  53.     mov r6, r2  /* save addr of destination */  
  54.   
  55.     /* Set up the stack                         */  
  56. stack_setup:  
  57.     mov sp, r4  
  58.   
  59.     adr r0, _start  
  60.     cmp r0, r6  
  61.     beq clear_bss       /* skip relocation */  
  62.     mov r1, r6          /* r1 <- scratch for copy_loop */  
  63.     ldr r2, _TEXT_BASE  
  64.     ldr r3, _bss_start_ofs  
  65.     add r2, r0, r3      /* r2 <- source end address      */  
  66.   
  67. copy_loop:  
  68.     ldmia   r0!, {r9-r10}       /* copy from source address [r0]    */  
  69.     stmia   r1!, {r9-r10}       /* copy to   target address [r1]    */  
  70.     cmp r0, r2          /* until source end address [r2]    */  
  71.     blo copy_loop  
  72.   
  73. #ifndef CONFIG_PRELOADER  
  74.     /* 
  75.      * fix .rel.dyn relocations 
  76.      */  
  77.     ldr r0, _TEXT_BASE      /* r0 <- Text base */  
  78.     sub r9, r6, r0      /* r9 <- relocation offset */  
  79.     ldr r10, _dynsym_start_ofs  /* r10 <- sym table ofs */  
  80.     add r10, r10, r0        /* r10 <- sym table in FLASH */  
  81.     ldr r2, _rel_dyn_start_ofs  /* r2 <- rel dyn start ofs */  
  82.     add r2, r2, r0      /* r2 <- rel dyn start in FLASH */  
  83.     ldr r3, _rel_dyn_end_ofs    /* r3 <- rel dyn end ofs */  
  84.     add r3, r3, r0      /* r3 <- rel dyn end in FLASH */  
  85. fixloop:  
  86.     ldr r0, [r2]        /* r0 <- location to fix up, IN FLASH! */  
  87.     add r0, r0, r9      /* r0 <- location to fix up in RAM */  
  88.     ldr r1, [r2, #4]  
  89.     and r7, r1, #0xff  
  90.     cmp r7, #23         /* relative fixup? */  
  91.     beq fixrel  
  92.     cmp r7, #2          /* absolute fixup? */  
  93.     beq fixabs  
  94.     /* ignore unknown type of fixup */  
  95.     b   fixnext  
  96. fixabs:  
  97.     /* absolute fix: set location to (offset) symbol value */  
  98.     mov r1, r1, LSR #4      /* r1 <- symbol index in .dynsym */  
  99.     add r1, r10, r1     /* r1 <- address of symbol in table */  
  100.     ldr r1, [r1, #4]        /* r1 <- symbol value */  
  101.     add r1, r1, r9      /* r1 <- relocated sym addr */  
  102.     b   fixnext  
  103. fixrel:  
  104.     /* relative fix: increase location by offset */  
  105.     ldr r1, [r0]  
  106.     add r1, r1, r9  
  107. fixnext:  
  108.     str r1, [r0]  
  109.     add r2, r2, #8      /* each rel.dyn entry is 8 bytes */  
  110.     cmp r2, r3  
  111.     blo fixloop  
  112. #endif  
  113.   
  114. clear_bss:  
  115. #ifndef CONFIG_PRELOADER  
  116.     ldr r0, _bss_start_ofs  
  117.     ldr r1, _bss_end_ofs  
  118.     ldr r3, _TEXT_BASE      /* Text base */  
  119.     mov r4, r6          /* reloc addr */  
  120.     add r0, r0, r4  
  121.     add r1, r1, r4  
  122.     mov r2, #0x00000000     /* clear                */  
  123.   
  124. clbss_l:str r2, [r0]        /* clear loop...            */  
  125.     add r0, r0, #4  
  126.     cmp r0, r1  
  127.     bne clbss_l  
  128.   
  129.     bl coloured_LED_init  
  130.     bl red_LED_on  
  131. #endif  
  132.   
  133. /* 
  134.  * We are done. Do not return, instead branch to second part of board 
  135.  * initialization, now running from RAM. 
  136.  */  
  137. #ifdef CONFIG_NAND_SPL  
  138.     ldr     r0, _nand_boot_ofs  
  139.     mov pc, r0  
  140.   
  141. _nand_boot_ofs:  
  142.     .word nand_boot  
  143. #else  
  144.     ldr r0, _board_init_r_ofs  
  145.     adr r1, _start  
  146.     add lr, r0, r1  
  147.     add lr, lr, r9  
  148.     /* setup parameters for board_init_r */  
  149.     mov r0, r5      /* gd_t */  
  150.     mov r1, r6      /* dest_addr */  
  151.     /* jump to it ... */  
  152.     mov pc, lr  
  153. /*board_init_r 此处走至u-boot\arch\arm\lib\board.c的board_init_r()函数 */  
  154. _board_init_r_ofs:  
  155.     .word board_init_r - _start  
  156. #endif  
  157. /*至此走至C代码的阶段*/  
  158. _rel_dyn_start_ofs:  
  159.     .word __rel_dyn_start - _start  
  160. _rel_dyn_end_ofs:  
  161.     .word __rel_dyn_end - _start  
  162. _dynsym_start_ofs:  
  163.     .word __dynsym_start - _start  
  164.       
  165. ......  
  166.   
  167. #endif  

 

        根据这几条语句来判断系统是从nand启动的还是直接将程序下载到SDRAM中运行的,这里涉及到运行时域 和位置无关代码的概念,ldr r0,_TEXT_BASE的作用是将config.mk文件中定义的TEXT_BASE值(0x33f80000)装载到r0中,adr r1,_start该指令是条伪指令,在编译的时候会被转换成ADD或SUB指令根据当前pc值计算出_start标号的地址,这样的话就可以知道当前程序在什么地址运行(位置无关代码:做成程序的所有指令都是相对寻址的指令,包括跳转指令等,这样代码就可以不在链接所指定的地址上运行)。在上电之后,系统从nand启动,这里得到r0和r1值是不一样的,r0=0x33f80000,而r1=0x00000000。所以接下来会执行cpu_init_crit函数。

        cpu_init_crit函数,主要完成了两个工作:首先使ICache and Dcache,TLBs中早期内容失效,再设置p15 control register c1,关闭MMU,Dcache,但是打开了Icache和Fault checking,(要求mmu和Dcache是必须要关闭的,而Icache可以打开可以关闭);其次调用/board/nextdvr2410/memsetup.S文件中的memsetup函数来建立对SDRAM的访问时序。

        Relocate函数,加载nand flash中的uboot到SDRAM中,代码会加载到0x33f80000开始的地址,空间大小是512。

        //这里参考的是展讯平台7710的源代码,所以并无start_armboot函数,取而代之的是board_init_r函数。请知悉。

        ldr pc, _start_armboot        

       _start_armboot: .word start_armboot

       这里将会进入第二阶段的c代码部分:board_init_r()函数,/u-boot/arch/arm/lib/board.c。

2.3.2,C代码阶段

       先看/u-boot/arch/arm/lib/board.c的board_init_r()函数:

[cpp]  view plain   copy
  1. void board_init_r (gd_t *id, ulong dest_addr)  
  2. {  
  3. ......  
  4. /**一系列初始化操作之后 重点为do_cboot(NULL, 0, 1, NULL)和main_loop ()*/  
  5.     board_init();   /* Setup chipselects */  
  6.   
  7.   boot_pwr_check();  
  8.   
  9. #ifdef CONFIG_SERIAL_MULTI  
  10.     serial_initialize();  
  11. #endif  
  12.   
  13.     debug ("Now running in RAM - U-Boot at: %08lx\n", dest_addr);  
  14.   
  15. #ifdef CONFIG_LOGBUFFER  
  16.     logbuff_init_ptrs ();  
  17. #endif  
  18. #ifdef CONFIG_POST  
  19.     post_output_backlog ();  
  20. #endif  
  21.   
  22.     /* The Malloc area is immediately below the monitor copy in DRAM */  
  23.     malloc_start = dest_addr - TOTAL_MALLOC_LEN;  
  24. #ifdef SPRD_EVM_TAG_ON  
  25.         SPRD_EVM_TAG(4);  
  26. #endif  
  27.     mem_malloc_init (malloc_start, TOTAL_MALLOC_LEN);  
  28. #ifdef SPRD_EVM_TAG_ON  
  29.         SPRD_EVM_TAG(5);  
  30. #endif  
  31.     boot_pwr_check();  
  32.   
  33. #if !defined(CONFIG_SYS_NO_FLASH)  
  34.     puts ("FLASH: ");  
  35.   
  36.     if ((flash_size = flash_init ()) > 0) {  
  37. # ifdef CONFIG_SYS_FLASH_CHECKSUM  
  38.         print_size (flash_size, "");  
  39.         /* 
  40.          * Compute and print flash CRC if flashchecksum is set to 'y' 
  41.          * 
  42.          * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX 
  43.          */  
  44.         s = getenv ("flashchecksum");  
  45.         if (s && (*s == 'y')) {  
  46.             printf ("  CRC: %08X",  
  47.                 crc32 (0, (const unsigned char *) CONFIG_SYS_FLASH_BASE, flash_size)  
  48.             );  
  49.         }  
  50.         putc ('\n');  
  51. # else  /* !CONFIG_SYS_FLASH_CHECKSUM */  
  52.         print_size (flash_size, "\n");  
  53. # endif /* CONFIG_SYS_FLASH_CHECKSUM */  
  54.     } else {  
  55.         puts (failed);  
  56.         hang ();  
  57.     }  
  58. #endif  
  59.     boot_pwr_check();  
  60.   
  61. #if !defined(CONFIG_EMMC_BOOT)  
  62. #if defined(CONFIG_CMD_NAND)  
  63.     puts ("NAND:  ");  
  64.     ret = nand_init();      /* go init the NAND */  
  65.         if (ret) {  
  66.             puts ("NAND init error  ");  
  67.             while(1);  
  68.         }  
  69. #endif  
  70. #endif  
  71.   
  72.     boot_pwr_check();  
  73. #ifdef SPRD_EVM_TAG_ON  
  74.         SPRD_EVM_TAG(6);  
  75. #endif  
  76.   
  77. #if defined(CONFIG_CMD_ONENAND)  
  78. #if !(defined CONFIG_TIGER && defined CONFIG_EMMC_BOOT)  
  79.     onenand_init();  
  80. #endif  
  81. #endif  
  82.   
  83. #ifdef CONFIG_GENERIC_MMC  
  84.        puts("MMC:   ");  
  85.        mmc_initialize(bd);  
  86. #endif  
  87.   
  88. #ifdef CONFIG_HAS_DATAFLASH  
  89.     AT91F_DataflashInit();  
  90.     dataflash_print_info();  
  91. #endif  
  92.   
  93. #ifdef CONFIG_EMMC_BOOT  
  94.     mmc_legacy_init(1);  
  95. #endif  
  96.     /* initialize environment */  
  97.     env_relocate ();  
  98.     boot_pwr_check();  
  99.   
  100. #ifdef CONFIG_VFD  
  101.     /* must do this after the framebuffer is allocated */  
  102.     drv_vfd_init();  
  103. #endif /* CONFIG_VFD */  
  104.   
  105. /*tempaily use for tiger to avoid died as refreshing LCD*/  
  106.   
  107.     /* IP Address */  
  108.     gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");  
  109.   
  110.     stdio_init ();  /* get the devices list going. */  
  111.     boot_pwr_check();  
  112.   
  113.     jumptable_init ();  
  114.     boot_pwr_check();  
  115.   
  116. #if defined(CONFIG_API)  
  117.     /* Initialize API */  
  118.     api_init ();  
  119. #endif  
  120.     char fake[4]="fak";  
  121.     setenv("splashimage", fake);  
  122.   
  123.     console_init_r ();  /* fully init console as a device */  
  124.     boot_pwr_check();  
  125.   
  126. #if defined(CONFIG_ARCH_MISC_INIT)  
  127.     /* miscellaneous arch dependent initialisations */  
  128.     arch_misc_init ();  
  129. #endif  
  130. #if defined(CONFIG_MISC_INIT_R)  
  131.     /* miscellaneous platform dependent initialisations */  
  132.     misc_init_r ();  
  133. #endif  
  134.   
  135.      /* set up exceptions */  
  136.     interrupt_init ();  
  137.     /* enable exceptions */  
  138.     enable_interrupts ();  
  139.     boot_pwr_check();  
  140.   
  141.     /* Perform network card initialisation if necessary */  
  142. #if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)  
  143.     /* XXX: this needs to be moved to board init */  
  144.     if (getenv ("ethaddr")) {  
  145.         uchar enetaddr[6];  
  146.         eth_getenv_enetaddr("ethaddr", enetaddr);  
  147.         smc_set_mac_addr(enetaddr);  
  148.     }  
  149. #endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */  
  150.   
  151.     /* Initialize from environment */  
  152.     if ((s = getenv ("loadaddr")) != NULL) {  
  153.         load_addr = simple_strtoul (s, NULL, 16);  
  154.     }  
  155. #if defined(CONFIG_CMD_NET)  
  156.     if ((s = getenv ("bootfile")) != NULL) {  
  157.         copy_filename (BootFile, s, sizeof (BootFile));  
  158.     }  
  159. #endif  
  160.     boot_pwr_check();  
  161.     //usb_eth_initialize(NULL);  
  162. #ifdef BOARD_LATE_INIT  
  163.     board_late_init ();  
  164. #endif  
  165. ......  
  166.   
  167. #ifdef SPRD_EVM_TAG_ON  
  168.         SPRD_EVM_TAG(11);  
  169. #endif  
  170.     extern int do_cboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]);  
  171.     boot_pwr_check();  
  172.   
  173.     do_cboot(NULL, 0, 1, NULL);//重点操作函数,此处走至u-boot\property\cmd_cboot.c  
  174.     /* main_loop() can return to retry autoboot, if so just run it again. */  
  175.     for (;;) {  
  176.         main_loop ();  
  177.     }  
  178.   
  179.     /* NOTREACHED - no way out of command loop except booting */  
  180. }  


         该段代码完成了一些设备的初始化do_cboot(NULL, 0, 1, NULL)和main_loop ()是此处重点函数,其中do_cboot(NULL, 0, 1, NULL)的实现在u-boot/property/cmd_cboot.c而main_loop()则是在u-boot/common/main.c中。先看u-boot/property/cmd_cboot.c。

[cpp]  view plain   copy
  1. int boot_pwr_check(void)  
  2. {  
  3.     static int total_cnt = 0;  
  4.     if(!power_button_pressed())  
  5.       total_cnt ++;  
  6.     return total_cnt;  
  7. }  
  8. #define mdelay(_ms) udelay(_ms*1000)  
  9.   
  10.   
  11. int do_cboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])  
  12. {  
  13.     uint32_t key_mode = 0;  
  14.     uint32_t key_code = 0;  
  15.     volatile int i;  
  16.   
  17.     if(argc > 2)  
  18.       goto usage;  
  19.   
  20. #ifdef CONFIG_SC8830  
  21.         if(cali_file_check())  
  22.                 calibration_detect(2);  
  23. #endif  
  24. #ifdef CONFIG_SC7710G2  
  25.     {  
  26.     extern void set_cp_emc_pad(void);  
  27.     set_cp_emc_pad();  
  28.     }  
  29. #endif  
  30.     CHG_Init();  
  31.   
  32. #ifdef CONFIG_SC8830  
  33.     DCDC_Cal_ArmCore();  
  34.     //DCDC_Cal_All(0);  
  35. #endif  
  36.   
  37. #ifdef CONFIG_AUTOBOOT  
  38.     normal_mode();//如果down的是autopoweron的uboot,这里会直接去正常开机  
  39. #endif  
  40.   
  41. #ifdef CONFIG_SC7710G2  
  42.     if(!pbint2_connected())  
  43.         normal_mode();  
  44. #endif  
  45.   
  46.     boot_pwr_check();  
  47.       
  48. #ifdef CONFIG_SC8800G  
  49.     CHG_ShutDown();  
  50.     if(charger_connected()){  
  51.         mdelay(10);  
  52.         CHG_TurnOn();  
  53.     }else{  
  54.         //根据sp8810.h里的LOW_BAT_VOL,如果电压低于3.5V,则直接power down  
  55.         if(is_bat_low()){  
  56.             printf("shut down again for low battery\n");  
  57.             power_down_devices();  
  58.             while(1)  
  59.               ;  
  60.         }  
  61.     }  
  62. #else  
  63.   
  64. #ifndef CONFIG_MACH_CORI  
  65.     if(is_bat_low()){  
  66.                 printf("shut down again for low battery\n");  
  67.                 mdelay(10000);  
  68.                 power_down_devices();  
  69.                 while(1)  
  70.                   ;  
  71.     }  
  72. #endif      
  73. #endif    
  74.   
  75.     boot_pwr_check();  
  76.     board_keypad_init();//初始化键盘  
  77.     boot_pwr_check();  
  78.   
  79. #ifdef CONFIG_SPRD_SYSDUMP  
  80.     write_sysdump_before_boot();  
  81. #endif
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android系统启动流程可以分为以下几个步骤: 1. 启动电源以及系统启动:当电源按下时,引导芯片代码开始执行,加载引导程序Bootloader到RAM,并执行该程序。 2. 引导程序Bootloader:引导程序是一个小程序,其主要作用是将系统OS启动起来并运行。 3. Linux内核启动:内核启动时,进行系统设置,包括设置缓存、被保护存储器、计划列表,并加载驱动。内核会在系统文件中寻找"init"文件,并启动init进程或系统的第一个进程。 4. init进程启动:init进程是Android系统的第一个用户空间进程,它负责启动和管理其他系统进程。init进程会读取init.rc文件,根据其中的配置启动系统服务和应用进程。 5. Zygote进程和SystemServer进程启动:Zygote进程是一个特殊的进程,它作为应用进程的模板,用于快速创建新的应用进程。SystemServer进程是Android系统的核心服务进程,负责启动和管理各种系统服务。 6. 应用层进程启动:在Android系统中,应用层进程包括Launcher进程,即主屏幕的进程,以及其他应用程序的进程。这些进程会根据用户的操作和应用的需求来启动和管理。 总结起来,Android系统启动流程包括引导程序Bootloader的加载和执行、Linux内核的启动、init进程的启动、Zygote进程和SystemServer进程的启动,以及应用层进程的启动。这些步骤共同完成了Android系统的初始化和启动。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* [Android系统启动流程(一)解析init进程启动过程](https://blog.csdn.net/itachi85/article/details/54783506)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Android系统启动流程](https://blog.csdn.net/xhmj12/article/details/128149490)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Android 面试必备 - 系统、App、Activity 启动过程“一锅端”](https://blog.csdn.net/zzz777qqq/article/details/115698795)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值