看看山寨机子掉渣

从uboot开始:

 

1.1 Uboot的主流程第2阶段(C)

该函数进行了一系列的外设初始化,然后调用main_loop (),根据配置来选择是直接加载Linux内核还是进入等待命令模式。了解start_armboot()的主要功能:

 

图2

 

图3

 

 

1.1.1       start_armboot()分析

 

(1)  为gd申请并初始化这块内存

/* Pointer is writable since we allocated a register for it */  
  1.     gd = (gd_t*)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t));  
  2.     /* compiler optimization barrier needed for GCC >= 3.4 */  
  3.     __asm__ __volatile__("": : :"memory");  
  4. 这行语句参考http://blog.csdn.net/loongembedded/article/details/43371909  
  5.   
  6.     memset ((void*)gd, 0, sizeof (gd_t));  
  7.     gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));  
  8.     memset (gd->bd, 0, sizeof (bd_t));     
  9.   
  10.     monitor_flash_len = _bss_start - _armboot_start;  
/* 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");这行语句参考http://blog.csdn.net/loongembedded/article/details/43371909	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;


图4

_armboot_start等的地址是怎么知道的呢,我们可以使用readelf命令来elf文件的信息,而elf文件分三种类型:目标文件(通常是.o)、可执行文件(我们的运行文件)、动态库(.so)。

我们这里可以通过readelf –s u-boot|grep _start来获取包含_start的标号信息

图5

 

gd_t和bd_t是u-boot中两个重要的数据结构,在初始化操作很多都要靠这两个数据结构来保存或传递

 

1)     gd_t结构体

在bootable\bootloader\uboot\arch\arm\include\asm\global_data.h定义

/*  
  1.  * The following data structure is placed in some memory wich is  
  2.  * available very early after boot (like DPRAM on MPC8xx/MPC82xx, or  
  3.  * some locked parts of the data cache) to allow for a minimum set of  
  4.  * global variables during system initialization (until we have set  
  5.  * up the memory controller so that we can use RAM).  
  6.  *  
  7.  * Keep it *SMALL* and remember to set CONFIG_SYS_GBL_DATA_SIZE > sizeof(gd_t)  
  8.  */  
  9.   
  10. typedef struct  global_data {  
  11.     bd_t        *bd;// bd指针指向bd_info这个结构体,保存板子的相关参数  
  12.     unsigned long   flags; //指示标志,如设备已经初始化标志等  
  13.     unsigned long   baudrate; // 串口的波特率  
  14.     unsigned long   have_console;   /* serial_init() was called */  
  15.     unsigned long   env_addr;   /* Address  of Environment struct */  
  16.     unsigned long   env_valid;  /* Checksum of Environment valid? */  
  17.     unsigned long   fb_base;    /* base address of frame buffer */  
  18. #ifdef CONFIG_VFD  
  19.     unsigned char   vfd_type;   /* display type */  
  20. #endif  
  21. #ifdef CONFIG_FSL_ESDHC  
  22.     unsigned long   sdhc_clk;  
  23. #endif  
  24. #if !(defined(CONFIG_SYS_NO_ICACHE) && defined(CONFIG_SYS_NO_DCACHE))  
  25.     unsigned long tlb_addr;  
  26. #endif  
  27.     void        **jt;       /* jump table */  
  28. } gd_t;  
  29.   
  30. #define DECLARE_GLOBAL_DATA_PTR     register volatile gd_t *gd asm ("r8")  
/* * The following data structure is placed in some memory wich is * available very early after boot (like DPRAM on MPC8xx/MPC82xx, or * some locked parts of the data cache) to allow for a minimum set of * global variables during system initialization (until we have set * up the memory controller so that we can use RAM). * * Keep it *SMALL* and remember to set CONFIG_SYS_GBL_DATA_SIZE > sizeof(gd_t) */typedef	struct	global_data {	bd_t		*bd;// bd指针指向bd_info这个结构体,保存板子的相关参数	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#ifdef CONFIG_FSL_ESDHC	unsigned long	sdhc_clk;#endif#if !(defined(CONFIG_SYS_NO_ICACHE) && defined(CONFIG_SYS_NO_DCACHE))    unsigned long tlb_addr;#endif	void		**jt;		/* jump table */} gd_t;#define DECLARE_GLOBAL_DATA_PTR     register volatile gd_t *gd asm ("r8")


 

这个声明告诉编译器使用寄存器r8来存储gd_t类型的指针gd,即这个定义声明了一个指针,并且指明了它的存储位置。register表示变量放在机器的寄存器

volatile用于指定变量的值可以由外部过程异步修改

 

2)     bd_t结构体

在bootable\bootloader\uboot\arch\arm\include\asm\u-boot.h。board info数据结构定义,主要用于保存板子的参数

typedef struct bd_info {  
  1.     int         bi_baudrate;    /* serial console baudrate */  
  2.     unsigned long   bi_ip_addr; /* IP Address */  
  3.     struct environment_s           *bi_env;  
  4.     ulong           bi_arch_number; /* unique id for this board */  
  5.     ulong           bi_boot_params; /* where this board expects params */  
  6.     struct              /* RAM configuration */  
  7.     {  
  8.     ulong start;  
  9.     ulong size;  
  10.     }           bi_dram[MAX_NR_BANK];  
  11. } bd_t;  
  12.   
  13. #define bi_env_data bi_env->data  
  14. #define bi_env_crc  bi_env->crc  
  15. MAX_NR_BANK在\mediatek\platform\mt6577\uboot\inc\asm\arch\mt65xx.h定义:  
  16. #define MAX_NR_BANK   4  
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[MAX_NR_BANK];} bd_t;#define bi_env_data bi_env->data#define bi_env_crc  bi_env->crcMAX_NR_BANK在\mediatek\platform\mt6577\uboot\inc\asm\arch\mt65xx.h定义:#define MAX_NR_BANK   4


 

(1)  调用init_sequence()进行板级初始化

for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr)   
  1.     {  
  2.         if ((*init_fnc_ptr)() != 0) {  
  3.             hang ();  
  4.         }  
  5.     }  
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) 	{		if ((*init_fnc_ptr)() != 0) {			hang ();		}	}

 

init_sequence是一个全局的指针数组,也就是它的每个成员保存的指向init_fnc_t类型的函数指针。

typedef int (init_fnc_t) (void);  
  1. init_fnc_t *init_sequence[] = {  
  2.     cpu_init,       /* basic cpu dependent setup */  
  3.     dram_init,              /* configure available RAM banks */ /*  change the original init order */  
  4.     board_init,     /* basic board dependent setup */  
  5.     interrupt_init,     /* set up exceptions */  
  6.     env_init,       /* initialize environment */  
  7.     init_baudrate,      /* initialze baudrate settings */  
  8.     serial_init,        /* serial communications setup */  
  9.     console_init_f,     /* stage 1 init of console */  
  10.     display_banner,     /* say that we are here */  
  11. #if defined(CONFIG_DISPLAY_CPUINFO)  
  12.     print_cpuinfo,      /* display cpu info (and speed) */  
  13. #endif  
  14. #if defined(CONFIG_DISPLAY_BOARDINFO)  
  15.     checkboard,     /* display board info */  
  16. #endif  
  17.     display_dram_config,  
  18.     NULL,  
  19. };  
typedef int (init_fnc_t) (void);init_fnc_t *init_sequence[] = {	cpu_init,		/* basic cpu dependent setup */	dram_init,              /* configure available RAM banks */ /*  change the original init order */	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 */	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	display_dram_config,	NULL,};


 

下面依次简要介绍这些初始化函数

1)     cpu_init()

在\bootable\bootloader\uboot\arch\arm\cpu\arm_cortexa9\cpu.c

定义中断栈和快速中断栈空间的地址

 

2)     dram_init()

在\mediatek\platform\mt6577\uboot\mt6577.c中定义

DRAM的初始化,这里只是对gd中的 bi_dram结构中的两个成员赋值,也即BANK的起始地址和大小。

 

3)     board_init()

在\mediatek\platform\mt6577\uboot\mt6577_board.c中定义

此函数主要是进行串口初始化,看门狗初始化、GPIO引脚初始化、LCD背光初始化、初始化PMIC6329的ISINK0(是一种恒流源,一般可用于控制背光,但是我们的电流设计是用另外一个单独的IC来控制背光的)、显示控制器初始化、PMIC6329初始化。

