程序从start。S开始启动
start_code:
/*
* set the cpu to SVC32 mode 设置管理模式
*/
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd3
msr cpsr, r0
#ifdef CONFIG_S3C24X0
/* turn off the watchdog */
/*关看门狗 关中断*/
# if defined(CONFIG_S3C2400)
# define pWTCON 0x15300000
# define INTMSK 0x14400008 /* Interupt-Controller base addresses */
# define CLKDIVN 0x14800014 /* clock divisor register */
#else
# define pWTCON 0x53000000
# define INTMSK 0x4A000008 /* Interupt-Controller base addresses */
# define INTSUBMSK 0x4A00001C
# define CLKDIVN 0x4C000014 /* clock divisor register */
# endif
ldr r0, =pWTCON
mov r1, #0x0
str r1, [r0]
/*
* mask all IRQs by setting all bits in the INTMR - default
*/
mov r1, #0xffffffff
ldr r0, =INTMSK
str r1, [r0]
# if defined(CONFIG_S3C2410) //shut up all interrupt
ldr r1, =0x3ff
ldr r0, =INTSUBMSK
str r1, [r0]
# endif
/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
#endif /* CONFIG_S3C24X0 */
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit #跳转到cpu_init_crit处 对CPU的cashe mmu进行初始化 关闭
#endif
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate: /* relocate U-Boot to RAM */#加载uboot到RAM对于nor flash 启动boot//本可以直接运行但是效率低所以加载到RAM中运行
adr r0, _start /* r0 <- current position of code */ #加载运行起始地址到r0 如果从nor flash启动 这里为0x0
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */ #加载_TEXT_BASE到r1 _TEXT_BASE位于SDRAM中 默认为0x33f80000
cmp r0, r1 /* don't reloc during debug */ #比较r0 与 r1 即判断程序是从flash启动还是从RAM启动
beq stack_setup /*如果r0 == r1 就跳转到stack_up*/ #如果相等 表示从RAM启动 那么下面的代码搬运到RAM步骤就没比要了 直接跳到stack_setup运行
ldr r2, _armboot_start #代码搬运
ldr r3, _bss_start /*U-boot.lds中定义 uboot代码的结束地址*/
sub r2, r3, r2 /* r2 <- size of armboot */ #得到代码长度
add r2, r0, r2 /* r2 <- source end address */ #r2中存放uboot结束代码地址
copy_loop: /*将数据从norflash搬到SDRAM r0为_start程序开始地址r1为_TEXT_BASE属于SDRAM中的地址0x33f80000 所以我们的uboot 512KB*/
ldmia r0!, {r3-r10} /* copy from source address [r0] */ #从起始地址开始搬_start
stmia r1!, {r3-r10} /* copy to target address [r1] */ #搬到目的地址 从_TEXT_BASE开始
cmp r0, r2 /* until source end addreee [r2] */ #判断是否搬完 即r0中的值是否==上面r2中值
ble copy_loop
#endif /* CONFIG_SKIP_RELOCATE_UBOOT */
/* Set up the stack */
stack_setup: #搬完了后设置栈 前面说的判断程序启动地址 如果从RAM启动 则直接来设置栈,有栈了后才能使用c语言。。。
ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */ #栈为向下生长 在确定栈指针sp之前 先留出部分空间 放下面的内容
sub r0, r0, #CONFIG_SYS_MALLOC_LEN /* malloc area */ #1 一段长度放置malloc段
sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE /* bdinfo */ #2 一段长度放置GBL段
#ifdef CONFIG_USE_IRQ
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ) #3 还要留一段长度放置IRQ FIQ中断状态保存段
#endif
sub sp, r0, #12 /* leave 3 words for abort-stack */
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */ #接下来就是sp指针的位置了
clear_bss: #做完了后在开始跳到uboot第二阶段的C代码前 清BSS段 这里放了一些初始化为0的或者没有初始化的全局 # 变 量 局部变量 可以先清掉 在当要调用的时候再赋值
ldr r0, _bss_start /* find start of bss segment */
ldr r1, _bss_end /* stop here */
mov r2, #0x00000000 /* clear */ #全部清空
clbss_l:str r2, [r0] /* clear loop... */
add r0, r0, #4
cmp r0, r1
ble clbss_l
ldr pc, _start_armboot #将指针指向_start_armboot 这里为第二阶段C函数的入口了
_start_armboot: .word start_armboot
void start_armboot (void)
{
init_fnc_t **init_fnc_ptr;
char *s;
#if defined(CONFIG_VFD) || defined(CONFIG_LCD)
unsigned long addr;
#endif
/* Pointer is writable since we allocated a register for it */
gd = (gd_t*)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t));
/* compiler optimization barrier needed for GCC >= 3.4 */
__asm__ __volatile__("": : :"memory");
memset ((void*)gd, 0, sizeof (gd_t));
gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
memset (gd->bd, 0, sizeof (bd_t));
gd->flags |= GD_FLG_RELOC;
monitor_flash_len = _bss_start - _armboot_start;
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) { //这里为调用一系列初始化函数 具体见uboot源码,就是初始化各个外设模块 串口啊 GPIO USB
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
/* armboot_start is defined in the board-specific linker script */
mem_malloc_init (_armboot_start - CONFIG_SYS_MALLOC_LEN,
CONFIG_SYS_MALLOC_LEN);
#ifndef CONFIG_SYS_NO_FLASH
/* configure available FLASH banks */
display_flash_config (flash_init ());
#endif /* CONFIG_SYS_NO_FLASH */
#ifdef CONFIG_VFD
# ifndef PAGE_SIZE
# define PAGE_SIZE 4096
# endif
/*
* reserve memory for VFD display (always full pages)
*/
/* bss_end is defined in the board-specific linker script */
addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
vfd_setmem (addr);
gd->fb_base = addr;
#endif /* CONFIG_VFD */
#ifdef CONFIG_LCD
/* board init may have inited fb_base */
if (!gd->fb_base) {
# ifndef PAGE_SIZE
# define PAGE_SIZE 4096
# endif
/*
* reserve memory for LCD display (always full pages)
*/
/* bss_end is defined in the board-specific linker script */
addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
lcd_setmem (addr);
gd->fb_base = addr;
}
#endif /* CONFIG_LCD */
#if defined(CONFIG_CMD_NAND)
puts ("NAND: ");
nand_init(); /* go init the NAND */
#endif
#if defined(CONFIG_CMD_ONENAND)
onenand_init();
#endif
#ifdef CONFIG_HAS_DATAFLASH
AT91F_DataflashInit();
dataflash_print_info();
#endif
/* initialize environment */
env_relocate ();
#ifdef CONFIG_VFD
/* must do this after the framebuffer is allocated */
drv_vfd_init();
#endif /* CONFIG_VFD */
#ifdef CONFIG_SERIAL_MULTI
serial_initialize();
#endif
/* IP Address */
gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
stdio_init (); /* get the devices list going. */
jumptable_init ();
#if defined(CONFIG_API)
/* Initialize API */
api_init ();
#endif
console_init_r (); /* fully init console as a device */
#if defined(CONFIG_ARCH_MISC_INIT)
/* miscellaneous arch dependent initialisations */
arch_misc_init ();
#endif
#if defined(CONFIG_MISC_INIT_R)
/* miscellaneous platform dependent initialisations */
misc_init_r ();
#endif
/* enable exceptions */
enable_interrupts ();
/* Perform network card initialisation if necessary */
#ifdef CONFIG_DRIVER_TI_EMAC
/* XXX: this needs to be moved to board init */
extern void davinci_eth_set_mac_addr (const u_int8_t *addr);
if (getenv ("ethaddr")) {
uchar enetaddr[6];
eth_getenv_enetaddr("ethaddr", enetaddr);
davinci_eth_set_mac_addr(enetaddr);
}
#endif
#if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)
/* XXX: this needs to be moved to board init */
if (getenv ("ethaddr")) {
uchar enetaddr[6];
eth_getenv_enetaddr("ethaddr", enetaddr);
smc_set_mac_addr(enetaddr);
}
#endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */
/* Initialize from environment */
if ((s = getenv ("loadaddr")) != NULL) {
load_addr = simple_strtoul (s, NULL, 16);
}
#if defined(CONFIG_CMD_NET)
if ((s = getenv ("bootfile")) != NULL) {
copy_filename (BootFile, s, sizeof (BootFile));
}
#endif
#ifdef BOARD_LATE_INIT
board_late_init ();
#endif
#ifdef CONFIG_GENERIC_MMC
puts ("MMC: ");
mmc_initialize (gd->bd);
#endif
#ifdef CONFIG_BITBANGMII
bb_miiphy_init();
#endif
#if defined(CONFIG_CMD_NET)
#if defined(CONFIG_NET_MULTI)
puts ("Net: ");
#endif
eth_initialize(gd->bd);
#if defined(CONFIG_RESET_PHY_R)
debug ("Reset Ethernet PHY\n");
reset_phy();
#endif
#endif
/* main_loop() can return to retry autoboot, if so just run it again. */
for (;;) {
main_loop (); //上面各个板级外设初始化完成后 开始进入main_loop()死循环
}
/* NOTREACHED - no way out of command loop except booting */
}
void main_loop (void)
s = getenv ("bootdelay");
bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY; //如果定义了延时 加载这条 这里涉及一个重要的函数getenv()获得环境变量
run_command (s, 0); //死循环中运行命令函数 我们在串口输入各种命令 就是靠这个函数解析