当前位置: 首页 > 工具软件 > ARMboot > 使用案例 >

U-BOOT-1.1.16分析二 ---- start_armboot

司马作人
2023-12-01

之前分析了汇编文件\u-boot-1.1.6\cpu\arm920t\start.S =》 u-boot1.1.6代码分析

第二阶段启动分析: u-boot-1.1.6\lib_arm\board.c

start_armboot 做了哪些事情?

 

1、定义了一个全局变量并分配空间初始化

CFG_MALLOC_LEN= CFG_ENV_LEN + 64*1024

gd指向的这个空间中 先分配了 CFG_MALLOC_LEN的空间

然后又分配了结构 gd_t的空间,之后会初始化这个结构中的变量;

gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));


typedef	struct	global_data {
	bd_t		*bd;           
	unsigned long	flags;
	unsigned long	baudrate;
	unsigned long	cpu_clk;	/* CPU clock in Hz!		*/
	unsigned long	have_console;	/* serial_init() was called */
	unsigned long	ram_size;	/* RAM size */
	unsigned long	reloc_off;	/* Relocation Offset */
	unsigned long	env_addr;	/* Address  of Environment struct */
	unsigned long	env_valid;	/* Checksum of Environment valid */
#if defined(CONFIG_POST) || defined(CONFIG_LOGBUFFER)
	unsigned long	post_log_word;	/* Record POST activities */
	unsigned long	post_init_f_time; /* When post_init_f started */
#endif
	void		**jt;		/* Standalone app jump table */
} gd_t;

typedef struct bd_info {
	unsigned long		bi_baudrate;           //波特率
	unsigned long		bi_ip_addr;            //ip地址
	unsigned char		bi_enetaddr[6];    
	unsigned char		bi_phy_id[4];          //网卡
	struct environment_s	*bi_env;               //环境变量
	unsigned long		bi_board_number;       //机器码
	void			*bi_boot_params;       //内核启动参数
	struct {
		unsigned long	start;                 //内存起始地址
		unsigned long	size;                  //内存的大小
	}			bi_dram[CONFIG_NR_DRAM_BANKS];
	unsigned long		bi_flashstart;         //flash 起始地址
	unsigned long		bi_flashsize;          //flash 大小
	unsigned long		bi_flashoffset;        //flash偏移地址
} bd_t;

定义了一个函数数组指针:    init_fnc_t **init_fnc_ptr;  遍历

typedef int (init_fnc_t) (void);
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,
};


init_fnc_t **init_fnc_ptr;
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
		if ((*init_fnc_ptr)() != 0) {
			hang ();
		}
	}

cpu_init:  设置中断栈空间

//设置cpu中断栈的空间  irq 和 firq的栈空间
int cpu_init (void)
{
	/*
	 * setup up stacks if necessary
	 */
#ifdef CONFIG_USE_IRQ
	IRQ_STACK_START = _armboot_start - CFG_MALLOC_LEN - CFG_GBL_DATA_SIZE - 4;
	FIQ_STACK_START = IRQ_STACK_START - CONFIG_STACKSIZE_IRQ;
#endif
	return 0;
}

board_init:1、设置系统时钟和时钟分频系数;2、配置GPIO    3、设置机器码和启动参数地址(以后内核从这里读取参数的)

