u-boot2020.04移植(6、board_init_r)

board_init_r和board_init_f差不多,都是执行一个循环,下面看下board_init_r干了些什么:

/*common/board_r.c*/

static init_fnc_t init_sequence_r[] = {
	initr_trace,
	initr_reloc,
	/* TODO: could x86/PPC have this also perhaps? */
#ifdef CONFIG_ARM
	initr_caches,
	/* Note: For Freescale LS2 SoCs, new MMU table is created in DDR.
	 *	 A temporary mapping of IFC high region is since removed,
	 *	 so environmental variables in NOR flash is not available
	 *	 until board_init() is called below to remap IFC to high
	 *	 region.
	 */
#endif
	initr_reloc_global_data,
	initr_barrier,
	initr_malloc,
	log_init,
	initr_bootstage,	/* Needs malloc() but has its own timer */
	initr_console_record,
#ifdef CONFIG_DM
	initr_dm,
#endif
#if defined(CONFIG_ARM) || defined(CONFIG_NDS32) || defined(CONFIG_RISCV) || \
	defined(CONFIG_SANDBOX)
	board_init,	/* Setup chipselects */
#endif
	/*
	 * TODO: printing of the clock inforamtion of the board is now
	 * implemented as part of bdinfo command. Currently only support for
	 * davinci SOC's is added. Remove this check once all the board
	 * implement this.
	 */
#ifdef CONFIG_EFI_LOADER
	efi_memory_init,
#endif
	initr_binman,
	initr_dm_devices,
	stdio_init_tables,
	initr_serial,
	initr_announce,
	power_init_board,
#ifdef CONFIG_CMD_ONENAND
	initr_onenand,
#endif
#ifdef CONFIG_MMC
	initr_mmc,
#endif
	initr_env,
	initr_secondary_cpu,
	stdio_add_devices,
	initr_jumptable,
	console_init_r,		/* fully init console as a device */
#ifdef CONFIG_MISC_INIT_R
	misc_init_r,		/* miscellaneous platform-dependent init */
#endif
	interrupt_init,
#ifdef CONFIG_ARM
	initr_enable_interrupts,
#endif
	/* PPC has a udelay(20) here dating from 2002. Why? */
	/*未定义,但后面要添加*/
#ifdef CONFIG_CMD_NET
	initr_ethaddr,
#endif
/*未定义,但后面要添加*/
#ifdef CONFIG_CMD_NET
	INIT_FUNC_WATCHDOG_RESET
	initr_net,
#endif
	run_main_loop,
};

老规矩,一个一个分析,不过这个可能没有board_init_f那样详细了,太多了,而且层次更加复杂:

/*common/board_r.c*/

static int initr_trace(void)
{
/*未定义*/
#ifdef CONFIG_TRACE
	trace_init(gd->trace_buff, CONFIG_TRACE_BUFFER_SIZE);
#endif

	return 0;
}
/*common/board_r.c*/

static int initr_reloc(void)
{
	/*设置个标志,表示重定位完成了*/
	/* tell others: relocation done */
	gd->flags |= GD_FLG_RELOC | GD_FLG_FULL_MALLOC_INIT;

	return 0;
}
/*common/board_r.c*/

static int initr_caches(void)
{
    /*使能缓存*/
	/* Enable caches */
	enable_caches();
	return 0;
}
/*common/board_r.c*/

static int initr_reloc_global_data(void)
{
#ifdef __ARM__
	/*u-boot重定位拷贝内容的大小加上动态符号表(rel_dyn)的大小*/
	monitor_flash_len = _end - __image_copy_start;
#elif defined(CONFIG_NDS32) || defined(CONFIG_RISCV)
	monitor_flash_len = (ulong)&_end - (ulong)&_start;
#elif !defined(CONFIG_SANDBOX) && !defined(CONFIG_NIOS2)
	monitor_flash_len = (ulong)&__init_end - gd->relocaddr;
#endif
/*未定义*/
#if defined(CONFIG_MPC85xx) || defined(CONFIG_MPC86xx)
	/*
	 * The gd->cpu pointer is set to an address in flash before relocation.
	 * We need to update it to point to the same CPU entry in RAM.
	 * TODO: why not just add gd->reloc_ofs?
	 */
	gd->arch.cpu += gd->relocaddr - CONFIG_SYS_MONITOR_BASE;

	/*
	 * If we didn't know the cpu mask & # cores, we can save them of
	 * now rather than 'computing' them constantly
	 */
	fixup_cpu();
#endif
#ifdef CONFIG_SYS_RELOC_GD_ENV_ADDR
	/*
	 * Relocate the early env_addr pointer unless we know it is not inside
	 * the binary. Some systems need this and for the rest, it doesn't hurt.
	 */
	/*环境变量地址也加上偏移*/
	gd->env_addr += gd->reloc_off;
#endif
/*未定义*/
#ifdef CONFIG_OF_EMBED
	/*
	 * The fdt_blob needs to be moved to new relocation address
	 * incase of FDT blob is embedded with in image
	 */
	gd->fdt_blob += gd->reloc_off;
#endif
/*这个是EFI引导相关的内容,之后去掉这个算了,反正也没有用*/
#ifdef CONFIG_EFI_LOADER
	/*
	 * On the ARM architecture gd is mapped to a fixed register (r9 or x18).
	 * As this register may be overwritten by an EFI payload we save it here
	 * and restore it on every callback entered.
	 */
	/*将gd保存到efi_gd全局变量中,因为r9这个寄存器可能被重写*/
	efi_save_gd();

	/*efi_runtime段的重定位*/
	efi_runtime_relocate(gd->relocaddr, NULL);
#endif

	return 0;
}
/*common/board_r.c*/

/*同步屏障*/
static int initr_barrier(void)
{
/*未定义*/
#ifdef CONFIG_PPC
	/* TODO: Can we not use dmb() macros for this? */
	asm("sync ; isync");
#endif
	return 0;
}
/*common/board_r.c*/

static int initr_malloc(void)
{
	ulong malloc_start;

#if CONFIG_VAL(SYS_MALLOC_F_LEN)
	debug("Pre-reloc malloc() used %#lx bytes (%ld KB)\n", gd->malloc_ptr,
	      gd->malloc_ptr / 1024);
#endif
	/* The malloc area is immediately below the monitor copy in DRAM */
	/*
	 * This value MUST match the value of gd->start_addr_sp in board_f.c:
	 * reserve_noncached().
	 */
	/*从board_init_f画出的内存图可知,重定位地址的下面就是预留的堆区*/
	malloc_start = gd->relocaddr - TOTAL_MALLOC_LEN;
	/*填充了三个全局变量并将堆区全部清零*/
	mem_malloc_init((ulong)map_sysmem(malloc_start, TOTAL_MALLOC_LEN),
			TOTAL_MALLOC_LEN);
	return 0;
}

现在画一个新的内存图表示board_init_r这个过程对内存做了什么,去掉之前board_init_f的中间过程,用紫色表示第二阶段,注意启动参数的地址是在后面设置的:

图1
/*include/log.h*/

/*未定义,所以用的是下面那个空的内联函数,如果定义了宏的话其函数实现在common/log.c*/
#if CONFIG_IS_ENABLED(LOG)
/**
 * log_init() - Set up the log system ready for use
 *
 * @return 0 if OK, -ENOMEM if out of memory
 */
int log_init(void);
#else
static inline int log_init(void)
{
	return 0;
}
#endif
/*common/board_r.c*/

static int initr_bootstage(void)
{
    /*显示当前运行进度,追进去是空*/
	bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_R, "board_init_r");

	return 0;
}
/*common/board_r.c*/

static int initr_console_record(void)
{
	/*未定义*/
#if defined(CONFIG_CONSOLE_RECORD)
	return console_record_init();
#else
	return 0;
#endif
}
/*common/board_r.c*/

/*驱动模型相关的,以后分析*/
static int initr_dm(void)
{
	int ret;

	/* Save the pre-reloc driver model and start a new one */
	gd->dm_root_f = gd->dm_root;
	gd->dm_root = NULL;
#ifdef CONFIG_TIMER
	gd->timer = NULL;
#endif
	bootstage_start(BOOTSTATE_ID_ACCUM_DM_R, "dm_r");
	ret = dm_init_and_scan(false);
	bootstage_accum(BOOTSTATE_ID_ACCUM_DM_R);
	if (ret)
		return ret;

	return 0;
}
/*board/samsung/goni/goni.c*/