此函数采用下面的代码为设备的board id进行了初始化。

gd->bd->bi_arch_number= MACH_TYPE_MT6577; /* board id for linux*/

这是机器的machine ID,uboot中和内核中的必须是一致,否则系统无法启动。

 

 

4)     interrupt_init()

在\bootable\bootloader\uboot\arch\arm\lib\interrupts.c中定义,但是实际上什么都没有做,直接返回0。

 

5)     env_init()

在\bootable\bootloader\uboot\common\env_nowhere.c下定义

初始化默认的环境变量,如果没有找到有效的环境变量,就采用这个默认的。

/************************************************************************  
  1.  * Initialize Environment use  
  2.  *  
  3.  * We are still running from ROM, so data use is limited  
  4.  */  
  5. int  env_init(void)  
  6. {  
  7.     gd->env_addr  = (ulong)&default_environment[0];  
  8.     gd->env_valid = 0;  
  9.     //printf("Env_nowhere.c--->env_init()\n"));  
  10.     return (0);  
  11. }  
/************************************************************************ * Initialize Environment use * * We are still running from ROM, so data use is limited */int  env_init(void){	gd->env_addr  = (ulong)&default_environment[0];	gd->env_valid = 0;	//printf("Env_nowhere.c--->env_init()\n"));	return (0);}


6)     init_baudrate()

在\bootable\bootloader\uboot\arch\arm\lib\board.c中定义,用于初始化串口波特率。

7)     serial_init()

在\mediatek\platform\mt6577\uboot\mtk_serial.c下定义,但这里实际什么都没有做,因为在前面的board_init()就调用mtk_serial_init()初始化串口了。

8)     console_init_f()

在\bootable\bootloader\uboot\common\console.c定义

初始化控制台,主要是设置全局变量gd的have_console和flags成员。

 

9)     print_cpuinfo()

在\bootable\bootloader\uboot\arch\arm\lib\board.c中定义,但此函数什么都没有做。

10) display_dram_config()

在\bootable\bootloader\uboot\arch\arm\lib\board.c中定义,用于显示DRAM的地址和大小,如此函数输出的串口信息:

RAM Configuration:

Bank #0: 01600000 490MiB

Bank #1: 20000000512 MiB

(2)  env_relocate()

在\bootable\bootloader\uboot\common\env_common.c定义.

u-boot的环境变量用来存储一些经常使用的参数变量,uboot希望将环境变量存储在静态存储器中(如nand nor eeprom mmc)。其中有一些也是大家经常使用,有一些是使用人员自己定义的,下面的表中我们列出了一些常用的环境变量:

 

    bootdelay    执行自动启动的等候秒数

    baudrate     串口控制台的波特率

    netmask    以太网接口的掩码

    ethaddr       以太网卡的网卡物理地址

    bootfile        缺省的下载文件

    bootargs     传递给内核的启动参数

    bootcmd    自动启动时执行的命令

    serverip       服务器端的ip地址

    ipaddr         本地ip地址

    stdin           标准输入设备

    stdout        标准输出设备

    stderr         标准出错设备

 

上面这些是uboot默认存在的环境变量,uboot本身会使用这些环境变量来进行配置。我们可以自己定义一些环境变量来供我们自己uboot驱动来使用。

 

Uboot环境变量的设计逻辑是在启动过程中将env从静态存储器中读出放到RAM中,之后在uboot下对env的操作(如printenv editenv setenv)都是对RAM中env的操作,只有在执行saveenv时才会将RAM中的env重新写入静态存储器中。

这种设计逻辑可以加快对env的读写速度。

 

env_relocate()主要做了两件事:

1)     为环境变量分配buffer。

2)     由于在前面调用的env_init()设置gd->env_valid = 0;,所以这里会调用set_default_env()来设置默认的环境变量。

void set_default_env(void)  
  1. {  
  2.     if (sizeof(default_environment) > ENV_SIZE) {  
  3.         puts ("*** Error - default environment is too large\n\n");  
  4.         return;  
  5.     }  
  6.   
  7.     memset(env_ptr, 0, sizeof(env_t));  
  8.     memcpy(env_ptr->data, default_environment,  
  9.            sizeof(default_environment));  
  10. #ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT  
  11.     env_ptr->flags = 0xFF;  
  12. #endif  
  13.     env_crc_update ();  
  14.     gd->env_valid = 1;  
  15. }  
void set_default_env(void){	if (sizeof(default_environment) > ENV_SIZE) {		puts ("*** Error - default environment is too large\n\n");		return;	}	memset(env_ptr, 0, sizeof(env_t));	memcpy(env_ptr->data, default_environment,	       sizeof(default_environment));#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT	env_ptr->flags = 0xFF;#endif	env_crc_update ();	gd->env_valid = 1;}

 

(3)  stdio_init()

在\bootable\bootloader\uboot\common\stdio.c定义。设置标准的输出输入描述符表

(4)  mt65xx_bat_init()

在\mediatek\platform\mt6577\uboot\mt6577_bat.c定义,主要关机充电和拔出充电器关机。对于正常的启动来说,只是执行了关闭LED等和进行过电流检测(Over-current)。

(5)  mt65xx_backlight_on()

在\mediatek\platform\mt6577\uboot\mt65xx_leds.c定义,打开背光

 

(6)  main_loop()

在\bootable\bootloader\uboot\common\main.c定义,主要做的都是与具体平台无关的工作,主要包括初始化启动次数限制机制、设置软件版本号、打印启动信息、解析命令等,这部分后面作为单独的一部分来学习。

参考链接:

start_armboot分析

start_armboot()函数的主要作用,其实该函数就是进行一系列的硬件初始化,然后进入main_loop,等待用户的命令,
 
typedef int (init_fnc_t) (void);   //define init_fnc_t  type
init_fnc_t *init_sequence[] = { //define point array init_sequence type's pionter
 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 *///串口初始化后我们就可以打印信息了
 console_init_f,  /* stage 1 init of console */
 display_banner,  /* say that we are here */
 dram_init,  /* configure available RAM banks */
 display_dram_config,
#if defined(CONFIG_VCMA9)
 checkboard,
#endif
 NULL,
};
 
void start_armboot (void)
{
 DECLARE_GLOBAL_DATA_PTR;
 ulong size;
 init_fnc_t **init_fnc_ptr;  ///point initial function's pointer
 char *s;
#if defined(CONFIG_VFD)
 unsigned long addr;
#endif
 
#if CFG_LED_FLASH
LED();    ///all leds power on flash once
#endif
 
 /* Pointer is writable since we allocated a register for it */

 gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
 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;
 
///This for{} init arry init_sequence[] paraments one by one
 for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
  if ((*init_fnc_ptr)() != 0) {
   hang ();///f init fail output "error" and go to dead cycle,if that we must reset cpu
  }
 }
 
 /* configure available FLASH banks */
 size = flash_init ();                     ///init flash  source code don't understand???
 display_flash_config (size);      /// print flash's config information
#ifdef CONFIG_VFD     ///#define CONFIG_VFD  1     in Trab.h
# ifndef PAGE_SIZE
#   define PAGE_SIZE 4096  //若没定义则用4096
# endif

 /*
  * reserve memory for VFD display (always full pages)
  */
 /* armboot_end is defined in the board-specific linker script */
 addr = (_bss_start + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
 size = vfd_setmem (addr);
 gd->fb_base = addr;
#endif /* CONFIG_VFD */
 /* armboot_start is defined in the board-specific linker script */
 mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
 puts ("NAND:");
 nand_init();  /* go init the NAND */
#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");
 /* MAC Address */
 {
  int i;
  ulong reg;
  char *s, *e;
  uchar 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;
  }
 }
 
 devices_init (); /* get the devices list going. */
 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 ();
 /* Perform network card initialisation if necessary */
#ifdef CONFIG_DRIVER_CS8900
 cs8900_get_enetaddr (gd->bd->bi_enetaddr);
#endif
#ifdef CONFIG_DRIVER_LAN91C96
 if (getenv ("ethaddr")) {
  smc_set_mac_addr(gd->bd->bi_enetaddr);
 }
 /* eth_hw_init(); */
#endif /* 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
 /* main_loop() can return to retry autoboot, if so just run it again. */
 for (;;) {
  main_loop ();
 }
 /* NOTREACHED - no way out of command loop except booting */
}
 
