虫虫首页| 资源下载| 资源专辑| 精品软件
登录| 注册

您现在的位置是:首页 > 技术阅读 >  u-boot2020.04移植(6、board_init_r)

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

时间:2024-05-31

点击下方阅读原文可访问文中超链接

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初始化相关的内容后(直接通过menuconfig关掉所有onenand相关的配置),虽然能够进入控制台了,但是MMC读取不了卡,这个也要解决,最后附上成功启动的图:

图2


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