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_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_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;//上个命令为空,执行命令情况是将获得的命令赋值给上个命令然后运行上个命令
}
}
原文地址:http://blog.csdn.net/u014104588/article/details/46500537