首页 > 代码库 > u-boot-2014.10移植第9天----深入分析代码(四)
u-boot-2014.10移植第9天----深入分析代码(四)
硬件平台:tq2440
开发环境:Ubuntu-3.11
u-boot版本:2014.10
本文允许转载,请注明出处:http://blog.csdn.net/fulinus
ENTRY(_main)
/*
* Set up initial C runtime environment and call board_init_f(0).
*/
#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK) //在smdk2410开发板的相关目录中没有定义;
ldr sp, =(CONFIG_SPL_STACK)
#else
//CONFIG_SYS_INIT_SP_ADDR在include/configs/smdk2410.h中定义:
/* additions for new relocation code, must be added to all boards */
#define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_1
#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + 0x1000 - \
GENERATED_GBL_DATA_SIZE)
PHYS_SDRAM_1:
#define PHYS_SDRAM_1 0x30000000 /* SDRAM Bank #1 */
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
#endif
8字节对齐
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
栈顶保存到r2中
mov r2, sp
将栈指针下移GD_SIZE,sp上面的GD_SIZE大小用于放全局变量
sub sp, sp, #GD_SIZE /* allocate one GD above SP */
8字节对齐
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
保存栈底到r9中
mov r9, sp /* GD is above SP */
同上
mov r1, sp
r0 = 0
mov r0, #0
下面循环用于将栈空间和GD区域清零操作。
clr_gd:
cmp r1, r2 /* while not at end of GD */strlo r0, [r1] /* clear 32-bit GD word */
addlo r1, r1, #4 /* move to next */
blo clr_gd
未定义,跳过
#if defined(CONFIG_SYS_MALLOC_F_LEN) && !defined(CONFIG_SPL_BUILD)sub sp, sp, #CONFIG_SYS_MALLOC_F_LEN
str sp, [r9, #GD_MALLOC_BASE]
#endif
* 2. Call board_init_f(). This function prepares the hardware for
调用board_init_f函数,为从系统的RAM中执行做硬件初始化。
* execution from system RAM (DRAM, DDR...) As system RAM may not
作为系统RAM可能还是不可用的,函数必须用现在的GD区域来保存
* be available yet, , board_init_f() must use the current GD to
需要传递给下一阶段的任意数据。
* store any data which must be passed on to later stages. These
包括重定位的目的地址,未来的栈和GD位置
* data include the relocation destination, the future stack, and
* the future GD location.
board_init_f函数在文件arch/arm/lib/board.c中定义如下:
void board_init_f(ulong bootflag)
{
bd_t *bd;
init_fnc_t **init_fnc_ptr;
gd_t *id;
ulong addr, addr_sp;
#ifdef CONFIG_PRAM
ulong reg;
#endif
void *new_fdt = NULL;
size_t fdt_size = 0;
先将GD区域清零gd的值就是前面的r9,GD的首地址。gd_t是一个很大的数据结构体。如下:
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 */
#ifdef CONFIG_PRE_CONSOLE_BUFFER
unsigned long precon_buf_idx; /* Pre-Console buffer index */
#endif
#ifdef CONFIG_MODEM_SUPPORT
unsigned long do_mdm_init;
unsigned long be_quiet;
#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
const void *fdt_blob; /* Our device tree, NULL if none */
void *new_fdt; /* Relocated FDT */
unsigned long fdt_size; /* Space reserved for relocated FDT */
void **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
struct arch_global_data arch; /* architecture-specific data */
} gd_t;
memset((void *)gd, 0, sizeof(gd_t));
下面基本上就是在初始化GD区域。
gd->mon_len = (ulong)&__bss_end - (ulong)_start; 初始化mon_len,代表uboot code的大小。
#ifdef CONFIG_OF_EMBED //未定义
/* Get a pointer to the FDT */
gd->fdt_blob = __dtb_dt_begin;
#elif defined CONFIG_OF_SEPARATE //未定义
/* FDT is at end of image */
gd->fdt_blob = &_end;
#endif
/* Allow the early environment to override the fdt address */
gd->fdt_blob = (void *)getenv_ulong("fdtcontroladdr", 16,
(uintptr_t)gd->fdt_blob);
init_fnc_t *init_sequence[] = {
arch_cpu_init, /* basic arch cpu dependent setup */
mark_bootstage, //标记启动阶段
#ifdef CONFIG_OF_CONTROL //未定义
fdtdec_check_fdt,
#endif
#if defined(CONFIG_BOARD_EARLY_INIT_F)
board_early_init_f, //函数中主要完成减小PLL锁定时间,调整闭锁寄存器,配置MPLL、UPLL、I/O端口
#endif
timer_init, /* initialize timer */
#ifdef CONFIG_BOARD_POSTCLK_INIT //未定义
board_postclk_init,
#endif
#ifdef CONFIG_FSL_ESDHC
get_clocks,
#endif
env_init, /* initialize environment */
init_baudrate, /* initialze baudrate settings */
serial_init, /* serial communications setup */
console_init_f, /* stage 1 init of console */
display_banner, /* say that we are here */
print_cpuinfo, /* display cpu info (and speed) */
#if defined(CONFIG_DISPLAY_BOARDINFO)
checkboard, /* display board info */
#endif
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SYS_I2C)
init_func_i2c,
#endif
dram_init, /* configure available RAM banks */
NULL,
};
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
#ifdef CONFIG_OF_CONTROL //未定义
/* For now, put this check after the console is ready */
if (fdtdec_prepare_fdt()) {
panic("** CONFIG_OF_CONTROL defined but no FDT - please see "
"doc/README.fdt-control");
}
#endif
串口和控制台初始化好后,下面就可以调用debug打印信息了。
debug("monitor len: %08lX\n", gd->mon_len);
/*
* Ram is setup, size stored in gd !!
*/
debug("ramsize: %08lX\n", gd->ram_size);
#if defined(CONFIG_SYS_MEM_TOP_HIDE) //未定义
/*
* 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 should work
* for arch/ppc and arch/powerpc. Only Linux board ports in
* arch/powerpc with bootwrapper support, that recalculate the
* memory size from the SDRAM controller setup will have to
* get fixed.
*/
gd->ram_size -= CONFIG_SYS_MEM_TOP_HIDE;
#endif
addr = CONFIG_SYS_SDRAM_BASE + get_effective_memsize(); //获取SDRAM结束地址
#ifdef CONFIG_LOGBUFFER //
#ifndef CONFIG_ALT_LB_ADDR
/* reserve kernel log buffer */
addr -= (LOGBUFF_RESERVE);
debug("Reserving %dk for kernel logbuffer at %08lx\n", LOGBUFF_LEN,
addr);
#endif
#endif
#ifdef CONFIG_PRAM //未定义
/*
* reserve protected RAM
*/
reg = getenv_ulong("pram", 10, CONFIG_PRAM);
addr -= (reg << 10); /* size is in kB */
debug("Reserving %ldk for protected RAM at %08lx\n", reg, addr);
#endif /* CONFIG_PRAM */
#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))
/* reserve TLB table */
gd->arch.tlb_size = PGTABLE_SIZE; //预留TLB表
addr -= gd->arch.tlb_size;
/* round down to next 64 kB limit */
addr &= ~(0x10000 - 1);
gd->arch.tlb_addr = addr;
debug("TLB table from %08lx to %08lx\n", addr, addr + gd->arch.tlb_size);
#endif
/* round down to next 4 kB limit */
addr &= ~(4096 - 1);
debug("Top of RAM usable for U-Boot at: %08lx\n", addr);
#ifdef CONFIG_LCD
#ifdef CONFIG_FB_ADDR
gd->fb_base = CONFIG_FB_ADDR;
#else
/* reserve memory for LCD display (always full pages) */
addr = lcd_setmem(addr);
gd->fb_base = addr;
#endif /* CONFIG_FB_ADDR */
#endif /* CONFIG_LCD */
/*
* reserve memory for U-Boot code, data & bss
* round down to next 4 kB limit
*/
为u-boot的代码和bss预留空间
addr -= gd->mon_len;
addr &= ~(4096 - 1);
debug("Reserving %ldk for U-Boot at: %08lx\n", gd->mon_len >> 10, addr);
#ifndef CONFIG_SPL_BUILD //http://blog.csdn.net/voice_shen/article/details/17373671
/*
* reserve memory for malloc() arena
*/
addr_sp = addr - TOTAL_MALLOC_LEN;
debug("Reserving %dk for malloc() at: %08lx\n",
TOTAL_MALLOC_LEN >> 10, addr_sp);
/*
* (permanently) allocate a Board Info struct
* and a permanent copy of the "global" data
*/
addr_sp -= sizeof (bd_t);
bd = (bd_t *) addr_sp;
gd->bd = bd;
debug("Reserving %zu Bytes for Board Info at: %08lx\n",
sizeof (bd_t), addr_sp);
#ifdef CONFIG_MACH_TYPE //未定义
gd->bd->bi_arch_number = CONFIG_MACH_TYPE; /* board id for Linux */
#endif
addr_sp -= sizeof (gd_t);
id = (gd_t *) addr_sp;
debug("Reserving %zu Bytes for Global Data at: %08lx\n",
sizeof (gd_t), addr_sp);
#if defined(CONFIG_OF_SEPARATE) && defined(CONFIG_OF_CONTROL) //未定义
/*
* If the device tree is sitting immediate 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) {
fdt_size = ALIGN(fdt_totalsize(gd->fdt_blob) + 0x1000, 32);
addr_sp -= fdt_size;
new_fdt = (void *)addr_sp;
debug("Reserving %zu Bytes for FDT at: %08lx\n",
fdt_size, addr_sp);
}
#endif
#ifndef CONFIG_ARM64 //未定义 ARM64!
/* setup stackpointer for exeptions */
gd->irq_sp = addr_sp;
#ifdef CONFIG_USE_IRQ
addr_sp -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ);
debug("Reserving %zu Bytes for IRQ stack at: %08lx\n",
CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ, addr_sp);
#endif
/* leave 3 words for abort-stack */
addr_sp -= 12;
/* 8-byte alignment for ABI compliance */
addr_sp &= ~0x07;
#else /* CONFIG_ARM64 */
/* 16-byte alignment for ABI compliance */
addr_sp &= ~0x0f;
#endif /* CONFIG_ARM64 */
#else
addr_sp += 128; /* leave 32 words for abort-stack */
gd->irq_sp = addr_sp;
/* mov r0, #0 not needed due to above code */ 将r0 = 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 */
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
ldr r9, [r9, #GD_BD] /* r9 = gd->bd */
sub r9, r9, #GD_SIZE /* new GD is below bd */
adr lr, here //保存返回地址,here在下面。
ldr r0, [r9, #GD_RELOC_OFF] /* r0 = gd->reloc_off */
add lr, lr, r0 // lr = lr + r0 代码重定位后执行的地址,起始下面b relocate_code返回后就跳到了u-boot代码被重新拷贝的地方。
ldr r0, [r9, #GD_RELOCADDR] /* r0 = gd->relocaddr */
b relocate_code //函数定义在arch/arm/lib/relocate.S文件中。明天继续。
here:
/* Set up final (full) environment */
bl c_runtime_cpu_setup /* we still call old routine here */
//.globl c_runtime_cpu_setup
c_runtime_cpu_setup:
mov pc, lr 直接返回了
ldr r0, =__bss_start /* this is auto-relocated! */
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 */
strlo r2, [r0] /* clear 32-bit BSS word */
addlo r0, r0, #4 /* move to next */
blo clbss_l
bl coloured_LED_init
bl red_led_on
/* 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 */
ldr pc, =board_init_r /* this is auto-relocated! */
/* we should not return here. */
#endif
ENDPROC(_main)
u-boot-2014.10移植第9天----深入分析代码(四)