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

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

u-boot2020.04移植(4、board_init_f)

时间:2024-05-31

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

接着上篇,执行了ldr pc, =_main后,就到arch/arm/lib/crt0.S文件了,本篇基本全是源码分析,是一个很枯燥的过程,如果你只想看修改的部分可直接搜索“修改”两个字,就能直接找到修改的地方,这个阶段只修改了三个地方:

ENTRY(_main)

/*
* Set up initial C runtime environment and call board_init_f(0).
*/


/*未定义*/
#if defined(CONFIG_TPL_BUILD) && defined(CONFIG_TPL_NEEDS_SEPARATE_STACK)
ldr r0, =(CONFIG_TPL_STACK)
/*未定义*/
#elif defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
ldr r0, =(CONFIG_SPL_STACK)
#else
/*这里还是设置栈,但这个值和start.S中设置的是一样的值*/
ldr r0, =(CONFIG_SYS_INIT_SP_ADDR)
#endif
bic r0, r0, #7 /* 8-byte alignment for ABI compliance */
mov sp, r0

我们画一个内存分布图,这样可以更好的理解后面u-boot的重定位:

图1

接下来调用board_init_f_alloc_reserve,位于common/init/board_init.c文件:

bl board_init_f_alloc_reserve
/*又更改了一次栈*/
mov sp, r0
ulong board_init_f_alloc_reserve(ulong top)
{
/* Reserve early malloc arena */
/*定义了CONFIG_SYS_MALLOC_F_LEN,大小0x400*/
#if CONFIG_VAL(SYS_MALLOC_F_LEN)
top -= CONFIG_VAL(SYS_MALLOC_F_LEN);
#endif
/* LAST : reserve GD (rounded up to a multiple of 16 bytes) */
/*sizeof(struct global_data)的大小定义在include/generated/generic-asm-offsets.h文件(自动生成的)*/
top = rounddown(top-sizeof(struct global_data), 16);

return top;
}

此函数又更改了sp的位置,现在内存分布如下:

图2

调用board_init_f_init_reserve,主要干了两件事,将图2 sizeof(struct global_data)对应的区域清零,然后建立一个gd全局数据结构,并填充gd->malloc_base字段:

mov r9, r0
bl board_init_f_init_reserve
void board_init_f_init_reserve(ulong base)
{
struct global_data *gd_ptr;

/*
* clear GD entirely and set it up.
* Use gd_ptr, as gd may not be properly set yet.
*/


gd_ptr = (struct global_data *)base;
/* zero the area */
memset(gd_ptr, '\0', sizeof(*gd));
/* set GD unless architecture did it already */
#if !defined(CONFIG_ARM)
arch_setup_gd(gd_ptr);
#endif

/*未定义*/
if (CONFIG_IS_ENABLED(SYS_REPORT_STACK_F_USAGE))
board_init_f_init_stack_protection_addr(base);

/* next alloc will be higher by one GD plus 16-byte alignment */
base += roundup(sizeof(struct global_data), 16);

/*
* record early malloc arena start.
* Use gd as it is now properly set for all architectures.
*/


#if CONFIG_VAL(SYS_MALLOC_F_LEN)
/* go down one 'early malloc arena' */
gd->malloc_base = base;
#endif

/*未定义*/
if (CONFIG_IS_ENABLED(SYS_REPORT_STACK_F_USAGE))
board_init_f_init_stack_protection();
}

gd这个全局变量的定义有点特殊,下面来看一下:

/*gd定义在common/board_f.c的顶部*/
#ifdef XTRN_DECLARE_GLOBAL_DATA_PTR/*未定义*/
#undef XTRN_DECLARE_GLOBAL_DATA_PTR
#define XTRN_DECLARE_GLOBAL_DATA_PTR /* empty = allocate here */
DECLARE_GLOBAL_DATA_PTR = (gd_t *)(CONFIG_SYS_INIT_GD_ADDR);
#else
DECLARE_GLOBAL_DATA_PTR;
#endif
/*此宏位于arch/arm/include/asm/global_data.h文件,原型如下,
这个是定义一个gd_t类型的指针,指针和r9这个寄存器绑定了,
也就是r9这个寄存器之后就不能用于别的用途了,调用board_init_f_init_reserve前,
将r0的值放到了r9里面,而r0指向的位置就是sizeof(struct global_data)对应的
那片内存区域的起始地址,所以r9当然就是gd这个数据结构的起始地址了*/

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

