uboot_启动过程分析

uboot源码分析(分为两个阶段)

第一阶段:
	.globl _start		u-boot-1.1.6\cpu\arm920t\start.S
	_start:	b       reset


	reset:				u-boot-1.1.6\cpu\arm920t\start.S
		adr	r0, _start		/* r0 <- current position of code   */
		ldr	r1, _TEXT_BASE		/* test if we run from flash or RAM */
		cmp     r0, r1                  /* don't reloc during debug         */
		blne	cpu_init_crit
	stack_setup:
		ldr	r0, _TEXT_BASE		/* upper 128 KiB: relocated uboot   */
		sub	r0, r0, #CFG_MALLOC_LEN	/* malloc area                      */
		sub	r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo                        */
		sub	r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
	relocate:				/* relocate U-Boot to RAM	    */
		bl  CopyCode2Ram	/* r0: source, r1: dest, r2: size */			u-boot-1.1.6\board\100ask24x0\boot_init.c
	clear_bss:
	SetLoadFlag:
		ldr	pc, _start_armboot
		_start_armboot:	.word start_armboot				u-boot-1.1.6\lib_arm\board.c
		

	cpu_init_crit:		u-boot-1.1.6\cpu\arm920t\start.S
			bl	lowlevel_init			u-boot-1.1.6\board\smdk2410\lowlevel_init.S
