基于IMX6Q的uboot启动流程分析(3):_main函数之relocate_code与board_init_r

基于IMX6Q的uboot启动流程分析(1):uboot入口函数
基于IMX6Q的uboot启动流程分析(2):_main函数之board_init_f
基于IMX6Q的uboot启动流程分析(3):_main函数之relocate_code与board_init_r
基于IMX6Q的uboot启动流程分析(4):uboot中的串口设备

第3章:_main函数之relocate_code与board_init_r

3.1 relocate_code函数

上一小节,介绍了board_init_f函数,主要的是对整个DRAM的内存进行了分配,以便uboot的重定位。

3.1.1 设置中间环境

在调用relocate_code函数前,需设置中间环境,更新分配DRAM后的sp指针值和gd指针值,其内容如下

	ldr	r0, [r9, #GD_START_ADDR_SP]	/* sp = gd->start_addr_sp */ //新的sp
	bic	r0, r0, #7	/* 8-byte alignment for ABI compliance */
	mov	sp, r0
	ldr	r9, [r9, #GD_NEW_GD]		/* r9 <- gd->new_gd */

	adr	lr, here
	ldr	r0, [r9, #GD_RELOC_OFF]		/* r0 = gd->reloc_off */
	add	lr, lr, r0
#if defined(CONFIG_CPU_V7M)
	orr	lr, #1				/* As required by Thumb-only */
#endif
	ldr	r0, [r9, #GD_RELOCADDR]		/* r0 = gd->relocaddr */
	b	relocate_code

将新的sp地址赋值给r0 = 0x4DF68F50

3.1.2 relocate_code函数详解

uboot重定位主要由relocate_code函数实现,其定义在arch/arm/lib/relocate.S文件中,内容为:

 80 ENTRY(relocate_code)
 81         ldr     r1, =__image_copy_start /* r1 <- SRC &__image_copy_start */
 82         subs    r4, r0, r1              /* r4 <- relocation offset */
 83         beq     relocate_done           /* skip relocation */
 84         ldr     r2, =__image_copy_end   /* r2 <- SRC &__image_copy_end */
 85 
 86 copy_loop:
 87         ldmia   r1!, {r10-r11}          /* copy from source address [r1]    */
 88         stmia   r0!, {r10-r11}          /* copy to   target address [r0]    */
 89         cmp     r1, r2                  /* until source end address [r2]    */
 90         blo     copy_loop
 91 
 92         /*
 93          * fix .rel.dyn relocations
 94          */
 95         ldr     r2, =__rel_dyn_start    /* r2 <- SRC &__rel_dyn_start */
 96         ldr     r3, =__rel_dyn_end      /* r3 <- SRC &__rel_dyn_end */
 97 fixloop:
 98         ldmia   r2!, {r0-r1}            /* (r0,r1) <- (SRC location,fixup) */
 99         and     r1, r1, #0xff
100         cmp     r1, #R_ARM_RELATIVE
101         bne     fixnext
102 
103         /* relative fix: increase location by offset */
104         add     r0, r0, r4
105         ldr     r1, [r0]
106         add     r1, r1, r4
107         str     r1, [r0]
108 fixnext:
109         cmp     r2, r3
110         blo     fixloop
111 
112 relocate_done:
113 
114 #ifdef __XSCALE__
115         /*
116          * On xscale, icache must be invalidated and write buffers drained,
117          * even with cache disabled - 4.2.7 of xscale core developer's manual
118          */
119         mcr     p15, 0, r0, c7, c7, 0   /* invalidate icache */
120         mcr     p15, 0, r0, c7, c10, 4  /* drain write buffer */
121 #endif
122 
123         /* ARMv4- don't know bx lr but the assembler fails to see that */
124 
125 #ifdef __ARM_ARCH_4__
126         mov     pc, lr
127 #else
128         bx      lr
129 #endif
130 
131 ENDPROC(relocate_code)
  • 第81行,将__image_copy_start的值赋值给r1寄存器。由uboot.map文件得知

    __image_copy_start = 0x17800000
    
  • 第82行,r4寄存器保存重定位前后位置的偏移量。r4 = r0 - r1 = 0x4DF68F50 - 0x17800000 = 0x36768F50。

  • 第83行,跳转relocate_done函数,判断uboot重定位的目的地址是否和uboot源地址是否相等,如果相等的话,表示不需要重定位,跳到relocate_done处,继续运行,如果不相等的话,则是需要进行重定位。

  • 第84行,r2寄存器保存uboot复制结束的地址__image_copy_end。由uboot.map文件得知,__image_copy_end = 0x1787ba9c。

  • 第86-90行,copy_loop区域,执行拷贝,将uboot从低地址重定位到高地址。重定位过程描述为:

    • 第一:从r1,也就是__image_copy_start开始,读取uboot代码到r10和r11寄存器,一次就拷贝两个32位的数据,r1自动更新,保存下一个需要拷贝的地址,
    • 第二:将r10和r11里面的数据,写到r0保存的地址,也就是uboot重定位的目的地址,r0自动更新。
    • 第三:比较r1和r2是否相等,也就是判断uboot代码是否拷贝完成,如果没完成的话,跳转到copy_loop处,继续循环,直到uboot拷贝完成。
  • 第95-110行,重定位.rel.dyn段,.rel.dyn段是存放.text段中需要重定位地址的集合。

补充:

一个可执行的bin文件,它的链接地址和运行地址一定要相等,也就是链接到哪个地址,运行之前就需要拷贝到哪个地址中进行运行,在前面的重定位后,运行地址和链接地址就不一样了,这样在进行寻址就会出问题,对.rel.dyn的定位问题进行修复,就是为了解决该问题。

至此uboot的重定位工作已经完成,将保存在低地址的uboot,自搬移到高地址中执行。
基于IMX6Q的uboot启动流程分析(3):_main函数之relocate_code与board_init_r_第1张图片

3.1.3 relocate_vectors函数详解

在重定位uboot后,需要调用relocate_vectors函数,来重定位向量表。函数内容为:

ENTRY(relocate_vectors)

#ifdef CONFIG_CPU_V7M
	/*
	 * On ARMv7-M we only have to write the new vector address
	 * to VTOR register.
	 */
	ldr	r0, [r9, #GD_RELOCADDR]	/* r0 = gd->relocaddr */
	ldr	r1, =V7M_SCB_BASE
	str	r0, [r1, V7M_SCB_VTOR]
#else
#ifdef CONFIG_HAS_VBAR
	/*
	 * If the ARM processor has the security extensions,
	 * use VBAR to relocate the exception vectors.
	 */
	ldr	r0, [r9, #GD_RELOCADDR]	/* r0 = gd->relocaddr */
	mcr     p15, 0, r0, c12, c0, 0  /* Set VBAR */
#else
	...
#endif
#endif
	bx	lr

ENDPROC(relocate_vectors)

在IMX6Q中,定义了CONFIG_HAS_VBAR,因此这个函数只用执行以下语句:

	ldr	r0, [r9, #GD_RELOCADDR]	/* r0 = gd->relocaddr */
	mcr     p15, 0, r0, c12, c0, 0  /* Set VBAR */

首先是将gd->relocaddr的值赋给r0,也就是r0里面保存重定位后uboot的首地址,中断向量表也是从这个首地址开始存储的,接下来,使用mcr指令,将r0的值写到CP15的VBAR寄存器中,其实就是将新的中断向量表首地址写到VBAR寄存器中,设置中断向量表偏移。

至此uboot的重定位与中断向量表重定位的工作已经完成。

3.2 board_init_r函数

2.1节对board_init_f函数进行介绍,其作用gd结构体的成员变量,以及对DRAM内存进行规划。而本节board_init_r函数是将一些板子需要的外设进行初始化。

3.2.1 设置board_init_r环境

调用board_init_r函数前,需要设置一些参数,其代码为:

	bl	c_runtime_cpu_setup	/* we still call old routine here */
#endif
#if !defined(CONFIG_SPL_BUILD) || CONFIG_IS_ENABLED(FRAMEWORK)

#if !defined(CONFIG_SPL_BUILD) || !defined(CONFIG_SPL_EARLY_BSS)
	CLEAR_BSS
#endif
	...
#if ! defined(CONFIG_SPL_BUILD)
	bl coloured_LED_init
	bl red_led_on
#endif
	/* call board_init_r(gd_t *id, ulong dest_addr) */
	mov     r0, r9                  /* gd_t */
	ldr	r1, [r9, #GD_RELOCADDR]	/* dest_addr */
	/* call board_init_r */
#if CONFIG_IS_ENABLED(SYS_THUMB_BUILD)
	ldr	lr, =board_init_r	/* this is auto-relocated! */
	bx	lr
#else
	ldr	pc, =board_init_r	/* this is auto-relocated! */
#endif
	/* we should not return here. */
#endif

首先是调用了函数c_runtime_cpu_setup函数,关闭cache。然后调用CLEAR_BSS清除bss段。接着将gd地址赋值给r0,将gd->relocaddr地址赋值给r1。board_init_r(gd_t *id, ulong dest_addr)函数具有两个参数,第一个参数为gd指针的值,第二个参数为gd->relocaddr。最后跳转到board_init_r函数执行。

3.2.2 board_init_r函数详解

board_init_r函数定义在common/board_r.c文件中。函数的主要内容为:

void board_init_r(gd_t *new_gd, ulong dest_addr)
{
    ...
#ifdef CONFIG_NEEDS_MANUAL_RELOC
	int i;
#endif

#if !defined(CONFIG_X86) && !defined(CONFIG_ARM) && !defined(CONFIG_ARM64)
	gd = new_gd;
#endif
	gd->flags &= ~GD_FLG_LOG_READY;

#ifdef CONFIG_NEEDS_MANUAL_RELOC
	for (i = 0; i < ARRAY_SIZE(init_sequence_r); i++)
		init_sequence_r[i] += gd->reloc_off;
#endif

	if (initcall_run_list(init_sequence_r))
		hang();

	/* NOTREACHED - run_main_loop() does not return */
	hang();
}

该函数的重点是initcall_run_list(init_sequence_r)init_sequence_r是一个函数集合的数组,也就是函数初始化序列。其内容为:

641 static init_fnc_t init_sequence_r[] = {  //函数初始化序列
642         initr_trace,
643         initr_reloc,
644         /* TODO: could x86/PPC have this also perhaps? */
645 #ifdef CONFIG_ARM
646         initr_caches,
647         /* Note: For Freescale LS2 SoCs, new MMU table is created in DDR.
648          *       A temporary mapping of IFC high region is since removed,
649          *       so environmental variables in NOR flash is not available
650          *       until board_init() is called below to remap IFC to high
651          *       region.
652          */
653 #endif
654         initr_reloc_global_data,
655 #if defined(CONFIG_SYS_INIT_RAM_LOCK) && defined(CONFIG_E500)
656         initr_unlock_ram_in_cache,
657 #endif
658         initr_barrier,
659         initr_malloc,
660         log_init,
661         initr_bootstage,        /* Needs malloc() but has its own timer */
662 #if defined(CONFIG_CONSOLE_RECORD)
663         console_record_init,
664 #endif
665 #ifdef CONFIG_SYS_NONCACHED_MEMORY
666         noncached_init,
667 #endif
668         initr_of_live,
669 #ifdef CONFIG_DM
670         initr_dm,
671 #endif
672 #ifdef CONFIG_ADDR_MAP
673         initr_addr_map,
674 #endif
675 #if defined(CONFIG_ARM) || defined(CONFIG_NDS32) || defined(CONFIG_RISCV) || \
676         defined(CONFIG_SANDBOX)
677         board_init,     /* Setup chipselects */
678 #endif
679         /*
680          * TODO: printing of the clock inforamtion of the board is now
681          * implemented as part of bdinfo command. Currently only support for
682          * davinci SOC's is added. Remove this check once all the board
683          * implement this.
684          */
685 #ifdef CONFIG_CLOCKS
686         set_cpu_clk_info, /* Setup clock information */
687 #endif
688 #ifdef CONFIG_EFI_LOADER
689         efi_memory_init,
690 #endif
691         initr_binman,
692 #ifdef CONFIG_FSP_VERSION2
693         arch_fsp_init_r,
694 #endif
695         initr_dm_devices,
696         stdio_init_tables,
697         serial_initialize,
698         initr_announce,
699 #if CONFIG_IS_ENABLED(WDT)
700         initr_watchdog,
701 #endif
702         INIT_FUNC_WATCHDOG_RESET
703 #if defined(CONFIG_NEEDS_MANUAL_RELOC) && defined(CONFIG_BLOCK_CACHE)
704         blkcache_init,
705 #endif
706 #ifdef CONFIG_NEEDS_MANUAL_RELOC
707         initr_manual_reloc_cmdtable,
708 #endif
709         arch_initr_trap,
710 #if defined(CONFIG_BOARD_EARLY_INIT_R)
711         board_early_init_r,
712 #endif
713         INIT_FUNC_WATCHDOG_RESET
714 #ifdef CONFIG_POST
715         post_output_backlog,
716 #endif
717         INIT_FUNC_WATCHDOG_RESET
718 #if defined(CONFIG_PCI_INIT_R) && defined(CONFIG_SYS_EARLY_PCI_INIT)
719         /*
720          * Do early PCI configuration _before_ the flash gets initialised,
721          * because PCU resources are crucial for flash access on some boards.
722          */
723         pci_init,
724 #endif
725 #ifdef CONFIG_ARCH_EARLY_INIT_R
726         arch_early_init_r,
727 #endif
728         power_init_board,
729 #ifdef CONFIG_MTD_NOR_FLASH
730         initr_flash,
731 #endif
732         INIT_FUNC_WATCHDOG_RESET
733 #if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_X86)
734         /* initialize higher level parts of CPU like time base and timers */
735         cpu_init_r,
736 #endif
737 #ifdef CONFIG_CMD_NAND
738         initr_nand,
739 #endif
740 #ifdef CONFIG_CMD_ONENAND
741         initr_onenand,
742 #endif
743 #ifdef CONFIG_MMC
744         initr_mmc,
745 #endif
746 #ifdef CONFIG_XEN
747         xen_init,
748 #endif
749 #ifdef CONFIG_PVBLOCK
750         initr_pvblock,
751 #endif
752         initr_env,
753 #ifdef CONFIG_SYS_BOOTPARAMS_LEN
754         initr_malloc_bootparams,
755 #endif
756         INIT_FUNC_WATCHDOG_RESET
757         cpu_secondary_init_r,
758 #if defined(CONFIG_ID_EEPROM) || defined(CONFIG_SYS_I2C_MAC_OFFSET)
759         mac_read_from_eeprom,
760 #endif
761         INIT_FUNC_WATCHDOG_RESET
762 #if defined(CONFIG_PCI_INIT_R) && !defined(CONFIG_SYS_EARLY_PCI_INIT)
763         /*
764          * Do pci configuration
765          */
766         pci_init,
767 #endif
768         stdio_add_devices,
769         jumptable_init,
770 #ifdef CONFIG_API
771         api_init,
772 #endif
773         console_init_r,         /* fully init console as a device */
774 #ifdef CONFIG_DISPLAY_BOARDINFO_LATE
775         console_announce_r,
776         show_board_info,
777 #endif
778 #ifdef CONFIG_ARCH_MISC_INIT
779         arch_misc_init,         /* miscellaneous arch-dependent init */
780 #endif
781 #ifdef CONFIG_MISC_INIT_R
782         misc_init_r,            /* miscellaneous platform-dependent init */
783 #endif
784         INIT_FUNC_WATCHDOG_RESET
785 #ifdef CONFIG_CMD_KGDB
786         initr_kgdb,
787 #endif
788         interrupt_init,
789 #if defined(CONFIG_MICROBLAZE) || defined(CONFIG_M68K)
790         timer_init,             /* initialize timer */
791 #endif
792 #if defined(CONFIG_LED_STATUS)
793         initr_status_led,
794 #endif
795         /* PPC has a udelay(20) here dating from 2002. Why? */
796 #ifdef CONFIG_CMD_NET
797         initr_ethaddr,
798 #endif
799 #if defined(CONFIG_GPIO_HOG)
800         gpio_hog_probe_all,
801 #endif
802 #ifdef CONFIG_BOARD_LATE_INIT
803         board_late_init,
804 #endif
805 #ifdef CONFIG_FSL_FASTBOOT
806         initr_fastboot_setup,
807 #endif
808 #if defined(CONFIG_SCSI) && !defined(CONFIG_DM_SCSI)
809         INIT_FUNC_WATCHDOG_RESET
810         initr_scsi,
811 #endif
812 #ifdef CONFIG_BITBANGMII
813         bb_miiphy_init,
814 #endif
815 #ifdef CONFIG_PCI_ENDPOINT
816         pci_ep_init,
817 #endif
818 #ifdef CONFIG_CMD_NET
819         INIT_FUNC_WATCHDOG_RESET
820         initr_net,
821 #endif
822 #ifdef CONFIG_POST
823         initr_post,
824 #endif
825 #if defined(CONFIG_IDE) && !defined(CONFIG_BLK)
826         initr_ide,
827 #endif
828 #ifdef CONFIG_LAST_STAGE_INIT
829         INIT_FUNC_WATCHDOG_RESET
830         /*
831          * Some parts can be only initialized if all others (like
832          * Interrupts) are up and running (i.e. the PC-style ISA
833          * keyboard).
834          */
835         last_stage_init,
836 #endif
837 #ifdef CONFIG_CMD_BEDBUG
838         INIT_FUNC_WATCHDOG_RESET
839         bedbug_init,
840 #endif
841 #if defined(CONFIG_PRAM)
842         initr_mem,
843 #endif
844 #ifdef CONFIG_EFI_SETUP_EARLY
845         (init_fnc_t)efi_init_obj_list,
846 #endif
847 #if defined(AVB_RPMB) && !defined(CONFIG_SPL)
848         initr_avbkey,
849 #endif
850 #ifdef CONFIG_IMX_TRUSTY_OS
851         initr_tee_setup,
852 #endif
853 #ifdef CONFIG_FSL_FASTBOOT
854         initr_check_fastboot,
855 #endif
856 #ifdef CONFIG_DUAL_BOOTLOADER
857         initr_check_spl_recovery,
858 #endif
859         run_main_loop,
860 };
  • 第642行,initr_trace,该函数是与初始化和调试跟踪相关的内容。

  • 第643行,initr_reloc,该函数设置了gd->flags成员,标记uboot重定位完成。

  • 第646行,initr_reloc,该函数用于初始化cache,使能cache。

  • 第654行,initr_reloc_global_data,该函数用于初始化重定为后gd的一些成员变量。。

  • 第659行,initr_malloc,该函数用于初始化malloc。

    int board_init(void)
    {
    	/* address of boot parameters */
    	gd->bd->bi_boot_params = PHYS_SDRAM + 0x100;
    
    #if defined(CONFIG_DM_REGULATOR)
    	regulators_enable_boot_on(false);
    #endif
    
    #ifdef CONFIG_MXC_SPI
    	setup_spi();
    #endif
    
    #ifdef CONFIG_SYS_I2C
    	setup_i2c(1, CONFIG_SYS_I2C_SPEED, 0x7f, &i2c_pad_info1);
    #endif
    
    #if defined(CONFIG_PCIE_IMX) && !defined(CONFIG_DM_PCI)
    	setup_pcie();
    #endif
    
    #if defined(CONFIG_MX6DL) && defined(CONFIG_MXC_EPDC)
    	setup_epdc();
    #endif
    
    #ifdef CONFIG_FEC_MXC
    	setup_fec();
    #endif
    
    	return 0;
    }
    
  • 第696行,stdio_init_tables,该函数用于stdio相关初始化。

  • 第 697行,serial_initialize,该函数初始化串口相关东西。

  • 第738行,initr_nand,该函数用于nand flash初始化,需要时调用。

  • 第744行,initr_mmc该函数用来初始化和sd/mmc相关的接口,实际调用mmc_initialize函数实现,定义在drivers/mmc/mmc.c文件中,其内容为:

    int mmc_initialize(struct bd_info *bis)
    {
    	static int initialized = 0;
    	int ret;
    	if (initialized)	/* Avoid initializing mmc multiple times */
    		return 0;
    	initialized = 1;
    
    #if !CONFIG_IS_ENABLED(BLK)
    #if !CONFIG_IS_ENABLED(MMC_TINY)
    	mmc_list_init();
    #endif
    #endif
    	ret = mmc_probe(bis);
    	if (ret)
    		return ret;
    
    #ifndef CONFIG_SPL_BUILD
    	print_mmc_devices(',');
    #endif
    
    	mmc_do_preinit();
    	return 0;
    }
    
  • 第744行,initr_env,该函数用来初始化环境变量。

  • 第768行,stdio_add_devices,该函数用于初始化各种输入输出设备,例如LCD相关的设备。

  • 第769行,stdio_add_devices,该函数用来初始化跳转表相关的内容。

  • 第78行,interrupt_init,该函数用来初始化中断相关内容。IMX6Q为空,需要时使用。

  • 第797行,interrupt_init,该函数用于初始化网络地址,用于获取网卡的MAC地址。

  • 第803行,board_late_init,该函数用于板级后续的一些外设初始化。

  • 第806行,initr_fastboot_setup,初始化fastboot。

  • 第820行,initr_net,初始化以太网,实际调用eth_initialize函数实现,其定义在net/eth-uclass.c文件。

  • 第859行,run_main_loop,该函数主循环函数,用于处理输入的命令,也就是uboot进入了命令行终端模式,内容为:

    static int run_main_loop(void)
    {
    #ifdef CONFIG_SANDBOX
    	sandbox_main_loop_init();
    #endif
    	/* main_loop() can return to retry autoboot, if so just run it again */
    	for (;;)
    		main_loop();
    	return 0;
    }
    

    函数在无线循环执行main_loop函数,此函数将在下一小节详细介绍。

    至此board_init_r函数介绍完,主要是完成一些需要的外设初始化,不同的板子,会进行不同的初始化。

3.2.3 main_loop函数

main_loop函数主要作用是实现目标板与人的交互,其定义在common/main.c文件中,内容为:

 40 void main_loop(void)
 41 {
 42         const char *s;
 43 
 44         bootstage_mark_name(BOOTSTAGE_ID_MAIN_LOOP, "main_loop");
 45 
 46         if (IS_ENABLED(CONFIG_VERSION_VARIABLE))
 47                 env_set("ver", version_string);  /* set version variable */
 48 
 49         cli_init();
 50 
 51         if (IS_ENABLED(CONFIG_USE_PREBOOT))
 52                 run_preboot_environment_command();
 53 
 54         if (IS_ENABLED(CONFIG_UPDATE_TFTP))
 55                 update_tftp(0UL, NULL, NULL);
 56 
 57         if (IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK_EARLY))
 58                 efi_launch_capsules();
 59 
 60         s = bootdelay_process();
 61         if (cli_process_fdt(&s))
 62                 cli_secure_boot_cmd(s);
 63 
 64         autoboot_command(s);
 65 
 66         cli_loop();
 67         panic("No CLI available");
 68 }
  • 第60行,bootdelay_process,该函数获取bootdelaybootcmd参数的内容,返回值为环境变量bootcmd的值。

  • 第64行,autoboot_command,该函数的作用是,用于检测u-boot启动过程中的倒计时过程是否结束。倒计时结束之前是否被打断。函数定义在文件common/autoboot.c,其内容为:

    void autoboot_command(const char *s)
    {
    	debug("### main_loop: bootcmd=\"%s\"\n", s ? s : "");
    
    	if (s && (stored_bootdelay == -2 ||
    		 (stored_bootdelay != -1 && !abortboot(stored_bootdelay)))) {
    		bool lock;
    		int prev;
    
    		lock = IS_ENABLED(CONFIG_AUTOBOOT_KEYED) &&
    			!IS_ENABLED(CONFIG_AUTOBOOT_KEYED_CTRLC);
    		if (lock)
    			prev = disable_ctrlc(1); /* disable Ctrl-C checking */
    
    		run_command_list(s, -1, 0);
    
    		if (lock)
    			disable_ctrlc(prev);	/* restore Ctrl-C checking */
    	}
    
    	if (IS_ENABLED(CONFIG_USE_AUTOBOOT_MENUKEY) &&
    	    menukey == AUTOBOOT_MENUKEY) {
    		s = env_get("menucmd");
    		if (s)
    			run_command_list(s, -1, 0);
    	}
    }
    

    如果倒计时正常结束,那么将执行run_command_list,此函数会执行参数s指定的一系列命令,也就是bootcmd中配置中的命令,一般配置为linux内核启动命令,因此linux内核启动。

    如果在倒计时结束前按下回车键,run_command_list就不会执行,autoboot_command相当于空函数。

    run_command_list函数定义在common/cli.c文件,其内容为:

    int run_command_list(const char *cmd, int len, int flag)
    {
    	int need_buff = 1;
    	char *buff = (char *)cmd;	/* cast away const */
    	int rcode = 0;
    
    	if (len == -1) {
    		len = strlen(cmd);
    #ifdef CONFIG_HUSH_PARSER
    		/* hush will never change our string */
    		need_buff = 0;
    #else
    		/* the built-in parser will change our string if it sees \n */
    		need_buff = strchr(cmd, '\n') != NULL;
    #endif
    	}
    	if (need_buff) {
    		buff = malloc(len + 1);
    		if (!buff)
    			return 1;
    		memcpy(buff, cmd, len);
    		buff[len] = '\0';
    	}
    #ifdef CONFIG_HUSH_PARSER
    	rcode = parse_string_outer(buff, FLAG_PARSE_SEMICOLON);
    #else
    #ifdef CONFIG_CMDLINE
    	rcode = cli_simple_run_command_list(buff, flag);
    #else
    	rcode = board_run_command(buff);
    #endif
    #endif
    	if (need_buff)
    		free(buff);
    
    	return rcode;
    }
    

    主要工作内容为,调用parse_string_outer函数解析并执行bootcmd中配置中的命令。

  • 第66行,cli_init,该函数是uboot命令行处理函数,输入的各种命令,进行各种操作就是cli_loop函数来处理的,函数处理过程比较复杂,就不单独分析。

至此整个uboot2021启动流程分析完成,下面介绍uboot中的串口模块。

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