/*gd_t数据结构定义在include/asm-generic/global_data.h文件*/
typedef struct global_data {
bd_t *bd;
unsigned long flags;
unsigned int baudrate;
unsigned long cpu_clk; /* CPU clock in Hz! */
unsigned long bus_clk;
/* We cannot bracket this with CONFIG_PCI due to mpc5xxx */
unsigned long pci_clk;
unsigned long mem_clk;
/*未定义*/
#if defined(CONFIG_LCD) || defined(CONFIG_VIDEO) || defined(CONFIG_DM_VIDEO)
unsigned long fb_base; /* Base address of framebuffer mem */
#endif
/*未定义*/
#if defined(CONFIG_POST)
unsigned long post_log_word; /* Record POST activities */
unsigned long post_log_res; /* success of POST test */
unsigned long post_init_f_time; /* When post_init_f started */
#endif
/*未定义*/
#ifdef CONFIG_BOARD_TYPES
unsigned long board_type;
#endif
unsigned long have_console; /* serial_init() was called */
/*未定义*/
#if CONFIG_IS_ENABLED(PRE_CONSOLE_BUFFER)
unsigned long precon_buf_idx; /* Pre-Console buffer index */
#endif
unsigned long env_addr; /* Address of Environment struct */
unsigned long env_valid; /* Environment valid? enum env_valid */
unsigned long env_has_init; /* Bitmask of boolean of struct env_location offsets */
int env_load_prio; /* Priority of the loaded environment */

unsigned long ram_base; /* Base address of RAM used by U-Boot */
unsigned long ram_top; /* Top address of RAM used by U-Boot */
unsigned long relocaddr; /* Start address of U-Boot in RAM */
phys_size_t ram_size; /* RAM size */
unsigned long mon_len; /* monitor len */
unsigned long irq_sp; /* irq stack pointer */
unsigned long start_addr_sp; /* start_addr_stackpointer */
unsigned long reloc_off;
struct global_data *new_gd; /* relocated global data */

#ifdef CONFIG_DM
struct udevice *dm_root; /* Root instance for Driver Model */
struct udevice *dm_root_f; /* Pre-relocation root instance */
struct list_head uclass_root; /* Head of core tree */
#endif
/*未定义*/
#ifdef CONFIG_TIMER
struct udevice *timer; /* Timer instance for Driver Model */
#endif

const void *fdt_blob; /* Our device tree, NULL if none */
void *new_fdt; /* Relocated FDT */
unsigned long fdt_size; /* Space reserved for relocated FDT */
/*未定义*/
#ifdef CONFIG_OF_LIVE
struct device_node *of_root;
#endif

/*未定义*/
#if CONFIG_IS_ENABLED(MULTI_DTB_FIT)
const void *multi_dtb_fit; /* uncompressed multi-dtb FIT image */
#endif
struct jt_funcs *jt; /* jump table */
char env_buf[32]; /* buffer for env_get() before reloc. */
/*未定义*/
#ifdef CONFIG_TRACE
void *trace_buff; /* The trace buffer */
#endif
/*未定义*/
#if defined(CONFIG_SYS_I2C)
int cur_i2c_bus; /* current used i2c bus */
#endif
unsigned int timebase_h;
unsigned int timebase_l;
#if CONFIG_VAL(SYS_MALLOC_F_LEN)
unsigned long malloc_base; /* base address of early malloc() */
unsigned long malloc_limit; /* limit address */
unsigned long malloc_ptr; /* current address */
#endif
/*未定义*/
#ifdef CONFIG_PCI
struct pci_controller *hose; /* PCI hose for early use */
phys_addr_t pci_ram_top; /* top of region accessible to PCI */
#endif
/*未定义*/
#ifdef CONFIG_PCI_BOOTDELAY
int pcidelay_done;
#endif
struct udevice *cur_serial_dev; /* current serial device */
struct arch_global_data arch; /* architecture-specific data */
/*未定义*/
#ifdef CONFIG_CONSOLE_RECORD
struct membuff console_out; /* console output */
struct membuff console_in; /* console input */
#endif
/*未定义*/
#ifdef CONFIG_DM_VIDEO
ulong video_top; /* Top of video frame buffer area */
ulong video_bottom; /* Bottom of video frame buffer area */
#endif
/*未定义*/
#ifdef CONFIG_BOOTSTAGE
struct bootstage_data *bootstage; /* Bootstage information */
struct bootstage_data *new_bootstage; /* Relocated bootstage info */
#endif
/*未定义*/
#ifdef CONFIG_LOG
int log_drop_count; /* Number of dropped log messages */
int default_log_level; /* For devices with no filters */
struct list_head log_head; /* List of struct log_device */
int log_fmt; /* Mask containing log format info */
#endif

/*未定义*/
#if CONFIG_IS_ENABLED(BLOBLIST)
struct bloblist_hdr *bloblist; /* Bloblist information */
struct bloblist_hdr *new_bloblist; /* Relocated blolist info */
# ifdef CONFIG_SPL
struct spl_handoff *spl_handoff;
# endif
#endif
/*未定义*/
#if defined(CONFIG_TRANSLATION_OFFSET)
fdt_addr_t translation_offset; /* optional translation offset */
#endif
/*未定义*/
#if CONFIG_IS_ENABLED(WDT)
struct udevice *watchdog_dev;
#endif
} gd_t;

这里再建一张表,用于记录gd_t这个数据结构,未定义的不记录:

bd_t *bd;
unsigned long flags;
unsigned int baudrate;
unsigned long cpu_clk;
unsigned long bus_clk;

unsigned long pci_clk;
unsigned long mem_clk;
unsigned long have_console;
unsigned long env_addr;
unsigned long env_valid;
unsigned long env_has_init;
int env_load_prio;

unsigned long ram_base;
unsigned long ram_top;
unsigned long relocaddr;
phys_size_t ram_size;
unsigned long mon_len;
unsigned long irq_sp;
unsigned long start_addr_sp;
unsigned long reloc_off;
struct global_data *new_gd;
struct udevice *dm_root;
struct udevice *dm_root_f;
struct list_head uclass_root;
const void *fdt_blob;
void *new_fdt;
unsigned long fdt_size;
struct jt_funcs *jt;
char env_buf[32];
unsigned int timebase_h;
unsigned int timebase_l;
unsigned long malloc_base;
unsigned long malloc_limit;
unsigned long malloc_ptr;
struct udevice *cur_serial_dev;
struct arch_global_data arch;

