start_armboot()函数位于lib_arm/board.c文件中。主要完成的任务有
- 硬件初始化(UART Timer 网络等)
- 将kernel映像和根文件系统ramdisk映像从FLASH 上载到RAM 空间
- 命令交互(main_loop)
- 传递参数(tag链表)
- 加载linux内核镜像并跳转
多处地址的运算用到这张图。
先介绍下gd_t数据结构,该数据结构保存了u-boot需要的配置信息,注释简单明了:
- typedef struct global_data {
- bd_t *bd; 与板子相关
- unsigned long flags;
- unsigned long baudrate; 波特率
- unsigned long cpu_clk; /* CPU clock in Hz! */
- unsigned long have_console; /* serial_init() was called */
- unsigned long ram_size; /* RAM size */
- unsigned long reloc_off; /* Relocation Offset */
- unsigned long env_addr; /* Address of Environment struct */
- unsigned long env_valid; /* Checksum of Environment valid */
- #if defined(CONFIG_POST) || defined(CONFIG_LOGBUFFER)
- unsigned long post_log_word; /* Record POST activities */
- unsigned long post_init_f_time; /* When post_init_f started */
- #endif
- void **jt; /* Standalone app jump table */
- } gd_t;
- /* flags */
- #define GD_FLG_RELOC 0x00001 /* Code was relocated to RAM */
- #define GD_FLG_DEVINIT 0x00002 /* Devices have been initialized */
- #define GD_FLG_SILENT 0x00004 /* Silent mode */
介绍下bd_t结构体,保存于板子相关的配置参数:
- typedef struct bd_info {
- unsigned int bi_tag; /* Should be 0x42444944 "BDID" */
- unsigned int bi_size; /* Size of this structure */
- unsigned int bi_revision; /* revision of this structure */
- unsigned int bi_bdate; /* bootstrap date, i.e. 0x19971106 */
- unsigned int bi_memstart; /* Memory start address */
- unsigned int bi_memsize; /* Memory (end) size in bytes */
- unsigned int bi_intfreq; /* Internal Freq, in Hz */
- unsigned int bi_busfreq; /* Bus Freq, in Hz */
- unsigned int bi_cpmfreq; /* CPM Freq, in Hz */
- unsigned int bi_brgfreq; /* BRG Freq, in Hz */
- unsigned int bi_vco; /* VCO Out from PLL */
- unsigned int bi_pci_freq; /* PCI Freq, in Hz */
- unsigned int bi_baudrate; /* Default console baud rate */
- unsigned int bi_immr; /* IMMR when called from boot rom */
- unsigned char bi_enetaddr[6];
- unsigned int bi_flashbase; /* Physical address of FLASH memory */
- unsigned int bi_flashsize; /* Length of FLASH memory */
- int bi_flashwidth; /* Width (8,16,32,64) */
- unsigned char *bi_cmdline; /* Pointer to command line */
- unsigned char bi_esa[3][6]; /* Ethernet station addresses */
- unsigned int bi_ramdisk_begin, bi_ramdisk_end;
- struct { /* Information about [main] video screen */
- short x_res; /* Horizontal resolution in pixels */
- short y_res; /* Vertical resolution in pixels */
- short bpp; /* Bits/pixel */
- short mode; /* Type of pixels (packed, indexed) */
- unsigned long fb; /* Pointer to frame buffer (pixel) memory */
- } bi_video;
- void (*bi_cputc)(char); /* Write a character to the RedBoot console */
- char (*bi_cgetc)(void); /* Read a character from the RedBoot console */
- int (*bi_ctstc)(void); /* Test for input on the RedBoot console */
- } bd_t;
start_armboot()源码:
- void start_armboot (void)
- {
- //typedef int (init_fnc_t)(void);
- init_fnc_t **init_fnc_ptr; //初始化硬件时使用,这是函数指针的一种巧妙用法
- //init_fnc_t *init_sequence[] = {
// cpu_init, /* basic cpu dependent setup */这些都是需要初始化的硬件 数组里面都是函数名
// board_init, /* basic board dependent setup */
// interrupt_init, /* set up exceptions */
// env_init, /* initialize environment */
// init_baudrate, /* initialze baudrate settings */
// serial_init, /* serial communications setup */
// display_banner,
// dram_init, /* configure available RAM banks */
// display_dram_config,
// NULL,
// }; - char *s;
- #ifndef CFG_NO_FLASH
- ulong size;
- #endif
- #if defined(CONFIG_VFD) || defined(CONFIG_LCD)
- unsigned long addr;
- #endif
- #if defined(CONFIG_BOOT_MOVINAND) //SDcard
- uint *magic = (uint *) (PHYS_SDRAM_1);
- #endif
- /* Pointer is writable since we allocated a register for it */
- #ifdef CONFIG_MEMORY_UPPER_CODE /* by scsuh */
- ulong gd_base;
- gd_base = CFG_UBOOT_BASE + CFG_UBOOT_SIZE - CFG_MALLOC_LEN - CFG_STACK_SIZE - sizeof(gd_t); //由图可知。不过+CFG_UBOOT_SIZE有点奇怪啊?
- #ifdef CONFIG_USE_IRQ
- gd_base -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ); //如图: 因为IRQ与FIQ在下面有独立堆栈空间。
- #endif
- gd = (gd_t*)gd_base;
- #else
- gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t)); //_armboot_start又是什么地址呢?不是镜像在SFRAM中的起始地址吧?
- #endif
- //从上面可知,是在动态分配全局变量区的首地址,为什么呢?而堆栈大小的变化都会影响到其起始地址的变化。
- /* compiler optimization barrier needed for GCC >= 3.4 */
- __asm__ __volatile__("": : :"memory");
- //“memory强制gcc编译器假设RAM所有内存单元均被汇编指令修改,这样cpu中的registers和cache中已缓存的内存单元中的数据将作 废。cpu将不得不在需要的时候重新读取内存中的数据。这就阻止了//cpu又将registers,cache中的数据用于去优化指令,而避免去访问内 存。”
- //__asm__用于指示编译器在此插入汇编语句
- //__volatile__用于告诉编译器,严禁将此处的汇编语句与其它的语句重组合优化。即:原原本本按原来的样子处理这这里的汇编。
- //:::表示这是个空指令
- memset ((void*)gd, 0, sizeof (gd_t));
- gd->bd = (bd_t*)((char*)gd - sizeof(bd_t)); //又吃掉了用户空间的一段内存。
- memset (gd->bd, 0, sizeof (bd_t)); //仅仅是为2个数据结构初始化为0?
-
// gd_t和bd_t中存放着随后会用到的相关信息如环境变量,跳转表等
- monitor_flash_len = _bss_start - _armboot_start; //stage2代码所占的空间大小
- for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
- if ((*init_fnc_ptr)() != 0) {
- hang (); // 各个模块的硬件初始化 初始化成功返回的是一个整数0。如果不等于0,则会打印一段出错的提示。
- //void hang (void)
//{ - // puts ("### ERROR ### Please RESET the board ###\n");
// for (;;);
//} - }
- }
- #ifndef CFG_NO_FLASH
- /* configure available FLASH banks */
- size = flash_init (); //这是有选择的硬件初始化,不是必须得。都属于选择性编译。
- display_flash_config (size);//打印flash配置信息
- #endif /* CFG_NO_FLASH */
- //如果启用CONFIG_VFD,则在RAM中bss_end之后的整页处为VFD留下相应memory
- #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);
- size = vfd_setmem (addr);
- gd->fb_base = addr;
- #endif /* CONFIG_VFD */
- //如果启用CONFIG_LCD,则在RAM中bss_end之后的整页处为LCD留下相应memory 那么VFD与LCD可以一起定义么?
- #ifdef CONFIG_LCD
- # 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);
- size = lcd_setmem (addr);
- gd->fb_base = addr;
- #endif /* CONFIG_LCD */
- /* armboot_start is defined in the board-specific linker script */
- #ifdef CONFIG_MEMORY_UPPER_CODE /* by scsuh */
- mem_malloc_init (CFG_UBOOT_BASE + CFG_UBOOT_SIZE - CFG_MALLOC_LEN - CFG_STACK_SIZE);
- #else
- mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);
- #endif
- #if defined(CONFIG_SMDK6400) || defined(CONFIG_SMDK6410) || defined(CONFIG_SMDK6430) || defined(CONFIG_SMDK2450) || defined(CONFIG_SMDK2416)
- #if defined(CONFIG_NAND)
- puts ("NAND: ");
- nand_init(); /* go init the NAND */ //初始化nand
- #endif
- #if defined(CONFIG_ONENAND)
- puts ("OneNAND: ");
- onenand_init(); /* go init the One-NAND */ //初始化onenand
- #endif
- #if defined(CONFIG_BOOT_MOVINAND)
- puts ("MMC: ");
- if ((0x24564236 == magic[0]) && (0x20764316 == magic[1])) {
- printf("Boot up for burning\n");
- } else {
- movi_set_capacity();
- movi_set_ofs(MOVI_TOTAL_BLKCNT);
- movi_init(); //初始化sdcard
- }
- #endif
- #else
- #if (CONFIG_COMMANDS & CFG_CMD_NAND)
- puts ("NAND: ");
- nand_init(); /* go init the NAND */ //这也是初始化nand
- #endif
- #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 */
- /* IP Address */
- gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr"); //读取IP地址,保存到bd_t数据结构中
- /* MAC Address *///MAC地址的初始化
- {
- int i;
- ulong reg;
- char *s, *e;
- char tmp[64];
- i = getenv_r ("ethaddr", tmp, sizeof (tmp));
- s = (i > 0) ? tmp : NULL;
- for (reg = 0; reg < 6; ++reg) {
- gd->bd->bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
- if (s)
- s = (*e) ? e + 1 : e;
- }
- #ifdef CONFIG_HAS_ETH1
- i = getenv_r ("eth1addr", tmp, sizeof (tmp));
- s = (i > 0) ? tmp : NULL;
- for (reg = 0; reg < 6; ++reg) {
- gd->bd->bi_enet1addr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
- if (s)
- s = (*e) ? e + 1 : e;
- }
- #endif
- }
- devices_init (); /* get the devices list going. *///获得设备列表
- #ifdef CONFIG_CMC_PU2
- load_sernum_ethaddr ();
- #endif /* CONFIG_CMC_PU2 */
- jumptable_init ();//跳转表
- console_init_r (); /* fully init console as a device *///控制台
- #if defined(CONFIG_MISC_INIT_R)
- /* miscellaneous platform dependent initialisations */
- misc_init_r ();
- #endif
- /* enable exceptions */
- enable_interrupts ();//打开中断,在stage1阶段是关掉的,在这里打开
- /* Perform network card initialisation if necessary */
- #ifdef CONFIG_DRIVER_CS8900//网卡初始化
- cs8900_get_enetaddr (gd->bd->bi_enetaddr);
- #endif
- #if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)
- if (getenv ("ethaddr")) {
- smc_set_mac_addr(gd->bd->bi_enetaddr);
- }
- #endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */
- /* Initialize from environment */
- if ((s = getenv ("loadaddr")) != NULL) {
- load_addr = simple_strtoul (s, NULL, 16);
- }
- #if (CONFIG_COMMANDS & CFG_CMD_NET)//获取启动文件
- if ((s = getenv ("bootfile")) != NULL) {
- copy_filename (BootFile, s, sizeof (BootFile));
- }
- #endif /* CFG_CMD_NET */
- #ifdef BOARD_LATE_INIT
- board_late_init ();
- #endif
- #if (CONFIG_COMMANDS & CFG_CMD_NET)
- #if defined(CONFIG_NET_MULTI)
- puts ("Net: ");
- #endif
- eth_initialize(gd->bd);
- #endif
- /* main_loop() can return to retry autoboot, if so just run it again. */ //这边怎么是死循环呢?不是有延迟3秒的吗,那么传递参数,跳转到内核在哪儿呢?都在do_bootm_linux函数中。
- for (;;) {
- main_loop ();
- }
- /* NOTREACHED - no way out of command loop except booting */ //就是说boot命令是可以打断循环的,可以开始内核的启动,而bootm是带参数的打断,