【Uboot学习随笔-基于tiny6410和uboot-2010.09】之-----启用MMU

来源:互联网 发布:mac airplay 关闭 编辑:程序博客网 时间:2024/06/05 18:17

随笔中记录的都是笔者学习Uboot过程中遇到的一些问题和解决方法,主要是将解决问题的过程和一些小经验、小技巧记录了下来。现在把一些感觉有点价值的内容搬到博客中供读者参考。

 

-----------------12.23-----------------

 

20:47


根据刚才说的,我在Makefile里直接设置RAM_TEXT为0xce000000,这样就可以启用MMU。(参见:http://blog.csdn.net/newthinker_wei/article/details/8424275)
但实际操作时又出现问题:

common/libcommon.a(cmd_ext2.o): In function `do_ext2load':
/public_desk/temp/uboot/u-boot-2010.09/common/cmd_ext2.c:191: undefined reference to `get_partition_info'
fs/ext2/libext2fs.a(dev.o): In function `ext2fs_set_blk_dev':
/public_desk/temp/uboot/u-boot-2010.09/fs/ext2/dev.c:45: undefined reference to `get_partition_info'
make: *** [u-boot] Error 1

第一反应就是,可能由于我将RAM_TEXT设为高端地址开起了CONFIG_ENABLE_MMU这个宏后,影响了其他的一些宏定义,导致有些库没有被编译。看看哪些地方涉及到了CONFIG_ENABLE_MMU这个宏吧,于是在源码目录下搜索包含CONFIG_ENABLE_MMU的文件,找到了五六个这样的文件,依次打开看看,找找其中跟CONFIG_ENABLE_MMU相关的部分。在 include/configs/smdk6400.h 中,发现有以下几行可能会对编译产生些影响,其他地方出现的CONFIG_ENABLE_MMU对编译结果的影响并不大:

#if !defined(CONFIG_ENABLE_MMU)
#define CONFIG_CMD_USB                  1
#define CONFIG_USB_S3C64XX
#define CONFIG_SYS_USB_OHCI_REGS_BASE           0x74300000
#define CONFIG_SYS_USB_OHCI_SLOT_NAME           "s3c6400"
#define CONFIG_SYS_USB_OHCI_MAX_ROOT_PORTS      3
#define CONFIG_SYS_USB_OHCI_CPU_INIT            1
#define CONFIG_USB_STORAGE      1
#define CONFIG_USB_OHCI_NEW             1
#endif

这里发现如果使能了MMU,那么USB相关的一系列宏将被屏蔽掉。这个影响应该比较大,但是到底怎么影响编译结果了?再回头看看make时的出错信息,发现出现的两个错误都是提示获取分区信息的函数找不到了,而且都跟ext2文件相关,但USB的设置会影响文件系统部分吗?个人感觉这个关联度应该不大啊,于是开始怀疑除了USB这块儿可能还有其他地方出问题。但没有使用MMU的时候可以正确编译,而现在跟刚才比就是多设置了一个使能MMU而已,根据刚才搜索出来的几个文件MMU的设置除了USB外貌似没有影响其他部分阿,难道还有些小地方我没注意到?uboot这么庞大的代码树让人看了就觉得头痛,去分析它下面的细节就更加纠结。进行到这里时我已感觉有点力不从心,脑子里特别乱,而且也快没耐心再分析下去了。

歇一会儿,继续研究。

根据出错提示可以知道get_partition_info这个函数找不到了,于是在snavigator环境中进入cmd_ext2.c找到get_partition_info,跳到定义处,发现这个函数的定义在 disk/part.c 文件中。进入disk子目录,打开此目录下的Makefile,找到出现part.o的地方,发现这样几句:
COBJS-y += part.o
COBJS-$(CONFIG_MAC_PARTITION)   += part_mac.o
COBJS-$(CONFIG_DOS_PARTITION)   += part_dos.o
看来part.o是无条件生成的,所以不可能是缺少哪个宏定义而没有编译part.c。但出错提示却说part.o里的一个函数找不到了,于是问题应该出在part.c本身,看这个源文件内部是否有什么条件编译不能满足。进入part.c,细看一下,果然发现这个文件大部分内容都有这个编译条件:

#if (defined(CONFIG_CMD_IDE) || \
     defined(CONFIG_CMD_MG_DISK) || \
     defined(CONFIG_CMD_SATA) || \
     defined(CONFIG_CMD_SCSI) || \
     defined(CONFIG_CMD_USB) || \
     defined(CONFIG_MMC)  || \
     defined(CONFIG_SYSTEMACE) )

刚才make时提示所缺的get_partition_info也受这个条件约束。终于有点眉目,而且更加令人兴奋的是这里也出现了CONFIG_CMD_USB,回头看看刚才的 include/configs/smdk6400.h 文件,发现如果使能了MMU,那么USB这个宏将被屏蔽。不过这还不够,因为只有当上面括号里所有的宏都没有被定义时,才可以确定part.o文件中的内容没有被编译。这些宏看起来都是跟硬盘、SD卡相关的,嵌入式一般没人用硬盘,SD卡倒有可能用。不乱猜了,直接回到smdk6400.h文件中看一下。依次搜索上面的宏,果然都没有出现!(USB宏出现了,不过被屏蔽了,哈哈)。看来确实是这里出的问题,刚才发现的被屏蔽掉的USB相关宏就通过这里影响了编译结果!
找到问题根源所在,下面就是解决问题了。通过错误提示可以看出,有两个解决方案。第一个方案就是把part.c中的条件编译改成无条件编译,这样get_partition_info函数就有了;第二个方案就是把用到part.o中函数的模块都去掉。我用的是第二个方案,因为用不到ext2文件系统。part.c文件中用条件编译,也是告诉我们,当括号里那几个宏都没有出现时,part.o中的函数是用不到的(当不用硬盘不用SD卡时,ext2确实也没什么用,NADN上一般都是用的yaffs2)。

动手前重新看看出错信息
common/libcommon.a(cmd_ext2.o): In function `do_ext2load':
/public_desk/temp/uboot/u-boot-2010.09/common/cmd_ext2.c:191: undefined reference to `get_partition_info'
fs/ext2/libext2fs.a(dev.o): In function `ext2fs_set_blk_dev':
/public_desk/temp/uboot/u-boot-2010.09/fs/ext2/dev.c:45: undefined reference to `get_partition_info'
make: *** [u-boot] Error 1

对于第一个错误,需要将libcommon.a库中的cmd_ext2.o模块去掉。于是进入common子目录,打开其中的Makefile,找到这一行:
COBJS-$(CONFIG_CMD_EXT2) += cmd_ext2.o
可见,cmd_ext2.o模块的编译与否,取决于CONFIG_CMD_EXT2这个宏的值。所以我们只需去掉这个宏即可。再次进入smdk6400.h文件,找到"#define CONFIG_CMD_EXT2",将其注释掉。(重新make smdk6400_config后 include/autoconf.mk 中就不存在CONFIG_CMD_EXT2的定义了)。当然这一步也可直接在 common/Makefile 中将cmd_ext2.o去掉,但感觉这样不好,因为这样的话uboot中就多了一个垃圾宏(CONFIG_CMD_EXT2)。

对于第二个错误,我们直接不要libext2fs.a这个库了。进入顶层Makefile,去掉LIBS中的"libext2fs.a"即可 。

这样再次编译就可以通过了。但是编译通过后,下载到开发板上无法运行。猜想可能是u-boot中没有进行内存映射,但依稀记得start.S文件中好像有关于mmu_table的定义,难道是内存映射表设置的有问题?如果uboot自己设置页表的话,那它肯定需要知道实际物理内存的起始地址和对应的虚拟起始地址(uboot一般都是线性映射),也就是说肯定有相应的宏定义。重新打开start.S文件,注意到了这行:
_TEXT_PHY_BASE:
        .word   CONFIG_SYS_PHY_UBOOT_BASE
这里用到一个CONFIG_SYS_PHY_UBOOT_BASE宏,再结合前面的标号_TEXT_PHY_BASE,不难猜到这个就是指物理内存的起始地址。追踪一下这个宏定义,start.S开头是:
#include <config.h>
#include <version.h>
#ifdef CONFIG_ENABLE_MMU
#include <asm/proc/domain.h>
#endif
那这个宏定义肯定就在上面包含进来的这几个文件中了(还有这几个文件包含的其他文件),一个一个找吧。一般这些平台相关的宏定义都在与开发板同名的头文件中,于是就先找 smdk6400.h (虽然我用的是tiny6410,但我移植Uboot没有再新建tiny6410相关目录,因为那样的话命名带来的问题就要改一大堆东西),果然找到了,都在这里:

/* base address for uboot */
#define CONFIG_SYS_PHY_UBOOT_BASE       (CONFIG_SYS_SDRAM_BASE + 0x07e00000)
/* total memory available to uboot */
……
……
#ifdef CONFIG_ENABLE_MMU
#define CONFIG_SYS_MAPPED_RAM_BASE      0xc0000000
#define CONFIG_BOOTCOMMAND      "nand read 0xc0018000 0x60000 0x1c0000;" \
                                "bootm 0xc0018000"
#else
#define CONFIG_SYS_MAPPED_RAM_BASE      CONFIG_SYS_SDRAM_BASE
#define CONFIG_BOOTCOMMAND      "nand read 0x50018000 0x60000 0x1c0000;" \
                                "bootm 0x50018000"
#endif
/* NAND U-Boot load and start address */
#define CONFIG_SYS_UBOOT_BASE           (CONFIG_SYS_MAPPED_RAM_BASE + 0x07e00000)
……
……
……
#define CONFIG_SYS_SDRAM_BASE   0x50000000
……

好了,物理内存起始地址(0x50000000)、对应的虚拟起始地址(0xc0000000)、Uboot的起始位置都有了,看样子uboot里确实将页表按照这些宏设置好了?看了下这些地址的设置,跟我的开发板一样(主要是内存起始地址0x50000000没错就行),那为什么不能运行呢?难道是把IO、寄存器也映射到其他地址了?

后来直接 arm-linux-objdump -d u-boot,  仔细看了看U-boot的反汇编,发现虽然在start.S文件中有mmu_table的定义,但u-boot中只是指定了这个页表的地址,而没有真正实现这个页表。推断依据:

反汇编中
  c7e00188 <_mmu_table_base>:
  c7e00188:       c7e28000        .word   0xc7e28000
这两行对应start.S文件中的:
#ifdef CONFIG_ENABLE_MMU
_mmu_table_base:
        .word mmu_table
#endif
如果Uboot确实实现了这个页表,那么在反汇编文件的其他地方肯定还会出现 _mmu_table_base、c7e28000、c7e00188 这样的字眼,但是搜索后发现其他地方并未出现这些标号和数字。


所以要想使用MMU可能还要自己花功夫设置页表。
我开发板带的编译好的内核需要放在0xc0000000地址处才能正常bootm,以前一直是用开发版带的Uboot,这次想用自己的Uboot引导一下那个内核,发现问题还真不少,衰。


 

 

原创粉丝点击