uboot分析之第二阶段

uboot分析之第二阶段:

///////////////////////////////////////各部分初始化入口序列///////////////////////////////////////////////////
typedef int (init_fnc_t) (void);
init_fnc_t *init_sequence[] = {
#if defined(CONFIG_ARCH_CPU_INIT)
	arch_cpu_init,		/* basic arch cpu dependent setup */
#endif
	board_init,		/* basic board dependent setup */
#if defined(CONFIG_USE_IRQ)
	interrupt_init,		/* set up exceptions */
#endif
	timer_init,		/* initialize timer */
	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
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
	init_func_i2c,
#endif
	dram_init,		/* configure available RAM banks */
#if defined(CONFIG_CMD_PCI) || defined (CONFIG_PCI)
	arm_pci_init,
#endif
	display_dram_config,
	NULL,
};
///////////////////////////////////全局变量gd的定义////////////////////////////////////////////////////////////
typedef struct bd_info {
    int			bi_baudrate;	/* serial console baudrate */
    unsigned long	bi_ip_addr;	/* IP Address */
    struct environment_s	       *bi_env;
    ulong	        bi_arch_number;	/* unique id for this board */
    ulong	        bi_boot_params;	/* where this board expects params */
    struct				/* RAM configuration */
    {
	ulong start;
	ulong size;
    }			bi_dram[CONFIG_NR_DRAM_BANKS];
} bd_t;
/* Keep it *SMALL* and remember to set CONFIG_SYS_GBL_DATA_SIZE > sizeof(gd_t)
 */
typedef	struct	global_data {
	bd_t		*bd;
	unsigned long	flags;
	unsigned long	baudrate;
	unsigned long	have_console;	/* serial_init() was called */
	unsigned long	reloc_off;	/* Relocation Offset */
	unsigned long	env_addr;	/* Address  of Environment struct */
	unsigned long	env_valid;	/* Checksum of Environment valid? */
	unsigned long	fb_base;	/* base address of frame buffer */
#ifdef CONFIG_VFD
	unsigned char	vfd_type;	/* display type */
#endif
	void		**jt;		/* jump table */
} gd_t;
#define DECLARE_GLOBAL_DATA_PTR     register volatile gd_t *gd asm ("r8")
//////////////////////////////////第二阶段入口函数start_armboot///////////////////////////////////////////////
.globl _armboot_start
_armboot_start:
	.word _start
/*
 * Size of malloc() pool
 */
#define CONFIG_ENV_SIZE		0x10000	/* Total Size of Environment Sector */
#define CONFIG_SYS_MALLOC_LEN		(CONFIG_ENV_SIZE + 128*1024)

void hang (void)
{
	puts ("### ERROR ### Please RESET the board ###\n");
	for (;;);
}

void start_armboot (void)
{
	init_fnc_t **init_fnc_ptr;
	
	gd = (gd_t*)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t));
	memset ((void*)gd, 0, sizeof (gd_t));
	
	gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
	memset (gd->bd, 0, sizeof (bd_t));
	
	/*设置全局变量gd的值*/
	
	/*调用各部分初始化函数*/
	for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
		if ((*init_fnc_ptr)() != 0) {
			hang ();
		}
	}
	
	#if defined(CONFIG_CMD_NAND)
	puts ("NAND:  ");
	nand_init();		/* go init the NAND */
	#endif
	
	/* initialize environment */
	env_relocate ();
	
	#ifdef CONFIG_SERIAL_MULTI
	serial_initialize();
	#endif
	
	stdio_init ();	/* get the devices list going. */
	jumptable_init ();
	console_init_r ();	/* fully init console as a device */
	/* enable exceptions */
	enable_interrupts ();
	
	/* Initialize from environment *///getenv("name")函数返回name参数的地址
	if ((s = getenv ("loadaddr")) != NULL) {
		load_addr = simple_strtoul (s, NULL, 16);
	}
	#if defined(CONFIG_CMD_NET)
		if ((s = getenv ("bootfile")) != NULL) {
			copy_filename (BootFile, s, sizeof (BootFile));
		}
	#endif


	puts ("Net:   ");
	eth_initialize(gd->bd);
	
	/* main_loop() can return to retry autoboot, if so just run it again. */
	for (;;) {
		main_loop ();
	}

	/* NOT REACHED - no way out of command loop except booting */
}
////////////////////////////////////////////进入main_loop函数////////////////////////////////////////////////////
void main_loop (void)
{
	#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
		char *s;
		int bootdelay;
	#endif
	
	#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
	s = getenv ("bootdelay");
	bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
	debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);
	s = getenv ("bootcmd");
	debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "");
	if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
		run_command (s, 0);
	}
	#endif	/* CONFIG_BOOTDELAY */
	
	/*
	 * Main Loop for Monitor Command Processing
	 */
	for (;;){
		len = readline (CONFIG_SYS_PROMPT);
		flag = 0;	/* assume no special flags for now */
		if (len > 0)
			strcpy (lastcommand, console_buffer);
		else if (len == 0)
			flag |= CMD_FLAG_REPEAT;			
		if (len == -1)
			puts ("\n");
		else
			rc = run_command (lastcommand, flag);
		if (rc <= 0) {
			/* invalid command or not repeatable, forget it */
			lastcommand[0] = 0;
		}
	}
}
/////////////////////////////////根据配置和输入命令执行run_command函数//////////////////////////////////////////
/*
 * Monitor Command Table
 */