int board_init (void)
{
	DECLARE_GLOBAL_DATA_PTR;
	S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
	S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();

	/* to reduce PLL lock time, adjust the LOCKTIME register */
	clk_power->LOCKTIME = 0xFFFFFF;

	/* configure MPLL */
	clk_power->MPLLCON = ((M_MDIV << 12) + (M_PDIV << 4) + M_SDIV);

	/* some delay between MPLL and UPLL */
	delay (4000);

	/* configure UPLL */
	clk_power->UPLLCON = ((U_M_MDIV << 12) + (U_M_PDIV << 4) + U_M_SDIV);

	/* some delay between MPLL and UPLL */
	delay (8000);

	/* set up the I/O ports */
	gpio->GPACON = 0x007FFFFF;
	gpio->GPBCON = 0x00044556;
	gpio->GPBUP = 0x000007FF;
	gpio->GPCCON = 0xAAAAAAAA;
	gpio->GPCUP = 0x0000FFFF;
	gpio->GPDCON = 0xAAAAAAAA;
	gpio->GPDUP = 0x0000FFFF;
	gpio->GPECON = 0xAAAAAAAA;
	gpio->GPEUP = 0x0000FFFF;
	gpio->GPFCON = 0x000055AA;
	gpio->GPFUP = 0x000000FF;
	gpio->GPGCON = 0xFF95FF3A;
	gpio->GPGUP = 0x0000FFFF;
	gpio->GPHCON = 0x0016FAAA;
	gpio->GPHUP = 0x000007FF;

	gpio->EXTINT0=0x22222222;
	gpio->EXTINT1=0x22222222;
	gpio->EXTINT2=0x22222222;

	/* arch number of SMDK2410-Board */
	gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;

	/* adress of boot parameters */
	gd->bd->bi_boot_params = 0x30000100;

	icache_enable();  //这里先忽略
	dcache_enable();  //先忽略

	return 0;

interrupt_init:定时器和计数器的初始化

typedef volatile unsigned int AT91_REG;
typedef struct _AT91S_TC
{
	AT91_REG	 TC_CCR; 	/* Channel Control Register */
	AT91_REG	 TC_CMR; 	/* Channel Mode Register */
	AT91_REG	 Reserved0[2]; 	/*  */
	AT91_REG	 TC_CV; 	/* Counter Value */
	AT91_REG	 TC_RA; 	/* Register A */
	AT91_REG	 TC_RB; 	/* Register B */
	AT91_REG	 TC_RC; 	/* Register C */
	AT91_REG	 TC_SR; 	/* Status Register */
	AT91_REG	 TC_IER; 	/* Interrupt Enable Register */
	AT91_REG	 TC_IDR; 	/* Interrupt Disable Register */
	AT91_REG	 TC_IMR; 	/* Interrupt Mask Register */
} AT91S_TC, *AT91PS_TC;

AT91PS_TC tmr;

int interrupt_init (void)
{
	tmr = AT91C_BASE_TC0;

	/* enables TC1.0 clock */
	*AT91C_PMC_PCER = 1 << AT91C_ID_TC0;  /* enable clock */

	*AT91C_TCB0_BCR = 0;
	*AT91C_TCB0_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_NONE | AT91C_TCB_TC2XC2S_NONE;
	tmr->TC_CCR = AT91C_TC_CLKDIS;
#define AT91C_TC_CMR_CPCTRG (1 << 14)
	/* set to MCLK/2 and restart the timer when the vlaue in TC_RC is reached */
	tmr->TC_CMR = AT91C_TC_TIMER_DIV1_CLOCK | AT91C_TC_CMR_CPCTRG;

	tmr->TC_IDR = ~0ul;
	tmr->TC_RC = TIMER_LOAD_VAL;
	lastinc = 0;
	tmr->TC_CCR = AT91C_TC_SWTRG | AT91C_TC_CLKEN;
	timestamp = 0;

	return (0);
}

env_init:做了两件事

1、判断flash中是否有存放环境变量 

2、初始化环境变量,若是flash中有,使用flash中的环境变量如果没有使用默认的。代码太多且重复就不附代码了

串口中断初始化:

   init_baudrate,        /* initialze baudrate settings */
   serial_init,        /* serial communications setup */
   console_init_f,        /* stage 1 init of console */

 

 

display_banner(); 显示版本信息

//显示版本信息

static int display_banner (void)
{
	printf ("\n\n%s\n\n", version_string);
	debug ("U-Boot code: %08lX -> %08lX  BSS: -> %08lX\n",
	       _armboot_start, _bss_start, _bss_end);
#ifdef CONFIG_MODEM_SUPPORT
	debug ("Modem Support enabled\n");
#endif
#ifdef CONFIG_USE_IRQ
	debug ("IRQ Stack: %08lx\n", IRQ_STACK_START);
	debug ("FIQ Stack: %08lx\n", FIQ_STACK_START);
#endif

	return (0);
}

print_cpuinfo、 checkboard   : 打印cpu和单板信息

 

dram_init 初始化之前定义的变量 gd_t中的内存信息  

display_dram_config 显示内存信息

int dram_init (void)
{
	gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
	gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;

	return 0;
}


static int display_dram_config (void)
{
	int i;

#ifdef DEBUG
	puts ("RAM Configuration:\n");

	for(i=0; i<CONFIG_NR_DRAM_BANKS; i++) {
		printf ("Bank #%d: %08lx ", i, gd->bd->bi_dram[i].start);
		print_size (gd->bd->bi_dram[i].size, "\n");
	}
#else
	ulong size = 0;

	for (i=0; i<CONFIG_NR_DRAM_BANKS; i++) {
		size += gd->bd->bi_dram[i].size;
	}
	puts("DRAM:  ");
	print_size(size, "\n");
#endif

	return (0);
}

 

======================函数指针数组到这里就遍历完了===================================

接下来初始化norflash:

#ifndef CFG_NO_FLASH
	/* configure available FLASH banks */
	size = flash_init ();
	display_flash_config (size);
#endif /* CFG_NO_FLASH */

初始化LCD:

#ifdef CONFIG_LCD
#	ifndef PAGE_SIZE
#	  define PAGE_SIZE 4096
#	endif
	/*
	 * reserve memory for LCD display (always full pages)
	 */
	/* bss_end is defined in the board-specific linker script */
	addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
	size = lcd_setmem (addr);
	gd->fb_base = addr;
#endif /* CONFIG_LCD */

初始化堆空间:

/* armboot_start is defined in the board-specific linker script */
	mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);

