全局数据
声明
# < lib_arm\board.c >
DECLARE_GLOBAL_DATA_PTR;
定义
# < include\asm\global_data.h >
typedef struct global_data {
bd_t *bd;
unsigned long flags;
unsigned long baudrate;
unsigned long have_console; /* serial_init() was called */
unsigned long env_addr; /* Address of Environment struct */
unsigned long env_valid; /* Checksum of Environment valid? */
unsigned long fb_base; /* base address of frame buffer */
#ifdef CONFIG_VFD
unsigned char vfd_type; /* display type */
#endif
#if 0
unsigned long cpu_clk; /* CPU clock in Hz! */
unsigned long bus_clk;
phys_size_t ram_size; /* RAM size */
unsigned long reset_status; /* reset status register at boot */
#endif
void **jt; /* jump table */
} gd_t;
// 申明一个gd_t类型的指针gd,存于寄存器r8
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8")
字段说明
bd_t *bd:board info数据结构定义,位于文件 include/asm-arm/u-boot.h定义,主要是保存开发板的相关参数。
typedef struct bd_info {
int bi_baudrate; /* serial console baudrate */
unsigned long bi_ip_addr; /* IP Address */
struct environment_s *bi_env;
ulong bi_arch_number; /* unique id for this board */
ulong bi_boot_params; /* where this board expects params */
struct /* RAM configuration */
{
ulong start;
ulong size;
}bi_dram[CONFIG_NR_DRAM_BANKS];
} bd_t;
unsigned long env_addr:环境变量的地址。
unsigned long ram_top:RAM空间的顶端地址
unsigned long relocaddr:UBOOT重定向后地址
phys_size_t ram_size:物理ram的size
unsigned long irq_sp:中断的堆栈地址
unsigned long start_addr_sp:堆栈地址
unsigned long reloc_off:uboot的relocation的偏移
struct global_data *new_gd:重定向后的struct global_data结构体
const void *fdt_blob:我们设备的dtb地址
void *new_fdt:relocation之后的dtb地址
unsigned long fdt_size:dtb的长度
struct udevice *cur_serial_dev:当前使用的串口设备。
初始化序列(板子初始化函数序列)
原型
# < lib_arm\board.c >
typedef int (init_fnc_t) (void);
int print_cpuinfo (void);
init_fnc_t *init_sequence[] = {
#if defined(CONFIG_ARCH_CPU_INIT)
arch_cpu_init, /* basic arch cpu dependent setup */
#endif
board_init, /* basic board dependent setup */
#if defined(CONFIG_USE_IRQ)
interrupt_init, /* set up exceptions */
#endif
timer_init, /* initialize timer */
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 */
#if defined(CONFIG_DISPLAY_CPUINFO)
print_cpuinfo, /* display cpu info (and speed) */
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
checkboard, /* display board info */
#endif
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
init_func_i2c,
#endif
dram_init, /* configure available RAM banks */
#if defined(CONFIG_CMD_PCI) || defined (CONFIG_PCI)
arm_pci_init,
#endif
display_dram_config,
NULL,
};
结果
init_fnc_t *init_sequence[] = {
board_init, /* basic board dependent setup */
timer_init, /* initialize timer */
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 */
dram_init, /* configure available RAM banks */
display_dram_config,
NULL,
};
入口函数
入口
# < lib_arm\board.c >
void start_armboot (void)
申请gd全局数据
gd = (gd_t*)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t));
防止高版本gcc优化产生错误
_asm__ __volatile__("": : :"memory");
说明:
1) __asm__用于指示编译器在此插入汇编语句。
2) __volatile__用于告诉编译器,严禁将此处的汇编语句与其它的语句重组合优化。即:原原本本按原来的样子处理这这里的汇编。
3) memory强制gcc编译器假设RAM所有内存单元均被汇编指令修改,这样cpu中的registers和cache中已缓存的内存单元中的数据将作废。cpu将不得不在需要的时候重新读取内存中的数据。这就阻止了cpu又将registers,cache中的数据用于去优化指令,而避免去访问内存。
4) "":::表示这是个空指令。barrier()不用在此插入一条串行化汇编指令。
清空全局数据
memset ((void*)gd, 0, sizeof (gd_t));
gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
memset (gd->bd, 0, sizeof (bd_t));
设置标志位(当前代码在RAM)
gd->flags |= GD_FLG_RELOC;
获取整个uboot长度
monitor_flash_len = _bss_start - _armboot_start;
说明:
_bss_start是bss的开始地址,_armboot_start是Uboot的开始代码地址,这里monitor_flash_len得到的是整个Uboot的长度
使用初始化函数序列初始化
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr)
{
if ((*init_fnc_ptr)() != 0) //函数返回值不为零,直接进入死循环
{
hang (); //死循环 { for(;;); }
}
}
初始化内存堆区
mem_malloc_init (_armboot_start - CONFIG_SYS_MALLOC_LEN, CONFIG_SYS_MALLOC_LEN);
说明:
_armboot_start = TEXT_BASE = 0x33F80000
# < common\dlmalloc.c >
void mem_malloc_init(ulong start, ulong size)
{
mem_malloc_start = start;
mem_malloc_end = start + size;
mem_malloc_brk = start;
memset((void *)mem_malloc_start, 0, size);
}
flash驱动器初始化
#ifndef CONFIG_SYS_NO_FLASH
/* configure available FLASH banks */
display_flash_config (flash_init ());
#endif /* CONFIG_SYS_NO_FLASH */
说明:
# < lib_arm\board.c >
static void display_flash_config (ulong size)
{
puts ("Flash: ");
print_size (size, "\n");
}
初始化Nand驱动器
#if defined(CONFIG_CMD_NAND)
puts ("NAND: ");
nand_init(); /* go init the NAND */
#endif
说明:
# < include\configs\mini2440.h >
#define CONFIG_SYS_MAX_NAND_DEVICE 1
# < drivers\mtd\nand\nand.c >
void nand_init(void)
{
int i;
unsigned int size = 0;
for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) {
nand_init_chip(&nand_info[i], &nand_chip[i], base_address[i]);
size += nand_info[i].size / 1024;
if (nand_curr_device == -1)
nand_curr_device = i;
}
printf("%u MiB\n", size / 1024);
#ifdef CONFIG_SYS_NAND_SELECT_DEVICE
/*
* Select the chip in the board/cpu specific driver
*/
board_nand_select_device(nand_info[nand_curr_device].priv, nand_curr_device);
#endif
}
环境变量初始化
env_relocate ();
从环境变量获取ip
gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
说明:
IPaddr_t getenv_IPaddr (char *var)
{
return (string_to_ip(getenv(var)));
}
char *getenv (char *name)
{
int i, nxt;
WATCHDOG_RESET();
// 便利所有字符串
for (i=0; env_get_char(i) != '\0'; i=nxt+1)
{
int val;
// 查找出一个字符串(以'\0'结束)
for (nxt=i; env_get_char(nxt) != '\0'; ++nxt)
{
if (nxt >= CONFIG_ENV_SIZE)
{
return (NULL);
}
}
if ((val=envmatch((uchar *)name, i)) < 0) // 判断名称
continue;
return ((char *)env_get_addr(val));
}
return (NULL);
}
uchar env_get_char_memory (int index)
{
if (gd->env_valid) {
return ( *((uchar *)(gd->env_addr + index)) );
} else {
return ( default_environment[index] );
}
}
uchar *env_get_addr (int index)
{
if (gd->env_valid) {
return ( ((uchar *)(gd->env_addr + index)) );
} else {
return (&default_environment[index]);
}
}
标准输入、标准输出、标准错误初始化("stdin", "stdout", "stderr")
stdio_init()
int stdio_init (void)
{ //其余代码由于宏被屏蔽
drv_system_init ();
return (0);
}
static void drv_system_init (void)
{
struct stdio_dev dev;
memset (&dev, 0, sizeof (dev));
strcpy (dev.name, "serial");
dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
dev.putc = serial_putc;
dev.puts = serial_puts;
dev.getc = serial_getc;
dev.tstc = serial_tstc;
stdio_register (&dev);
}
struct stdio_dev {
int flags; /* Device flags: input/output/system */
int ext; /* Supported extensions */
char name[16]; /* Device name */
/* GENERAL functions */
int (*start) (void); /* To start the device */
int (*stop) (void); /* To stop the device */
/* OUTPUT functions */
void (*putc) (const char c); /* To put a char */
void (*puts) (const char *s); /* To put a string (accelerator) */
/* INPUT functions */
int (*tstc) (void); /* To test if a char is ready... */
int (*getc) (void); /* To get that char */
/* Other functions */
void *priv; /* Private extensions */
struct list_head list;
};
int stdio_register (struct stdio_dev * dev)
{
struct stdio_dev *_dev;
_dev = stdio_clone(dev);
if(!_dev)
return -1;
list_add_tail(&(_dev->list), &(devs.list));
return 0;
}
struct stdio_dev* stdio_clone(struct stdio_dev *dev)
{
struct stdio_dev *_dev;
if(!dev)
return NULL;
_dev = calloc(1, sizeof(struct stdio_dev));
if(!_dev)
return NULL;
memcpy(_dev, dev, sizeof(struct stdio_dev));
strncpy(_dev->name, dev->name, 16);
return _dev;
}
跳转表初始化
jumptable_init ();
void jumptable_init (void)
{ //函数地址
int i;
gd->jt = (void **) malloc (XF_MAX * sizeof (void *));
for (i = 0; i < XF_MAX; i++)
gd->jt[i] = (void *) dummy;
gd->jt[XF_get_version] = (void *) get_version;
gd->jt[XF_malloc] = (void *) malloc;
gd->jt[XF_free] = (void *) free;
gd->jt[XF_getenv] = (void *) getenv;
gd->jt[XF_setenv] = (void *) setenv;
gd->jt[XF_get_timer] = (void *) get_timer;
gd->jt[XF_simple_strtoul] = (void *) simple_strtoul;
gd->jt[XF_udelay] = (void *) udelay;
gd->jt[XF_simple_strtol] = (void *) simple_strtol;
gd->jt[XF_strcmp] = (void *) strcmp;
#if defined(CONFIG_I386) || defined(CONFIG_PPC)
gd->jt[XF_install_hdlr] = (void *) irq_install_handler;
gd->jt[XF_free_hdlr] = (void *) irq_free_handler;
#endif /* I386 || PPC */
#if defined(CONFIG_CMD_I2C)
gd->jt[XF_i2c_write] = (void *) i2c_write;
gd->jt[XF_i2c_read] = (void *) i2c_read;
#endif
#ifdef CONFIG_CMD_SPI
gd->jt[XF_spi_init] = (void *) spi_init;
gd->jt[XF_spi_setup_slave] = (void *) spi_setup_slave;
gd->jt[XF_spi_free_slave] = (void *) spi_free_slave;
gd->jt[XF_spi_claim_bus] = (void *) spi_claim_bus;
gd->jt[XF_spi_release_bus] = (void *) spi_release_bus;
gd->jt[XF_spi_xfer] = (void *) spi_xfer;
#endif
}
终端设备第二阶段初始化
console_init_r ();
中断初始化
enable_interrupts ();
说明:
根据宏:CONFIG_USE_IRQ,该函数功能被屏蔽
void enable_interrupts (void)
{
return;
}
从环境变量获取加载地址(未使用,环境变量没有该参数)
if ((s = getenv ("loadaddr")) != NULL) {
load_addr = simple_strtoul (s, NULL, 16);
}
主循环
for (;;)
{
main_loop ();
}
滞后说明
各种初始化(init_sequence)
nand初始化(nand_init)
环境变量初始化(env_relocate)
终端初始化(console_init_r)
主循环(main_loop )