打印

u-boot代码分析和移植,连载中

[复制链接]
楼主: 8421bcd
手机看帖
扫描二维码
随时随地手机跟帖
21
itelectron| | 2009-11-19 18:33 | 只看该作者 回帖奖励 |倒序浏览
补充下 上面说的 是 定义0x30000000为 RAM的其始地址的情况下

使用特权

评论回复
22
liliang9554| | 2009-11-19 18:35 | 只看该作者
果然很“酷”

使用特权

评论回复
23
itelectron| | 2009-11-19 18:36 | 只看该作者

使用特权

评论回复
24
贾君鹏子| | 2009-11-19 18:40 | 只看该作者
哈哈,那属于盗版吗?

使用特权

评论回复
25
五谷道场| | 2009-11-19 18:59 | 只看该作者
再次提出来学习,不算啥吧

使用特权

评论回复
26
itelectron| | 2009-11-19 20:44 | 只看该作者
NAND闪存的硬件 ECC

2410的硬件NAND ECC是 怎么使用的????

使用特权

评论回复
27
8421bcd|  楼主 | 2009-11-19 21:10 | 只看该作者
to : itelectron

你超前我很多了,以后还要向你学习,呵呵,我也是刚开始接触U-BOOT,不到一个星期,很多问题也没弄明白,一起努力!

ECC,NAND ECC可以参考BOOTLOADER下的格式化命令吧

使用特权

评论回复
28
LIU_XF| | 2009-11-19 21:14 | 只看该作者
好帖,做个记号,俺要加入

使用特权

评论回复
29
8421bcd|  楼主 | 2009-11-19 23:43 | 只看该作者
发现board.c代码里有好多东东不知道什么意思,郁闷,加油```

使用特权

评论回复
30
changyongid| | 2009-11-20 08:35 | 只看该作者
1. 在楼主的给出的流程图里面有

设置FCLK HCLK PCLK 时钟频率

在start.S里只是 设置了它们的分频比而已,并没有设置具体频率

具体频率应该在board.c里设置的。

2. 没有设置PLL时,默认的频率应该是12M才对。但uboot里的注释确实是写的120M。不知道为虾米

3. 在板子的文件夹里,会有个config.mk文件,里面是TEXT_BASE = 0x33f80000
这个参数在链接的时候会被用到。具体是-Ttext  $(TEXT_BASE)。
这样的话,整个代码的绝对地址相当于是从0x33f80000开始计算的。

在ldr pc, _start_armboot        ;pc <-- _start_armboot   之前,所有的代码均为地址无关代码,而_start_armboot的中的值是start_armboot,其具体地址是编译时就确定了的。也就是说,start_armboot的地址是从_start=0x33f80000开始往后算出来的。0x33f80000在sdram的最后一M内,所以start_armboot的地址一定在sdram最后一M,即0x33f80000之后,至于具体多少,就不用管了。

使用特权

评论回复
31
itelectron| | 2009-11-20 18:15 | 只看该作者
TO 8421bcd  我啊是 断断续续的 学 没有 效果啊 !!
疑问 很多  自己解决的太慢了!网上 书店 都讲的 太 粗了!
努力吧!!

使用特权

评论回复
32
zyok| | 2009-11-20 19:28 | 只看该作者
顶顶看..

使用特权

评论回复
33
8421bcd|  楼主 | 2009-11-20 20:10 | 只看该作者
30# changyongid
谢谢changyongid的提示!:)

使用特权

评论回复
34
bespecial| | 2009-11-20 21:10 | 只看该作者
顶一个
做个记号

使用特权

评论回复
35
8421bcd|  楼主 | 2009-11-20 23:19 | 只看该作者
我使用的是u-boot-1.3.0-rc2。在cpu/pxa/start.S中,有如下的标号定义:
_TEXT_BASE:
.word TEXT_BASE /*uboot映像在SDRAM中的重定位地址,我设置为0xa170 0000 */

.globl _armboot_start
_armboot_start:
.word _start /*_start是程序入口,链接完毕它的值应该是0xa170 0000=TEXT_BASE*/
/* 这句话的意思应该是在_armboot_start标号处,保存了_start的值,也就是说,_armboot_start是存放_start的地址,该地址对应的存储单元内容是0xa170 0000*/
/*
* These are defined in the board-specific linker script. 下面的定义与上面应该是一个意思。
*/
.globl _bss_start
_bss_start:
.word __bss_start
======================
按照上面的理解,__bss_start是uboot 的bss段起始地址,那么uboot映像的大小就是__bss_start - _start;在relocate代码段中计算uboot的大小时,也体现了这一点。
实际上,_armboot_start并没有实际意义,它只是在"ldr r2, _armboot_start"中用來寻址_start的值而已,_bss_start也是一样的道理,真正有意义的应该是_start和 __bss_start本身。
但是,令我不解的是,在C入口函数start_armboot()中(对应文件为lib_arm/board.c),有如下代码:
void start_armboot (void)
{
.........
gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t)); //第一句话
..........
monitor_flash_len = _bss_start - _armboot_start; //第二句话
...............
mem_malloc_init (_armboot_start - CFG_MALLOC_LEN); //第三句话
..........
}
==============================================
按照上面的理解,_armboot_start与_bss_start都是没有实际意义的,它们只是一个地址,有实际意义的是地址中的内容_start和 __bss_start(虽然也还是地址)。象第一句话,其“意图”很明显,是把gd作为全局数据结构体的指针,并初始化为“SDRAM中的uboot起始地址(即TEXT_BASE)-CFG_MALLOC_LEN-全局数据结构体大小”。
要实现这个“意图”,应该是写成:gd = (gd_t*)(_start - CFG_MALLOC_LEN - sizeof(gd_t));或者gd = (gd_t*)(TEXT_BASE- CFG_MALLOC_LEN - sizeof(gd_t));才对阿?用_armboot_start来作运算应该是没有任何意义才对!?
第二句话也是一样的道理,它的意图是要计算u-boot映像的大小,应该写成__bss_start - _start才对阿?
我使用readelf工具查看编译所得到的uboot映像文件得到信息如下:
[aaronwong@localhost build]$ readelf -s u-boot|grep _start
1018: a1700048 0 NOTYPE GLOBAL DEFAULT 1 _bss_start
1083: a1700044 0 NOTYPE GLOBAL DEFAULT 1 _armboot_start
1142: a1700000 0 NOTYPE GLOBAL DEFAULT 1 _start
1197: a171b070 0 NOTYPE GLOBAL DEFAULT ABS __bss_start
上面我删除了与该讨论无关的包含“_start""t的标号信息。
显然,我前面的理解应该是正确的(_start=TEXT_BASE=0xa170 0000)。那么u-boot源代码中的monitor_flash_len=_bss_start - _armboot_start=0xa1700048 - 0xa1700044 = 4,有什么意义??
迷茫中,期盼大虾指点迷津,谢谢~!!!



--------------------------------------------------------------------------------
eltshan: [Re: aaronwong]
-----------------
1018: a1700048 0 NOTYPE GLOBAL DEFAULT 1 _bss_start
1083: a1700044 0 NOTYPE GLOBAL DEFAULT 1 _armboot_start
1142: a1700000 0 NOTYPE GLOBAL DEFAULT 1 _start
1197: a171b070 0 NOTYPE GLOBAL DEFAULT ABS __bss_start

我想:
_start所在的地址是a1700000,
_armboot_start 所在的地址是a1700044,
那么 根据这句:
_armboot_start: .word _start
所以_armboot_start的值应该是a1700000

所以
monitor_flash_len = _bss_start - _armboot_start = a171b070 - a1700000 = 1b070
而不是你说的 = 4

以上个人意见.

--------------------------------------------------------------------------------
aaronwong: [Re: eltshan]
-------------------
谢谢,eltshan!你的理解是正确的,不过我看了之后还是没能想得很明白,因为我在想,按你所说,那么_start的值应该是多少呢?难道是“b reset”这条指令的机器码?所以我对ELF格式的u-boot映像文件作了反汇编,分析之后终于找到了症结所在。以下是部分分析过程,首先是反汇编:
arm-iwmmxt-linux-gnueabi-objectdump -D u-boot > u-boot.s
并提取了monitor_flash_len = _bss_start - _armboot_start;这条语句相关的反汇编代码如下:
==============================
a1700044 <_armboot_start>:
a1700044: a1700000 .word 0xa1700000

a1700048 <_bss_start>:
a1700048: a171b070 .word 0xa171b070

a171b070 <monitor_flash_len>:
a171b070: 00000000 .word 0x00000000

.....
a1700f40: e59f41d0 ldr r4, [pc, #464] ; a1701118 <start_armboot+0x1dc>
//r4=[a1701118]=a1700044
.....
a1700f7c: e59f3198 ldr r3, [pc, #408] ; a170111c <start_armboot+0x1e0>
//r3=[a1700044]=a1700048
a1700f80: e5942000 ldr r2, [r4]
//r2=[a1700044]=a1700000
a1700f84: e59f4194 ldr r4, [pc, #404] ; a1701120 <start_armboot+0x1e4>
//r4=[a1701120]=a1719d24
a1700f88: e5933000 ldr r3, [r3]
//r3=[a1700048]=a171b070
a1700f8c: e0623003 rsb r3, r2, r3
//r3= r3-r2 = a171b070-a1700000 = 1b070;
a1700f90: e59f218c ldr r2, [pc, #396] ; a1701124 <start_armboot+0x1e8>
//r2=[a1701124]=a171b070
a1700f94: e5823000 str r3, [r2]
//monitor_flash_len=[r2]=r3=1b070
......

a1701118: a1700044 .word 0xa1700044
a170111c: a1700048 .word 0xa1700048
a1701120: a1719d24 .word 0xa1719d24
a1701124: a171b070 .word 0xa171b070
========================================
上面//是我自己的注释。这表明,你的理解的确是正确的。
经过这个过程之后,我终于认识到自己的误解在哪里了。原来,我是把"汇编语言中LDR伪指令对符号的引用"与"C语言中对汇编程序中符号/常量/变量的引用"搞混淆了。我想说明以下几点:

(1) readelf以及u-boot.map和System.map所给出的符号表中符号的值,实际上是表示符号所在的地址,而不是指符号本身的值。

(2) 汇编语言中没有指针的概念,因此对符号的引用是"赤裸裸"的。例如:
==========
.globl _armboot_start
_armboot_start: .word _start
ldr r2, _armboot_start
==========
实际上反汇编以后是:
============
a1700044 <_armboot_start>:
a1700044: a1700000 .word 0xa1700000
a1700074: e51f2038 ldr r2, [pc, #-56] ; a1700044 <_armboot_start>
============
也就是说,_armboot_start是一个地址0xa1700044,其中的内容是0xa1700000,上面对_armboot_start的引用是直接将其替换为其表示的地址0xa1700044,而非其中的内容0xa1700000。这就是"赤裸裸"的引用。

(3) C语言则不同,对变量/符号/常量的引用必须要通过地址来寻址,不管是全局变量还是局部变量,不同的是局部变量在生命期结束后,所占的地址空间会被释放而已。即使是函数调用时的参数传递,虽然是将实参的值"拷贝"给形参,但"拷贝"的过程也是通过实参和形参的地址来对两者进行访问的。
所以,在C语言中的 "monitor_flash_len = _bss_start - _armboot_start" 这句话中对_armboot_star的引用,实际上是把它用作了指针,把它作为访问对象的地址来使用,通过这个地址即a1700044 来访问对应存储空间所存放的内容亦即0xa1700000,_bss_start也是同样的道理。所以这句话实际上是monitor_flash_len =[a1700048]-[0xa1700044]=a171b070-a1700000 = 1b070,这样就得到了正确的结果。

现在,我们再回答最前面的问题:_start的值是什么?_start表示地址0xa1700000 ,在汇编语言中,对_start的"绝对引用"(这里是与用相对寻址进行跳转进行区别)就是将其替换为0xa1700000,但其中存放的内容的的确确就是"b reset"这条指令的机器码,所以如果在C语言中引用_start,得到的结果反而就是这个指令的机器码了。其实这个问题很简单,只是和C语言的引用搅在一起,一些概念被偷换了而已。

以上是我的个人理解,有什么不对,还请指正。

再次感谢eltshan的提点。

转自http://blog.chinaunix.net/u2/70445/showart_1084562.html

使用特权

评论回复
36
gyjdk0601| | 2009-11-21 21:35 | 只看该作者
留个位置,以后慢慢看

使用特权

评论回复
37
liliang9554| | 2009-11-22 23:22 | 只看该作者
看不懂啊,哎

使用特权

评论回复
38
8421bcd|  楼主 | 2009-11-24 00:28 | 只看该作者
其中的函数调用的比较多,还就是有两人结构体gd_t、bd_t,其中gd_t嵌套bd_t,用SOURCEINSIGHT看会方便很多。
void start_armboot (void)
{
        DECLARE_GLOBAL_DATA_PTR;                /* 告诉编译器使用寄存器r8来存储gd_t类型的指针gd,gd是这样来的*/
/*gd_t和bd_t是u-boot中两个重要的数据结构,在初始化操作很多都要靠这两个数据结构来保存或传递.http://hi.baidu.com/hawkingzhao/ ... 4078d5e7113a85.html  */
        ulong size;
        init_fnc_t **init_fnc_ptr;        /* 定义一个双指针,不清楚什么类型???*/
        char *s;
#if defined(CONFIG_VFD) || defined(CONFIG_LCD)       
        unsigned long addr;
#endif

        /* Pointer is writable since we allocated a register for it */
        gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));        /* gd 是一个全局指针,gd_t是一个结构体变量,_armboot_start是代码开始地址,意思是定义一个全局指针,指针指向的类型为gd_t结构体,指向的地址有后面小括号的表达式算出*/       
        /* compiler optimization barrier needed for GCC >= 3.4 */                /* 编译器优化屏障http://blog.chinaunix.net/u1/55599/showart_1099203.html */

        __asm__ __volatile__("": : :"memory");                        /* 一条汇编指令        http://blog.chinaunix.net/u3/93809/showart_1890394.html  */       
        memset ((void*)gd, 0, sizeof (gd_t));                                /* 对gd指向的结构体全部填冲0 */               
        gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));                /* 对gd的成员变量bd赋值*/
        memset (gd->bd, 0, sizeof (bd_t));                                /* 再对gd结构体的成员变量bd(为一指针变量)清填0 */

        monitor_flash_len = _bss_start - _armboot_start;                 /* 计算出代码长度*/

/*  这个循环用于判断整个系统有没有初始
      没有的话就会输出错误信息,提示复位系统*/
        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 ();        /*用于初始化Nor flash的函数,初始化了每个扇区的首地址http://blog.chinaunix.net/u1/58780/showart_459188.html */
        display_flash_config (size);        /*打印Norflash的容量信息*/

#ifdef CONFIG_VFD                /* 没有用这种显示器吧,不管它。*/
#        ifndef PAGE_SIZE
#          define PAGE_SIZE 4096
#        endif
        /*
         * reserve memory for VFD display (always full pages)
         */
        /* bss_end is defined in the board-specific linker script */
        addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
        size = vfd_setmem (addr);
        gd->fb_base = addr;
#endif /* CONFIG_VFD */

#ifdef CONFIG_LCD                /*关于LCD的,这个有用,看下。*/
#        ifndef PAGE_SIZE
#          define PAGE_SIZE 4096
#        endif
        /*
         * reserve memory for LCD display (always full pages)
         */
        /* bss_end is defined in the board-specific linker script */
        addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);                /* 把视频帧缓冲区设置在bss_end后面http://group.**/1300/17234.aspx  */
        size = lcd_setmem (addr);                /* 设置缓存*/
        gd->fb_base = addr;        /* 为显存缓冲区地址变量赋值http://blog.mcuol.com/User/okti/Article/8239_1.htm  */
       
#endif /* CONFIG_LCD */

        /* armboot_start is defined in the board-specific linker script */
        mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);        /* 定义一段内存空间地址程序入口地址-128K,并对其初始化

#if (CONFIG_COMMANDS & CFG_CMD_NAND)
        puts ("NAND:");
        nand_init();                /* go init the NAND */                        /* 初始化NAND FLASH */
#endif

#ifdef CONFIG_HAS_DATAFLASH
        AT91F_DataflashInit();                        /* 如果系统支持的话就初始化Dataflash */
        dataflash_print_info();                        /* 打印检测到硬件信息*/
#endif

        /* initialize environment */
        env_relocate ();                /* 进行环境变量的重定位,即从Flash 中搬移到RAM 中*/

#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");        /* 从环境变量"ipaddr"中读取IP 地址,初始化gd->bd->bi_ip_addr */

        /* MAC Address */        /* 从环境变量"ethaddr"中读取MAC 地址,初始化gd->bd->bi_enetaddr */
        {
                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);        /* CS8900 网卡初始化*/
#endif

#if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)
        if (getenv ("ethaddr")) {
                smc_set_mac_addr(gd->bd->bi_enetaddr);        /*SMC91111 初始化*/
        }
#endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */

        /* Initialize from environment        读取环境变量"loadaddr"到loadaddr 变量 */
        if ((s = getenv ("loadaddr")) != NULL) {
                load_addr = simple_strtoul (s, NULL, 16);
        }
#if (CONFIG_COMMANDS & CFG_CMD_NET)        /* 读取环境变量"bootfile"到BootFile 变量 */
        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 */
}

使用特权

评论回复
39
一朝成名| | 2009-11-24 09:01 | 只看该作者
非常不错~

使用特权

评论回复
40
changyongid| | 2009-11-24 09:12 | 只看该作者
补充一个。

初始120M的频率。。。

MPLL= ((M+8) * Fin) / ((P+2) * 2 ^ S)
上电后,默认M = 0X5C , P = 0X08 , S = 0X0,
而FIN = 12M
这样计算下来,FCLK=120M

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则