针对s3c2440 u-boot-1.1.6
u-boot第一阶段主要就是:关闭看门狗,关中断,初始化存储器,初始化nand,u-boot代码的重定位。
u-boot第二阶段的主要任务:初始化网口、nor、LCD等外设,初始化u-boot全局变量,初始化u-boot传递给内核参数,循环等待用户输入,它的位置在/lib_arm/board.c下面。
#include <common.h>#include <command.h>
#include <malloc.h>
#include <devices.h>
#include <version.h>
#include <net.h>
#ifdef CONFIG_DRIVER_SMC91111 //宏开关
#include "../drivers/smc91111.h"
#endif
#ifdef CONFIG_DRIVER_LAN91C96
#include "../drivers/lan91c96.h"
#endif
DECLARE_GLOBAL_DATA_PTR;
#if (CONFIG_COMMANDS & CFG_CMD_NAND) //u-boot很多重要的宏开关定义在/include/configs/smdk2410.h在u-boot配置时起作用
void nand_init (void); // 点击访问u-boot配置过程
#endif
ulong monitor_flash_len; //u-boot代码长度
#ifdef CONFIG_HAS_DATAFLASH
extern int AT91F_DataflashInit(void);
extern void dataflash_print_info(void);
#endif
#ifndef CONFIG_IDENT_STRING
#define CONFIG_IDENT_STRING ""
#endif
const char version_string[] =U_BOOT_VERSION" (" __DATE__ " - " __TIME__ ")"CONFIG_IDENT_STRING;
#ifdef CONFIG_DRIVER_CS8900 //网卡CS8900开关,每个开发板的网卡可能会不同,此处有链接
extern void cs8900_get_enetaddr (uchar * addr);
#endif
#ifdef CONFIG_DRIVER_RTL8019
extern void rtl8019_get_enetaddr (uchar * addr);
#endif
static ulong mem_malloc_start = 0; //malloc可分配的开始地址
static ulong mem_malloc_end = 0; //malloc可分配的结束地址
static ulong mem_malloc_brk = 0;
static void mem_malloc_init (ulong dest_addr) //malloc区域初始化
{
mem_malloc_start = dest_addr;
mem_malloc_end = dest_addr + CFG_MALLOC_LEN;//CFG_MALLOC_LEN在/include/configs/xxxx.h中定义
mem_malloc_brk = mem_malloc_start;
memset ((void *) mem_malloc_start, 0,mem_malloc_end - mem_malloc_start);
}
void *sbrk (ptrdiff_t increment)
{
ulong old = mem_malloc_brk;
ulong new = old + increment;
if ((new < mem_malloc_start) || (new > mem_malloc_end)) {
return (NULL);
}
mem_malloc_brk = new;
return ((void *) old);
}
/************************************************************************
* 初始化函数,根据情况选择合适的编译进u-boot*
************************************************************************
static int init_baudrate (void) //波特率初始化函数
{
char tmp[64]; /* long enough for environment variables */
int i = getenv_r ("baudrate", tmp, sizeof (tmp));
gd->bd->bi_baudrate = gd->baudrate = (i > 0)? (int) simple_strtoul (tmp, NULL, 10): CONFIG_BAUDRATE;
return (0);
}
static int display_banner (void)//显示打印基本信息
{
printf ("\n\n%s\n\n", version_string);
debug ("U-Boot code: %08lX -> %08lX BSS: -> %08lX\n", _armboot_start, _bss_start, _bss_end);
#ifdef CONFIG_MODEM_SUPPORT
debug ("Modem Support enabled\n");
#endif
#ifdef CONFIG_USE_IRQ
debug ("IRQ Stack: %08lx\n", IRQ_STACK_START);
debug ("FIQ Stack: %08lx\n", FIQ_STACK_START);
#endif
return (0);
}
static int display_dram_config (void)//显示dram的信息
{
int i;
#ifdef DEBUG
puts ("RAM Configuration:\n");
for(i=0; i<CONFIG_NR_DRAM_BANKS; i++) {
printf ("Bank #%d: %08lx ", i, gd->bd->bi_dram[i].start);
print_size (gd->bd->bi_dram[i].size, "\n");}
#else
ulong size = 0;
for (i=0; i<CONFIG_NR_DRAM_BANKS; i++) {
size += gd->bd->bi_dram[i].size;}
puts("DRAM: ");
print_size(size, "\n");
#endif
return (0);
}
#ifndef CFG_NO_FLASH
static void display_flash_config (ulong size)//显示nor flash 的大小
{
puts ("Flash: ");
print_size (size, "\n");
}
#endif /* CFG_NO_FLASH */
typedef int (init_fnc_t) (void);//定义一个函数类型,原型为 int f(void)
int print_cpuinfo (void); //打印CPU信息,仅作测试用
i nit_fnc_t *init_sequence[] = { //定义一个函数指针数组
cpu_init, //cpu初始化代码
board_init, //开发板相关的初始化代码
interrupt_init, //中断设置代码
env_init, //uboot环境变量设置
init_baudrate, //设置波特率
serial_init, //串口通信设置 u-boot一般都是通过串口来作为标准输入出, 点击访问串口初始化全过程
console_init_f, //控制台初始化
display_banner, //打印信息
#if defined(CONFIG_DISPLAY_CPUINFO)
print_cpuinfo, //打印cpu信息
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
checkboard, //显示板子信息
#endif
dram_init, //初始化bank信息
display_dram_config, //显示bank信息
NULL,
};
void start_armboot (void)//uboot第一阶段跳转的的位置,uboot第二阶段的第一句
{
init_fnc_t **init_fnc_ptr;
char *s;
#ifndef CFG_NO_FLASH
ulong size;
#endif
#if defined(CONFIG_VFD) || defined(CONFIG_LCD)
unsigned long addr;
#endif
gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
__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));
monitor_flash_len = _bss_start - _armboot_start;
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {//调用初始化函数进行初始化
if ((*init_fnc_ptr)() != 0)
{hang ();} }
#ifndef CFG_NO_FLASH
size = flash_init (); //获得可用的flash的大小
display_flash_config (size); //打印flash信息
#endif /* CFG_NO_FLASH */
#ifdef CONFIG_VFD
#ifndef PAGE_SIZE
#define PAGE_SIZE 4096
#endif
addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);//配置虚拟的显存,必须页对齐,_bss_end 在链接脚本u-boot.lds中定义
size = vfd_setmem (addr);
gd->fb_base = addr;
#endif /* CONFIG_VFD */
#ifdef CONFIG_LCD
#ifndef PAGE_SIZE
#define PAGE_SIZE 4096
#endif
addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); //配置显存,必须页对齐,_bss_end 在链接脚本u-boot.lds中定义
size = lcd_setmem (addr);
gd->fb_base = addr;
#endif /* CONFIG_LCD */
mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);//初始化malloc区域,_armboot_start 在u-boot.lds中有定义
#if (CONFIG_COMMANDS & CFG_CMD_NAND)//nand宏开关,因为板子使用的nand各不相同,需要移植,此处有链接
puts ("NAND: ");
nand_init(); //点击访问nand层次化分析
#endif
#ifdef CONFIG_HAS_DATAFLASH
AT91F_DataflashInit();
dataflash_print_info();
#endif
env_relocate (); //点击访问u-boot环境变量初始化全过程
#ifdef CONFIG_VFD
drv_vfd_init();/* must do this after the framebuffer is allocated */
#endif /* CONFIG_VFD */
gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr"); //获得u-boot的ip地址
{ //获得u-boot的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_interrupts ();//使能中断
#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 */
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 ();//board进一步初始化
#endif
#if (CONFIG_COMMANDS & CFG_CMD_NET)
#if defined(CONFIG_NET_MULTI)
puts ("Net: ");
#endif
eth_initialize(gd->bd);
#endif
//u-boot主循环,除了boot启动内核没有其他方式跳出该循环,在里面可以执行很多的命令,而这些命令也是u-boot的精华
for (;;) {
main_loop (); }//点击查看main_loop分析} //end start_armboot
void hang (void)
{
puts ("### ERROR ### Please RESET the board ###\n");
for (;;);
}
u-boot有两大功能:启动内核,调试功能。这两种功能都是在main_loop中通过不同的命令来实现的。
启动内核:1,传递芯片的机器码
2,传递内核需要的参数到默认位置
3,拷贝内核到内存,并跳转到内核处
调试功能:1,读写nand
2,tftp下载支持
3,读写sdram