码迷,mamicode.com
首页 > 其他好文 > 详细

uboot第二阶段分析

时间:2015-06-15 11:18:54      阅读:107      评论:0      收藏:0      [点我收藏+]

标签:c语言   linux   嵌入式   

uboot的第二阶段主要是start_armboot函数

 

gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));

uboot代码和堆空间下面开辟一个全局变量gd的空间,大小就是gd_t的大小

gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));//gd结构体中bd结构体开辟空间,紧挨着gd

 

typedefstructglobal_data {

bd_t*bd;//板子的相关信息

unsigned longflags;

unsigned longbaudrate;//波特率

unsigned longhave_console;//是否有控制台

unsigned longreloc_off;/* Relocation Offset */

unsigned longenv_addr;/* 环境变量的地址*/

unsigned longenv_valid;/* Checksum of Environment valid? */

unsigned longfb_base;/* base address of frame buffer */

unsigned charvfd_type;/* display type */

void**jt;/* jump table */

} gd_t;

typedef struct bd_info {

    intbi_baudrate;/* 串口波特率 */

    unsigned longbi_ip_addr;/* IP地址*/

    unsigned charbi_enetaddr[6]; /* Ethernet adress */

    struct environment_s       *bi_env;

    ulong        bi_arch_number;/* 板子的ID */

    ulong        bi_boot_params;/* 启动内核时,参数在内存中存放的地址 */

    struct/* RAM configuration */

    {

ulong start;

ulong size;

    } bi_dram[CONFIG_NR_DRAM_BANKS];

} bd_t;

 

for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {

if ((*init_fnc_ptr)() != 0) {//如果返回不为0则错误

hang ();//打印ERROR并终止

}

}

这里就是运行相关的函数。关于init_fnc_ptr 

strar_armboart函数开始位置这样定义init_fnc_t **init_fnc_ptr;

init_fnc_t board.c中有这样定义:typedef int (init_fnc_t) (void);这表明可以用init_fnc_t来命名一个无形参,返回值为int的函数

所以init_fnc_t **init_fnc_ptr;就表示定义了一个无形参返回值为整型的二级指针。(因为指向指针数组)

init_sequence是一个函数指针数组,里面包含了一些函数指针。

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 */

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,

};

函数名本身就是一个指针,所以可以用函数名初始化指针数组,最后一个函数指针为NULL用于判断结束。

下面就是介绍各个函数。

 

int cpu_init (void)

{

//暂时用不到 ,先不介绍

}

int board_init (void)

{

S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();

//获取时钟相关寄存器的地址。

S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();

//获取GPIO相关寄存器的地址

..........

//这里省略的代码就是配置GPIO和时钟相关寄存器,每个处理器的配置不一样

/* arch number of s3c2440-Board */

gd->bd->bi_arch_number = MACH_TYPE_S3C2440;

//给板子id赋数值

 

/* adress of boot parameters */

gd->bd->bi_boot_params = 0x30000100;

//启动内核时所用到参数的存放地址

 

icache_enable();

dcache_enable();

 

return 0;

}

所以在移植的时候board_init函数要根据自己的处理器来修改

int interrupt_init (void)

{

S3C24X0_TIMERS * const timers = S3C24X0_GetBase_TIMERS();

 

/* use PWM Timer 4 because it has no output */

/* prescaler for Timer 4 is 16 */

timers->TCFG0 = 0x0f00;

if (timer_load_val == 0)

{

/*

 * for 10 ms clock period @ PCLK with 4 bit divider = 1/2

 * (default) and prescaler = 16. Should be 10390

 * @33.25MHz and 15625 @ 50 MHz

 */

timer_load_val = get_PCLK()/(2 * 16 * 100);

}

/* load value for 10 ms timeout */

lastdec = timers->TCNTB4 = timer_load_val;

/* auto load, manual update of Timer 4 */

timers->TCON = (timers->TCON & ~0x0700000) | 0x600000;

/* auto load, start Timer 4 */

timers->TCON = (timers->TCON & ~0x0700000) | 0x500000;

timestamp = 0;

 

return (0);

}

这个函数就是初始产生中断的各个寄存器,在ubootcpu/arm920t\s3c24x0\interrupts.c中定义,所以只要是3c24x0系列芯片就不需要修改

 

env_init函数在多个文件内部都有定义。但是在每个文件开始位置都有一个预编译,来根据配置文件来决定是否来编译。

比如在env_nand.c文件开始位置

#if defined(CFG_ENV_IS_IN_NAND) /* Environment is in Nand Flash */

如果在相关配置文件中定义了 则执行这个文件中的函数。下面就以这个为例

从宏名字就可以知道,这个函数是将环境变量放在NAND中的。

int env_init(void)

{

#if defined(ENV_IS_EMBEDDED)

ulong total;

int crc1_ok = 0, crc2_ok = 0;

env_t *tmp_env1, *tmp_env2;

 

total = CFG_ENV_SIZE;//环境变量的空间大小,需要配置文件定义

 

tmp_env1 = env_ptr;//env_ptr的类型在environmect.h定义

tmp_env2 = (env_t *)((ulong)env_ptr + CFG_ENV_SIZE);

 

crc1_ok = (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc);//crc校验

crc2_ok = (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc);

//在刚把uboot镜像烧到nor中时 此时

if (!crc1_ok && !crc2_ok)

gd->env_valid = 0;

else if(crc1_ok && !crc2_ok)

gd->env_valid = 1;

else if(!crc1_ok && crc2_ok)

gd->env_valid = 2;

else {

/* both ok - check serial */

if(tmp_env1->flags == 255 && tmp_env2->flags == 0)

gd->env_valid = 2;

else if(tmp_env2->flags == 255 && tmp_env1->flags == 0)

gd->env_valid = 1;

else if(tmp_env1->flags > tmp_env2->flags)

gd->env_valid = 1;

else if(tmp_env2->flags > tmp_env1->flags)

gd->env_valid = 2;

else /* flags are equal - almost impossible */

gd->env_valid = 1;

}

 

if (gd->env_valid == 1)

env_ptr = tmp_env1;

else if (gd->env_valid == 2)

env_ptr = tmp_env2;

#else /* ENV_IS_EMBEDDED */

gd->env_addr  = (ulong)&default_environment[0];

gd->env_valid = 1;

#endif /* ENV_IS_EMBEDDED */

 

return (0);

}

 

typedef struct environment_s {

unsigned long crc; /* CRC32 over data bytes */

unsigned char flags; /* active/obsolete flags */

unsigned char data[ENV_SIZE]; /* Environment data */

} env_t;

 

 

 

static int init_baudrate (void)

{

char tmp[64]; /* long enough for environment variables */

int i = getenv_r ("baudrate", tmp, sizeof (tmp));//从存放环境变量的地方取出baudrate变量,此时没有移动变量到内存,若以norflash存放uboot则是从nor中取,

gd->bd->bi_baudrate = gd->baudrate = (i > 0)

? (int) simple_strtoul (tmp, NULL, 10)//将字符串转换为10进制的整数

: CONFIG_BAUDRATE;

 

return (0);

}

//所以这个函数就是给gd->bd->bi_baudrate gd->baudrate 赋值

 

int serial_init (void)

{

serial_setbrg ();//初始化串口相关参数

return (0);

}

//serial_setbrg ();函数中调用了get_PCLK();函数,这个函数在jason_arm目录下的speed.c中定义根据不同芯片 不同。

//初始化串口,这个函数执行完后,就可以使用串口来打印数据了。

int console_init_f (void)

{

gd->have_console = 1;控制台标记置1

return (0);

}

static int display_banner (void)

{

printf ("\n\n%s\n\n", version_string);//打印出第一条语句,uboot的版本,烧写时间

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);

}

//version_string定义如下

const char version_string[] =

U_BOOT_VERSION" (" __DATE__ " - " __TIME__ ")"CONFIG_IDENT_STRING;

打印出来就是  : uboot版本(日期-时间)

 

int dram_init (void)

{

gd->bd->bi_dram[0].start = PHYS_SDRAM_1;//sdram的开始地址

gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;//一个sdram的大小

 

return 0;

}

//这个函数在每个板子的.h文件中定义,需要自己移植

 

static int display_dram_config (void)

{

int i;

 

#ifdef DEBUG//没有定义 省略代码

#else

ulong size = 0;

 

for (i=0; i<CONFIG_NR_DRAM_BANKS; i++) {

//CONFIG_NR_DRAM_BANKS 在板子的配置文件中定义

size += gd->bd->bi_dram[i].size;

//int dram_init (void)函数中初始化了sdram的大小

}

puts("DRAM:  ");//打印sdram的大小

print_size(size, "\n");

#endif

 

return (0);

至此for循环中的函数执行完毕。假如板子名称为arm_jason可以看到在这些函数中移植的时候需要修改的是

board_init:在arm_jason.c中从新定义)

env_init:根据arm_jason.h中的定义来执行,这里假设有 CFG_ENV_IS_IN_NAND定义

则执行env_nand.c.在这个函数里default_environment是默认参数,这里在 arm_jason.h中定义。

serial_init :在这个函数中会调用serial_setbrg ();然后serial_setbrg ();调用 get_PCLK() get_PCLK()jaosn_arm目录下的 speed.c中定义。所以需要根据处理器来移speed.c

dram_init:在arm_jason.c中定义,为给gd赋值sdram大小和开始地址

 

然后

size = flash_init ();//返回norflash的大小

display_flash_config (size);//打印norflash的大小

 

 

ulong flash_init (void)

{

int i, j;

ulong size = 0;

 

for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) {

ulong flashbase = 0;

 

flash_info[i].flash_id =

#if defined(CONFIG_AMD_LV400)//如果jason_arm.h中定义了则执行

(AMD_MANUFACT & FLASH_VENDMASK) |

(AMD_ID_LV400B & FLASH_TYPEMASK);

#elif defined(CONFIG_AMD_LV800)

(AMD_MANUFACT & FLASH_VENDMASK) |

(AMD_ID_LV800B & FLASH_TYPEMASK);

#else

#error "Unknown flash configured"

#endif

flash_info[i].size = FLASH_BANK_SIZE;//jason_arm定义

flash_info[i].sector_count = CFG_MAX_FLASH_SECT;

memset (flash_info[i].protect, 0, CFG_MAX_FLASH_SECT);

if (i == 0)

flashbase = PHYS_FLASH_1;//jaosn_arm.h定义nor的起始地址

else

panic ("configured too many flash banks!\n");

for (j = 0; j < flash_info[i].sector_count; j++) {

if (j <= 3) {

/* 1st one is 16 KB */

if (j == 0) {

flash_info[i].start[j] =

flashbase + 0;

}

 

/* 2nd and 3rd are both 8 KB */

if ((j == 1) || (j == 2)) {

flash_info[i].start[j] =

flashbase + 0x4000 + (j -

      1) *

0x2000;

}

 

/* 4th 32 KB */

if (j == 3) {

flash_info[i].start[j] =

flashbase + 0x8000;

}

} else {

flash_info[i].start[j] =

flashbase + (j - 3) * MAIN_SECT_SIZE;

}

}

size += flash_info[i].size;

}

 

flash_protect (FLAG_PROTECT_SET,

       CFG_FLASH_BASE,

       CFG_FLASH_BASE + monitor_flash_len - 1,

       &flash_info[0]);

//设置保护在uboot存放的位置CFG_FLASH_BASE为起始位置,monitor_flash_len uboot大小

flash_protect (FLAG_PROTECT_SET,

       CFG_ENV_ADDR,

       CFG_ENV_ADDR + CFG_ENV_SIZE - 1, &flash_info[0]);

//设置保护在uboot的环境参数的位置CFG_ENV_ADDR为参数在nor中存放的位置

return size;

}

所以在jason_arm.h中需要定义如下宏

#define CONFIG_AMD_LV800 1 /* uncomment this if you have a LV800 flash */

#define CFG_MAX_FLASH_BANKS 1 /* max number of memory banks */

#ifdef CONFIG_AMD_LV800

#define PHYS_FLASH_SIZE 0x00100000 /* 1MB */

#define CFG_MAX_FLASH_SECT (19) /* max number of sectors on one chip */

#define CFG_ENV_ADDR (CFG_FLASH_BASE + 0x0F0000) /* addr of environment */

 

#define PHYS_FLASH_1 0x00000000 /* Flash Bank #1 */

所以flash_init函数需要移植

    define PAGE_SIZE 4096

addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);//PAGE_SIZE字节对齐

size = lcd_setmem (addr);

gd->fb_base = addr;

这些语句就是在nor中分配LCDframebuffer缓存区

mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);

分配堆空间

 

puts ("NAND:  ");

nand_init(); /* go init the NAND */

上面两行就是现实NADN的大小,下面进入nand_init函数,它在nand.c中定义

 

void nand_init(void)

{

int i;

unsigned int size = 0;

for (i = 0; i < CFG_MAX_NAND_DEVICE; i++) {

nand_init_chip(&nand_info[i], &nand_chip[i], base_address[i]);

size += nand_info[i].size;

if (nand_curr_device == -1)

nand_curr_device = i;

}

printf("%lu MiB\n", size / (1024 * 1024));//打印nand的大小

board_nand_select_device(nand_info[nand_curr_device].priv, nand_curr_device);

}

经过对nand_init_chip的一系列跟踪可得

nand_init_chip->board_nand_init;

board_nand_init需要开发者根据板子创建

 

env_relocate ();然后就是环境变量重定位,判断nandflash是否有环境参数(jason_arm.h中有#define CFG_ENV_IS_IN_NAND 1),如果有则从nand中读参数,反之从nor中读取

void env_relocate (void)

{

DEBUGF ("%s[%d] offset = 0x%lx\n", __FUNCTION__,__LINE__,

gd->reloc_off);

env_ptr = (env_t *)malloc (CFG_ENV_SIZE);

DEBUGF ("%s[%d] malloced ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);

 

env_get_char = env_get_char_memory;

 

if (gd->env_valid == 0) {//不知道为什么不为0,串口返回信息表明不为0

...

}

else {

env_relocate_spec ();//运行这个函数

}

gd->env_addr = (ulong)&(env_ptr->data);

 

#ifdef CONFIG_AMIGAONEG3SE

disable_nvram();

#endif

}

 

 

 

void env_relocate_spec (void)

{

#if !defined(ENV_IS_EMBEDDED)//没有定义,运行

ulong total;

int crc1_ok = 0, crc2_ok = 0;

env_t *tmp_env1, *tmp_env2;

 

total = CFG_ENV_SIZE;

 

tmp_env1 = (env_t *) malloc(CFG_ENV_SIZE);

tmp_env2 = (env_t *) malloc(CFG_ENV_SIZE);//给临时变量在nor中申请堆空间

 

nand_read(&nand_info[0], CFG_ENV_OFFSET, &total,

  (u_char*) tmp_env1);

nand_read(&nand_info[0], CFG_ENV_OFFSET_REDUND, &total,

  (u_char*) tmp_env2);//nand中相应位置读取数据

 

crc1_ok = (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc);

crc2_ok = (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc);

 

if(!crc1_ok && !crc2_ok)//在第一次启动时nand中并没有数据,因此全部为0

return use_default();//函数在下面

else if(crc1_ok && !crc2_ok)

gd->env_valid = 1;

else if(!crc1_ok && crc2_ok)

gd->env_valid = 2;

else {

/* both ok - check serial */

if(tmp_env1->flags == 255 && tmp_env2->flags == 0)

gd->env_valid = 2;

else if(tmp_env2->flags == 255 && tmp_env1->flags == 0)

gd->env_valid = 1;

else if(tmp_env1->flags > tmp_env2->flags)

gd->env_valid = 1;

else if(tmp_env2->flags > tmp_env1->flags)

gd->env_valid = 2;

else /* flags are equal - almost impossible */

gd->env_valid = 1;

 

}

 

free(env_ptr);

if(gd->env_valid == 1) {

env_ptr = tmp_env1;

free(tmp_env2);

} else {

env_ptr = tmp_env2;

free(tmp_env1);

}//这一个判断就是说nand中有环境参数,因此直接将数据复制给全局变量env_ptr 

 

#endif /* ! ENV_IS_EMBEDDED */

}

 

//当第一次启动uboot时候,nand中并没有环境参数,因此引用下面的函数

static void use_default()

{

puts ("*** Warning - bad CRC or NAND, using default environment\n\n");//和串口打印出 来的相符合

 

if (default_environment_size > CFG_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,

default_environment_size);//env_ptr赋环境参数值

env_ptr->crc = crc32(0, env_ptr->data, ENV_SIZE);

gd->env_valid = 1;//标志置1

 

}

 

经过上面的三个函数后,环境参数被就明确了。具体是如果nand中没有参数,则使用nor中自带的,并且打印“*** Warning - bad CRC or NAND, using default environment”,如果在启动之后执行saveenv命令,则此时环境参数被保存在nand中了,则就从nand取数据,

 

/* IP Address */

gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");//获取板子的IP地址

 

/* MAC Address */

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;

}//获取MAC地址

 

然后就是

devices_init (); /* get the devices list going. */

int devices_init (void)

{

#ifndef CONFIG_ARM     /* already relocated for current ARM implementation */

#endif

 

/* Initialize the list */

devlist = ListCreate (sizeof (device_t));

 

if (devlist == NULL) {

eputs ("Cannot initialize the list of devices!\n");

return -1;

}

#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)

i2c_init (CFG_I2C_SPEED, CFG_I2C_SLAVE);

#endif

#ifdef CONFIG_LCD//没有定义

drv_lcd_init ();

#endif

#if defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE)//没有定义

drv_video_init ();

#endif

#ifdef CONFIG_KEYBOARD

drv_keyboard_init ();

#endif

#ifdef CONFIG_LOGBUFFER//没有定义

drv_logbuff_init ();

#endif

drv_system_init ();//函数在下面

#ifdef CONFIG_SERIAL_MULTI//没有定义

serial_devices_init ();

#endif

#ifdef CONFIG_USB_TTY

drv_usbtty_init ();

#endif

#ifdef CONFIG_NETCONSOLE

drv_nc_init ();

#endif

return (0);

}

 

static void drv_system_init (void)

{

device_t dev;

 

memset (&dev, 0, sizeof (dev));

 

strcpy (dev.name, "serial");//设备名字为serial(串口)

dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;

//device.h中定义分别为设备可被用为输出控制台,输入控制台,设备是一个系统设备

#ifdef CONFIG_SERIAL_SOFTWARE_FIFO

...

#else

dev.putc = serial_putc;//添加设备输出字符函数

dev.puts = serial_puts;//添加设备输出字符串函数

dev.getc = serial_getc;//添加设备读取字符函数

dev.tstc = serial_tstc;

#endif

 

device_register (&dev);//注册设备

 

#ifdef CFG_DEVICE_NULLDEV///为防止设备列表中什么设备都没有,注册一个空设备???

memset (&dev, 0, sizeof (dev));

 

strcpy (dev.name, "nulldev");

dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;

dev.putc = nulldev_putc;

dev.puts = nulldev_puts;

dev.getc = nulldev_input;

dev.tstc = nulldev_input;

 

device_register (&dev);

#endif

}

所以上面三个函数就是将串口作为系统设备添加到设备链表中。

然后就是

jumptable_init ();//初始化gd中的jump table中的函数,如get_versionmallocgetenv

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;

#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 (CONFIG_COMMANDS & CFG_CMD_I2C)

gd->jt[XF_i2c_write] = (void *) i2c_write;

gd->jt[XF_i2c_read] = (void *) i2c_read;

#endif /* CFG_CMD_I2C */

}

 

然后就是

console_init_r ();//初始化标准输入标准输出标准错误

int console_init_r (void)

{

device_t *inputdev = NULL, *outputdev = NULL;

int i, items = ListNumItems (devlist);//设备链表中的设备数目

 

#ifdef CONFIG_SPLASH_SCREEN

#endif

 

#ifdef CONFIG_SILENT_CONSOLE

/* Suppress all output if "silent" mode requested */

if (gd->flags & GD_FLG_SILENT)

outputdev = search_device (DEV_FLAGS_OUTPUT, "nulldev");

#endif

 

/* Scan devices looking for input and output devices */

for (i = 1;

     (i <= items) && ((inputdev == NULL) || (outputdev == NULL));

     i++

    ) {

device_t *dev = ListGetPtrToItem (devlist, i);

 

if ((dev->flags & DEV_FLAGS_INPUT) && (inputdev == NULL)) {

inputdev = dev;

}

if ((dev->flags & DEV_FLAGS_OUTPUT) && (outputdev == NULL)) {

outputdev = dev;

}

}//for循环就是遍历链表来寻找标准输入标准输出标准错误

 

/* Initializes output console first */

if (outputdev != NULL) {

console_setfile (stdout, outputdev);//这个函数可以给stdio_devices[stdout]指针赋值

console_setfile (stderr, outputdev);//这个函数可以给stdio_devices[stdout]指针赋值

}

 

/* Initializes input console */

if (inputdev != NULL) {

console_setfile (stdin, inputdev);//这个函数可以给stdio_devices[stdin]指针赋值

}

 

gd->flags |= GD_FLG_DEVINIT; /* device initialization completed */

//GD_FLG_DEVINIT说明设备被初始化过了

 

#ifndef CFG_CONSOLE_INFO_QUIET

/* Print information */

puts ("In:    ");

if (stdio_devices[stdin] == NULL) {

puts ("No input devices available!\n");

} else {

printf ("%s\n", stdio_devices[stdin]->name);

}

 

puts ("Out:   ");

if (stdio_devices[stdout] == NULL) {

puts ("No output devices available!\n");

} else {

printf ("%s\n", stdio_devices[stdout]->name);

}

 

puts ("Err:   ");

if (stdio_devices[stderr] == NULL) {

puts ("No error devices available!\n");

} else {

printf ("%s\n", stdio_devices[stderr]->name);

}

//上面就是打印标准输出标准输入和标准错误使用的是什么设备

#endif /* CFG_CONSOLE_INFO_QUIET */

 

/* Setting environment variables */

for (i = 0; i < 3; i++) {

setenv (stdio_names[i], stdio_devices[i]->name);

}

 

#if 0

/* If nothing usable installed, use only the initial console */

if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL))

return (0);

#endif

 

return (0);

}

//从上面可以看出,在设备初始化的时候,将系统设备serial添加到设备链表中。然后在添加一个空设备在链表中。在console_init_r ()中又将这个serial设备传给标准输入标准输出标准错误。

#ifdef CONFIG_DRIVER_CS8900

cs8900_get_enetaddr (gd->bd->bi_enetaddr);

这里就是设置一些网卡的信息

 

然后就是进入main_loop函数了。

void main_loop (void)

{

#ifndef CFG_HUSH_PARSER

static char lastcommand[CFG_CBSIZE] = { 0, };

int len;

int rc = 1;

int flag;

#endif

#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)

char *s;

int bootdelay;

#endif

#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)

s = getenv ("bootdelay");//获取延迟的时间

bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;

 

debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);

s = getenv ("bootcmd");//获取启动内核的命令

 

debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");

 

if (bootdelay >= 0 && s && !abortboot (bootdelay)) {//这句话就是说如果bootdelay>=0并且配置了启动命令并且在bootlelay内没有按键按下则执行下面的语句

# ifdef CONFIG_AUTOBOOT_KEYED

int prev = disable_ctrlc(1); /* disable Control C checking */

# endif

 

# ifndef CFG_HUSH_PARSER

run_command (s, 0);

 

# ifdef CONFIG_AUTOBOOT_KEYED

disable_ctrlc(prev); /* restore Control C checking */

# endif

}

#endif

 

for (;;) {

len = readline (CFG_PROMPT);//从串口读取数据,CFG_PROMPT为每一行显示的头字符串

 

flag = 0; /* assume no special flags for now */

if (len > 0)

strcpy (lastcommand, console_buffer);

else if (len == 0)

flag |= CMD_FLAG_REPEAT;

if (len == -1)

puts ("<INTERRUPT>\n");//中断符

else

rc = run_command (lastcommand, flag);//运行命令

if (rc <= 0) {

/* invalid command or not repeatable, forget it */

lastcommand[0] = 0;//上个命令为空,执行命令情况是将获得的命令赋值给上个命令然后运行上个命令

 

}

}

uboot第二阶段分析

标签:c语言   linux   嵌入式   

原文地址:http://blog.csdn.net/u014104588/article/details/46500537

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!