新的内存分布图如下:

图3

正式进入board_init_f了,位于common/board_f.c:

/*未定义*/
#if defined(CONFIG_SPL_EARLY_BSS)
SPL_CLEAR_BSS
#endif

mov r0, #0
bl board_init_f
void board_init_f(ulong boot_flags)
{
gd->flags = boot_flags;
gd->have_console = 0;

if (initcall_run_list(init_sequence_f))
hang();
/*定义了,不执行*/
#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) && \
!defined(CONFIG_EFI_APP) && !CONFIG_IS_ENABLED(X86_64) && \
!defined(CONFIG_ARC)

/* NOTREACHED - jump_to_copy() does not return */
hang();
#endif
}

填充了flags和have_console字段后就执行一个初始化列表循环,这个循环里面有很多的函数,只要其中一个出错,u-boot启动就会停止,initcall_run_list函数这里就不追进去看了(位于include/initcall.h),就是一个循环,直接看下需要循环执行哪些函数(由于这个列表太长了,未定义的这里就不列出来了):

/*虽然未定义的都删除了,但是还是有这么多*/
static const init_fnc_t init_sequence_f[] = {
setup_mon_len,
fdtdec_setup,
initf_malloc,
log_init,
initf_bootstage, /* uses its own timer, so does not need DM */
setup_spl_handoff,
initf_console_record,
arch_cpu_init, /* basic arch cpu dependent setup */
mach_cpu_init, /* SoC/machine dependent CPU setup */
initf_dm,
arch_cpu_init_dm,
timer_init, /* initialize timer */
env_init, /* initialize environment */
init_baud_rate, /* initialze baudrate settings */
serial_init, /* serial communications setup */
console_init_f, /* stage 1 init of console */
display_options, /* say that we are here */
display_text_info, /* show debugging info if required */
checkcpu,
print_cpuinfo, /* display cpu info (and speed) */
show_board_info,
INIT_FUNC_WATCHDOG_INIT
INIT_FUNC_WATCHDOG_RESET
announce_dram_init,
dram_init, /* configure available RAM banks */
INIT_FUNC_WATCHDOG_RESET
INIT_FUNC_WATCHDOG_RESET
INIT_FUNC_WATCHDOG_RESET
/*
* Now that we have DRAM mapped and working, we can
* relocate the code and continue running from DRAM.
*
* Reserve memory at end of RAM for (top down in that order):
* - area that won't get touched by U-Boot and Linux (optional)
* - kernel log buffer
* - protected RAM
* - LCD framebuffer
* - monitor code
* - board info struct
*/

setup_dest_addr,
reserve_round_4k,
reserve_mmu,
reserve_video,
reserve_trace,
reserve_uboot,
reserve_malloc,
reserve_board,
setup_machine,
reserve_global_data,
reserve_fdt,
reserve_bootstage,
reserve_bloblist,
reserve_arch,
reserve_stacks,
dram_init_banksize,
show_dram_config,
display_new_sp,
INIT_FUNC_WATCHDOG_RESET
reloc_fdt,
reloc_bootstage,
reloc_bloblist,
setup_reloc,
clear_bss,
NULL,
};

一个函数一个函数的看:

/*common/board_f.c*/

static int setup_mon_len(void)
{
/*__ARM__这个是编译的时候才给定的*/
#if defined(__ARM__) || defined(__MICROBLAZE__)
/*设置mon_len的值为整个u-boot的大小*/
gd->mon_len = (ulong)&__bss_end - (ulong)_start;
/*
省略
*/

return 0;
}
/*lib/fdtdec.c*/

/*获取设备树存放的地址*/
int fdtdec_setup(void)
{
#if CONFIG_IS_ENABLED(OF_CONTROL)
/*未定义*/
# if CONFIG_IS_ENABLED(MULTI_DTB_FIT)
void *fdt_blob;
# endif
/*未定义*/
# ifdef CONFIG_OF_EMBED
/* Get a pointer to the FDT */
# ifdef CONFIG_SPL_BUILD
gd->fdt_blob = __dtb_dt_spl_begin;
# else
gd->fdt_blob = __dtb_dt_begin;
# endif
/*CONFIG_OF_SEPARATE定义了*/
# elif defined(CONFIG_OF_BOARD) || defined(CONFIG_OF_SEPARATE)
/* Allow the board to override the fdt address. */
/*这里设置设备树放的位置为u-boot的末尾,通过对比u-boot.bin和u-boot-nodtb.bin也可以证实这一点,board_fdt_blob_setup函数就在本文件,内容很简单,这里就不追进去了*/
gd->fdt_blob = board_fdt_blob_setup();
# elif defined(CONFIG_OF_HOSTFILE)
if (sandbox_read_fdt_from_file()) {
puts("Failed to read control FDT\n");
return -1;
}
# elif defined(CONFIG_OF_PRIOR_STAGE)
gd->fdt_blob = (void *)prior_stage_fdt_address;
# endif
# ifndef CONFIG_SPL_BUILD
/* Allow the early environment to override the fdt address */
/*如果环境变量定义了fdtcontroladdr,就重新设置设备树放置的位置,我们没有设置,所以使用默认值,还是上面设置的值*/
gd->fdt_blob = map_sysmem
(env_get_ulong("fdtcontroladdr", 16,
(unsigned long)map_to_sysmem(gd->fdt_blob)), 0);
# endif
/*未定义*/
# if CONFIG_IS_ENABLED(MULTI_DTB_FIT)
/*
* Try and uncompress the blob.
* Unfortunately there is no way to know how big the input blob really
* is. So let us set the maximum input size arbitrarily high. 16MB
* ought to be more than enough for packed DTBs.
*/

if (uncompress_blob(gd->fdt_blob, 0x1000000, &fdt_blob) == 0)
gd->fdt_blob = fdt_blob;

/*
* Check if blob is a FIT images containings DTBs.
* If so, pick the most relevant
*/

fdt_blob = locate_dtb_in_fit(gd->fdt_blob);
if (fdt_blob) {
gd->multi_dtb_fit = gd->fdt_blob;
gd->fdt_blob = fdt_blob;
}

# endif
#endif

/*没做什么,就是检查了一下设备树的头*/
return fdtdec_prepare_fdt();
}
/*common/dlmalloc.c*/

