您的位置:首页 > 其它

u-boot第二阶段board.c分析

2013-08-02 19:24 330 查看
针对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信息,仅作测试用

init_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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  uboot第二阶段