struct cmd_tbl_s {
	char		*name;		/* Command Name			*/
	int		maxargs;	/* maximum number of arguments	*/
	int		repeatable;	/* autorepeat allowed?		*/
						/* Implementation function	*/
	int		(*cmd)(struct cmd_tbl_s *, int, int, char *[]);
	char		*usage;		/* Usage message	(short)	*/
#ifdef	CONFIG_SYS_LONGHELP
	char		*help;		/* Help  message	(long)	*/
#endif
#ifdef CONFIG_AUTO_COMPLETE
	/* do auto completion on the arguments */
	int		(*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[]);
#endif
};

typedef struct cmd_tbl_s	cmd_tbl_t;
/****************************************************************************
 * returns:
 *	1  - command executed, repeatable
 *	0  - command executed but not repeatable, interrupted commands are
 *	     always considered not repeatable
 *	-1 - not executed (unrecognized, bootd recursion or too many args)
 *           (If cmd is NULL or "" or longer than CONFIG_SYS_CBSIZE-1 it is
 *           considered unrecognized)
 */
int run_command (const char *cmd, int flag)
{
	cmd_tbl_t *cmdtp;
	char cmdbuf[CONFIG_SYS_CBSIZE];	/* working copy of cmd		*/
	char *token;			/* start of token in cmdbuf	*/
	char *sep;			/* end of token (separator) in cmdbuf */
	char finaltoken[CONFIG_SYS_CBSIZE];
	char *str = cmdbuf;
	char *argv[CONFIG_SYS_MAXARGS + 1];	/* NULL terminated	*/
	int argc;
	int repeatable = 1;
	int rc = 0;
	
	strcpy (cmdbuf, cmd);
	token = str;
	
	/* find macros in this token and replace them */
	process_macros (token, finaltoken);
	
	/* Extract arguments */
	if ((argc = parse_line (finaltoken, argv)) == 0) {
		rc = -1;	/* no command at all */
		continue;
	}
	
	/* Look up command in command table */
	if ((cmdtp = find_cmd(argv[0])) == NULL) {
		printf ("Unknown command '%s' - try 'help'\n", argv[0]);
		rc = -1;	/* give up after bad command */
		continue;
	}
	
	/* OK - call function to do the command */
	if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {
		rc = -1;
	}

	repeatable &= cmdtp->repeatable;
	
	return rc ? rc : repeatable;
	
}
//////////////////////////////////////uboot命令的实现///////////////////////////////////////////////
//一个cmd_tbl_t结构体就代表一个uboot命令
//u-boot命令都在commom/目录下,文件一般是cmd_xxx.c
//以启动系统的命令bootm为例,实现文件为/common/目录下的cmd_bootm.c文件
//通过将所有的cmd_tbl_t定义个段属性Struct_Section,来将所有的cmd_tbl_t结构体有效的组织在一起
#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}
/////////////////////////////////////分析cmd_bootm.c文件//////////////////////////////////////////////////
typedef int boot_os_fn (int flag, int argc, char *argv[],
			bootm_headers_t *images); /* pointers to os/initrd/fdt */
			
#define CONFIG_BOOTM_LINUX 1

#ifdef CONFIG_BOOTM_LINUX
extern boot_os_fn do_bootm_linux;
#endif

boot_os_fn * boot_os[] = {
#ifdef CONFIG_BOOTM_LINUX
	[IH_OS_LINUX] = do_bootm_linux,
#endif
};

ulong load_addr = CONFIG_SYS_LOAD_ADDR;	/* Default Load Address */
static bootm_headers_t images;		/* pointers to os/initrd/fdt images */

/*******************************************************************/
/* bootm - boot application image from image in memory */
/*******************************************************************/
int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
	ulong		iflag;
	ulong		load_end = 0;
	int		ret;
	boot_os_fn	*boot_fn;
	
	if (bootm_start(cmdtp, flag, argc, argv))
		return 1;

	/*
	 * We have reached the point of no return: we are going to
	 * overwrite all exception vector code, so we cannot easily
	 * recover from any failures any more...
	 */
	iflag = disable_interrupts();
	
	ret = bootm_load_os(images.os, &load_end, 1);
	
	boot_fn = boot_os[images.os.os];
	
	boot_fn(0, argc, argv, &images); //boot_fn函数指针指向do_bootm_linux函数,即调用do_bootm_linux(0, argc, argv, &images);
}

U_BOOT_CMD(
	bootm,	CONFIG_SYS_MAXARGS,	1,	do_bootm,
	"boot application image from memory",
	
	"[addr [arg ...]]\n    - boot application image stored in memory\n"
	"\tpassing arguments 'arg ...'; when booting a Linux kernel,\n"
	"\t'arg' can be the address of an initrd image\n"	
	"\nSub-commands to do part of the bootm sequence.  The sub-commands "
	"must be\n"
	"issued in the order below (it's ok to not issue all sub-commands):\n"
	"\tstart [addr [arg ...]]\n"
	"\tloados  - load OS image\n"
	"\tbdt     - OS specific bd_t processing\n"
	"\tcmdline - OS specific command line processing/setup\n"
	"\tprep    - OS specific prep before relocation or go\n"
	"\tgo      - start OS"
);
///////////////////////////分析lib_arm/bootm.c文件中的do_bootm_linux函数////////////////////////////
/*
 * The new way of passing information: a list of tagged entries
 */
/* The list ends with an ATAG_NONE node. */
#define ATAG_NONE	0x00000000
struct tag_header {
	u32 size;
	u32 tag;
};
/* The list must start with an ATAG_CORE node */
#define ATAG_CORE	0x54410001
struct tag_core {
	u32 flags;		/* bit 0 = read-only */
	u32 pagesize;
	u32 rootdev;
};
/* it is allowed to have multiple ATAG_MEM nodes */
#define ATAG_MEM	0x54410002
struct tag_mem32 {
	u32	size;
	u32	start;	/* physical start address */
};
/* command line: \0 terminated string */
#define ATAG_CMDLINE	0x54410009
struct tag_cmdline {
	char	cmdline[1];	/* this is the minimum size */
};
/////////////////
struct tag {
	struct tag_header hdr;
	union {
		struct tag_core		core;
		struct tag_mem32	mem;
		struct tag_videotext	videotext;
		struct tag_ramdisk	ramdisk;
		struct tag_initrd	initrd;
		struct tag_serialnr	serialnr;
		struct tag_revision	revision;
		struct tag_videolfb	videolfb;
		struct tag_cmdline	cmdline;
	} u;
};
////////////////
typedef struct bd_info {
    int			bi_baudrate;	/* serial console baudrate */
    unsigned long	bi_ip_addr;	/* IP Address */
    struct environment_s	       *bi_env;
    ulong	        bi_arch_number;	/* unique id for this board */
    ulong	        bi_boot_params;	/* where this board expects params */
    struct				/* RAM configuration */
    {
	ulong start;
	ulong size;
    }			bi_dram[CONFIG_NR_DRAM_BANKS];
} bd_t;
//////////////////////////
DECLARE_GLOBAL_DATA_PTR;
static struct tag *params;
//////////////////////////
int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
{
	bd_t	*bd = gd->bd;
	char	*s;
	int	machid = bd->bi_arch_number;
	void	(*theKernel)(int zero, int arch, uint params);
	
	#ifdef CONFIG_CMDLINE_TAG
	char *commandline = getenv ("bootargs");
	#endif
	
	theKernel = (void (*)(int, int, uint))images->ep;
	
	//设置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);
	#ifdef CONFIG_SERIAL_TAG
		setup_serial_tag (¶ms);
	#endif
	#ifdef CONFIG_REVISION_TAG
		setup_revision_tag (¶ms);
	#endif
	#ifdef CONFIG_SETUP_MEMORY_TAGS
		setup_memory_tags (bd);
	#endif
	#ifdef CONFIG_CMDLINE_TAG
		setup_commandline_tag (bd, commandline);
	#endif
	#ifdef CONFIG_INITRD_TAG
		if (images->rd_start && images->rd_end)
			setup_initrd_tag (bd, images->rd_start, images->rd_end);
	#endif
	#if defined (CONFIG_VFD) || defined (CONFIG_LCD)
		setup_videolfb_tag ((gd_t *) gd);
	#endif
		setup_end_tag (bd);
	#endif

	/* we assume that the kernel is in place */
	printf ("\nStarting kernel ...\n\n");
	
	theKernel (0, machid, bd->bi_boot_params);
	
	/* does not return */
	return 1;
}
////////////////////////
static void setup_start_tag (bd_t *bd)
{
	params = (struct tag *) bd->bi_boot_params;

	params->hdr.tag = ATAG_CORE;
	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_end_tag (bd_t *bd)
{
	params->hdr.tag = ATAG_NONE;
	params->hdr.size = 0;
}
/////////////////////////


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