"200分啊!" - 大家来分析一下,这个MMU的开关位置是否合理

HMGuardian 2013-02-05 11:08:02
故障位置在u-boot-2013.01的"arch/arm/cpu/arm1176/start.S"

//首先,在板的配置头文件中有如下定义:
#if !defined(CONFIG_NAND_SPL) && (CONFIG_SYS_TEXT_BASE >= 0xc0000000)
#define CONFIG_ENABLE_MMU
#endif

//其次,对start.S前部分的执行流程作简要描述:
_start: b reset
reset:
//更改CPU模式为SVC32
cpu_init_crit:
//主要行为,关MMU
bl lowleve_init
bl _main
//以前没有_main函数,而是执行一个名为board_init_f的函数,现此函数的调用位置_main函数
relocate_code:
//与主题无关
copy_loop:
//与主题无关
fixloop:
//与主题无关
fixabs:
//与主题无关
fixrel:
//与主题无关
fixnext:
//与主题无关
enable_mmu:
//开MMU



由上面的宏定义可知,只有当”CONFIG_SYS_TEXT_BASE >= 0xc0000000“才会开MMU,对于arm11这决对是个虚拟地址。
在Makefile中ld使用了参数-Ttext $(CONFIG_SYS_TEXT_BASE),也就是说最后生成的u-boot的入口地址是个虚拟地址。

好,问题来了:
入口_start进来 => 关MMU => 执行board_init_f(死掉)
虚拟地址 物理地址 为什么死呢?下面用反汇编分析


