2.6、uboot源码分析2-启动第二阶段(2021-4-29)


2.6.1、start_armboot函数简介

2.6.1.1、一个很长的函数

在这里插入图片描述

2.6.1.2、一个函数组成uboot第二阶段

2.6.1.3、宏观分析:uboot第二阶段应该做什么

在这里插入图片描述

2.6.1.4、思考:uboot第二阶段完结于何处?

在这里插入图片描述

    /* main_loop() can return to retry autoboot, if so just run it again. */
	//main_loop()可以返回重试自动引导,如果是这样,就再次运行它
	for (;;) {
   
   
		main_loop ();    //接收命令、解析命令、执行命令的死循环
	}

2.6.2.start_armboot解析1

2.6.2.1、init_fnc_t

在这里插入图片描述

//init_fnc_t:是一个函数类型
//其是用typedef给该函数重命名为init_fnc_t,该函数没有参数,其返回值为int类型
typedef int (init_fnc_t) (void);            

在这里插入图片描述
在这里插入图片描述

 //init_fnc_ptr:二重指针
 //typedef int (init_fnc_t) (void);  是一个函数类型
 init_fnc_t **init_fnc_ptr; 

2.6.2.DECLARE_GLOBAL_DATA_PTR

在这里插入图片描述

//gd:全局变量,为指针类型
//volatile:表示其是可变的
//register:表示其放在寄存器中
//asm("r8"):gcc支持的一种语法,意思就是要把gd放到寄存器r8中
//gd_t:是一个结构体;gd是一个结构体指针,其指向gd_t。

#define DECLARE_GLOBAL_DATA_PTR     register volatile gd_t *gd asm ("r8")

在这里插入图片描述

#ifndef	__ASM_GBL_DATA_H
#define __ASM_GBL_DATA_H
/*
 * The following data structure is placed in some memory wich is
 * available very early after boot (like DPRAM on MPC8xx/MPC82xx, or
 * some locked parts of the data cache) to allow for a minimum set of
 * global variables during system initialization (until we have set
 * up the memory controller so that we can use RAM).
 *
 * Keep it *SMALL* and remember to set CFG_GBL_DATA_SIZE > sizeof(gd_t)
 *下面的数据结构放在内存中
 *启动后很早就可用(如MPC8xx/MPC82xx上的DPRAM,或数据缓存的一些锁定部分),
 *以便在系统初始化期间允许最小的全局变量集(直到我们设置了内存控制器,以便可以使用RAM)。
 *保持*小*并且记得设置CFG _ GBL _数据_大小>大小of(gd_t)
 */

typedef	struct	global_data {
   
   
	bd_t		*bd;             //bd_t:存放开发板的硬件信息的结构体
	unsigned long	flags;       //标志位
	unsigned long	baudrate;    //波特率
	unsigned long	have_console;/* serial_init() was called;serial_init()被调用*/
	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
#if 0
	unsigned long	cpu_clk;	/* CPU clock in Hz!		*/
	unsigned long	bus_clk;
	phys_size_t	ram_size;	/* RAM size */
	unsigned long	reset_status;	/* reset status register at boot */
#endif
	void		**jt;		/* jump table 跳转表*/
} gd_t;
********************************************************************
 * NOTE: This header file defines an interface to U-Boot. Including
 * this (unmodified) header file in another file is considered normal
 * use of U-Boot, and does *not* fall under the heading of "derived
 * work".
 * 注意:这个头文件定义了一个U-Boot盘接口。将这个(未修改的)头文件包含在另一个
 * 文件中被认为是U-Boot的正常使用,并且不*属于“衍生作品”的标题。
 ********************************************************************
 */

#ifndef _U_BOOT_H_
#define _U_BOOT_H_	1

typedef struct bd_info {
   
   
    int			bi_baudrate;	/* 串口控制台波特率*/
    unsigned long	bi_ip_addr;	/* IP Address 开发板的IP地址*/
    unsigned char	bi_enetaddr[6]; /* Ethernet adress 开发板的MAC地址*/
    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]; //开发板的DDR
#ifdef CONFIG_HAS_ETH1
    /* second onboard ethernet port */
    unsigned char   bi_enet1addr[6];
#endif
} bd_t;

2.6.3、内存使用排布

2.6.3.1、为什么要分配内存

在这里插入图片描述

2.6.3.2、内存排布

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

下面展示一些 内联代码片

/* Pointer is writable since we allocated a register for it */
//指针是可写的,因为我们为它分配了一个寄存器
#ifdef CONFIG_MEMORY_UPPER_CODE             //此处定义了
	ulong gd_base;                      //定义了gd_base变量,gd是DDR中内存分配的起始地址
    //CFG_UBOOT_BASE:33E00000,uboot的基地址;CFG_UBOOT_SIZE:2MB;
    //CFG_MALLOC_LEN:堆区;CFG_STACK_SIZE:栈区;gd_t:结构体
    //#define CFG_UBOOT_BASE  0x33e00000   uboot的基地址
    /* total memory required by uboot;uboot所需的总内存 */
    //#define CFG_UBOOT_SIZE  (2*1024*1024)  2MB
    //#define CFG_ENV_SIZE		0x4000	/* Total Size of Environment Sector 环境变量的总大小16KB*/
    //#define CFG_MALLOC_LEN  (CFG_ENV_SIZE + 896*1024)  912KB
    //#define CFG_STACK_SIZE   512*1024           512KB
	gd_base = CFG_UBOOT_BASE + CFG_UBOOT_SIZE - CFG_MALLOC_LEN - CFG_STACK_SIZE - sizeof(gd_t);  //gd在DDR中内存分配的  起始地址
