本文转载自:http://blog.csdn.net/dkleikesa/article/details/9792747

本人用的android平台用的bootloader用的是uboot,貌似大多数手持设备平台都不用这个,因为功能过于强大用不上,反而显得太复杂了。不知道这个平台开发者是怎么想的。既然用了那就来分析一下,顺便修改一下其中的几个小问题,以符合我们的要求。

uboot等同于其他所有的bootloader程序,从根本上讲是一个稍复杂的裸机程序,是最底层的东西,要分析裸机程序我们要从它的连接文件开始。连接文件(.lds文件)定义了程序编译之后整个连接过程,这样我们就可以找到这个程序的第一句汇编代码,进而来下一步分析。uboot的链接文件代码在android\bootable\bootloader\uboot-imx\u-boot.lds

  1. OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")  //文件输出格式
  2. OUTPUT_ARCH(arm)
  3. ENTRY(_start)       //首地址标示符
  4. SECTIONS
  5. {
  6. . = 0x00000000;    //其实地址0
  7. . = ALIGN(4);      //4字节对齐
  8. .text :        //代码段
  9. {
  10. board/freescale/mx6q_sabresd/flash_header.o (.text.flasheader)   //第一个文件是board/freescale/mx6q_sabresd/flash_header.o
  11. cpu/arm_cortexa8/start.o         //第二个cpu/arm_cortexa8/start.o
  12. board/freescale/mx6q_sabresd/libmx6q_sabresd.a (.text)
  13. lib_arm/libarm.a (.text)
  14. net/libnet.a (.text)
  15. drivers/mtd/libmtd.a (.text)
  16. drivers/mmc/libmmc.a (.text)
  17. . = DEFINED(env_offset) ? env_offset : .;
  18. common/env_embedded.o(.text)
  19. *(.text)             //剩余的所有代码
  20. }
  21. . = ALIGN(4);
  22. .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } //readonly data 段
  23. . = ALIGN(4);
  24. .data : { *(.data) }       //所有的readonly data
  25. . = ALIGN(4);
  26. .got : { *(.got) }
  27. . = .;
  28. __u_boot_cmd_start = .;        //u_boot_cmd段,里面是所有uboot命令的一个列表
  29. .u_boot_cmd : { *(.u_boot_cmd) }
  30. __u_boot_cmd_end = .;
  31. . = ALIGN(4);
  32. _end_of_copy = .;
  33. __bss_start = .;           //bss段 就是内存数据段
  34. .bss : { *(.bss) }
  35. _end = .;
  36. }

从上面的代码可以看出我们编译生成的二进制应用程序组成是:代码段->rodata段->uboot命令列表->bss段。我们启动这个应用程序时候是从,0地址开始的,因此我们来看
board/freescale/mx6q_sabresd/flash_header.s这个文件。
  这个文件中除了分配内存和宏定义的伪汇编指令以外,真正执行的命令有一条

  1. .section ".text.flasheader", "x"
  2. b   _start
  3. .org    CONFIG_FLASH_HEADER_OFFSET

也就是说,这个文件一执行就直接跳到_start 位置处。_start 在android\bootable\bootloader\uboot-imx\cpu\arm_cortexa8\ start.S中,因此我们来看这个文件代码

  1. .globl _start
  2. _start: b   reset

这里直接跳转的reset中接下来看

  1. reset:
  2. /*
  3. * set the cpu to SVC32 mode    cpu设置成32位管理模式
  4. */
  5. mrs r0, cpsr
  6. bic r0, r0, #0x1f
  7. orr r0, r0, #0xd3
  8. msr cpsr,r0
  9. #if (CONFIG_OMAP34XX)   //因为我们的cpu不是ompa的 所以这段不会编译
  10. .............................
  11. #endif
  12. /* the mask ROM code should have PLL and others stable */
  13. #ifndef CONFIG_SKIP_LOWLEVEL_INIT
  14. bl  cpu_init_crit
  15. #endif