初始化NAND Flash:

#if (CONFIG_COMMANDS & CFG_CMD_NAND)
	puts ("NAND:  ");
	nand_init();		/* go init the NAND */
#endif

将环境变量里的值赋值给 gd_t结构:

/* initialize environment */
	env_relocate ();

接下来是网卡和ip地址初始化:

	gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");

	/* MAC Address */
	{
		int i;
		ulong reg;
		char *s, *e;
		char tmp[64];

		i = getenv_r ("ethaddr", tmp, sizeof (tmp));
		s = (i > 0) ? tmp : NULL;

		for (reg = 0; reg < 6; ++reg) {
			gd->bd->bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
			if (s)
				s = (*e) ? e + 1 : e;
		}

#ifdef CONFIG_HAS_ETH1
		i = getenv_r ("eth1addr", tmp, sizeof (tmp));
		s = (i > 0) ? tmp : NULL;

		for (reg = 0; reg < 6; ++reg) {
			gd->bd->bi_enet1addr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
			if (s)
				s = (*e) ? e + 1 : e;
		}
#endif
	}

	devices_init ();	/* get the devices list going. */

#ifdef CONFIG_CMC_PU2
	load_sernum_ethaddr ();
#endif /* CONFIG_CMC_PU2 */

	jumptable_init ();

	console_init_r ();	/* fully init console as a device */

#if defined(CONFIG_MISC_INIT_R)
	/* miscellaneous platform dependent initialisations */
	misc_init_r ();
#endif

	/* enable exceptions */
	enable_interrupts ();

	/* Perform network card initialisation if necessary */
#ifdef CONFIG_DRIVER_CS8900
	cs8900_get_enetaddr (gd->bd->bi_enetaddr);
#endif

#if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)
	if (getenv ("ethaddr")) {
		smc_set_mac_addr(gd->bd->bi_enetaddr);
	}
#endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */

	/* Initialize from environment */
	if ((s = getenv ("loadaddr")) != NULL) {
		load_addr = simple_strtoul (s, NULL, 16);
	}
#if (CONFIG_COMMANDS & CFG_CMD_NET)
	if ((s = getenv ("bootfile")) != NULL) {
		copy_filename (BootFile, s, sizeof (BootFile));
	}
#endif	/* CFG_CMD_NET */

#ifdef BOARD_LATE_INIT
	board_late_init ();
#endif
#if (CONFIG_COMMANDS & CFG_CMD_NET)
#if defined(CONFIG_NET_MULTI)
	puts ("Net:   ");
#endif
	eth_initialize(gd->bd);
#endif

进入了一个死循环:

	/* main_loop() can return to retry autoboot, if so just run it again. */
	for (;;) {
		main_loop ();
	}

我们知道uboot起来之后,uboot默认是启动内核,但是如果没有内核的话会报错,然后加载一个uboot界面,可以输入uboot相关的命令;

这些命令就是在mian_loop中执行:

会从串口读取用户输入的数据然后和已经定义命令比较,成功执行对应的命令;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 类似资料: