Chinaunix

标题: u-boot相关powerpc处理器 [打印本页]

作者: bitliu1983    时间: 2009-12-04 08:56
标题: u-boot相关powerpc处理器
大家好,又来请教大家了。
之前咨询过大家关于powerpc的一些问题,现在我们板子用uboot引导起来了,我们裁剪了u-boot。
在之后应用编程发现一个问题,用汇编语言编写的函数,访问一个已经初始化的全局变量,全局变量在之后在一个C代码函数里修改过,在汇编函数里读取值发现全局变量的值还是初始化的。
过程如下:

unsigned long globala=111;//全局变量

在一个C函数里:
void A()
{
...
修改globala =200;
...
}
在一个B汇编函数里:
读取修改的全局变量:
.globl  global
global:
    mflr r27
    lis  r3,globala@ha
    lwz r3,globala@l(r3)
    bl printgl //打印globala的值,发现还是111,而不是200,
   mtlr r27
    blr
我们认为和got全局偏移量表有关,是不是全局变量放在偏移量表里面了,所以没法访问:
然后汇编修改如下:
    lis  r3,globala@got@ha
    lwz r3,globala@got@l(r3)
发现还是111.而不是200??
想请教下大家。
作者: xuhui250    时间: 2009-12-06 15:09
你这个代码是在rom里面还是ram里面运行的呢?
作者: bitliu1983    时间: 2009-12-06 16:51
惨了,我发现freescale的基于e300内核的mpc8313开发板。
在boot起来时,CPU片选nor flash(地址为0xfe000000,ram的地址为0x0),在flash里启动,然后重定位到ram里进行,在ram里起来后,ram地址为0x0,flash还是为0xfe000000,这就导致了程序编译和运行的地址不一样,导致访问全局变量时,地址还是flash的地址,除非在函数里,申请临时变量来获取全局变量的地址(编译器解决了这个问题),直接在汇编代码里获取全局变量的值和地址还是在flash里的,没有取到ram里的。我们不知道怎么解决全局变量地址问题?这和arm不一样,arm起来时,flash是0x0,内存是0x50000000,重定位后,又把ram映射为0x0,flash映射为0x50000000,不会使同一个变量有2个地址。
各位大侠,有什么高见啊?
linux怎么做的~
作者: abutter    时间: 2009-12-06 20:11
原帖由 bitliu1983 于 2009-12-6 16:51 发表
惨了,我发现freescale的基于e300内核的mpc8313开发板。
在boot起来时,CPU片选nor flash(地址为0xfe000000,ram的地址为0x0),在flash里启动,然后重定位到ram里进行,在ram里起来后,ram地址为0x0,flash还 ...

关键在你的 A 函数是在哪个位置调用的,如果是在重定位初始化之后,变量的地址就应该进行修正,也就是说赋值的语句要加上偏移的。

你的具体需求是啥?感觉你的做法很怪异。
作者: cjaizss    时间: 2009-12-06 21:42
emulator+breakpoint+watch+step
作者: bitliu1983    时间: 2009-12-07 08:50
标题: 回复 #4 abutter 的帖子
是啊,重定位初始化之后,变量的地址就应该进行修正,也就是说赋值的语句要加上偏移的。
但是,在u-boot起来后,不可能在写应用程序时,每访问一个全局变量都要手工加上偏移地址吧,想知道,在start.S里或在编译过程中,做些什么工作,使得重定位前和之后,地址一致?
我们需求是,在u-boot起来后,加上自己的调度程序,系统保护及mmu,然后自己在此基础上写应用程序,也就是说把u-boot和我们自己的应用绑在一起。不是用boot来引导linux。
作者: cjaizss    时间: 2009-12-07 10:10
经验告诉我,发生"灵异事件"99%以上来源于自己的想当然,每个人,包括我,经常会遇到这种事.
先调试看看吧.
确认,这个变量你真的可以修改,你确认修改的是RAM里的数据?你用的是某种DRAM?你确认初始化过了?代码真的按你想象的执行的?.......等等,诸如此类
作者: bitliu1983    时间: 2009-12-07 10:48
原帖由 cjaizss 于 2009-12-7 10:10 发表
经验告诉我,发生"灵异事件"99%以上来源于自己的想当然,每个人,包括我,经常会遇到这种事.
先调试看看吧.
确认,这个变量你真的可以修改,你确认修改的是RAM里的数据?你用的是某种DRAM?你确认初始化过了?代码真的 ...


实在不理解版主的回答??
这不是什么灵异事件,我们用codewarrier仿真器查了,我是想问大家,当重定位前,和重定位后,数据或代码地址不一致怎么解决?
除非mpc8313板子有额外的硬件,把从ram启动之前,把flash地址0xfe000000就定为0x0。
我想知道linux在u-boot起来后,怎么解决这个问题的~
召唤Cyberman.Wu 达人,最近还逛论坛吗?
作者: xuhui250    时间: 2009-12-07 13:39
在board_init_f最后会有relocate_code操作,这个地方会把Rom中的代码、数据搬移到Ram中,相关单板信息、堆栈等都会一并搬到RAM,然后运行board_init_r。

所有u-boot分为两段,如果两段运行(Run in ROM/RAM)需要有数据共享,就需要重定位或者通过relocate_code放方式把数据拷贝过去。

RAM/ROM之间一般不共享全局变量。
作者: readkernel    时间: 2009-12-07 17:54
把flash的那个全局变量所在的地址块映射到程序需要访问的地址上(虚拟地址),打开MMU
作者: xuhui250    时间: 2009-12-07 22:41
原帖由 readkernel 于 2009-12-7 17:54 发表
把flash的那个全局变量所在的地址块映射到程序需要访问的地址上(虚拟地址),打开MMU


肯定不能这样解决。MMU功能映射到FLASH,这个数据还是不能修改的。
我看看u-boot如何链接,然后在给个答案。

u-boot有个链接脚本u-boot.lds在各board下面,另外和TEXT_BASE一起决定第一条指令定位到哪里。
作者: 大鬼不动    时间: 2009-12-08 07:48
学习了
作者: readkernel    时间: 2009-12-08 10:21
感觉问题不是lz描述的那么复杂
把D-cache关掉或在全局变量定义的地方加个volatile试一试
作者: bitliu1983    时间: 2009-12-10 19:44
mmu只是做虚拟地址和实际物理地址的映射问题,这个是由于编译,链接阶段的地址和运行地址不一致造成的。
不过我们想做的是在boot后,再干这个事情,或者说,之前是实地址,或是BAT映射,起来后我从新初始化mmu,然后改为页地址映射。
我们试验了另一个方案,采用redboot+启动linux方式。
boot和系统不编译到一个bin文件中。从boot起来后,再拷贝os的bin到TEXT_BASE的地方。这样两个bin文件就不存在地址共享和重定位问题了,不过这需要试试。

[ 本帖最后由 bitliu1983 于 2009-12-11 09:34 编辑 ]
作者: bitliu1983    时间: 2009-12-11 09:32
原帖由 readkernel 于 2009-12-8 10:21 发表
感觉问题不是lz描述的那么复杂
把D-cache关掉或在全局变量定义的地方加个volatile试一试



不行,D-cache和这个应该没关系,我们关掉了指令cache和数据cache。连TLB和BAT都清理了。
volatile是对外设访问时,加的一个不优化选项。和全局变量地址重映射还没关系。
作者: readkernel    时间: 2009-12-11 10:49
从flash引导,在ram重定位后,在访问全局变量之前,把ram的物理地址映射到虚拟地址0xfe000000,当然你的bin文件有多大就映射多少页,然后打开mmu。估计所谓的arm引导后flash和ram地址自动转换也是通过mmu转了一下,因为总线上的ram和flash接法已经决定了片选的物理地址

如果你嫌这样太麻烦,可以在引导代码里自己做自定义全局变量symbol重定位,但这样更麻烦

[ 本帖最后由 readkernel 于 2009-12-11 10:56 编辑 ]
作者: bitliu1983    时间: 2009-12-11 17:23
原帖由 readkernel 于 2009-12-11 10:49 发表
从flash引导,在ram重定位后,在访问全局变量之前,把ram的物理地址映射到虚拟地址0xfe000000,当然你的bin文件有多大就映射多少页,然后打开mmu。估计所谓的arm引导后flash和ram地址自动转换也是通过mmu转了一 ...



在ram重定位后,在访问全局变量之前,把ram的物理地址映射到虚拟地址0xfe000000?
这个方法估计工作量很大,还有一点,我们系统会做mmu,配置相应的读写访问属性和权限。
但是我们物理地址和实际地址是一一对应的。就是地址空间是划分好了的,哪里是栈,哪里是text段,哪里是data段。到后面的外设空间。
如果映射到0xfe000000,那么后续系统就很难做了,带来其它问题。
作者: bitliu1983    时间: 2009-12-11 17:25
对,还有一个问题,因为起来后,flash地址是0xfe000000,那flash地址起始也得从新映射到其它地址空间。
作者: readkernel    时间: 2009-12-13 21:44
-mrelocatable

* On ppc32 we compile with -mrelocatable, which means that references
* to extern and static variables get relocated automatically.
* On ppc64 we have to relocate the references explicitly with
* RELOC.  (Note that strings count as static variables.)

去看看arch\powerpc\kernel\prom_init.c
获许会对你的实现有帮助

[ 本帖最后由 readkernel 于 2009-12-13 21:49 编辑 ]
作者: xuhui250    时间: 2009-12-15 22:46
不好意思,这么才回来。

如果关键就是你这个A函数在哪里被执行的呢?而后C语言又是在那个地方执行呢?

从你描述来看,都应该是在RAM中运行了,这样的话最好的调试方法就是将两个函数中globala的地址打印处理,
这样好分析你访问的地址究竟是否是同一个。
作者: readkernel    时间: 2009-12-16 09:31
或者可以用一个更简单的方法

在.lds文件里把.data段的运行地址定义在ram的物理地址空间中,加载地址还是跟在.text后面

操作系统下普通的二进制文件在加载运行时,加载程序 会根据 链接定义 自动把.data段加载到它的运行地址上。

但你这段并不是由操作系统加载的,而是CPU上电启动引导的,所以.text段中的程序开头部分必须做.data段加载操作,把.data段copy到它的运行地址上,后面读写全局变量都是在ram中了。

google里搜 链接脚本文件定义

作者: rw99yy    时间: 2009-12-16 09:57
楼主可以将链接地址改成ram地址,relocate之前的代码应该用与地址无关的代码.
你现在的链接地址是多少那?

u-boot在relocate之前没有对全局基本没有对全局变量作修改,都是relocate后作的修改吧.

[ 本帖最后由 rw99yy 于 2009-12-16 10:17 编辑 ]
作者: bitliu1983    时间: 2010-01-19 14:06
ok,谢谢各位大大,前段时间没来得及上论坛。
已经解决了,把链接地址改为拷贝到ram的目的物理地址,我们通通改为0x0,使得代码段和数据段都从0x0开始,然后boot后把bin从flash拷贝到内存的0x0处,就不需要重定位了,内存地址在引导阶段和后面地址都是0x0起始。
作者: pppStar    时间: 2010-01-26 12:27
跟21楼说的很相似!
MARK




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2