Chinaunix首页 | 论坛 | 博客
  • 博客访问: 168515
  • 博文数量: 109
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 147
  • 用 户 组: 普通用户
  • 注册时间: 2015-01-23 16:12
文章分类

全部博文(109)

文章存档

2015年(109)

我的朋友

分类: LINUX

2015-01-23 16:15:03

原文地址:研究生项目回顾之uboot 作者:myleeming

 

其实u-boot还是比较简单的,总结下来就是以下这么多点:

1。在board目录下相应平台下:congfig.mk规定了TEXT_BASE的地址(也就是希望运行的地址,链接地址,真实(上电启动,pc指针指过去)是在.start里执行的),链接脚本u-boot.lds也在这里。

cpu目录相应平台下:除了主要的start.s等文件,也有一个config.mk文件,不过该文件主要定义了编译选项,比如armv6架构等。

2 通过链接地址TEXT_BASE和运行地址.start的不同来决定是否要relocate

3 在启动部分可以看到在uboot中栈的位置是在TEXT_BASE下面(小于TEXT_BASE的地址)的:

ldr        r0, _TEXT_BASE

sub        r0, r0, #CFG_MALLOC_LEN //这些参数是在include/configs/相应平台下设定的,

sub        r0, r0, #CFG_GBL_DATA_SIZE

sub        r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)

因此uboot部分的内存分布应该如下:

Svc stack

Irq stack

Fiq stack

Gbl(放全局变量gd)

malloc

TEXT_BASE

4系统c部分的代码主要是在lib/lib_arm/board.c中的start_armboot函数中:

gbl区存放了uboot中唯一一个全局变量(当然因为这个全局变量涵盖的东西够多了,所以只需要这么一个了)gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));

看一下这个gd_t的类型:

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

unsigned long        fb_base;        /* base address of frame buffer */

#ifdef CONFIG_VFD

unsigned char        vfd_type;        /* display type */

#endif

void                **jt;                /* jump table */

} gd_t;

bd的位置紧挨gd之下:

gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));

typedef struct bd_info {

unsigned long        bi_memstart;        /* start of DRAM memory */

unsigned long        bi_memsize;        /* size         of DRAM memory in bytes */

unsigned long        bi_flashstart;        /* start of FLASH memory */

unsigned long        bi_flashsize;        /* size         of FLASH memory */

unsigned long        bi_flashoffset; /* reserved area for startup monitor */

unsigned long        bi_sramstart;        /* start of SRAM memory */

unsigned long        bi_sramsize;        /* size         of SRAM memory */

unsigned long        bi_ip_addr;        /* IP Address */

unsigned char        bi_enetaddr[6]; /* Ethernet adress */

unsigned long        bi_baudrate;        /* Console Baudrate */

} bd_t;

5。接下来主要完成这么一个数组的执行,数组中存放一个指针,指针指向的内容是一个函数。

init_fnc_t *init_sequence[] = {

cpu_init,                /* basic cpu dependent setup */

board_init,        //这里会设定传递给os的机器号和参数地址

interrupt_init,                /* set up exceptions */

env_init,                //根据配置的不同,将环境变量初始化在不同的地方

根据:CFG_ENV_IS_IN_FLASH,CFG_ENV_IS_IN_ONENAND,CFG_ENV_IS_IN_NAND,CFG_ENV_IS_NOWHERE等选项来调用相应的env_init函数。当然这些配置在include/configs/具体平台文件中。比如4020uboot中是定义的IN_FLASH,因此会执行common/env_flash.c中的函数。

init_baudrate,                //这里会从env中获得波特率的值然后赋给gd->bd->bi_baudrate

//have passed here

serial_init,                /* serial communications setup */

//console also passed

console_init_f,                /* stage 1 init of console */

display_banner,                /* 打印点信息 */

dram_init,                //其实一般到这里ram早就配置好了,这里也是将ram信息赋给gd->bd->bi*

display_dram_config,

NULL,

};

6。完成了上面那个数组的函数,其实已经完成了基本的配置。接下来的函数就是进一步细化模块的初始化,包括有:(注:一下均为功能性伪码,不一定要相同的函数名)

flash_init ();

Frambuffer_init();

nand_init();

env_relocate ();(虽然上面数组中有env_init的,但是在env是有crc校验的,一般而言刚开始flash中的初始数据肯定是不满足crc的,此时系统会自动做以下操作gd->env_addr  =(ulong)&default_environment[0];gd->env_valid = 0;因此其实env并没有完全初始化好,在这里会将defalut的拷贝至flash中(如果定义的话),然后重新将gd->env_addr指向configs中规定的地方)

ethernet_init()

最终进入main_loopmain_loop中就是不断的循环等待你输入命令,然后执行命令。

7 命令的执行:

uboot中所有的命令都通过以下这种方式定义:

#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \

cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage, help}

比如:printenv命令

U_BOOT_CMD(

printenv, CFG_MAXARGS, 1,        do_printenv,

"printenv- print environment variables\n",

"\n    - print values of all environment variables\n"

"printenv name ...\n"

"    - print value of environment variable 'name'\n"

);这个其实就定义了一个cmd_tbl_t类型的结构体,并且由于在编译的时候依旧加了限定符Struct_Section,因此这些命令的空间都在.u_boot_cmd的地方,在lds脚本中也是将它们独立存放的

#define Struct_Section  __attribute__ ((unused,section (".u_boot_cmd")))

这种方法的好处,就是在用户输入一条命令,系统去查找这条命令是否存在,以及它的处理函数时非常方便,这种做法在linux中解析bootargs等也大量用到了,详见之前linux c语言启动部分——参数分析专题。

阅读(602) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~