c7e0004c <_bss_end_ofs>:
c7e0004c: 0006d2a0 andeq sp, r6, r0, lsr #5
......
c7e00d88 <board_init_f>:
c7e00d88: e92d44f0 push {r4, r5, r6, r7, sl, lr}
c7e00d8c: e3a01000 mov r1, #0
c7e00d90: e3a02080 mov r2, #128 ; 0x80
c7e00d94: e1a00008 mov r0, r8
c7e00d98: eb00746f bl c7e1df5c <memset>
#下面这句把内存单元'0xc7e00e98'的内存加载到‘r0’.
c7e00d9c: e59f00f4 ldr r0, [pc, #244] ; c7e00e98 <board_init_f+0x110>
c7e00da0: e3a01010 mov r1, #16
#对照下面‘0xc7e00e98’处的内容后,可知此时'r0'的值为‘0xc7e0004c’.
#如果不出意外的话,执行完这句后,‘r3’的值应该为‘0x0006d2a0’。
c7e00da4: e5903000 ldr r3, [r0]
c7e00da8: e59f00ec ldr r0, [pc, #236] ; c7e00e9c <board_init_f+0x114>
......
c7e00e98: c7e0004c strbgt r0, [r0, ip, asr #32]!
c7e00e9c: c7e27d6d strbgt r7, [r2, sp, ror #26]!


好,咋一看木有问题,对,确实没有问题啊!
不过,大家似乎忘记了,此时MMU的状态!
此时的MMU还处于关闭状态,因此,此时的pc值应该是以"0x57e"开头的。

c7e00d9c: e59f00f4 ldr r0, [pc, #244] ; c7e00e98 <board_init_f+0x110>
这句不会有问题,因为ldr访问的目标地址是基于当前PC的一个偏移,能得到正确的地址"0x57e00e98",但它加载到'r0'的值却不会有任何的变化,仍然为‘0xc7e0004c’。不过,至少此时还没死,往下走。

c7e00da4: e5903000 ldr r3, [r0]
这句就不同了,ldr访问了一个不可访问的地址'0xc7e0004c',DRAM是挂到Bank6或Bank7的,两块空间都挂满物理地址也到不了0xc0000000,所以死了…………


嗯,
最后,我接触了u-boot的两个版本,2012.10及2013.01。两者代码虽有变化但执行流程流程是一样的。
我相信官方这么写应该是有其原因的,但我怎么想也想不通。因自己要用smdk6400这个板作为基础移植一个能在real6410上跑的u-boot,因此在此发问。
我这里是nand起动,算上nand_spl部分还是一样的。
nand_spl部分:
上电 => IROM => _start => 不执行relocate,开MMU被跳过,实际开不开都不影响 => 加载u-boot到RAM
非nand_spl,为什么又从_start开始,请参考nand_spl/nand_boot.c里"nand_boot"函数最后那华丽的一跳。
_start => 关MMU => 执行board_init_f(死掉)

请各位指正我分析的误点,如无误,请说下官方这么写的理由(猜的也行)。
...全文
2213 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
袁保康 2013-02-26
  • 打赏
  • 举报
回复
学习,学习真有人喜欢移植最新的东西 2013的,利害!
zhenghn2010 2013-02-08
  • 打赏
  • 举报
回复
也算我无聊 你是nand起动和非nand起动都实验了? 没做过该芯片的nand flash启动,但根据你的描述,我理解是这样: 分nand_spl.bin部分和u_boot.bin部分。 nand_spl.bin影射到0,也就是一般启动时候的地址。然后nand_spl.bin将u_boot.bin搬移到sdram中,接着跳转到u_boot.bin的start开始正常的启动。 你所说的 CONFIG_SYS_TEXT_BASE,目前看来是对nand_spl.bin起作用了,它也包含start. 而对于u_boot.bin中的start,也许也用到这个宏,或者有其他宏控制? 这个对u_boot.bin start影响目前倒是不大,可以认为它是地址无关,还没有跳转。 但根据你的反汇编,其地址明显是在sdram中了?你贴的是u_boot.bin中的start吧?接着跳转就出了问题。 nand_spl.bin搬uboot.bin到sdram的地址是多少? 谁控制的? nand_spl.bin的start是谁控制?uboot.bin的start是谁控制? 他们一样吗?还有就是你上面帖的那个bl main, 符号main的地址是谁控制的? 弄清了这些,估计就知道问题在哪里了。可能自己的configuration没作对,可能其build tree的机制不完善,得自己手动改写地址。
zhenghn2010 2013-02-07
  • 打赏
  • 举报
回复
一般在boot mmu没有必要打开。os开始时是要打开的。 boot阶段也有打开的。 这主要看你的代码需要,简单代码不需要。 boot如果打开mmu,就要用好它,可能只映射一部分内存。
zhenghn2010 2013-02-07
  • 打赏
  • 举报
回复
看一下你的连接脚本,在mmu没有打开之前,一些code_base是指定的,一定要正确。包括启动阶段和代码搬运阶段。包括mmu开启后的代码所在位置,都要对应好。 按我的理解, board_init_f应该是在mmu没有打开的时候调用的,怎么此时会是c7e00d88? 这个值可能和你的编译连接脚本有关,没有设置正确。 board_init_f是已经拷到内存中了? 或是是mmu打开后的值? boot中一些阶段后是可以打开mmu的。
HMGuardian 2013-02-07
  • 打赏
  • 举报
回复
引用 12 楼 zhenghn2010 的回复:
一般在boot mmu没有必要打开。os开始时是要打开的。 boot阶段也有打开的。 这主要看你的代码需要,简单代码不需要。 boot如果打开mmu,就要用好它,可能只映射一部分内存。
其实,u-boot开MMU目前我还没发现有什么好处。而且linux kernel要求在进入之前mmu和cache都处于关闭状态。 好吧,可能你会觉得我有些无聊-_- 我想多了解一些u-boot里面的东西,因此开了mmu,结果发现了这个问题……
HMGuardian 2013-02-07
  • 打赏
  • 举报
回复
引用 11 楼 zhenghn2010 的回复:
看一下你的连接脚本,在mmu没有打开之前,一些code_base是指定的,一定要正确。包括启动阶段和代码搬运阶段。包括mmu开启后的代码所在位置,都要对应好。 按我的理解, board_init_f应该是在mmu没有打开的时候调用的,怎么此时会是c7e00d88? 这个值可能和你的编译连接脚本有关,没有设置正确。 board_init_f是已经拷到内存中了? 或是是mmu打开后的值? b……
这个,用的是nand起动!分两部分ram运行的u-boot(step_2)及nand_spl目录构成的(step_1)! nand_spl部分的链接时的重定位志始地址是“0“。 ram部分的链接地址自己指定,只有在是址大于"0xc0000000"时会开启mmu,这个是配置文件里的一个宏控制的! 这些都是u-boot官方smdk6400预设的……不关我的事…… 我只是想知道写代码的人为何这样做,是失误还是出于什么方面的考虑……
Panda_熊猫 2013-02-06
  • 打赏
  • 举报
回复
其实我是接分的。。。
HMGuardian 2013-02-06
  • 打赏
  • 举报
回复
引用 6 楼 woshi_ziyu 的回复:
不懂 start.S
。。。。。。
HMGuardian 2013-02-06
  • 打赏
  • 举报
回复
引用 5 楼 zlgkaixin68 的回复:
board_init_f函数 该函数为板级初始化的第一个函数,会对板子上很多硬件外设做初始化,其中最重要的为init_sequence数组,该数组里面包含了很多板级的硬件初始化函数,在board_init_f函数中会依次的调用该数组中的函数去初始化各个硬件,该数组如下: init_fnc_t *init_sequence[] = { #if defined(CON……
好吧,你说的这些我都知道,board_init_f还对内存的使用做了规划,并将内存的划分数据写入了全局数据结构. 我只是想知道官方的源码将MMU的开启放置在board_init_f之后是出于什么考虑,是失误还是有什么其他原因!因为我发现如果配置时的地址大于0xc0000000的话,执行到board_init_f会死掉…… 连续几个版本都是这样,其维护人员或设计者肯定有其目的,但我想不透……
jdygrdzh 2013-02-06
  • 打赏
  • 举报
回复
ARM不懂,但是在powerpc上,上电后,MMU默认有一条是有效的,就是你最初的启动的4K空间,映射到你的启动设备比如nor flash上
woshi_ziyu 2013-02-06
  • 打赏
  • 举报
回复
不懂 start.S
Panda_熊猫 2013-02-06
  • 打赏
  • 举报
回复
board_init_f函数 该函数为板级初始化的第一个函数,会对板子上很多硬件外设做初始化,其中最重要的为init_sequence数组,该数组里面包含了很多板级的硬件初始化函数,在board_init_f函数中会依次的调用该数组中的函数去初始化各个硬件,该数组如下: init_fnc_t *init_sequence[] = { #if defined(CONFIG_BOARD_EARLY_INIT_F) board_early_init_f, #endif #if defined(CONFIG_MPC85xx) || defined(CONFIG_MPC86xx) probecpu, #endif ... 希望对你能有帮助
Panda_熊猫 2013-02-06
  • 打赏
  • 举报
回复
Uboot启动过程中,MMU和CACHE处于什么状态,为什么处于这个状态 先说 CACHE:数据cache必须关闭指令cache可以关闭也可以启动Bootloader主要是装载内核镜像,镜像数据必须真实写回SDRAM中,所以数据cache必须关闭,而对于指令cache,不存在强制性的规定,但在一般情况下,推荐关闭cache。 关于MMU :似乎没什么太大影响。将飞凌提供的UBOOT源码关闭MMU时也能正常运行,只是要将地址修改成物理地址(似乎是用宏和偏移的方式控制的,不必手动修改,但还是注意一下吧)。
HMGuardian 2013-02-05
  • 打赏
  • 举报
回复
引用 1 楼 wjcapple 的回复:
我最近也准备看linux,听楼主表描述的问题,根据其他操作系统的经验,重点检查一下平台相关的配置,相关芯片是是否正常工作,很多时候,硬件的问题会导致我们的系统无法正常启动的。
我敢肯定,你根本木有认真看我的问题……
曹大夯 2013-02-05
  • 打赏
  • 举报
回复
不懂。帮顶。
wjcapple 2013-02-05
  • 打赏
  • 举报
回复
我最近也准备看linux,听楼主表描述的问题,根据其他操作系统的经验,重点检查一下平台相关的配置,相关芯片是是否正常工作,很多时候,硬件的问题会导致我们的系统无法正常启动的。

21,600

社区成员

发帖
与我相关
我的任务
社区描述
硬件/嵌入开发 驱动开发/核心开发
社区管理员
  • 驱动开发/核心开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