/*这个有点恶心啊,在前面board_init_f中也设置了,这里又有,算了,把前面设置过的取消吧*/
int board_init(void)
{
	/* Set Initial global variables */
    /*修改成SMDKV210的机器码,启动linux需要的,但实际测试,这个就算不设置也能够启动,貌似是因为用了设备树后,这个就废弃了,
	但我们还是将其添加上(可在arch/arm/include/asm/mach-types.h中找到)*/
	gd->bd->bi_arch_number = MACH_TYPE_SMDKV210;
    /*存放启动参数的地址,CONFIG_SYS_SDRAM_BASE + 0x100,也就是在DRAM的底部*/
	gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100;

	return 0;
}
/*lib/efi_loader/efi_memory.c*/

/*EFI引导相关的*/
int efi_memory_init(void)
{
	efi_add_known_memory();

	add_u_boot_and_runtime();

#ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER
	/* Request a 32bit 64MB bounce buffer region */
	uint64_t efi_bounce_buffer_addr = 0xffffffff;

	if (efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, EFI_LOADER_DATA,
			       (64 * 1024 * 1024) >> EFI_PAGE_SHIFT,
			       &efi_bounce_buffer_addr) != EFI_SUCCESS)
		return -1;

	efi_bounce_buffer = (void*)(uintptr_t)efi_bounce_buffer_addr;
#endif

	return 0;
}
/*common/board_r.c*/

static int initr_binman(void)
{
	/*未定义,满足条件直接返回*/
	if (!CONFIG_IS_ENABLED(BINMAN_FDT))
		return 0;

    /*也不知道这是干嘛的*/
	return binman_init();
}
/*common/board_r.c*/

/*初始化设备驱动*/
static int initr_dm_devices(void)
{
	int ret;

	/*未定义*/
	if (IS_ENABLED(CONFIG_TIMER_EARLY)) {
		ret = dm_timer_init();
		if (ret)
			return ret;
	}

	return 0;
}
/*common/stdio.c*/

int stdio_init_tables(void)
{
	/*未定义*/
#if defined(CONFIG_NEEDS_MANUAL_RELOC)
	/* already relocated for current ARM implementation */
	ulong relocation_offset = gd->reloc_off;
	int i;

	/* relocate device name pointers */
	for (i = 0; i < (sizeof (stdio_names) / sizeof (char *)); ++i) {
		stdio_names[i] = (char *) (((ulong) stdio_names[i]) +
						relocation_offset);
	}
#endif /* CONFIG_NEEDS_MANUAL_RELOC */

	/* Initialize the list */
	/*初始化了一个双向循环链表*/
	INIT_LIST_HEAD(&(devs.list));

	return 0;
}
/*common/board_r.c*/

static int initr_serial(void)
{
	/*在board_init_f中最终调用的同一个函数,前面已经执行了,这里又执行一遍,不知道是不是多此一举,以后再详细分析一下*/
	serial_initialize();
	return 0;
}
/*common/board_r.c*/

static int initr_announce(void)
{
	/*没有开启调试信息的输出*/
	debug("Now running in RAM - U-Boot at: %08lx\n", gd->relocaddr);
	return 0;
}
/*common/board_r.c*/

__weak int power_init_board(void)
{
	return 0;
}
/*common/board_r.c*/

static int initr_onenand(void)
{
	/*onenand的初始化,还记得之前u-boot启动就是卡onenand的初始化的,因为我的板子上没有,所以直接去掉相关宏*/
	puts("NAND:  ");
	onenand_init();
	return 0;
}
/*common/board_r.c*/

/*MMC相关的初始化*/
static int initr_mmc(void)
{
	puts("MMC:   ");
	mmc_initialize(gd->bd);
	return 0;
}
/*common/board_r.c*/

/*初始化环境变量*/
static int initr_env(void)
{
	/* initialize environment */
	if (should_load_env())
		/*追进去发现执行的是这个*/
		env_relocate();
	else
		env_set_default(NULL, 0);
#ifdef CONFIG_OF_CONTROL
	/*设备树中没有fdtcontroladdr属性,先不管*/
	env_set_hex("fdtcontroladdr",
		    (unsigned long)map_to_sysmem(gd->fdt_blob));
#endif

	/* Initialize from environment */
	/*如果设备树中设置了loadaddr就使用设备树中的,没有设置就是用默认的CONFIG_SYS_LOAD_ADDR*/
	image_load_addr = env_get_ulong("loadaddr", 16, image_load_addr);

	return 0;
}

-->
/*common/board_r.c*/

static int should_load_env(void)
{
#ifdef CONFIG_OF_CONTROL
	/*设备树没有设置过load-environment,默认返回1*/
	return fdtdec_get_config_int(gd->fdt_blob, "load-environment", 1);
#elif defined CONFIG_DELAY_ENVIRONMENT
	return 0;
#else
	return 1;
#endif
}

-->
/*env/common.c*/

void env_relocate(void)
{
	/*未定义*/
#if defined(CONFIG_NEEDS_MANUAL_RELOC)
	env_reloc();
	env_fix_drivers();
	env_htab.change_ok += gd->reloc_off;
#endif
/*在board_init_f中已经设置了这个标志,所以不满足条件*/
	if (gd->env_valid == ENV_INVALID) {
#if defined(CONFIG_ENV_IS_NOWHERE) || defined(CONFIG_SPL_BUILD)
		/* Environment not changable */
		env_set_default(NULL, 0);
#else
		bootstage_error(BOOTSTAGE_ID_NET_CHECKSUM);
		env_set_default("bad CRC", 0);
#endif
	} else {
		/*从设置的存储环境变量的介质中加载环境变量*/
		env_load();
	}
}
/*common/board_r.c*/

static int initr_secondary_cpu(void)
{
	/*
	 * after non-volatile devices & environment is setup and cpu code have
	 * another round to deal with any initialization that might require
	 * full access to the environment or loading of some image (firmware)
	 * from a non-volatile device
	 */
	/* TODO: maybe define this for all archs? */
	/*空*/
	cpu_secondary_init_r();

	return 0;
}
/*common/stdio.c*/

/*各种驱动初始化,但是我们都没有定义*/
int stdio_add_devices(void)
{
    /*
        省略
    */
}
/*common/board_r.c*/

static int initr_jumptable(void)
{
	/*初始化跳转表common/exports.c*/
	jumptable_init();
	return 0;
}

-->
/*common/exports.c*/

#define EXPORT_FUNC(f, a, x, ...)  gd->jt->x = f;

/*
    省略
*/

/*struct jt_funcs结构体位于include/exports.h,定义了一系列的函数指针*/
void jumptable_init(void)
{
	/*申请内存*/
	gd->jt = malloc(sizeof(struct jt_funcs));
	/*include/_exports.h在上面定义了宏EXPORT_FUNC,就是给一系列的函数指针绑定上对应的函数实体*/
#include <_exports.h>
}

-->
/*include/exports.h*/

struct jt_funcs {
#define EXPORT_FUNC(impl, res, func, ...) res(*func)(__VA_ARGS__);
/*宏展开后就是一系列的函数指针*/
#include <_exports.h>
#undef EXPORT_FUNC
};
/*common/console.c*/

/*将stdin,stdout,stderr与具体的终端设备绑定起来*/
int console_init_r(void)
{
    /*
        省略
    */
}
/*从设备树获取各种板子信息,但是设备树都没有定义*/

int misc_init_r(void)
{
#ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
/*board/samsung/common/misc.c*/
	set_board_info();
#endif
	return 0;
}
/*arch/arm/lib/interrupts.c*/

int interrupt_init(void)
{
	/*
	 * setup up stacks if necessary
	 */
	/*这个宏在arch/arm/lib/vectors.S中,最开始里面随便填充的一个值,现在填上可以使用的值*/
	IRQ_STACK_START_IN = gd->irq_sp + 8;

	return 0;
}

-->
/*arch/arm/lib/vectors.S*/

/* IRQ stack memory (calculated at run-time) + 8 bytes */
.globl IRQ_STACK_START_IN
IRQ_STACK_START_IN:
/*未定义*/
#ifdef IRAM_BASE_ADDR
	.word   IRAM_BASE_ADDR + 0x20
#else
	.word	0x0badc0de
#endif
/*common/board_r.c*/

static int initr_enable_interrupts(void)
{
	/*实际是个空函数*/
	enable_interrupts();
	return 0;
}

到此,board_init_r也就分析完了,最后就是进入u-boot的大循环run_main_loop了,这个里面就是启动内核或者处理用户输入的命令,这部分以后再详细分析一下。

截至目前,虽然将大部分代码都看了一遍,但还是有很多不知道的地方,不过收获还是挺大的,后面还需要让开发板支持网络,并且目前的u-boot在屏蔽掉onenand初始化后,虽然能够进入控制台了,但是MMC读取不了卡,这个也要解决,最后附上成功启动的图:

图2

欢迎扫码关注我的微信公众号

漫长当下

猜你喜欢

转载自blog.csdn.net/a1598025967/article/details/107030642