请问BOOTLOAD中怎么跳转到RAM中的MAIN函数中
网上看了些资料,基本上是说先拷贝代码到RAM,然后考RW、ZI什么的,最后跳转到RAM的MAIN函数中,有些不明白,烦请各位能提点一下:
我打算用ADS编译一个BOOTLOAD,程序放FLASH中,运行时在RAM中跑以便能修改FLASH中的内容。那我是不是需要按以下方法进行编写代码:
1.在ADS中填写的RO、RW、IMAGE ENTRY POINT好像都是指的是运行地址吧,那我需要正确填写程序运行时的地址
2.拷贝完成后怎么跳转到RAM中的MAIN函数?
用ldr pc, __main好像跳不过去,用BL __main好像会跳到FLASH的MAIN函数。
3.比如ADS设置的运行地址为0X81000000,这样编译好后我用H-FLASHER把他烧入FLASH中(FLASH上电后的地址是0X80000000),应该是这样
吧?
有些东西实在是不明白,恳请各位大侠能帮忙,谢谢!
你把FLASH里的东西都拷到RAM里,然后一个 BL main,就能跳到ram里的 main了 ,不会跳到flash里的 我试过的
BL是一个相对寻址,在使用BL之前你的PC要先跳到RAM里 例如你把代码(这些代码包括了BL main)都拷到 0xc0000000开始的地方,那么你需要 ldr pc,=0xc0000000 ,而因为在0xc0000000 后面也有个 BL main , 所以,PC执行到那里自动会BL到 RAM里面的 main ,而不会到flash里的main
不知道楼主明白了没?
呵呵,我就没想到要先把PC值跳到RAM中,呵呵,那我先期在ADS中设定运行地址(RO、RW的选项)RAM的地址,编译后再烧入FLASH应该可以吧?我试试先,谢谢了
那个ldr pc,=0xc0000000 然后再BL main应该是不对了吧?第一句就已经对PC赋值了,就马上跳到0XC0000000去了,BL MAIN这句更本就不会执行的吧。
我在ADS中设置运行地址为0X80000000,RW为0X81100000,(这样我就只对RO部分操作而不用对RW部分进行操作了)编译过后烧BIN文件于0X80000000的FLASH中,然后在FLASH中通过
ldr r0,=STARADDR;0X80000000代码起点
ldr r1,=RAMADDRS;0X81000000运行起点
ldr r2,=CODELEN;0X80010000代码结尾
copy_loop
ldmia r0!, {r3-r10}
stmia r1!, {r3-r10}
cmp r0, r2
ble copy_loop
简单拷贝到RAM,然后就跟着一句BL __main,在main中我有段程序想得到某个函数的位置
uint32 addrpc,tmp;
addrpc=(uint32)UART0_Init;
这个位置我用串口发到PC,观察到是0X800....,而不是0X81....,这样就判断出这个MAIN并不是在RAM中执行的。
请问sherlock_lai 你是怎么判断程序在RAM中执行而不是在FLASH中执行?
谢谢!
在boot的汇编部分最后,会先取得main函数相对系统复位入口的偏移地址量,对于大部分ARM体系CPU来说,复位入口是0x0,那么main的地址偏移量假设是0x3000(这只是个假设值,每个cpu,每个版本对应的boot都可能有差别,不过因为是取相对偏移,所以没关系)。
然后RAM有一个确定好的地址,如果是无MMU,那么直接操作RAM的物理地址,如果有MMU并且已启用,那么操作RAM的虚拟地址。
boot复制到RAM中也会有一个地址,以这个地址作为boot入口地址(相当于复位时的0x0),然后加上main的相对地址偏移量,就可以得到main在RAM中的地址,然后jump过去就行。
判断在RAM还是flash,直接看地址就行,不管是物理地址,还是虚拟地址,总归有空间大小规定的。
你用ADS的AXD RO先设在flash里,就直接可以单步看程序往哪跳了
至于这条指令
ldr pc,#0xc0000000 //我的0xc0000000 是RAM地址,
在这条指令之前,不是已经把代码都搬到 0xc0000000了吗?
那么PC执行 0xc0000000 就相当于执行你刚开始在flash里的代码了
如果是拷贝整个BOOT到RAM,再执行ldr pc,#0xc0000000 将再次进入复位中断处理而不是进入MAIN函数,这样再次进行拷贝再次跳转到RAM,将进入循环而到不了MAIN。
另找到MAIN函数的偏移地址再在RAM基址的基础上加上偏移量进行跳转可以到达MAIN函数,不过我汇编不是太好,请问以下是否可以?
LDR R1,=MAIN;获取MAIN的绝对地址
ADD R1,R1,#0X10000000;RAM和FLASH地址只差了0X10000000,所以把在FLASH中的MAIN地址加上0X10000000即可得到在RAM中的MAIN地址
BX R1;到底LDR PC,R1还是BX这条?
谢谢!
我也碰到过这个问题,虽然用的不是ARM Core,但是希望能对你有帮助。
我是先修改.lds文件,将所有程序的vma指向ram的地址,然后在boot程序一开始先初始化ram再将所有程序从flash搬移到ram中。因为在链接时已经将main的程序地址指向了ram中的vma所以直接main();就可以了。
很感谢大家的指点,经过几天的摸索,我探出了点眉目,各位看了有问题请指出来,如果正确那也对正遇上我这种问题的兄弟们一点帮助:以下都为LPC2200为基础,FLASH为BANK0(0x80000000),RAM为BANK1(0X81000000)
1.中断向量表
;中断向量表
Reset
LDR PC, ResetAddr
LDR PC, UndefinedAddr
LDR PC, SWI_Addr
LDR PC, PrefetchAddr
LDR PC, DataAbortAddr
DCD 0xb9205f80
LDR PC, IRQ_Addr
LDR PC, FIQ_Addr
ResetAddr DCD ResetInit
UndefinedAddr DCD 0x81000004
SWI_Addr DCD 0x81000008
PrefetchAddr DCD 0x8100000c
DataAbortAddr DCD 0x81000010
Nouse DCD 0
IRQ_Addr DCD 0x81000018
FIQ_Addr DCD 0x8100001c
2.BOOTLOAD的ADS中我为了怕整理RW麻烦就没用分散加载了,把RO写了0X80000000,RW写了0X81F00000,IIMAGE 入口地址0X80000000,第一步拷贝我只是做个试验,所以就拷贝固定大小的代码到RAM了
ldr r0,=STARADDR;0x80000000
ldr r1,=RAMADDRS;0x81000000
ldr r2,=CODELEN;0x80010000代码结尾地址
copy_loop
ldmia r0!, {r3-r10}
stmia r1!, {r3-r10}
cmp r0, r2
ble copy_loop
3然后跳转
ldr pc,=main+0x1000000
4.在应用程序中的中断,因为向量地址在0XFFFFF030,所以需要动一下
;中断向量表
Reset
LDR PC, ResetAddr
LDR PC, UndefinedAddr
LDR PC, SWI_Addr
LDR PC, PrefetchAddr
LDR PC, DataAbortAddr
DCD 0xb9205f80
LDR PC, IRQ_Addr
LDR PC, FIQ_Addr
ResetAddr DCD ResetInit
UndefinedAddr DCD Undefined
SWI_Addr DCD SoftwareInterrupt
PrefetchAddr DCD PrefetchAbort
DataAbortAddr DCD DataAbort
Nouse DCD 0
IRQ_Addr DCD IRQ_Handler
FIQ_Addr DCD FIQ_Handler
。。。。。。
;中断
IRQ_Handler
STMFD SP!, {R0-R3, LR}
mov r0,#0x020
ldr pc,[r0,#-0x0ff0]
LDMFD SP!, {R0-R3, LR}
SUBS PC, LR, #4
。。。。。。。
请各位大侠指点指点,有错可要一定指出哟,谢谢!
忘了说了,应用程序中ADS中应该RO设为0x81000000
原来用的是LPC22xx系列的,没有MMU,难怪是操作物理地址的。
3然后跳转
ldr pc,=main+0x1000000
是关键,只要这个地址不写错,就不会有问题。当然也得要求你的boot的main是正确的可执行才行。
直接发我写的汇编程序好了 可以用的
;copy code,data, clear zi
ldr r0,=beg
ldr r1,=0x0c008000
ldr r2,Topofrom
0
ldmia r0!,{r4-r7}
stmia r1!,{r4-r7}
cmp r0,r2
bcc %b0
ldr pc,=0x0c008000
beg
LDR r0, Topofrom ; Get pointer to ROM data
LDR r1, Baseofram ; and RAM copy
LDR r3, Baseofzi
0
CMP r1, r3 ; Copy init data
ldrcc r2, [r0], #4 ;--> LDRCC r2, [r0] + ADD r0, r0, #4
strcc r2, [r1], #4 ;--> STRCC r2, [r1] + ADD r1, r1, #4
BCC %B0
LDR r1, Topofzi ; Top of zero init segment
MOV r2, #0
2
CMP r3, r1 ; Zero init
STRCC r2, [r3], #4
BCC %B2
;--------enter main
BL Main
B .
LZ慢慢研究吧,这个是我用的程序
从beg开始的代码都copy到ram里,然后从 ram里的beg开始执行,beg后面的代码是对数据区的复制清零操作,之所以把这个也copy到ram里执行是因为这段操作可能需要一点时间(如果数据段很长的话),放到ram里执行会比较快
谢谢,这种拷贝部分代码也是种好方法,呵呵,我原也想用这种,但当时一门心思想着定位MAIN,没想过从MAIN前拷贝,呵呵,谢谢大家了。
sherlock_lai 的那段是自己写的吗?我似乎在2410的公版bootload中看到过