这里接下来执行cpu_init_crit

  1. /*************************************************************************
  2. *
  3. * CPU_init_critical registers
  4. *
  5. * setup important registers
  6. * setup memory timing
  7. *
  8. *************************************************************************/
  9. cpu_init_crit:
  10. /*
  11. * Invalidate L1 I/D
  12. */
  13. mov r0, #0          @ set up for MCR
  14. mcr p15, 0, r0, c8, c7, 0   @ invalidate TLBs
  15. mcr p15, 0, r0, c7, c5, 0   @ invalidate icache
  16. /*
  17. * disable MMU stuff and caches     //关闭mmu
  18. */
  19. mrc p15, 0, r0, c1, c0, 0
  20. bic r0, r0, #0x00002000 @ clear bits 13 (--V-)
  21. bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM)
  22. orr r0, r0, #0x00000002 @ set bit 1 (--A-) Align
  23. orr r0, r0, #0x00000800 @ set bit 12 (Z---) BTB
  24. mcr p15, 0, r0, c1, c0, 0
  25. /*
  26. * Jump to board specific initialization...
  27. * The Mask ROM will have already initialized
  28. * basic memory. Go here to bump up clock rate and handle
  29. * wake up conditions.
  30. */
  31. mov ip, lr      @ persevere link reg across call
  32. bl  lowlevel_init   @ go setup pll,mux,memory//执行lowlevel_init这个函数代码在
  33. @\bootloader\uboot-imx\board\freescale\mx6q_sabresd\lowlevel_init.S中
  34. @主要对时钟,外部ram,rom等进行了初始化代码不贴了。
  35. mov lr, ip      @ restore link
  36. mov pc, lr      @ back to my caller

初始化完成后,接下来执行

  1. #ifndef CONFIG_SKIP_RELOCATE_UBOOT
  2. relocate:               @ relocate U-Boot to RAM    将uboot重新定位到内存中
  3. adr r0, _start      @ r0 <- current position of code
  4. ldr r1, _TEXT_BASE      @ test if we run from flash or RAM
  5. cmp r0, r1          @ don't reloc during debug测试当前代码是否已经在内存中
  6. beq stack_setup     @如果在的话就直接跳转到stack_setup
  7. ldr r2, _armboot_start  @如果不在的话,加载_armboot_start地址到r2中。_armboot_start是uboot执行的主体c函数。
  8. ldr r3, _bss_start
  9. sub r2, r3, r2      @ r2 <- size of armboot计算bss_start-armboot_start 保存到R2中,也就是uboot的总大小
  10. add r2, r0, r2      @ r2 <- source end address 计算出uboot代码和rodata地址
  11. copy_loop:              @ copy 32 bytes at a time   //开始拷贝
  12. ldmia   r0!, {r3 - r10}     @ copy from source address [r0]
  13. stmia   r1!, {r3 - r10}     @ copy to   target address [r1]
  14. cmp r0, r2          @ until source end addreee [r2]
  15. ble copy_loop
  16. #endif  /* CONFIG_SKIP_RELOCATE_UBOOT */
  17. /* Set up the stack */
  18. stack_setup:
  19. ldr r0, _TEXT_BASE      @ upper 128 KiB: relocated uboot
  20. sub r0, r0, #CONFIG_SYS_MALLOC_LEN @ malloc area//为c语言malloc函数分配内存
  21. sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE @ bdinfo
  22. #ifdef CONFIG_USE_IRQ
  23. sub r0, r0, #(CONFIG_STACKSIZE_IRQ + CONFIG_STACKSIZE_FIQ)
  24. #endif
  25. sub sp, r0, #12     @ leave 3 words for abort-stack//分配c语言堆栈
  26. and sp, sp, #~7     @ 8 byte alinged for (ldr/str)d
  27. /* Clear BSS (if any). Is below tx (watch load addr - need space) */
  28. clear_bss:
  29. ldr r0, _bss_start      @ find start of bss segment //清除bss段
  30. ldr r1, _bss_end        @ stop here
  31. mov r2, #0x00000000     @ clear value
  32. clbss_l:
  33. str r2, [r0]        @ clear BSS location
  34. cmp r0, r1          @ are we at the end yet
  35. add r0, r0, #4      @ increment clear index pointer
  36. bne clbss_l         @ keep clearing till at end
  37. #ifdef CONFIG_ARCH_MMU
  38. bl board_mmu_init   //初始化mmu
  39. #endif
  40. ldr pc, _start_armboot  @ jump to C code以上所有的初始化就已经完成了,接下类正式执行c语言代码了。这才是我们的重点
  41. _start_armboot: .word start_armboot