void hang (void)
{
 puts ("### ERROR ### Please RESET the board ###\n");
 for (;;);
}
 
 
#ifdef CONFIG_MODEM_SUPPORT
/* called from main loop (common/main.c) */
extern void  dbg(const char *fmt, ...);

int mdm_init (void)
{
 char env_str[16];
 char *init_str;
 int i;
 extern char console_buffer[];
 static inline void mdm_readline(char *buf, int bufsiz);
 extern void enable_putc(void);
 extern int hwflow_onoff(int);
 enable_putc(); /* enable serial_putc() */
#ifdef CONFIG_HWFLOW
 init_str = getenv("mdm_flow_control");
 if (init_str && (strcmp(init_str, "rts/cts") == 0))
  hwflow_onoff (1);
 else
  hwflow_onoff(-1);
#endif
 for (i = 1;;i++) {
  sprintf(env_str, "mdm_init%d", i);
  if ((init_str = getenv(env_str)) != NULL) {
   serial_puts(init_str);
   serial_puts("\n");
   for(;;) {
    mdm_readline(console_buffer, CFG_CBSIZE);
    dbg("ini%d: [%s]", i, console_buffer);
    if ((strcmp(console_buffer, "OK") == 0) ||
     (strcmp(console_buffer, "ERROR") == 0)) {
     dbg("ini%d: cmd done", i);
     break;
    } else /* in case we are originating call ... */
     if (strncmp(console_buffer, "CONNECT", 7) == 0) {
      dbg("ini%d: connect", i);
      return 0;
     }
   }
  } else
   break; /* no init string - stop modem init */
  udelay(100000);
 }
 udelay(100000);
 /* final stage - wait for connect */
 for(;i > 1;) { /* if 'i' > 1 - wait for connection
      message from modem */
  mdm_readline(console_buffer, CFG_CBSIZE);
  dbg("ini_f: [%s]", console_buffer);
  if (strncmp(console_buffer, "CONNECT", 7) == 0) {
   dbg("ini_f: connected");
   return 0;
  }
 }
 return 0;
}
/* 'inline' - We have to do it fast */
static inline void mdm_readline(char *buf, int bufsiz)
{
 char c;
 char *p;
 int n;
 n = 0;
 p = buf;
 for(;;) {
  c = serial_getc();
  /*  dbg("(%c)", c); */
  switch(c) {
  case '\r':
   break;
  case '\n':
   *p = '\0';
   return;
  default:
   if(n++ > bufsiz) {
    *p = '\0';
    return; /* sanity check */
   }
   *p = c;
   p++;
   break;
  }
 }
}
#endif /* CONFIG_MODEM_SUPPORT */
 
 
 
在介绍该函数之前,我们需要看一看几个数据结构,这些是u-boot中几个重要的数据结构:

1)、gd_t该数据结构保存了u-boot需要的配置信息,注释简单明了
typedef    struct    global_data {
    bd_t        *bd; //与板子相关的结构,见下面
    unsigned long    flags;
    unsigned long    baudrate;
    unsigned long    have_console;    /* serial_init() was called */
    unsigned long    reloc_off;    /* Relocation Offset */
    unsigned long    env_addr;    /* Address  of Environment struct */
    unsigned long    env_valid;    /* Checksum of Environment valid? */
#ifdef CONFIG_VFD  //我们一般没有配置这个,这个是frame buffer的首地址
    unsigned long    fb_base;    /* base address of frame buffer */
#endif
} gd_t;

2)、bd_t 保存与板子相关的配置参数
typedef struct bd_info {
    int            bi_baudrate;    /* serial console baudrate */
    unsigned long    bi_ip_addr;    /* IP Address */
    unsigned char    bi_enetaddr[6]; /* Ethernet adress */
    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];//在我的板子上是1个
} bd_t;

现在我贴出start_armboot ()的源代码,然后具体的在其中解释一些代码的作用:


void start_armboot (void)
{
    DECLARE_GLOBAL_DATA_PTR;

    ulong size;
    gd_t gd_data;
    bd_t bd_data;
    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,
                       //     };

    //printf("**********Start *************\n");
    /* Pointer is writable since we allocated a register for it */
    gd = &gd_data;
    memset (gd, 0, sizeof (gd_t));//初始化为0
    gd->bd = &bd_data;
    memset (gd->bd, 0, sizeof (bd_t));//初始化为0

//注意,下面的循环是依次调用各个硬件初始化函数,顺序见上面的的数组,我们在下一篇中依次解释每种硬//件的初始化,第六个就是串口的初始化,这时候我们就可以通过串口输出信息了
    for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
        if ((*init_fnc_ptr)() != 0) {
            hang ();      //如果不成功的话,就“输出信息,然后就进入死循环”
        }
    }

    /* configure available FLASH banks */
    size = flash_init ();  //flash的初始化
    display_flash_config (size);//打印flash的配置信息

    /* initialize environment */
    env_relocate ();//环境的初始化,代码在common\env_common.c中

    /* IP Address */
    bd_data.bi_ip_addr = getenv_IPaddr ("ipaddr");//读取IP地址,保存到bd_t数据结构中

    /* MAC Address */ //MAC地址的初始化
    {
        int i;
        ulong reg;
        char *s, *e;
        uchar tmp[64];

        i = getenv_r ("ethaddr", tmp, sizeof (tmp));
        s = (i > 0) ? tmp : NULL;

        for (reg = 0; reg < 6; ++reg) {
            bd_data.bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
            if (s)
                s = (*e) ? e + 1 : e;
        }
    }


    /* enable exceptions */  //允许中断
    enable_interrupts ();

#ifdef CONFIG_DRIVER_CS8900  //配置网卡
    if (!getenv ("ethaddr")) {
        cs8900_get_enetaddr (gd->bd->bi_enetaddr);
    } 
#endif

//直接进入main_loop 该函数在common\main.c中,至此,硬件初始化完成
    /* main_loop() can return to retry autoboot, if so just run it again. */
    for (;;) {
        main_loop ()
    }

    /* NOTREACHED - no way out of command loop except booting */
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ava实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),可运行高分资源 Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。下面详细介绍C语言的基本概念和语法。 1. 变量和数据类型 在C语言中,变量用于存储数据,数据类型用于定义变量的类型和范围。C语言支持多种数据类型,包括基本数据类型(如int、float、char等)和复合数据类型(如结构体、联合等)。 2. 运算符 C语言中常用的运算符包括算术运算符(如+、、、/等)、关系运算符(如==、!=、、=、<、<=等)、逻辑运算符(如&&、||、!等)。此外,还有位运算符(如&、|、^等)和指针运算符(如、等)。 3. 控制结构 C语言中常用的控制结构包括if语句、循环语句(如for、while等)和switch语句。通过这些控制结构,可以实现程序的分支、循环和多路选择等功能。 4. 函数 函数是C语言中用于封装代码的单元,可以实现代码的复用和模块化。C语言中定义函数使用关键字“void”或返回值类型(如int、float等),并通过“{”和“}”括起来的代码块来实现函数的功能。 5. 指针 指针是C语言中用于存储变量地址的变量。通过指针,可以实现对内存的间接访问和修改。C语言中定义指针使用星号()符号,指向数组、字符串和结构体等数据结构时,还需要注意数组名和字符串常量的特殊性质。 6. 数组和字符串 数组是C语言中用于存储同类型数据的结构,可以通过索引访问和修改数组中的元素。字符串是C语言中用于存储文本数据的特殊类型,通常以字符串常量的形式出现,用双引号("...")括起来,末尾自动添加'\0'字符。 7. 结构体和联合 结构体和联合是C语言中用于存储不同类型数据的复合数据类型。结构体由多个成员组成,每个成员可以是不同的数据类型;联合由多个变量组成,它们共用同一块内存空间。通过结构体和联合,可以实现数据的封装和抽象。 8. 文件操作 C语言中通过文件操作函数(如fopen、fclose、fread、fwrite等)实现对文件的读写操作。文件操作函数通常返回文件指针,用于表示打开的文件。通过文件指针,可以进行文件的定位、读写等操作。 总之,C语言是一种功能强大、灵活高效的编程语言,广泛应用于各种领域。掌握C语言的基本语法和数据结构,可以为编程学习和实践打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值