/*堆相关的参数设置*/
int initf_malloc(void)
{
#if CONFIG_VAL(SYS_MALLOC_F_LEN)
assert(gd->malloc_base); /* Set up by crt0.S */
gd->malloc_limit = CONFIG_VAL(SYS_MALLOC_F_LEN);
gd->malloc_ptr = 0;
#endif

return 0;
}
/*include/log.h*/

/*log信息相关的*/
/*这个函数在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_f.c*/
/*这个函数没有追进去的必要,基本最后全是空函数,主要就是用于显示当前u-boot运行的进度*/

static int initf_bootstage(void)
{
/*
省略
*/

}
/*common/board_f.c*/

static int setup_spl_handoff(void)
{
/*未定义*/
#if CONFIG_IS_ENABLED(HANDOFF)
gd->spl_handoff = bloblist_find(BLOBLISTT_SPL_HANDOFF,
sizeof(struct spl_handoff));
debug("Found SPL hand-off info %p\n", gd->spl_handoff);
#endif

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

static int initf_console_record(void)
{
/*CONFIG_CONSOLE_RECORD未定义*/
#if defined(CONFIG_CONSOLE_RECORD) && CONFIG_VAL(SYS_MALLOC_F_LEN)
return console_record_init();
#else
return 0;
#endif
}
/*arch/arm/cpu/armv7/s5p-common/cpu_info.c*/

#ifdef CONFIG_ARCH_CPU_INIT
int arch_cpu_init(void)
{
s5p_set_cpu_id();

return 0;
}
#endif

-->

/*arch/arm/mach-s5pc1xx/include/mach/cpu.h*/

static inline void s5p_set_cpu_id(void)
{
/*将CPU ID保存到s5p_cpu_id全局变量中*/
s5p_cpu_id = readl(S5PC100_PRO_ID);
s5p_cpu_rev = s5p_cpu_id & 0x000000FF;
s5p_cpu_id = 0xC000 | ((s5p_cpu_id & 0x00FFF000) >> 12);
}
/*common/board_f.c*/

__weak int mach_cpu_init(void)
{
return 0;
}
/*common/board_f.c*/

/*驱动模型相关的初始化,新版的u-boot引入的,以后专门的分析一下这部分*/
static int initf_dm(void)
{
#if defined(CONFIG_DM) && CONFIG_VAL(SYS_MALLOC_F_LEN)
int ret;

/*显示当前u-boot的进度,没有定义相关宏,不管*/
bootstage_start(BOOTSTATE_ID_ACCUM_DM_F, "dm_f");
ret = dm_init_and_scan(true);
/*空函数*/
bootstage_accum(BOOTSTATE_ID_ACCUM_DM_F);
if (ret)
return ret;
#endif
/*未定义*/
#ifdef CONFIG_TIMER_EARLY
ret = dm_timer_init();
if (ret)
return ret;
#endif

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

__weak int arch_cpu_init_dm(void)
{
return 0;
}
/*arch/arm/cpu/armv7/s5p-common/timer.c*/
/*这个在arch/arm/cpu/armv7/arch_timer.c里面也有定义,但是通过Makefile得知,是没有被编译的*/

int timer_init(void)
{
/*初始化timer4,之后u-boot启动倒计时的时候需要*/
/* PWM Timer 4 */
pwm_init(4, MUX_DIV_4, 0);
pwm_config(4, 100000, 100000);
pwm_enable(4);

/* Use this as the current monotonic time in us */
gd->arch.timer_reset_value = 0;

/* Use this as the last timer value we saw */
gd->arch.lastinc = timer_get_us_down();
reset_timer_masked();

return 0;
}
/*env/env.c*/

/*环境变量初始化*/
int env_init(void)
{
struct env_driver *drv;
int ret = -ENOENT;
int prio;

/*遍历u-boot存放环境变量硬件驱动的那个段,取出相应的结构,然后执行初始化*/
for (prio = 0; (drv = env_driver_lookup(ENVOP_INIT, prio)); prio++) {
/*找到驱动后执行初始化操作,如果没有指定初始化函数(那可能已经初始化过硬件了)或者指定了初始化函数并且初始化成功就置位相应的标志位,表示环境变量的硬件驱动已经初始化了*/
if (!drv->init || !(ret = drv->init()))
env_set_inited(drv->location);

debug("%s: Environment %s init done (ret=%d)\n", __func__,
drv->name, ret);
}

if (!prio)
return -ENODEV;

if (ret == -ENOENT) {
/*因为env/mmc.c里面没有提供初始化函数,所以这里是满足条件的,设置环境变量为默认环境变量,并且标志环境变量可用*/
gd->env_addr = (ulong)&default_environment[0];
gd->env_valid = ENV_VALID;

return 0;
}

return ret;
}

-->

static struct env_driver *env_driver_lookup(enum env_operation op, int prio)
{
enum env_location loc = env_get_location(op, prio);
struct env_driver *drv;

if (loc == ENVL_UNKNOWN)
return NULL;

/*这里就要去查找loc(也就是ENVL_MMC)对应的驱动了*/
drv = _env_driver_lookup(loc);
if (!drv) {
debug("%s: No environment driver for location %d\n", __func__,
loc);
return NULL;
}

return drv;
}

-->

__weak enum env_location env_get_location(enum env_operation op, int prio)
{
/*env_locations定义在本文件中,是一个enum env_location类型的数组,
因为只定义了宏CONFIG_ENV_IS_IN_MMC,所以里面只有一个ENVL_MMC*/

if (prio >= ARRAY_SIZE(env_locations))
return ENVL_UNKNOWN;

/*0*/
gd->env_load_prio = prio;

/*经过查表,返回值为ENVL_MMC*/
return env_locations[prio];
}

-->

static struct env_driver *_env_driver_lookup(enum env_location loc)
{
struct env_driver *drv;
const int n_ents = ll_entry_count(struct env_driver, env_driver);
struct env_driver *entry;

/*这里遍历的是u-boot的一个段(从ll_entry_start得知),所有的存放环境变量的介质的硬件驱动都放在这个段,
驱动直接搜的话是搜不到的,相关的文件都在env目录,比如这里是存放在MMC中,对应的驱动文件为env/mmc.c,
通过U_BOOT_ENV_LOCATION宏定义*/

drv = ll_entry_start(struct env_driver, env_driver);
for (entry = drv; entry != drv + n_ents; entry++) {
if (loc == entry->location)
return entry;
}

/* Not found */
return NULL;
}
/*common/board_f.c*/

static int init_baud_rate(void)
{
/*从环境变量读取波特率,如果没有这个变量就设置为CONFIG_BAUDRATE*/
gd->baudrate = env_get_ulong("baudrate", 10, CONFIG_BAUDRATE);
return 0;
}
/*drivers/serial/serial-uclass.c*/

/*从Makefile得知,使用的serial-uclass.c文件,这是新引入驱动模型*/
ifdef CONFIG_DM_SERIAL
obj-y += serial-uclass.o
else
obj-y += serial.o
endif

int serial_init(void)
{
#if CONFIG_IS_ENABLED(SERIAL_PRESENT)
/*在设备树中查找stdout-path或者console属性,并将其与驱动绑定起来,对设备树这块还不是很了解,没有深入的分析*/
serial_find_console_or_panic();
/*标记串口(终端)已经可用*/
gd->flags |= GD_FLG_SERIAL_READY;
#endif

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

/* Called before relocation - use serial functions */
int console_init_f(void)
{
/*标记终端可用*/
gd->have_console = 1;

/*静默终端,没有使用*/
console_update_silent();

/*空*/
print_pre_console_buffer(PRE_CONSOLE_FLUSHPOINT1_SERIAL);

return 0;
}
/*lib/display_options.c*/

int display_options(void)
{
char buf[DISPLAY_OPTIONS_BANNER_LENGTH];

/*显示当前的u-boot版本号*/
display_options_get_banner(true, buf, sizeof(buf));
printf("%s", buf);

return 0;
}
/*common/board_f.c*/
/*显示bss段及u-boot的链接地址信息,但是没有开启输出调试信息,所以没有输出*/

static int display_text_info(void)
{
/*都没有定义,要执行*/
#if !defined(CONFIG_SANDBOX) && !defined(CONFIG_EFI_APP)
ulong bss_start, bss_end, text_base;

/*获取bss段的信息*/
bss_start = (ulong)&__bss_start;
bss_end = (ulong)&__bss_end;

#ifdef CONFIG_SYS_TEXT_BASE
text_base = CONFIG_SYS_TEXT_BASE;
#else
text_base = CONFIG_SYS_MONITOR_BASE;
#endif

debug("U-Boot code: %08lX -> %08lX BSS: -> %08lX\n",
text_base, bss_start, bss_end);
#endif

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

__weak int checkcpu(void)
{
return 0;
}
/*arch/arm/cpu/armv7/s5p-common/cpu_info.c*/

int print_cpuinfo(void)
{
const char *cpu_model;
int len;

/* For SoC with no real CPU ID in naming convention. */
/*看设备树是否有cpu-model相关的描述,有的话就使用设备树中的*/
cpu_model = fdt_getprop(gd->fdt_blob, 0, "cpu-model", &len);
if (cpu_model)
printf("CPU: %.*s @ ", len, cpu_model);
else
/*显示CPU型号*/
printf("CPU: %s%X @ ", s5p_get_cpu_name(), s5p_cpu_id);

/*显示当前CPU时钟频率*/
print_freq(get_arm_clk(), "\n");

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

int __weak show_board_info(void)
{
#ifdef CONFIG_OF_CONTROL
DECLARE_GLOBAL_DATA_PTR;
const char *model;

/*从设备树中获取model这个属性*/
model = fdt_getprop(gd->fdt_blob, 0, "model", NULL);

/*如果有的话就显示*/
if (model)
printf("Model: %s\n", model);
#endif

/*board/samsung/goni/goni.c显示板子信息*/
return checkboard();
}
/*common/board_f.c*/

static int announce_dram_init(void)
{
/*表示要开始DRAM的一些初始化了*/
puts("DRAM: ");
return 0;
}
/*board/samsung/goni/goni.c*/

int dram_init(void)
{
/*将DRAM的大小填充到ram_size这个字段,由于我的板子只有两片DRAM(总共4片,因为每两片合并成了一片32bit的DRAM了,所以相当于两片),这里需要修改*/
/*修改前*/
/*gd->ram_size = PHYS_SDRAM_1_SIZE + PHYS_SDRAM_2_SIZE +
PHYS_SDRAM_3_SIZE;*/

/*修改后*/
gd->ram_size = PHYS_SDRAM_1_SIZE + PHYS_SDRAM_2_SIZE;

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

/*设置重定位地址*/
static int setup_dest_addr(void)
{
debug("Monitor len: %08lX\n", gd->mon_len);
/*
* Ram is setup, size stored in gd !!
*/

debug("Ram size: %08lX\n", (ulong)gd->ram_size);
/*未定义,是否隐藏DRAM的顶部一片内存*/
#if defined(CONFIG_SYS_MEM_TOP_HIDE)
/*
省略
*/

gd->ram_size -= CONFIG_SYS_MEM_TOP_HIDE;
#endif
/*0x30000000,DRAM的基地址*/
#ifdef CONFIG_SYS_SDRAM_BASE
gd->ram_base = CONFIG_SYS_SDRAM_BASE;
#endif
/*设置ram_top的值*/
gd->ram_top = gd->ram_base + get_effective_memsize();
/*检查ram_top是不是小于内存基地址*/
gd->ram_top = board_get_usable_ram_top(gd->mon_len);
/*重定位地址设置为ram_top*/
gd->relocaddr = gd->ram_top;
debug("Ram top: %08lX\n", (ulong)gd->ram_top);
/*未定义*/
/*
省略
*/

return 0;
}

执行到这里的内存图:

图4/*common/board_f.c*/

static int reserve_round_4k(void)
{
/*4k对齐*/
gd->relocaddr &= ~(4096 - 1);
return 0;
}

新的内存图如下:

图5 没有截取的没有变化/*common/board_f.c*/

__weak int reserve_mmu(void)
{
/*都没有定义,要执行*/
#if !(CONFIG_IS_ENABLED(SYS_ICACHE_OFF) && CONFIG_IS_ENABLED(SYS_DCACHE_OFF))
/* reserve TLB table */
/*arch/arm/include/asm/system.h*/
gd->arch.tlb_size = PGTABLE_SIZE;
gd->relocaddr -= gd->arch.tlb_size;

/*保留页表的内存,保留64K*/
/* round down to next 64 kB limit */
gd->relocaddr &= ~(0x10000 - 1);

/*设置页表的地址*/
gd->arch.tlb_addr = gd->relocaddr;
debug("TLB table from %08lx to %08lx\n", gd->arch.tlb_addr,
gd->arch.tlb_addr + gd->arch.tlb_size);

/*未定义,安全启动相关*/
/*
省略
*/

#endif

return 0;
}

新的内存图如下:

图6/*common/board_f.c*/

static int reserve_video(void)
{
/*未定义*/
#ifdef CONFIG_DM_VIDEO
省略
#endif

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

static int reserve_trace(void)
{
/*未定义*/
#ifdef CONFIG_TRACE
省略
#endif

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

static int reserve_uboot(void)
{
if (!(gd->flags & GD_FLG_SKIP_RELOC)) {
/*
* reserve memory for U-Boot code, data & bss
* round down to next 4 kB limit
*/

/*mon_len这个字段在前面已经填充了,也就是整个u-boot的大小*/
gd->relocaddr -= gd->mon_len;
/*4K对齐*/
gd->relocaddr &= ~(4096 - 1);
/*未定义*/
#if defined(CONFIG_E500) || defined(CONFIG_MIPS)
/* round down to next 64 kB limit so that IVPR stays aligned */
gd->relocaddr &= ~(65536 - 1);
#endif

debug("Reserving %ldk for U-Boot at: %08lx\n",
gd->mon_len >> 10, gd->relocaddr);
}

/*用于栈*/
gd->start_addr_sp = gd->relocaddr;

return 0;
}

新的内存图如下:

图7/*common/board_f.c*/

static int reserve_malloc(void)
{
/*保留堆内存CONFIG_SYS_MALLOC_LEN = CONFIG_ENV_SIZE + (80 << 20),CONFIG_ENV_SIZE+80M*/
gd->start_addr_sp = gd->start_addr_sp - TOTAL_MALLOC_LEN;
debug("Reserving %dk for malloc() at: %08lx\n",
TOTAL_MALLOC_LEN >> 10, gd->start_addr_sp);
/*未定义*/
#ifdef CONFIG_SYS_NONCACHED_MEMORY
reserve_noncached();
#endif

return 0;
}

新的内存图如下:

图8/*common/board_f.c*/

static int reserve_board(void)
{
/*为gd->bd保留内存,bd也是一个结构体,用于保存板子的一些信息*/
if (!gd->bd) {
gd->start_addr_sp -= sizeof(bd_t);
gd->bd = (bd_t *)map_sysmem(gd->start_addr_sp, sizeof(bd_t));
memset(gd->bd, '\0', sizeof(bd_t));
debug("Reserving %zu Bytes for Board Info at: %08lx\n",
sizeof(bd_t), gd->start_addr_sp);
}
return 0;
}

新的内存图如下:

图9

这里又看见了一个新的有用的数据结构,将其记录下来,未定义的没有列出来:

/*include/asm-generic/u-boot.h*/

unsigned long bi_memstart;
phys_size_t bi_memsize;
unsigned long bi_flashstart;
unsigned long bi_flashsize;
unsigned long bi_flashoffset;
unsigned long bi_sramstart;
unsigned long bi_sramsize;
unsigned long bi_arm_freq;
unsigned long bi_dsp_freq;
unsigned long bi_ddr_freq;
unsigned long bi_bootflags;
unsigned long bi_ip_addr;
unsigned char bi_enetaddr[6];
unsigned short bi_ethspeed;
unsigned long bi_intfreq;
unsigned long bi_busfreq;
ulong bi_arch_number;
ulong bi_boot_params;
struct {
phys_addr_t start;
phys_size_t size;
} bi_dram[CONFIG_NR_DRAM_BANKS];
/*common/board_f.c*/

static int setup_machine(void)
{
/*未定义,这个在board_init_r中会设置*/
#ifdef CONFIG_MACH_TYPE
gd->bd->bi_arch_number = CONFIG_MACH_TYPE; /* board id for Linux */
#endif
return 0;
}
/*common/board_f.c*/

static int reserve_global_data(void)
{
/*为gd_t这个数据结构保留内存*/
gd->start_addr_sp -= sizeof(gd_t);
gd->new_gd = (gd_t *)map_sysmem(gd->start_addr_sp, sizeof(gd_t));
debug("Reserving %zu Bytes for Global Data at: %08lx\n",
sizeof(gd_t), gd->start_addr_sp);
return 0;
}

图10/*common/board_f.c*/

static int reserve_fdt(void)
{
/*未定义*/
#ifndef CONFIG_OF_EMBED
省略
#endif

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

static int reserve_bootstage(void)
{
/*未定义*/
#ifdef CONFIG_BOOTSTAGE
省略
#endif

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

static int reserve_bloblist(void)
{
/*未定义*/
#ifdef CONFIG_BLOBLIST
省略
#endif

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

__weak int reserve_arch(void)
{
return 0;
}
/*common/board_f.c*/

static int reserve_stacks(void)
{
/*16字节对齐*/
/* make stack pointer 16-byte aligned */
gd->start_addr_sp -= 16;
gd->start_addr_sp &= ~0xf;

/*
* let the architecture-specific code tailor gd->start_addr_sp and
* gd->irq_sp
*/

/*arch/arm/lib/stack.c*/
return arch_reserve_stacks();
}

-->

/*arch/arm/lib/stack.c*/

int arch_reserve_stacks(void)
{
/*未定义*/
#ifdef CONFIG_SPL_BUILD
gd->start_addr_sp -= 128; /* leave 32 words for abort-stack */
gd->irq_sp = gd->start_addr_sp;
#else
/* setup stack pointer for exceptions */
/*设置irq的栈指针*/
gd->irq_sp = gd->start_addr_sp;

# if !defined(CONFIG_ARM64)
/*保留3个字给abort-stack,再加1字节对齐*/
/* leave 3 words for abort-stack, plus 1 for alignment */
gd->start_addr_sp -= 16;
# endif
#endif

return 0;
}

新的内存图如下,这里有点疑惑,貌似irq栈不止3个字的大小,但这里只保留了三个字:

图11/*board/samsung/goni/goni.c*/

int dram_init_banksize(void)
{
/*我的板子只有两片内存*/
gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;
gd->bd->bi_dram[1].start = PHYS_SDRAM_2;
gd->bd->bi_dram[1].size = PHYS_SDRAM_2_SIZE;
/*删掉下面这一块内存*/
/*
gd->bd->bi_dram[2].start = PHYS_SDRAM_3;
gd->bd->bi_dram[2].size = PHYS_SDRAM_3_SIZE;
*/


return 0;
}

/*这里顺便修改一下DDR的配置,现在的DDR配置是三星的goni这块板子,要修改成我们的板子,修改include/configs/s5p_goni.h头文件*/
#if 0/*修改前*/
/* Goni has 3 banks of DRAM, but swap the bank */
#define PHYS_SDRAM_1 CONFIG_SYS_SDRAM_BASE /* OneDRAM Bank #0 */
#define PHYS_SDRAM_1_SIZE (80 << 20) /* 80 MB in Bank #0 */
#define PHYS_SDRAM_2 0x40000000 /* mDDR DMC1 Bank #1 */
#define PHYS_SDRAM_2_SIZE (256 << 20) /* 256 MB in Bank #1 */
#define PHYS_SDRAM_3 0x50000000 /* mDDR DMC2 Bank #2 */
#define PHYS_SDRAM_3_SIZE (128 << 20) /* 128 MB in Bank #2 */
#else/*修改后*/
#define PHYS_SDRAM_1 CONFIG_SYS_SDRAM_BASE /* OneDRAM Bank #0 */
#define PHYS_SDRAM_1_SIZE (256 << 20) /* 256 MB in Bank #0 */
#define PHYS_SDRAM_2 0x40000000 /* mDDR DMC1 Bank #1 */
#define PHYS_SDRAM_2_SIZE (256 << 20) /* 256 MB in Bank #1 */
#endif
/*common/board_f.c*/

static int show_dram_config(void)
{
unsigned long long size;

/*显示DDR的信息*/
#ifdef CONFIG_NR_DRAM_BANKS
int i;

debug("\nRAM Configuration:\n");
for (i = size = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
size += gd->bd->bi_dram[i].size;
debug("Bank #%d: %llx ", i,
(unsigned long long)(gd->bd->bi_dram[i].start));
#ifdef DEBUG
print_size(gd->bd->bi_dram[i].size, "\n");
#endif
}
debug("\nDRAM: ");
#else
size = gd->ram_size;
#endif

print_size(size, "");
board_add_ram_info(0);
putc('\n');

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

static int display_new_sp(void)
{
debug("New Stack Pointer is: %08lx\n", gd->start_addr_sp);

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

static int reloc_fdt(void)
{
/*未定义*/
#ifndef CONFIG_OF_EMBED
省略
#endif

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

static int reloc_bootstage(void)
{
/*未定义*/
#ifdef CONFIG_BOOTSTAGE
省略
#endif

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

static int reloc_bloblist(void)
{
/*未定义*/
#ifdef CONFIG_BLOBLIST
省略
#endif

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

static int setup_reloc(void)
{
if (gd->flags & GD_FLG_SKIP_RELOC) {
debug("Skipping relocation due to flag\n");
return 0;
}

#ifdef CONFIG_SYS_TEXT_BASE
#ifdef ARM
/*计算u-boot重定位的偏移值*/
gd->reloc_off = gd->relocaddr - (unsigned long)__image_copy_start;
#elif defined(CONFIG_M68K)
/*
* On all ColdFire arch cpu, monitor code starts always
* just after the default vector table location, so at 0x400
*/

gd->reloc_off = gd->relocaddr - (CONFIG_SYS_TEXT_BASE + 0x400);
#elif !defined(CONFIG_SANDBOX)
gd->reloc_off = gd->relocaddr - CONFIG_SYS_TEXT_BASE;
#endif
#endif
/*将gd拷贝到新的地址*/
memcpy(gd->new_gd, (char *)gd, sizeof(gd_t));

debug("Relocation Offset is: %08lx\n", gd->reloc_off);
debug("Relocating to %08lx, new gd at %08lx, sp at %08lx\n",
gd->relocaddr, (ulong)map_to_sysmem(gd->new_gd),
gd->start_addr_sp);

return 0;
}

新的内存图如下:

图12/*common/board_f.c*/

__weak int clear_bss(void)
{
return 0;
}

到了这里board_init_f这个循环就结束了,下面将前面提到的两个重要的数据结构贴出来,有些值没有填进去,可能是我忘记填了,也有一些是还没出现的:

gd_t:

变量
bd_t *bd;指向gd_t这个数据结构
unsigned long flags;0 > GD_FLG_SERIAL_READY
unsigned int baudrate;115200
unsigned long cpu_clk;
unsigned long bus_clk;


unsigned long pci_clk;
unsigned long mem_clk;
unsigned long have_console;0 > 1
unsigned long env_addr;default_environment
unsigned long env_valid;ENV_VALID
unsigned long env_has_init;设置为对应的存放环境变量介质的枚举值
int env_load_prio;ENVL_MMC


unsigned long ram_base;CONFIG_SYS_SDRAM_BASE
unsigned long ram_top;ram_base+ram_size
unsigned long relocaddr;参考内存图
phys_size_t ram_size;设置为DRAM的大小
unsigned long mon_len;__bss_end - _start
unsigned long irq_sp;参考内存图
unsigned long start_addr_sp;参考内存图
unsigned long reloc_off;gd->relocaddr - (unsigned long)__image_copy_start
struct global_data *new_gd;参考内存图
struct udevice *dm_root;
struct udevice *dm_root_f;
struct list_head uclass_root;
const void *fdt_blob;_end
void *new_fdt;
unsigned long fdt_size;
struct jt_funcs *jt;
char env_buf[32];
unsigned int timebase_h;
unsigned int timebase_l;
unsigned long malloc_base;参考内存图
unsigned long malloc_limit;CONFIG_SYS_MALLOC_F_LEN
unsigned long malloc_ptr;0
struct udevice *cur_serial_dev;
struct arch_global_data arch;

bd_t:

变量
unsigned long bi_memstart;
phys_size_t bi_memsize;
unsigned long bi_flashstart;
unsigned long bi_flashsize;
unsigned long bi_flashoffset;
unsigned long bi_sramstart;
unsigned long bi_sramsize;
unsigned long bi_arm_freq;
unsigned long bi_dsp_freq;
unsigned long bi_ddr_freq;
unsigned long bi_bootflags;
unsigned long bi_ip_addr;
unsigned char bi_enetaddr[6];
unsigned short bi_ethspeed;
unsigned long bi_intfreq;
unsigned long bi_busfreq;
ulong bi_arch_number;MACH_TYPE_SMDKV210
ulong bi_boot_params;
struct {
phys_addr_t start;0x30000000
phys_size_t size;256M
} bi_dram[CONFIG_NR_DRAM_BANKS];

总结一下:对于board_init_f主要干的事就是在重定位之前规划好内存的划分,分析完这个函数最后能绘出内存图就差不多明白这个阶段了。

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