接下来正式看C代码,也就是start_armboot这个函数代码在android\bootable\bootloader\uboot-imx\lib_arm\board.c中

  1. void start_armboot (void)
  2. {
  3. init_fnc_t **init_fnc_ptr;
  4. char *s;
  5. #if defined(CONFIG_VFD) || defined(CONFIG_LCD)
  6. unsigned long addr;
  7. #endif
  8. /* Pointer is writable since we allocated a register for it */
  9. gd = (gd_t*)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t));
  10. //分配一段内存.在cpu存储控制器初始化之前,是不能访问外部ram的,因此需要一小段
  11. //内存来运行最初的初始化函数,这段内存一般是cpu内部ram
  12. /* compiler optimization barrier needed for GCC >= 3.4 */
  13. __asm__ __volatile__("": : :"memory");
  14. memset ((void*)gd, 0, sizeof (gd_t));
  15. gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
  16. memset (gd->bd, 0, sizeof (bd_t));
  17. gd->flags |= GD_FLG_RELOC;
  18. monitor_flash_len = _bss_start - _armboot_start;
  19. for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
  20. if ((*init_fnc_ptr)() != 0) {
  21. hang ();
  22. }
  23. }

注意看这里init_sequence的定义

  1. init_fnc_t *init_sequence[] = {
  2. #if defined(CONFIG_ARCH_CPU_INIT)
  3. arch_cpu_init,      /* basic arch cpu dependent setup */
  4. #endif
  5. board_init,     /* basic board dependent setup */
  6. #if defined(CONFIG_USE_IRQ)
  7. interrupt_init,     /* set up exceptions */
  8. #endif
  9. timer_init,     /* initialize timer */
  10. env_init,       /* initialize environment */
  11. init_baudrate,      /* initialze baudrate settings */
  12. serial_init,        /* serial communications setup */
  13. console_init_f,     /* stage 1 init of console */
  14. display_banner,     /* say that we are here */
  15. #if defined(CONFIG_DISPLAY_CPUINFO)
  16. print_cpuinfo,      /* display cpu info (and speed) */
  17. #endif
  18. #if defined(CONFIG_DISPLAY_BOARDINFO)
  19. checkboard,     /* display board info */
  20. #endif
  21. #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
  22. init_func_i2c,
  23. #endif
  24. dram_init,      /* configure available RAM banks */
  25. #if defined(CONFIG_CMD_PCI) || defined (CONFIG_PCI)
  26. arm_pci_init,
  27. #endif
  28. display_dram_config,
  29. NULL,
  30. };

这个是一个函数指针的数组,涉及到cpu的最后的一些初始化。到了这里cpu的所有初始化都完成了

