您的位置:首页 > 其它

uboot第二阶段分析

2015-06-15 09:56 288 查看
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);

}

这个函数就是初始产生中断的各个寄存器,在uboot的cpu/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中分配LCD的framebuffer缓存区

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_SL***E);

#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_version,malloc,getenv

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;//上个命令为空,执行命令情况是将获得的命令赋值给上个命令然后运行上个命令



}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: