接着第四节的继续分析,下面的是整个uboot前半部分的核心。
/*
* entry point of crt0 sequence
*/
ENTRY(_main)
/*
* Set up initial C runtime environment and call board_init_f(0).
*/
#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK) /* 我们没定义这个 */
ldr sp, =(CONFIG_SPL_STACK)
#else
/* 在s5pv210.h中定义,上一节有分析,0x33000000 */
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
#endif
#if defined(CONFIG_CPU_V7M) /* v7M forbids using SP as BIC destination 没定义 不用分析*/
mov r3, sp
bic r3, r3, #7
mov sp, r3
#else
bic sp, sp, #7 /* 8-byte alignment for ABI compliance,sp 8字节对齐,我们本就是对齐的*/
#endif
mov r0, sp /* 把上面的0x33000000,作为参数传给下面c函数 */
bl board_init_f_alloc_reserve
mov sp, r0
/* set up gd here, outside any C code */
mov r9, r0 /* r0即当前sp给r9, r9是gd全局变量的指针,同时作为参数传递给下面函数 */
bl board_init_f_init_reserve
mov r0, #0
bl board_init_f /* 把参数0,传给下面函数,并调用它 */
#if ! defined(CONFIG_SPL_BUILD) /* 没定义,所以下面的要执行,先分析完前面的,再分析后面的 */
/*
* Set up intermediate environment (new sp and gd) and call
* relocate_code(addr_moni). Trick here is that we'll return
* 'here' but relocated.
*/
ldr sp, [r9, #GD_START_ADDR_SP] /* sp = gd->start_addr_sp */
#if defined(CONFIG_CPU_V7M) /* v7M forbids using SP as BIC destination */
mov r3, sp
bic r3, r3, #7
mov sp, r3
#else
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
#endif
ldr r9, [r9, #GD_BD] /* r9 = gd->bd */
sub r9, r9, #GD_SIZE /* new GD is below bd */
adr lr, here
ldr r0, [r9, #GD_RELOC_OFF] /* r0 = gd->reloc_off */
add lr, lr, r0 /* lr = new_uboot-old_uboot + here */
#if defined(CONFIG_CPU_V7M)
orr lr, #1 /* As required by Thumb-only */
#endif
ldr r0, [r9, #GD_RELOCADDR] /* r0 = gd->relocaddr */
b relocate_code
here:
/*
* now relocate vectors
*/
bl relocate_vectors
/* Set up final (full) environment */
bl c_runtime_cpu_setup /* we still call old routine here */
#endif
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_FRAMEWORK)
# ifdef CONFIG_SPL_BUILD
/* Use a DRAM stack for the rest of SPL, if requested */
bl spl_relocate_stack_gd
cmp r0, #0
movne sp, r0
movne r9, r0
# endif
ldr r0, =__bss_start /* this is auto-relocated! */
#ifdef CONFIG_USE_ARCH_MEMSET
ldr r3, =__bss_end /* this is auto-relocated! */
mov r1, #0x00000000 /* prepare zero to clear BSS */
subs r2, r3, r0 /* r2 = memset len */
bl memset
#else
ldr r1, =__bss_end /* this is auto-relocated! */
mov r2, #0x00000000 /* prepare zero to clear BSS */
clbss_l:cmp r0, r1 /* while not at end of BSS */
#if defined(CONFIG_CPU_V7M)
itt lo
#endif
strlo r2, [r0] /* clear 32-bit BSS word */
addlo r0, r0, #4 /* move to next */
blo clbss_l
#endif
#if ! defined(CONFIG_SPL_BUILD)
bl coloured_LED_init
bl red_led_on
#endif
/* call board_init_r(gd_t *id, ulong dest_addr) */
mov r0, r9 /* gd_t */
ldr r1, [r9, #GD_RELOCADDR] /* dest_addr */
/* call board_init_r */
#if defined(CONFIG_SYS_THUMB_BUILD)
ldr lr, =board_init_r /* this is auto-relocated! */
bx lr
#else
ldr pc, =board_init_r /* this is auto-relocated! */
#endif
/* we should not return here. */
#endif
ENDPROC(_main)
在board_init_f_alloc_reserve函数之前的状态sp
1.board_init_f_alloc_reserve
ulong board_init_f_alloc_reserve(ulong top)
{
/* Reserve early malloc arena */
#if defined(CONFIG_SYS_MALLOC_F) /* 我有定义这个宏,是0x400 */
top -= CONFIG_SYS_MALLOC_F_LEN;
#endif
/* LAST : reserve GD (rounded up to a multiple of 16 bytes) */
top = rounddown(top-sizeof(struct global_data), 16); /* 再次16字节对齐 */
return top;
}
搜索uboot下面的.config可以确认
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r9")
上面这句话是定义一个寄存器全局变量指针,指定使用的寄存器是r9,类型为gd_t
gd_t是下面的这个结构体,因为我们没定义整个全局结构体变量,所以自己指定位置做这个结构体的存放地
/*
* The following data structure is placed in some memory which 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 GENERATED_GBL_DATA_SIZE > sizeof(gd_t)
*
* Each architecture has its own private fields. For now all are private
*/
#ifndef __ASSEMBLY__
#include
#include
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)
unsigned long fb_base; /* Base address of framebuffer mem */
#endif
#if defined(CONFIG_POST) || defined(CONFIG_LOGBUFFER)
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; /* Checksum of Environment valid? */
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 */
struct jt_funcs *jt; /* jump table */
char env_buf[32]; /* buffer for getenv() 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
#ifdef CONFIG_SYS_I2C_MXC
void *srdata[10];
#endif
unsigned long timebase_h;
unsigned long timebase_l;
#ifdef CONFIG_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
} gd_t;
#endif
2.board_init_f_init_reserve
void board_init_f_init_reserve(ulong base)
{
struct global_data *gd_ptr;
#ifndef _USE_MEMCPY /* 是否使用memcopy函数,通过meke menuconfig配置 */
int *ptr;
#endif
/*
* 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 把gd_t大小空间的内存置位0 */
#ifdef _USE_MEMCPY
memset(gd_ptr, '\0', sizeof(*gd));
#else
/* 如果使用这种方式,gd_ptr + 1是指针+1,即增加一个struct global_data类型 */
for (ptr = (int *)gd_ptr; ptr < (int *)(gd_ptr + 1); )
*ptr++ = 0;
#endif
/* set GD unless architecture did it already */
#if !defined(CONFIG_ARM) /* 咱们是ARM,所以不用管 */
arch_setup_gd(gd_ptr);
#endif
/* next alloc will be higher by one GD plus 16-byte alignment */
base += roundup(sizeof(struct global_data), 16); /* global_data大小以16字节向上对齐 */
/*
* record early malloc arena start.
* Use gd as it is now properly set for all architectures.
*/
#if defined(CONFIG_SYS_MALLOC_F)
/* go down one 'early malloc arena' */
gd->malloc_base = base;
/* next alloc will be higher by one 'early malloc arena' size */
base += CONFIG_SYS_MALLOC_F_LEN;
#endif
}
下面的gd_t是16字节向上对齐的。
3.board_init_f
DECLARE_GLOBAL_DATA_PTR; //注意这里声明了gd指针,下面就可以使用了
void board_init_f(ulong boot_flags)
{
#ifdef CONFIG_SYS_GENERIC_GLOBAL_DATA /* 这个我们没定义 */
/*
* For some architectures, global data is initialized and used before
* calling this function. The data should be preserved. For others,
* CONFIG_SYS_GENERIC_GLOBAL_DATA should be defined and use the stack
* here to host global data until relocation.
*/
gd_t data;
gd = &data;
/*
* Clear global data before it is accessed at debug print
* in initcall_run_list. Otherwise the debug print probably
* get the wrong value of gd->have_console.
*/
zero_global_data();
#endif
gd->flags = boot_flags; /* flag = 0 */
gd->have_console = 0; /* 标记console未初始化 */
if (initcall_run_list(init_sequence_f)) /* 调用这个函数初始化uboot的前半段 */
hang();
#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) && \
!defined(CONFIG_EFI_APP)
/* NOTREACHED - jump_to_copy() does not return */
hang();
#endif
}
做一个表格把常用的gd_t填充在里面,已被后面分析使用
bd_t | |
flag | 0 |
baudrate | |
cpu_clk | |
bus_clk | |
pci_clk | |
mem_clk | |
have_console | 0 |
env_addr | |
env_valid | |
ram_top | |
relocaddr | |
ram_size | |
mon_len | |
irq_sp | |
start_addr_sp | |
reloc_off | |
new_gd | |
fdt_blob | |
fdt_blob | |
new_fdt | |
fdt_size | |
jt | |
env_buf |
3.initcall_run_list
DECLARE_GLOBAL_DATA_PTR;
int initcall_run_list(const init_fnc_t init_sequence[])
{
const init_fnc_t *init_fnc_ptr;
/* 循环执行函数指针数组里面放的每个函数 */
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
unsigned long reloc_ofs = 0;
int ret;
if (gd->flags & GD_FLG_RELOC)
reloc_ofs = gd->reloc_off;
#ifdef CONFIG_EFI_APP /* 我们没定义,所以后面elf相关的都不再分析 */
reloc_ofs = (unsigned long)image_base;
#endif
debug("initcall: %p", (char *)*init_fnc_ptr - reloc_ofs);
if (gd->flags & GD_FLG_RELOC)
debug(" (relocated to %p)\n", (char *)*init_fnc_ptr);
else
debug("\n");
ret = (*init_fnc_ptr)(); /* 执行函数 */
if (ret) {
printf("initcall sequence %p failed at call %p (err=%d)\n",
init_sequence,
(char *)*init_fnc_ptr - reloc_ofs, ret);
return -1;
}
}
return 0;
}
3.1、init_sequence_f初始化uboot的前半段
static init_fnc_t init_sequence_f[] = {
#ifdef CONFIG_SANDBOX /* 没定义不分析 */
setup_ram_buf,
#endif
setup_mon_len, /* 设置gd->mon_len为编译出来的u-boot.bin+bss段的大小 */
#ifdef CONFIG_OF_CONTROL /* 定义了,设备树相关,先不分析 */
fdtdec_setup,
#endif
#ifdef CONFIG_TRACE /* 没定义 */
trace_early_init,
#endif
initf_malloc, /* 设置内存池的大小 */
initf_console_record, /* 平台信息记录初始化 */
#if defined(CONFIG_MPC85xx) || defined(CONFIG_MPC86xx) /* 没定义 */
/* TODO: can this go into arch_cpu_init()? */
probecpu,
#endif
#if defined(CONFIG_X86) && defined(CONFIG_HAVE_FSP) /* 没定义 */
x86_fsp_init,
#endif
arch_cpu_init, /* basic arch cpu dependent setup */
mach_cpu_init, /* SoC/machine dependent CPU setup */
initf_dm, /* dm 初始化 */
arch_cpu_init_dm,
mark_bootstage, /* need timer, go after init dm */
#if defined(CONFIG_BOARD_EARLY_INIT_F) /* 没定义 */
board_early_init_f, /* 时钟和GPIO口设置 */
#endif
/* TODO: can any of this go into arch_cpu_init()? */
#if defined(CONFIG_PPC) && !defined(CONFIG_8xx_CPUCLK_DEFAULT) /* 没定义 */
get_clocks, /* get CPU and bus clocks (etc.) */
#if defined(CONFIG_TQM8xxL) && !defined(CONFIG_TQM866M) \ /* 没定义 */
&& !defined(CONFIG_TQM885D)
adjust_sdram_tbs_8xx,
#endif
/* TODO: can we rename this to timer_init()? */
init_timebase,
#endif
#if defined(CONFIG_ARM) || defined(CONFIG_MIPS) || \ /* 定义arm了 */
defined(CONFIG_BLACKFIN) || defined(CONFIG_NDS32) || \
defined(CONFIG_SH) || defined(CONFIG_SPARC)
timer_init, /* initialize timer 初始化定时器*/
#endif
#ifdef CONFIG_SYS_ALLOC_DPRAM /* 没定义 */
#if !defined(CONFIG_CPM2)
dpram_init,
#endif
#endif
#if defined(CONFIG_BOARD_POSTCLK_INIT) /* 没定义 */
board_postclk_init,
#endif
#if defined(CONFIG_SYS_FSL_CLK) || defined(CONFIG_M68K) CONFIG_SYS_FSL_CLK
get_clocks,
#endif
env_init, /* initialize environment初始化环境变量的地址 */
#if defined(CONFIG_8xx_CPUCLK_DEFAULT) /* 没定义 */
/* get CPU and bus clocks according to the environment variable */
get_clocks_866,
/* adjust sdram refresh rate according to the new clock */
sdram_adjust_866,
init_timebase,
#endif
init_baud_rate, /* initialze baudrate settings 初始化波特率设置 */
serial_init, /* serial communications setup 串口初始化 */
console_init_f, /* stage 1 init of console 在重定位之前使能串口功能 */
#ifdef CONFIG_SANDBOX /* 没定义 */
sandbox_early_getopt_check,
#endif
display_options, /* say that we are here 打印当前banner 信息 */
display_text_info, /* show debugging info if required 显示 debug 信息 */
#if defined(CONFIG_MPC8260) /* 没定义 */
prt_8260_rsr,
prt_8260_clks,
#endif /* CONFIG_MPC8260 */
#if defined(CONFIG_MPC83xx) /* 没定义 */
prt_83xx_rsr,
#endif
#if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_SH) /* 没定义 */
checkcpu,
#endif
print_cpuinfo, /* display cpu info (and speed)显示CPU信息 */
#if defined(CONFIG_MPC5xxx) /* 没定义 */
prt_mpc5xxx_clks,
#endif /* CONFIG_MPC5xxx */
#if defined(CONFIG_DISPLAY_BOARDINFO) /* 定义了 */
show_board_info, /* 显示板子信息 */
#endif
INIT_FUNC_WATCHDOG_INIT
#if defined(CONFIG_MISC_INIT_F) /* 没定义 */
misc_init_f,
#endif
INIT_FUNC_WATCHDOG_RESET
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SYS_I2C) /* 没定义 */
init_func_i2c,
#endif
#if defined(CONFIG_HARD_SPI) /* 没定义 */
init_func_spi,
#endif
announce_dram_init, /* 准备显示 DRAM 大小 */
/* TODO: unify all these dram functions? */
#if defined(CONFIG_ARM) || defined(CONFIG_X86) || defined(CONFIG_NDS32) || \
defined(CONFIG_MICROBLAZE) || defined(CONFIG_AVR32) || \
defined(CONFIG_SH) /* 定义arm 了 */
dram_init, /* configure available RAM banks DRAM 初始化,打印DRAM大小*/
#endif
#if defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_M68K) /* 没定义 */
init_func_ram,
#endif
#ifdef CONFIG_POST /* 没定义 */
post_init_f,
#endif
INIT_FUNC_WATCHDOG_RESET
#if defined(CONFIG_SYS_DRAM_TEST) /* 没定义 */
testdram,
#endif /* CONFIG_SYS_DRAM_TEST */ /* 没定义 */
INIT_FUNC_WATCHDOG_RESET
#ifdef CONFIG_POST /* 没定义 */
init_post,
#endif
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, /* 设置重定位地址,gd->relocaddr */
#if defined(CONFIG_BLACKFIN) || defined(CONFIG_XTENSA) /* 没定义 */
/* Blackfin u-boot monitor should be on top of the ram */
reserve_uboot,
#endif
#if defined(CONFIG_SPARC) /* 没定义 */
reserve_prom,
#endif
#if defined(CONFIG_LOGBUFFER) && !defined(CONFIG_ALT_LB_ADDR) /* 没定义 */
reserve_logbuffer,
#endif
#ifdef CONFIG_PRAM /* 没定义 */
reserve_pram,
#endif
reserve_round_4k, /* 4 字节对齐 */
#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF)) && \
defined(CONFIG_ARM) /* 这里要执行 */
reserve_mmu, /* 预留 MMU 区域 */
#endif
#ifdef CONFIG_DM_VIDEO /* 没定义 */
reserve_video, /* 预留 video 区 */
#else
# ifdef CONFIG_LCD /* 没定义 */
reserve_lcd,
# endif
/* TODO: Why the dependency on CONFIG_8xx? */
# if defined(CONFIG_VIDEO) && (!defined(CONFIG_PPC) || defined(CONFIG_8xx)) && \
!defined(CONFIG_ARM) && !defined(CONFIG_X86) && \
!defined(CONFIG_BLACKFIN) && !defined(CONFIG_M68K) /* 没定义 */
reserve_legacy_video,
# endif
#endif /* CONFIG_DM_VIDEO */ /* 没定义 */
reserve_trace,
#if !defined(CONFIG_BLACKFIN) && !defined(CONFIG_XTENSA) /* 没定义,要执行 */
reserve_uboot, /* 预留 uboot 区,gd->start_addr_sp = gd->relocaddr -= gd->mon_len */
#endif
#ifndef CONFIG_SPL_BUILD /* 没定义 */
reserve_malloc, /* 预留堆区 gd->start_addr_sp 指向 malloc 段基地址*/
reserve_board, /* board 信息结构体分配区域 栈 gd->start_addr_sp 指向 bd 段 基地址*/
#endif
setup_machine, /* 板子ID 如果定义则有,我们没有 */ */
reserve_global_data, /* 预留 GD 区域,栈 gd->start_addr_sp 指向 gd 段 基地址*/
reserve_fdt, /* 预留设备树区域 */
reserve_arch, /* 架构相关预留区 */
reserve_stacks, /* 栈区预留区,gd->start_addr_sp 指向 栈底基地址 */
setup_dram_config, /* DRAM 的大小初始化 */
show_dram_config, /* 显示 DRAM 的配置 */
#if defined(CONFIG_M68K) || defined(CONFIG_MIPS) || defined(CONFIG_PPC) || \
defined(CONFIG_SH) /* 没定义 */
setup_board_part1,
#endif
#if defined(CONFIG_PPC) || defined(CONFIG_M68K) /* 没定义 */
INIT_FUNC_WATCHDOG_RESET
setup_board_part2,
#endif
display_new_sp, /* 显示新的栈地址 */
#ifdef CONFIG_SYS_EXTBDINFO /* 没定义 */
setup_board_extra,
#endif
INIT_FUNC_WATCHDOG_RESET
reloc_fdt, /* 设备树相关*/
setup_reloc, /* 建立重定向,设置 gd->rellocoff和新gd */
#if defined(CONFIG_X86) || defined(CONFIG_ARC) /* 没定义 */
copy_uboot_to_ram,
clear_bss,
do_elf_reloc_fixups,
#endif
#if defined(CONFIG_XTENSA) /* 没定义 */
clear_bss,
#endif
#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) /* 不执行 */
jump_to_copy,
#endif
NULL,
};
现在就先逐个分析,其实现的功能
在分析之前,我先列出来连接脚本中每个段的标记,方便下面使用到的时候过来查询。
3.1.1、setup_mon_len
/* _start为我们的.text的首地址
* _bss_end为我们uboot包含所有段的结束地址
*/
static int setup_mon_len(void)
{
#if defined(__ARM__) || defined(__MICROBLAZE__)
gd->mon_len = (ulong)&__bss_end - (ulong)_start; /* 得到uboot的总长度 */
#elif defined(CONFIG_SANDBOX) || defined(CONFIG_EFI_APP)
gd->mon_len = (ulong)&_end - (ulong)_init;
#elif defined(CONFIG_BLACKFIN) || defined(CONFIG_NIOS2) || \
defined(CONFIG_XTENSA)
gd->mon_len = CONFIG_SYS_MONITOR_LEN;
#elif defined(CONFIG_NDS32) || defined(CONFIG_SH)
gd->mon_len = (ulong)(&__bss_end) - (ulong)(&_start);
#elif defined(CONFIG_SYS_MONITOR_BASE)
/* TODO: use (ulong)&__bss_end - (ulong)&__text_start; ? */
gd->mon_len = (ulong)&__bss_end - CONFIG_SYS_MONITOR_BASE;
#endif
return 0;
}
3.1.2、initf_malloc内存池大小
int initf_malloc(void)
{
#ifdef CONFIG_SYS_MALLOC_F_LEN
assert(gd->malloc_base); /* Set up by crt0.S */
gd->malloc_limit = CONFIG_SYS_MALLOC_F_LEN; /* 我们这里是0x400 */
gd->malloc_ptr = 0;
#endif
return 0;
}
3.1.3、initf_console_record
static int initf_console_record(void)
{
/* CONFIG_CONSOLE_RECORD这个我们没定义 */
#if defined(CONFIG_CONSOLE_RECORD) && defined(CONFIG_SYS_MALLOC_F_LEN)
return console_record_init();
#else
return 0;
#endif
}
3.1.4、arch_cpu_init
/* S5PC100_PRO_ID 地址是0xe0000000 */
/* 我们最终计算完出来是0xC110 */
static inline void s5p_set_cpu_id(void)
{
s5p_cpu_id = readl(S5PC100_PRO_ID);
s5p_cpu_rev = s5p_cpu_id & 0x000000FF;
s5p_cpu_id = 0xC000 | ((s5p_cpu_id & 0x00FFF000) >> 12);
}
int arch_cpu_init(void)
{
s5p_set_cpu_id();
return 0;
}
3.1.5、timer_init
int timer_init(void)
{
/* 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;
}
3.1.6、env_init
int env_init(void)
{
/* 默认环境变量初始化 */
gd->env_addr = (ulong)&default_environment[0];
gd->env_valid = 0;
return 0;
}
3.1.7、初始化波特率,是从环境变量里面找,找不到了用后面的默认值,我们都是115200
static int init_baud_rate(void)
{
/* 设置波特率值,CONFIG_BAUDRATE是我们在smdkv210里面定义的115200 */
gd->baudrate = getenv_ulong("baudrate", 10, CONFIG_BAUDRATE);
return 0;
}
3.1.8、serial_init
/* Called prior to relocation */
int serial_init(void)
{
serial_find_console_or_panic(); /* 通过设备树方式初始化串口 */
gd->flags |= GD_FLG_SERIAL_READY; /* 标记串口初始化ready */
return 0;
}
3.1.9、console_init_f
int console_init_f(void)
{
gd->have_console = 1;
console_update_silent(); /* 设置flag,表明要不要静默控制台,我们没配置,不管 */
/* 如果有配置早期console,会把要发送的数据存储在一个buf中,这里统一输出,我们前面都没使用过标准的输出,所以这里对我们没用到 */
print_pre_console_buffer(PRE_CONSOLE_FLUSHPOINT1_SERIAL);
return 0;
}
3.1.10、display_options
#define U_BOOT_VERSION_STRING U_BOOT_VERSION " (" U_BOOT_DATE " - " \
U_BOOT_TIME " " U_BOOT_TZ ")" CONFIG_IDENT_STRING
//我们的这个定义为空
int display_options (void)
{
#if defined(BUILD_TAG) /* 我们没定义BUILD_TAG,所以不打印编译标签 */
printf ("\n\n%s, Build: %s\n\n", version_string, BUILD_TAG);
#else
printf ("\n\n%s\n\n", version_string);
#endif
return 0;
}
实际上面的函数,作用如下图的红框
3.1.11、print_cpuinfo
#define S5P_CPU_NAME "S5P"
static inline char *s5p_get_cpu_name(void)
{
return S5P_CPU_NAME;
}
int print_cpuinfo(void)
{
const char *cpu_model;
int len;
/* For SoC with no real CPU ID in naming convention. */
cpu_model = fdt_getprop(gd->fdt_blob, 0, "cpu-model", &len);
if (cpu_model)
printf("CPU: %.*s @ ", len, cpu_model);
else /* 我们使用下面这个的 */
/* 可以通过上面的函数看到,会打印出"CPU: S5PC110",s5p_cpu_id是前面判断cpu时确定的 */
printf("CPU: %s%X @ ", s5p_get_cpu_name(), s5p_cpu_id);
/* 前面没有换行,所以时钟继续跟在后面打印 */
print_freq(get_arm_clk(), "\n");
return 0;
}
可以看到CPU时钟1G,说明我们前面自己改的时钟初始化没问题。
3.1.12、show_board_info
int __weak show_board_info(void)
{
#ifdef CONFIG_OF_CONTROL
DECLARE_GLOBAL_DATA_PTR;
const char *model;
model = fdt_getprop(gd->fdt_blob, 0, "model", NULL); /* 设备树得到一些板子信息 */
if (model)
printf("Model: %s\n", model);
#endif
return checkboard();
}
int checkboard(void)
{
puts("Board:\tGoni\n"); /* 后面我们把这个改了,改成SMDKV210 */
return 0;
}
3.1.13、announce_dram_init
static int announce_dram_init(void)
{
puts("DRAM: "); /* 打印出"DRAM: "*/
return 0;
}
3.1.14、dram_init
int dram_init(void)
{
/* 已经配置过来了,2块256Mddr */
gd->ram_size = PHYS_SDRAM_1_SIZE + PHYS_SDRAM_2_SIZE ;
return 0;
}
3.1.15、setup_dest_addr
__weak phys_size_t board_reserve_ram_top(phys_size_t ram_size)
{
#ifdef CONFIG_SYS_MEM_TOP_HIDE /* 没定义 */
return ram_size - CONFIG_SYS_MEM_TOP_HIDE;
#else
return ram_size; /* 返回512M 0x20000000 */
#endif
}
__weak ulong board_get_usable_ram_top(ulong total_size)
{
#ifdef CONFIG_SYS_SDRAM_BASE
/*
* Detect whether we have so much RAM that it goes past the end of our
* 32-bit address space. If so, clip the usable RAM so it doesn't.
*/
if (gd->ram_top < CONFIG_SYS_SDRAM_BASE)
/*
* Will wrap back to top of 32-bit space when reservations
* are made.
*/
return 0;
#endif
return gd->ram_top; /* 我们返回这里0x50000000 */
}
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);
#ifdef CONFIG_SYS_MEM_RESERVE_SECURE /* 没定义 */
/* Reserve memory for secure MMU tables, and/or security monitor */
gd->ram_size -= CONFIG_SYS_MEM_RESERVE_SECURE;
/*
* Record secure memory location. Need recalcuate if memory splits
* into banks, or the ram base is not zero.
*/
gd->arch.secure_ram = gd->ram_size;
#endif
/*
* Subtract specified amount of memory to hide so that it won't
* get "touched" at all by U-Boot. By fixing up gd->ram_size
* the Linux kernel should now get passed the now "corrected"
* memory size and won't touch it either. This has been used
* by arch/powerpc exclusively. Now ARMv8 takes advantage of
* thie mechanism. If memory is split into banks, addresses
* need to be calculated.
*/
/* 从前面的函数,我们记录的表格查询ram_size = 512M */
gd->ram_size = board_reserve_ram_top(gd->ram_size);
#ifdef CONFIG_SYS_SDRAM_BASE
gd->ram_top = CONFIG_SYS_SDRAM_BASE; /* 我们在smdkv210.h定义的0x30000000 */
#endif
gd->ram_top += get_effective_memsize(); /* 返回0x20000000,ram_top = 0x50000000 */
gd->ram_top = board_get_usable_ram_top(gd->mon_len); /* 还是返回0x50000000 */
gd->relocaddr = gd->ram_top; /* 0x50000000 */
debug("Ram top: %08lX\n", (ulong)gd->ram_top);
#if defined(CONFIG_MP) && (defined(CONFIG_MPC86xx) || defined(CONFIG_E500))
/*
* We need to make sure the location we intend to put secondary core
* boot code is reserved and not used by any part of u-boot
*/
if (gd->relocaddr > determine_mp_bootpg(NULL)) {
gd->relocaddr = determine_mp_bootpg(NULL);
debug("Reserving MP boot page to %08lx\n", gd->relocaddr);
}
#endif
return 0;
}
目前gd->relocaddr = 0x50000000 指向DDR的顶端
3.1.16、reserve_round_4k
/* Round memory pointer down to next 4 kB limit */
static int reserve_round_4k(void)
{
gd->relocaddr &= ~(4096 - 1); /* 4k向下对齐 */
return 0;
}
这里4K先不放图了
3.1.17、reserve_mmu
#define PGTABLE_SIZE (4096 * 4) /* 16K的页表 */
static int reserve_mmu(void)
{
/* reserve TLB table */
gd->arch.tlb_size = PGTABLE_SIZE;
gd->relocaddr -= gd->arch.tlb_size; /* 从ox50000000向下少了16+4K */
/* round down to next 64 kB limit */
gd->relocaddr &= ~(0x10000 - 1); /* 64k向下对齐 */
gd->arch.tlb_addr = gd->relocaddr; /* 页表必须64k对齐存放 */
debug("TLB table from %08lx to %08lx\n", gd->arch.tlb_addr,
gd->arch.tlb_addr + gd->arch.tlb_size);
#ifdef CONFIG_SYS_MEM_RESERVE_SECURE
/*
* Record allocated tlb_addr in case gd->tlb_addr to be overwritten
* with location within secure ram.
*/
gd->arch.tlb_allocated = gd->arch.tlb_addr;
#endif
return 0;
}
3.1.18、reserve_uboot
static int reserve_uboot(void)
{
/*
* reserve memory for U-Boot code, data & bss
* round down to next 4 kB limit
*/
gd->relocaddr -= gd->mon_len; /* 减去boot的总长度(包括bss) */
gd->relocaddr &= ~(4096 - 1); /* 4k对齐 */
#ifdef CONFIG_E500
/* 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; /* 把 start_addr_sp 也置为同样的位置 */
return 0;
}
3.1.19、reserve_malloc,保留一段malloc的空间
/* reserve memory for malloc() area */
static int reserve_malloc(void)
{
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);
3.1.20、reserve_board保留bd的空间
/* (permanently) allocate a Board Info struct */
static int reserve_board(void)
{
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;
}
3.1.19、reserve_global_data
static int reserve_global_data(void)
{
gd->start_addr_sp -= sizeof(gd_t); /* 保留gd_t */
gd->new_gd = (gd_t *)map_sysmem(gd->start_addr_sp, sizeof(gd_t)); /* 设置新的gd地址 */
debug("Reserving %zu Bytes for Global Data at: %08lx\n",
sizeof(gd_t), gd->start_addr_sp);
return 0;
}
3.1.20、reserve_fdt
static int reserve_fdt(void)
{
#ifndef CONFIG_OF_EMBED /* 没定义,要分析 */
/*
* If the device tree is sitting immediately above our image then we
* must relocate it. If it is embedded in the data section, then it
* will be relocated with other data.
*/
/* 前面的没分析,所以这里先假设有 */
if (gd->fdt_blob) {
gd->fdt_size = ALIGN(fdt_totalsize(gd->fdt_blob) + 0x1000, 32);
gd->start_addr_sp -= gd->fdt_size;
gd->new_fdt = map_sysmem(gd->start_addr_sp, gd->fdt_size);
debug("Reserving %lu Bytes for FDT at: %08lx\n",
gd->fdt_size, gd->start_addr_sp);
}
#endif
return 0;
}
3.1.21、reserve_stacks
static int reserve_stacks(void)
{
/* make stack pointer 16-byte aligned */
gd->start_addr_sp -= 16; /* 预留16字节后 */
gd->start_addr_sp &= ~0xf; /* 16字节对齐 */
/*
* let the architecture-specific code tailor gd->start_addr_sp and
* gd->irq_sp
*/
return arch_reserve_stacks();
}
这里就不画图了
3.1.22、setup_dram_config,配置每个ddr的bank大小
void 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;
}
static int setup_dram_config(void)
{
/* Ram is board specific, so move it to board code ... */
dram_init_banksize();
return 0;
}
bd里面是板子相关的,这里就不列表了
2.1.23、show_dram_config
static int show_dram_config(void)
{
unsigned long long size;
#ifdef CONFIG_NR_DRAM_BANKS /* 我们是2 */
int i;
debug("\nRAM Configuration:\n");
for (i = size = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
size += gd->bd->bi_dram[i].size; /* debug我们没配置,所以这里就计算了总大小 */
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; /* 512M */
#endif
print_size(size, ""); /* 打印512 Mib */
board_add_ram_info(0); /*具体的细节我们没配,所以这个函数是空的 */
putc('\n');
return 0;
}
2.1.24、display_new_sp我们没开debug功能,看不到
static int display_new_sp(void)
{
debug("New Stack Pointer is: %08lx\n", gd->start_addr_sp);
return 0;
}
2.1.25、reloc_fdt重定位设备树
static int reloc_fdt(void)
{
#ifndef CONFIG_OF_EMBED /* 没定义,要执行 */
if (gd->flags & GD_FLG_SKIP_RELOC)
return 0;
if (gd->new_fdt) { 把设备树段拷贝到新的位置
memcpy(gd->new_fdt, gd->fdt_blob, gd->fdt_size);
gd->fdt_blob = gd->new_fdt; /* 然后把老的地址跟新为新地址 */
}
#endif
return 0;
}
深色表明已经拷贝成功
2.1.26、setup_reloc重定位gd_t
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
gd->reloc_off = gd->relocaddr - CONFIG_SYS_TEXT_BASE; /* 得到新旧uboot的偏移 */
#ifdef 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);
#endif
#endif
memcpy(gd->new_gd, (char *)gd, sizeof(gd_t)); /* 拷贝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;
}
board_init_f中的内容就已经分析完了。
接下来就剩下uboot本身的搬移和bss段的初始化。