我们继续看板子的其他配置

  1. #ifdef CONFIG_LCD   //lcd缓存设置
  2. /* board init may have inited fb_base */
  3. if (!gd->fb_base) {
  4. #       ifndef PAGE_SIZE
  5. #         define PAGE_SIZE 4096
  6. #       endif
  7. /*
  8. * reserve memory for LCD display (always full pages)
  9. */
  10. /* bss_end is defined in the board-specific linker script */
  11. addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
  12. lcd_setmem (addr);
  13. gd->fb_base = addr;
  14. }
  15. #endif /* CONFIG_LCD */
  16. env_relocate ();//设置环境变量 也就是printenv 打印出来的那些
  17. #ifdef CONFIG_VFD
  18. /* must do this after the framebuffer is allocated */
  19. drv_vfd_init(); //空函数
  20. #endif /* CONFIG_VFD */
  21. #ifdef CONFIG_SERIAL_MULTI
  22. serial_initialize();//串口初始化
  23. #endif
  24. /* IP Address */
  25. gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
  26. #if defined CONFIG_SPLASH_SCREEN && defined CONFIG_VIDEO_MX5
  27. setup_splash_image();//lcd显示log
  28. #endif
  29. //重新定义stdio的位置,在本环境中被定义到了串口上
  30. stdio_init ();  /* get the devices list going. */
  31. jumptable_init ();//把一些初始化函数的指针放到gd中,为以后调用
  32. #if defined(CONFIG_API)
  33. /* Initialize API */
  34. api_init ();
  35. #endif
  36. console_init_r ();  /* fully init console as a device 控制台初始化*/
  37. #if defined(CONFIG_ARCH_MISC_INIT)
  38. /* miscellaneous arch dependent initialisations */
  39. arch_misc_init ();//空函数
  40. #endif
  41. #if defined(CONFIG_MISC_INIT_R)
  42. /* miscellaneous platform dependent initialisations */
  43. misc_init_r ();//空函数
  44. #endif
  45. /* enable exceptions */
  46. enable_interrupts ();//使能中断
  47. /* Perform network card initialisation if necessary */
  48. #ifdef CONFIG_DRIVER_TI_EMAC
  49. /* XXX: this needs to be moved to board init */
  50. extern void davinci_eth_set_mac_addr (const u_int8_t *addr);//不编译
  51. if (getenv ("ethaddr")) {
  52. uchar enetaddr[6];
  53. eth_getenv_enetaddr("ethaddr", enetaddr);
  54. davinci_eth_set_mac_addr(enetaddr);
  55. }
  56. #endif
  57. #ifdef CONFIG_DRIVER_CS8900
  58. /* XXX: this needs to be moved to board init */
  59. cs8900_get_enetaddr ();//不编译
  60. #endif
  61. #if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)
  62. /* XXX: this needs to be moved to board init */
  63. if (getenv ("ethaddr")) {
  64. uchar enetaddr[6];
  65. eth_getenv_enetaddr("ethaddr", enetaddr);//不编译
  66. smc_set_mac_addr(enetaddr);
  67. }
  68. #endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */
  69. #if defined(CONFIG_ENC28J60_ETH) && !defined(CONFIG_ETHADDR)
  70. extern void enc_set_mac_addr (void);//不编译
  71. enc_set_mac_addr ();
  72. #endif /* CONFIG_ENC28J60_ETH && !CONFIG_ETHADDR*/
  73. /* Initialize from environment */
  74. if ((s = getenv ("loadaddr")) != NULL) {
  75. load_addr = simple_strtoul (s, NULL, 16);
  76. }
  77. #if defined(CONFIG_CMD_NET)
  78. if ((s = getenv ("bootfile")) != NULL) {
  79. copy_filename (BootFile, s, sizeof (BootFile));
  80. }
  81. #endif
  82. #ifdef BOARD_LATE_INIT
  83. board_late_init (); //初始化i2c,pmic等
  84. #endif

接下来涉及到了我们最关心的地方,启动模式和按键响应

  1. #ifdef CONFIG_ANDROID_RECOVERY
  2. check_recovery_mode();  //检测是否进入recovery
  3. #endif
  4. #if defined(CONFIG_CMD_NET)
  5. #if defined(CONFIG_NET_MULTI)
  6. puts ("Net:   ");
  7. #endif
  8. eth_initialize(gd->bd);  //根据gd的配置初始化以太网
  9. #if defined(CONFIG_RESET_PHY_R)
  10. debug ("Reset Ethernet PHY\n");
  11. reset_phy();
  12. #endif
  13. #endif
  14. #ifdef CONFIG_FASTBOOT
  15. check_fastboot_mode();  //检测是否进入fastboot
  16. #endif

从代码里可以看出我们是首先检测recovery,然后才检测fastboot模式。

我们先来看原版是怎么做的,首先是recovery

  1. void check_recovery_mode(void)
  2. {
  3. if (check_key_pressing())
  4. setup_recovery_env();
  5. else if (check_recovery_cmd_file()) {
  6. puts("Recovery command file founded!\n");
  7. setup_recovery_env();
  8. }
  9. }

这里首先检测是否有合法的按键按下,如果有的话就配置环境变量进入recovery

没有按键就检测uboot命令文件,看是不是主系统要求进入recovery

因此我们这里的重点是check_key_pressing()这个函数,仔细研究发现这个函数用的是uboot

标准的gpio驱动,官方给我们移植的uboot里面并没有初始化这个驱动,而是自己另外写的。也就是说

我们调用check_key_pressing()这个函数永远都返回0值而执行else if (check_recovery_cmd_file())这一句

我们来看 check_recovery_cmd_file()

  1. int check_recovery_cmd_file(void)
  2. {
  3. int button_pressed = 0;
  4. int recovery_mode = 0;
  5. recovery_mode = check_and_clean_recovery_flag();//读取kernel的recovery标志位,如果有的话就要进入recovery
  6. /* Check Recovery Combo Button press or not. */
  7. mxc_iomux_v3_setup_pad(MX6X_IOMUX(PAD_GPIO_5__GPIO_1_5));   //初始化vol down的gpio
  8. gpio_direction_input(GPIO_VOL_DN_KEY);
  9. if (gpio_get_value(GPIO_VOL_DN_KEY) == 0) { /* VOL_DN key is low assert *///如果vol down已经按下
  10. button_pressed = 1;
  11. printf("Recovery key pressed\n");
  12. }
  13. return recovery_mode || button_pressed; //返回进入recovery
  14. }