#ifdef CONFIG_USE_IRQ            //CONFIG_USE_IRQ没有定义,如果定义的话;gd_base需重新计算
	gd_base -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ);
#endif      
	gd = (gd_t*)gd_base;             //强制类型转换。gd就指向了gd_base地址指向的地方
#else       
	gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
#endif

	/* compiler optimization barrier needed for GCC >= 3.4 */
	//GCC需要编译器优化屏障
	__asm__ __volatile__("": : :"memory");

	//将gd内存处清0,将环境变量内存处清0
	memset ((void*)gd, 0, sizeof (gd_t));       
	gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));  //gd->bd指针指向存放开发板的硬件信息的结构体的地址
	memset (gd->bd, 0, sizeof (bd_t));         //将bd内存处清0

2.6.4、start_armboot解析2

2.6.4.1、for循环执行init_sequence

在这里插入图片描述
在这里插入图片描述
函数名其实就是一个函数指针。

//Board.c
////typedef int (init_fnc_t) (void);  init_fnc_t是一个函数类型
//函数指针数组。其是一个数组,该数组存放的元素是指针,该指针指向类型是一个函数。
init_fnc_t *init_sequence[] = {
   
   
	cpu_init,		/* 基本cpu相关设置 */
#if defined(CONFIG_SKIP_RELOCATE_UBOOT)  //CONFIG_SKIP_RELOCATE_UBOOT没定义
	reloc_init,		 //设置重定位完成标志,必须在cpu_init()之后完成,但要尽快*/
#endif
	board_init,		     /* 基本板相关设置*/
	interrupt_init,		/*  设置中断*/
	env_init,		    /* i 初始化环境*/
	init_baudrate,		/*  初始化波特率*/
	serial_init,		/* 串行通信设置*/
	console_init_f,		/*  控制台的第1阶段初始化*/
	display_banner,		/* say that we are here */
#if defined(CONFIG_DISPLAY_CPUINFO)   //CONFIG_DISPLAY_CPUINFO定义
	print_cpuinfo,		/* 显示cpu信息(和速度)*/
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO) //CONFIG_DISPLAY_BOARDINFO定义
	checkboard,		   /*显示板信息*/
#endif
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)  //CONFIG_HARD_I2C定义
	init_func_i2c,
#endif
	dram_init,		 /*配置可用内存库*/
	display_dram_config,
	NULL,
};

在这里插入图片描述

	//typedef int (init_fnc_t) (void);  是一个函数类型
	//init_fnc_t **init_fnc_ptr;  二重指针,
	//init_sequence是一个函数指针数组名,二重指针可以指向它
	for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
   
   
		if ((*init_fnc_ptr)() != 0) {
   
     //如果返回不是0 
			hang ();                    //死循环,挂起
		}
	}
void hang (void)
{
   
   
	while (1) ;
}

2.6.4.2、cpu_init

在这里插入图片描述

//Cpu.c
int cpu_init (void)
{
   
   
	/*
	 * 如有必要,设置堆栈
	 */  
#ifdef CONFIG_USE_IRQ      //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;
}

2.6.4.3、board_init

在这里插入图片描述

//X210.c
int board_init(void)           //开发板初始化
{
   
      
	//#define DECLARE_GLOBAL_DATA_PTR     register volatile gd_t *gd asm ("r8")
	DECLARE_GLOBAL_DATA_PTR;     //声明全局变量
#ifdef CONFIG_DRIVER_SMC911X     //CONFIG_DRIVER_SMC911X没定义
	smc9115_pre_init();          //网卡初始化,不使用
#endif

#ifdef CONFIG_DRIVER_DM9000     //CONFIG_DRIVER_DM9000定义
	dm9000_pre_init();          //网卡初始化,使用
#endif

	gd->bd->bi_arch_number = MACH_TYPE;
	gd->bd->bi_boot_params = (PHYS_SDRAM_1+0x100);

	return 0;
}

//X210_sd.h
#define CONFIG_DRIVER_DM9000	1           //DM9000网卡初始化

在这里插入图片描述

//X210_sd.h
#define CONFIG_DRIVER_DM9000	1           //DM9000网卡初始化

//X210.c
/*
 * Miscellaneous platform dependent initialisations
 * 网卡平台相关初始化
 */

static void dm9000_pre_init(void)    //网卡初始化,主要是网卡的GPIO和端口的配置
{
   
   
	unsigned int tmp;

#if defined(DM9000_16BIT_DATA)
	SROM_BW_REG &= ~(0xf << 4);
	SROM_BW_REG |= (1<<7) | (1<<6) | 
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值