第二阶段:(进入命令行状态)
	void start_armboot (void)			u-boot-1.1.6\lib_arm\board.c
	{
	//				init_fnc_t *init_sequence[] = {
	//					cpu_init,		/* basic cpu dependent setup */
	//					board_init,		/* basic board dependent setup */
	//					interrupt_init,		/* set up exceptions */
	//					env_init,		/* initialize environment */
	//					init_baudrate,		/* initialze baudrate settings */
	//					serial_init,		/* serial communications setup */
	//					console_init_f,		/* stage 1 init of console */
	//					display_banner,		/* say that we are here */
	//				#if defined(CONFIG_DISPLAY_CPUINFO)
	//					print_cpuinfo,		/* display cpu info (and speed) */
	//				#endif
	//				#if defined(CONFIG_DISPLAY_BOARDINFO)
	//					checkboard,		/* display board info */
	//				#endif
	//					dram_init,		/* configure available RAM banks */
	//					display_dram_config,
	//					NULL,
	//				};

		for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
			if ((*init_fnc_ptr)() != 0) {
				hang ();
			}
		}
		size = flash_init ();
		env_relocate ();
		cs8900_get_enetaddr (gd->bd->bi_enetaddr);
		for (;;) {
			main_loop ();						u-boot-1.1.6\common\main.c
		}
	}

	void main_loop (void)
	{
		s = getenv ("bootcmd");
		if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
				printf("Booting Linux ...\n");            
				run_command (s, 0);
		}
		
		for (;;) {
			strcpy (lastcommand, console_buffer);
			rc = run_command (lastcommand, flag);	
		}
	}

	int run_command (const char *cmd, int flag)		u-boot-1.1.6\common\main.c
	{
		process_macros (token, finaltoken);
		if ((argc = parse_line (finaltoken, argv)) == 0) {
		if ((cmdtp = find_cmd(argv[0])) == NULL) {
	}

	cmd_tbl_t *find_cmd (const char *cmd)		u-boot-1.1.6\common\command.c
	{
		cmd_tbl_t *cmdtp_temp = &__u_boot_cmd_start;	/*Init value */
		for (cmdtp = &__u_boot_cmd_start;
			 cmdtp != &__u_boot_cmd_end;
			 cmdtp++) {
	}

				u-boot-1.1.6\board\smdk2410/u-boot.lds
					__u_boot_cmd_start = .;
					.u_boot_cmd : { *(.u_boot_cmd) }
					__u_boot_cmd_end = .;


						u-boot-1.1.6\include\command.h
				#define Struct_Section  __attribute__ ((unused,section (".u_boot_cmd")))
				#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \										//本质是定义结构体
				cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage, help}


				U_BOOT_CMD(									//本质是定义结构体
					help,	CFG_MAXARGS,	1,	do_help,
					"help    - print online help\n",
					"[command ...]\n"
					"    - show help information (for 'command')\n"
					"'help' prints online help for the monitor commands.\n\n"
					"Without arguments, it prints a short usage message for all commands.\n\n"
					"To get detailed help information for specific commands you can type\n"
				  "'help' with one or more command names as arguments.\n"
				);

				int do_help (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
				{

				}

Uboot启动内核:

	bootcmd命令值为:nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0
					从NAND的的kernel分区读出内核放到0x30007FC0(并不是固定地址,可随意指定,因为bootm时会根据ih_load去判断加载),并启动
					分区名字kernel不重要,其代表 地址和长度
					等效于:nand read.jffs2 0x30007FC0 0x00060000 0x00200000;bootm 0x30007FC0
					
	void main_loop (void)
	{
		s = getenv ("bootcmd");
		if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
				printf("Booting Linux ...\n");            
				run_command (s, 0);
		}
		......
	}


	#define MTDIDS_DEFAULT "nand0=nandflash0"											u-boot-1.1.6\include\configs\100ask24x0.h
	#define MTDPARTS_DEFAULT "mtdparts=nandflash0:256k@0(bootloader)," \				
								"128k(params)," \
								"2m(kernel)," \										//分区是在源码中写死的
								"-(root)"

	int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])				u-boot-1.1.6\common\cmd_nand.c
	{
	    /* read write */
		if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) {
		ret = nand_read_opts(nand, &opts);
		ret = nand_write_opts(nand, &opts);
	}	


			typedef struct image_header {
				uint32_t	ih_magic;	/* Image Header Magic Number	*/
				uint32_t	ih_hcrc;	/* Image Header CRC Checksum	*/
				uint32_t	ih_time;	/* Image Creation Timestamp	*/
				uint32_t	ih_size;	/* Image Data Size		*/
				uint32_t	ih_load;	/* Data	 Load  Address		*/				重要:加载地址,可理解为运行时的地址
				uint32_t	ih_ep;		/* Entry Point Address		*/				重要:入口地址
				uint32_t	ih_dcrc;	/* Image Data CRC Checksum	*/
				uint8_t		ih_os;		/* Operating System		*/
				uint8_t		ih_arch;	/* CPU architecture		*/
				uint8_t		ih_type;	/* Image Type			*/
				uint8_t		ih_comp;	/* Compression Type		*/
				uint8_t		ih_name[IH_NMLEN];	/* Image Name		*/
			} image_header_t;
			
	image_header_t header;
	int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
	{
		image_header_t *hdr = &header;								//uImage = 头部 + 真正内核;	0x30007FC0 + 64(头部) = 0x30008000(真正内核的地址)
		memmove (&header, (char *)addr, sizeof(image_header_t));
		
		if(ntohl(hdr->ih_load) == data) {							//如果内核已在正确地址上,不需移动
			printf ("   XIP %s ... ", name);
		} else {
			memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len);		//将内核移到正确的地址
		}
		
		do_bootm_linux  (cmdtp, flag, argc, argv,					//启动
		 addr, len_ptr, verify);


	}

			
	void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],					u-boot-1.1.6\lib_arm\armlinux.c
				 ulong addr, ulong *len_ptr, int verify)
	{
		char *commandline = getenv ("bootargs");
		
		//设置启动参数,在某个地址(0x30000100),按某种格式(TAG),保存数据
		#if defined (CONFIG_SETUP_MEMORY_TAGS) || \
			defined (CONFIG_CMDLINE_TAG) || \
			defined (CONFIG_INITRD_TAG) || \
			defined (CONFIG_SERIAL_TAG) || \
			defined (CONFIG_REVISION_TAG) || \
			defined (CONFIG_LCD) || \
			defined (CONFIG_VFD)
			setup_start_tag (bd);		//必须
			setup_serial_tag (&params);
			setup_memory_tags (bd);
			setup_commandline_tag (bd, commandline);
			setup_end_tag (bd);			//必须

		
		//跳到入口地址,启动内核
		theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);		//取得入口地址
		theKernel (0, bd->bi_arch_number, bd->bi_boot_params);			//启动内核, bi_arch_number 为机器ID, int board_init (void){gd->bd->bi_arch_number = MACH_TYPE_SMDK2410; } 机器
	}


				static void setup_start_tag (bd_t *bd)
				{
					params = (struct tag *) bd->bi_boot_params;		// int board_init (void)	{gd->bd->bi_boot_params = 0x30000100;	}
					params->hdr.tag = ATAG_CORE;					//0x54410001
					params->hdr.size = tag_size (tag_core);

					params->u.core.flags = 0;
					params->u.core.pagesize = 0;
					params->u.core.rootdev = 0;

					params = tag_next (params);
				}

				static void setup_memory_tags (bd_t *bd)
				{
					for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
						params->hdr.tag = ATAG_MEM;					//0x54410002
						params->hdr.size = tag_size (tag_mem32);

						params->u.mem.start = bd->bi_dram[i].start;		//dram_init()函数中指定
						params->u.mem.size = bd->bi_dram[i].size;

						params = tag_next (params);
					}
				}

				static void setup_commandline_tag (bd_t *bd, char *commandline)
				{
					/* eat leading white space */
					for (p = commandline; *p == ' '; p++);

					/* skip non-existent command lines so the kernel will still
					 * use its default command line.
					 */
					if (*p == '\0')
						return;

					params->hdr.tag = ATAG_CMDLINE;					//0x54410009
					params->hdr.size =
						(sizeof (struct tag_header) + strlen (p) + 1 + 4) >> 2;

					strcpy (params->u.cmdline.cmdline, p);

					params = tag_next (params);
				}

				static void setup_end_tag (bd_t *bd)
				{
					params->hdr.tag = ATAG_NONE;
					params->hdr.size = 0;
				}

参考:韦东山Linux教程

posted @   charlie12345  阅读(29)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示