也就是说官方修改的uboot走了偷懒的方法,直接在check_recovery_cmd_file()增加了一个按键的盘定。很不正规

因此我们下一步要修改它,从官方的基础上走,我们也不走标准uboot 按键驱动,而是自己写。

修改之前先来看原版fastboot怎么进入的

  1. /* export to lib_arm/board.c */
  2. void check_fastboot_mode(void)
  3. {
  4. if (fastboot_check_and_clean_flag())
  5. do_fastboot(NULL, 0, 0, 0);
  6. }

这里调用fastboot_check_and_clean_flag()来判定是否进入fastboot

  1. /* check if the recovery bit is set by kernel, it can be set by kernel
  2. * issue a command '# reboot fastboot' */
  3. int fastboot_check_and_clean_flag(void)
  4. {
  5. int flag_set = 0;
  6. u32 reg;
  7. reg = readl(SRC_BASE_ADDR + SRC_GPR10);
  8. flag_set = !!(reg & ANDROID_FASTBOOT_BOOT);
  9. /* clean it in case looping infinite here.... */
  10. if (flag_set) {
  11. reg &= ~ANDROID_FASTBOOT_BOOT;
  12. writel(reg, SRC_BASE_ADDR + SRC_GPR10);
  13. }
  14. return flag_set;
  15. }

从这里看出,要进入进入fastboot,只能检测(SRC_BASE_ADDR + SRC_GPR10)寄存器的

ANDROID_FASTBOOT_BOOT位是否被kernel置位,并没有按键,因此我们的板子不可能靠

按键进入fastboot的实际情况也确实这样。因此我们要修改这一块,由于我们的cpu在power键按住5s

以后会强制关机。因此开机后我们必须松开power键,我们板子检测的按键只能是1个。开机时vol up键进入

recovery,按住vol down进入fastboot模式。我们修改代码如下

新建个按键检测函数check_key()

  1. int check_key(void)
  2. {
  3. #define PRESSED_VOLUP 1
  4. #define PRESSED_VOLDOWN 2
  5. #define KEY_MASK  (PRESSED_VOLUP|PRESSED_VOLDOWN)
  6. #define RECOVERY_KEY_MASK (PRESSED_VOLUP)
  7. #define FASTBOOT_KEY_MASK (PRESSED_VOLDOWN)
  8. int state = 0;
  9. mxc_iomux_v3_setup_pad(MX6X_IOMUX(PAD_GPIO_5__GPIO_1_5));//vol down
  10. mxc_iomux_v3_setup_pad(MX6X_IOMUX(PAD_GPIO_5__GPIO_1_4));//vol up
  11. gpio_direction_input(GPIO_VOL_DN_KEY);
  12. gpio_direction_input(GPIO_VOL_UP_KEY);
  13. if (gpio_get_value(GPIO_VOL_UP_KEY) == 0)
  14. state |= PRESSED_VOLUP;
  15. if (gpio_get_value(GPIO_VOL_DN_KEY) == 0)
  16. state |= PRESSED_VOLDOWN;
  17. //如果摁下power+voldown就进入fastboot 这个的优先级要比recovery高。
  18. //就算同时按下power+volup+voldown三个键也要进入fastboot模式
  19. if ((state & KEY_MASK) == FASTBOOT_KEY_MASK)
  20. return 1;
  21. if(((state & KEY_MASK) == FASTBOOT_KEY_MASK))
  22. return 2;
  23. return 0;
  24. }

主函数判定的代码段修改为

  1. if (check_key()==1)
  2. do_fastboot(NULL, 0, 0, 0);
  3. if (check_key()==2)
  4. setup_recovery_env();
  5. if (check_and_clean_recovery_flag()) {
  6. setup_recovery_env();
  7. }
  8. if (fastboot_check_and_clean_flag())
  9. do_fastboot(NULL, 0, 0, 0);

这样我们的启动模式按键就修改完成了,编译后测试成功。

下面我们还有代码没有分析完:uboot的主循环:main_loop()

代码在:\bootable\bootloader\uboot-imx\common\main.c

  1. void main_loop (void)
  2. {
  3. #ifndef CONFIG_SYS_HUSH_PARSER
  4. static char lastcommand[CONFIG_SYS_CBSIZE] = { 0, };
  5. int len;
  6. int rc = 1;
  7. int flag;
  8. #endif
  9. #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
  10. char *s;
  11. int bootdelay;
  12. #endif
  13. #ifdef CONFIG_PREBOOT
  14. char *p;
  15. #endif
  16. #ifdef CONFIG_BOOTCOUNT_LIMIT
  17. unsigned long bootcount = 0;
  18. unsigned long bootlimit = 0;
  19. char *bcs;
  20. char bcs_set[16];
  21. #endif /* CONFIG_BOOTCOUNT_LIMIT */
  22. #if defined(CONFIG_VFD) && defined(VFD_TEST_LOGO)
  23. ulong bmp = 0;      /* default bitmap */
  24. extern int trab_vfd (ulong bitmap);
  25. #ifdef CONFIG_MODEM_SUPPORT
  26. if (do_mdm_init)
  27. bmp = 1;    /* alternate bitmap */
  28. #endif
  29. trab_vfd (bmp);
  30. #endif  /* CONFIG_VFD && VFD_TEST_LOGO */
  31. #if defined(CONFIG_UPDATE_TFTP)
  32. update_tftp ();
  33. #endif /* CONFIG_UPDATE_TFTP */
  34. #ifdef CONFIG_BOOTCOUNT_LIMIT
  35. bootcount = bootcount_load();
  36. bootcount++;
  37. bootcount_store (bootcount);
  38. sprintf (bcs_set, "%lu", bootcount);
  39. setenv ("bootcount", bcs_set);
  40. bcs = getenv ("bootlimit");
  41. bootlimit = bcs ? simple_strtoul (bcs, NULL, 10) : 0;
  42. #endif /* CONFIG_BOOTCOUNT_LIMIT */
  43. #ifdef CONFIG_MODEM_SUPPORT
  44. debug ("DEBUG: main_loop:   do_mdm_init=%d\n", do_mdm_init);
  45. if (do_mdm_init) {
  46. char *str = strdup(getenv("mdm_cmd"));
  47. setenv ("preboot", str);  /* set or delete definition */
  48. if (str != NULL)
  49. free (str);
  50. mdm_init(); /* wait for modem connection */
  51. }
  52. #endif  /* CONFIG_MODEM_SUPPORT */
  53. #ifdef CONFIG_VERSION_VARIABLE
  54. {
  55. extern char version_string[];
  56. setenv ("ver", version_string);  /* set version variable */
  57. }
  58. #endif /* CONFIG_VERSION_VARIABLE */
  59. #ifdef CONFIG_SYS_HUSH_PARSER
  60. u_boot_hush_start ();
  61. #endif
  62. #if defined(CONFIG_HUSH_INIT_VAR)
  63. hush_init_var ();
  64. #endif
  65. #ifdef CONFIG_AUTO_COMPLETE
  66. install_auto_complete();
  67. #endif
  68. #ifdef CONFIG_PREBOOT
  69. if ((p = getenv ("preboot")) != NULL) {
  70. # ifdef CONFIG_AUTOBOOT_KEYED
  71. int prev = disable_ctrlc(1);    /* disable Control C checking */
  72. # endif
  73. # ifndef CONFIG_SYS_HUSH_PARSER
  74. run_command (p, 0);
  75. # else
  76. parse_string_outer(p, FLAG_PARSE_SEMICOLON |
  77. FLAG_EXIT_FROM_LOOP);
  78. # endif
  79. # ifdef CONFIG_AUTOBOOT_KEYED
  80. disable_ctrlc(prev);    /* restore Control C checking */
  81. # endif
  82. }
  83. #endif /* CONFIG_PREBOOT */
  84. #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
  85. s = getenv ("bootdelay");
  86. bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;//计算bootdelay
  87. debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);
  88. # ifdef CONFIG_BOOT_RETRY_TIME
  89. init_cmd_timeout ();
  90. # endif /* CONFIG_BOOT_RETRY_TIME */
  91. #ifdef CONFIG_POST
  92. if (gd->flags & GD_FLG_POSTFAIL) {
  93. s = getenv("failbootcmd");
  94. }
  95. else
  96. #endif /* CONFIG_POST */
  97. #ifdef CONFIG_BOOTCOUNT_LIMIT
  98. if (bootlimit && (bootcount > bootlimit)) {
  99. printf ("Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n",
  100. (unsigned)bootlimit);
  101. s = getenv ("altbootcmd");
  102. }
  103. else
  104. #endif /* CONFIG_BOOTCOUNT_LIMIT */
  105. s = getenv ("bootcmd");//得到bootcmd命令
  106. debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
  107. //每10ms从控制台读取一个字符,并且显示倒计时。如果读取成功的话就继续执行main_loop代码,
  108. //如果失败的话就执行下面的run_command(s,0)
  109. if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
  110. # ifdef CONFIG_AUTOBOOT_KEYED
  111. int prev = disable_ctrlc(1);    /* disable Control C checking */
  112. # endif
  113. # ifndef CONFIG_SYS_HUSH_PARSER
  114. run_command (s, 0);//执行 bootcmd命令
  115. # else
  116. parse_string_outer(s, FLAG_PARSE_SEMICOLON |
  117. FLAG_EXIT_FROM_LOOP);
  118. # endif
  119. # ifdef CONFIG_AUTOBOOT_KEYED
  120. disable_ctrlc(prev);    /* restore Control C checking */
  121. # endif
  122. }
  123. # ifdef CONFIG_MENUKEY
  124. if (menukey == CONFIG_MENUKEY) {
  125. s = getenv("menucmd");
  126. if (s) {
  127. # ifndef CONFIG_SYS_HUSH_PARSER
  128. run_command (s, 0);
  129. # else
  130. parse_string_outer(s, FLAG_PARSE_SEMICOLON |
  131. FLAG_EXIT_FROM_LOOP);
  132. # endif
  133. }
  134. }
  135. #endif /* CONFIG_MENUKEY */
  136. #endif  /* CONFIG_BOOTDELAY */
  137. #ifdef CONFIG_AMIGAONEG3SE
  138. {
  139. extern void video_banner(void);
  140. video_banner();
  141. }
  142. #endif
  143. /*
  144. * Main Loop for Monitor Command Processing
  145. */
  146. #ifdef CONFIG_SYS_HUSH_PARSER
  147. parse_file_outer();
  148. /* This point is never reached */
  149. for (;;);
  150. #else
  151. for (;;) {  //如果bootdelay时候有按键 就进入命令处理模式
  152. #ifdef CONFIG_BOOT_RETRY_TIME
  153. if (rc >= 0) {
  154. /* Saw enough of a valid command to
  155. * restart the timeout.
  156. */
  157. reset_cmd_timeout();
  158. }
  159. #endif
  160. len = readline (CONFIG_SYS_PROMPT);//从控制台读取一行数据,以回车为标志
  161. flag = 0;   /* assume no special flags for now */
  162. if (len > 0)
  163. z (lastcommand, console_buffer);
  164. else if (len == 0)
  165. flag |= CMD_FLAG_REPEAT;
  166. #ifdef CONFIG_BOOT_RETRY_TIME
  167. else if (len == -2) {
  168. /* -2 means timed out, retry autoboot
  169. */
  170. puts ("\nTimed out waiting for command\n");
  171. # ifdef CONFIG_RESET_TO_RETRY
  172. /* Reinit board to run initialization code again */
  173. do_reset (NULL, 0, 0, NULL);
  174. # else
  175. return;     /* retry autoboot */
  176. # endif
  177. }
  178. #endif
  179. if (len == -1)
  180. puts ("<INTERRUPT>\n");
  181. else
  182. rc = run_command (lastcommand, flag);//处理这条命令
  183. if (rc <= 0) {
  184. /* invalid command or not repeatable, forget it */
  185. lastcommand[0] = 0;
  186. }
  187. }
  188. #endif /*CONFIG_SYS_HUSH_PARSER*/
  189. }

到了这里整个的uboot流程已经走完了。从这里可以知道,uboot正式运行以后,实现的所有功能都是通过命令实现的,要继续分析的话,就要分析uboot的命令的实现了。

我们在下一篇文章里面讲述uboot命令是怎么实现的,kernel是怎么启动的。

uboot流程分析--修改android启动模式按键【转】的更多相关文章

  1. android 启动模式介绍

    Android启动模式 (1)Task:与Android系统是个多任务的系统中的任务是不同的.后者更倾向于多进程和多线程来说的,而这里的任务与application(应用程序)和activity(活动 ...

  2. Android 启动模式--任务(Task)--桟 的误区

    Android 启动模式--任务(Task)--桟 的误区 写这篇文章是因为前几天的一次面试,面试官说SingleInstance模式会新建一个桟,而SingleTask不会.首先不说这个对不对(非要 ...

  3. u-boot 流程分析

    u-boot 介绍: 对于计算机来说 , 从一开始上机通电是无法直接启动操作系统的 , 这中间需要一个引导过程 , 嵌入式Linux系统同样离不开引导程序 ,  这个启动程序就叫启动加载程序(Boot ...

  4. android启动模式2

    Android中的启动模式(下) 在这篇文章中,我会继续跟大家分享有关于Android中启动模式的相关知识.当然,如果对这个启动模式还不完全了解或者没有听过的话,可以先看看我之前写的有关于这个知识点的 ...

  5. Uboot流程分析

    1. uboot的配置分析 1).配置入口分析 首先分析配置: 从make mx6dl_sabresd_android_config可知配置项,搜索Makefile: mx6solo_sabresd_ ...

  6. 我所理解的Android 启动模式

    首先,这是从 一个开源网站转载的,觉得写得不错,对我们之前理解的activity的启动模式是一个新的理解方式,并给出实际的应用场景. 任务栈是什么 任务栈Task,是一种用来放置Activity实例的 ...

  7. Android启动模式

    在Android中每个界面都是一个Activity,切换界面操作其实是多个不同Activity之间的实例化操作.在Android中Activity的启动模式决定了Activity的启动运行方式. An ...

  8. Android启动模式launchMode

    在Android里,有4种Activity的启动模式并分别介绍下: standard singleTop singleTask singleInstance AndroidManifest.xml配置 ...

  9. Android启动模式(三种)

    1,标准启动模式 通过任务栈,每点一次button,将每一个实例都压入,然后点返回键时候,就弹出之前压入的实例. 每一次的地址都是不同的 测试代码:通过创建一个button和textView来显示本身 ...

随机推荐

  1. Python之IO编程

    前言:由于程序和运行数据是在内存中驻留的,由CPU这个超快的计算核心来执行.当涉及到数据交换的地方,通常是磁盘.网络等,就需要IO接口.由于CPU和内存的速度远远高于外设的速度,那么在IO编程中就存在 ...

  2. VM 安装ubuntu16.04简易方法

    在已经安装好VM10虚拟机后 首先文件—>新建虚拟机—>典型(标准)  选择稍后安装操作系统,后续要使用的是已经下载好的ubuntu16.04镜像  选择操作系统是linux ,版本是ub ...

  3. python爬虫29 | 使用scrapy爬取糗事百科的例子,告诉你它有多厉害!

    是时候给你说说 爬虫框架了 使用框架来爬取数据 会节省我们更多时间 很快就能抓取到我们想要抓取的内容 框架集合了许多操作 比如请求,数据解析,存储等等 都可以由框架完成 有些小伙伴就要问了 你他妈的 ...

  4. 3.6.5 空串与Null串

        空串""是长度为0的字符串.可以调用以下代码检查一个字符串是否为空:                 String s = "greeting";    ...

  5. hibernate的QBC查询之Criteria用法

    //return (DeliverCost) super.getSession().createCriteria(getMyClass()).add(Restrictions.eq("isd ...

  6. 树上启发式合并(DSU on tree)

    //heavy-light decomposition style .//http://codeforces.com/blog/entry/44351 int cnt[maxn]; bool big[ ...

  7. 52. spring boot日志升级篇—log4j多环境不同日志级别的控制【从零开始学Spring Boot】

    在上一章节中我们介绍了,仅通过log4j-spring.properties对日志级别进行控制,对于需要多环境部署的环境不是很方便,可能我们在开发环境大部分模块需要采用DEBUG级别,在测试环境可能需 ...

  8. [luoguP2486] [SDOI2011]染色(树链剖分)

    传送门 就是个模板啦 记录每一个点的左端点颜色和右端点颜色和当前端点颜色段数. 合并时如果左孩子右端点和右孩子左端点不同就 ans-- 在重链上跳的时候别忘记统计一下 ——代码 #include &l ...

  9. linux下安装并配置vim

    1.安装:sudo apt-get install vim-gtk  安装好后vim,并按“tab”键,可以看到vim的存在,则安装好2.设置更加人性化:sudo vim /etc/vim/vimrc ...

  10. Linux command2

    . CentOS 想查看哪个port开了,却提示命令无效 # yum -y install net-tools 2. How to install "wget" command i ...