接着上篇,執行了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的重定位:
接下來調用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的位置,現在內存分佈如下:
調用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;
新的內存分佈圖如下:
正式進入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;
}
執行到這裏的內存圖:
/*common/board_f.c*/
static int reserve_round_4k(void)
{
/*4k對齊*/
gd->relocaddr &= ~(4096 - 1);
return 0;
}
新的內存圖如下:
/*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;
}
新的內存圖如下:
/*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;
}
新的內存圖如下:
/*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;
}
新的內存圖如下:
/*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;
}
新的內存圖如下:
這裏又看見了一個新的有用的數據結構,將其記錄下來,未定義的沒有列出來:
/*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;
}
/*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個字的大小,但這裏只保留了三個字:
/*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;
}
新的內存圖如下:
/*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 | 0x40000000 | |||||
phys_size_t size; | 256M | 256M | |||||
} bi_dram[CONFIG_NR_DRAM_BANKS]; |
總結一下:對於board_init_f主要乾的事就是在重定位之前規劃好內存的劃分,分析完這個函數最後能繪出內存圖就差不多明白這個階段了。