|
楼主 |
发表于 2009-2-16 08:59:18
|
显示全部楼层
>> trampoline.x和UDF的秘密协定
任意打开一个UDF的Example,我们都能在src文件夹下看到这样两个文件:
<font color=blue>trampoline.x和boot.x
trampoline.x
#include "conf_isp.h"
// 这个section必须被放置在0x80000000地址上
.section .reset, "ax", @progbits
//定义了一个类似void _trampoline(void)的全局函数。
.global _trampoline
.type _trampoline, @function
_trampoline:
// 跳转到 program start.代码段
rjmp program_start
//这句话意思是说接下来的代码program_start:将放置在宏PROGRAM_START_OFFSET所在的地址偏移上,
//而这一偏移是相对整个.section的
.org PROGRAM_START_OFFSET
program_start:
// 跳转到用户应用程序(Startup代码段所在的内容)
lda.w pc, _stext
trampoline.x等效结构图
AVR UC3 Address Space -
\
\___ | . . . . . . . |
| |
|--.reset-----------------| 0x8000,0000 Internal Flash
-------| "rjmp program_start"| 内部FLASH起始地址
| | Maybe Nothings here |
|
| . . . . . . .
|
| | |
------>|-- program_start---------|0x8000,0200 trampoline.x在用户程序入口做了一个劫持,
-------| "lda.w pc, _stext" | 这样用户的_stext就可以存在于FLASH的任意
| | . . . . . . . | 地址,而不用人为的定位了。
|
|
| | |
------>|-- _stext----------------|Any address in User Application Area
boot.x
#include <avr32/io.h>
#include "conf_isp.h"
……
//定义了一个.reset段
.section .reset, "ax", @progbits
.balign 2
// Reset vector: This must be linked @ 0x80000000.
//定义了一个类似void _start(void)的全局函数。这个函数将被放置在0x8000000000上。
.global _start
.type _start, @function
_start:
mov.w r8, ISP_KEY_ADDRESS
mov.w r9, AVR32_WDT_ADDRESS
mov.w r10, AVR32_FLASHC_ADDRESS
mov.w r11, AVR32_PM_ADDRESS
……
//相对_start开始的一个子函数,用于跳转到虚拟入口地址,也就是用户应用程序区域去执行
start_program_no_isp_key:
……
lddpc pc, program_start_address
//这是一个UDF放置在用户应用程序区的代码片断,其功能是截获复位异常,并将PC指针重新指向
//_start,也就是0x80000000所在的位置执行。这也可以解释为什么重新恢复了UDF的芯片不用操作
//专门的按键时序就可以进入IAP模式——PC机立即认出一个设备。因为刚恢复了UDF的芯片,其用
//户代码区放置的就是下面的代码,这个代码又把程序goto回了UDF的入口处,就好比形成了一个
//大循环。一旦真正的用户程序覆盖了这一部分,循环就被破坏了。
program_start_address:
.word PROGRAM_START_ADDRESS
.section .evba, "ax", @progbits
.balign 2
//定义系统事件 _evba段,详细解释参照论坛的相关专题
// Start of exception vector table: Unrecoverable exception.
.global _evba
.type _evba, @function
_evba:
//将_start的地址送入r8寄存器,也就是将立即数0x80000000送入寄存器r8
lda.w r8, _start
//将对SR寄存器的设置内容送入寄存器R9,也就是将
//AVR32_SR_GM_MASK | AVR32_SR_EM_MASK | (AVR32_SR_M_SUP << AVR32_SR_M_OFFSET)指定的
//立即数送入寄存器r9
mov.w r9, AVR32_SR_GM_MASK | AVR32_SR_EM_MASK | (AVR32_SR_M_SUP << AVR32_SR_M_OFFSET)
//设置sp指针,使其指向堆栈段_estack - 6 * 4的位置
mov sp, _estack - 6 * 4
//将r8~r9的内容压入堆栈
pushm r8-r9
//伪造一个从异常处理程序中返回的操作,rete会自动从堆栈中pop出两个32位数字分别送入pc和sr寄存器
//实际上就完成了让程序返回_start的功能
rete
boot.x等效结构图
AVR UC3 Address Space -
\
\___ | . . . . . . . |
| |
----------------->|--.reset(_start)---------------------| 0x8000,0000 Internal Flash
| | "mov.w r8, ISP_KEY_ADDRESS" | 内部FLASH起始地址
| | "mov.w r9, AVR32_WDT_ADDRESS" |
| | . . . . . . . |
| |-- start_program_no_isp_key----------| start_program_no_isp_key 子程序
| | . . . . . . . |
| |-------| "lddpc pc, program_start_address"|
| |
| | . . . . . . .
| |
| | | |
| |------>|-- _evba-----------------------------|0x8000,0200 User Application Start Address
| | . . . . . . . | 用户应用程序起始地址
------------------| "rete" |
Boot.x约定了UDF的程序流程:从0x80000000进入,假设不满足ISP条件,则通过一个
公共子程序start_program_no_isp_key跳转到0x80000200地址,也就是用户应用程序的实际
入口。同时UDF在用户应用程序做了一个劫持——如果没有任何用户应用程序,则重新进入
UDF状态,也就是形成了一个超级循环。
trampoline.x约定了用户应用程序的结构:程序从0x80000000开始执行,用户应用程序
必须从_stext作为起始入口地址,其位置任意。而trampoline.x自动在虚拟入口0x80000200
处加入了一个跳转语句,将系统控制权交给_stext的代码。实际上trampoline.x不是一个
简单的代码定位汇编函数,而是一个一石二鸟的补丁程序:
如果芯片中有UDF,因为trampoline.x编译生成的代码正好与UDF的代码重合,因此不会
被实际写入到芯片中,因而,系统地引导实际是由UDF完成的:UDF把控制权交给0x80000200
处的trampoline.x子程序program start,而trampoline.x的program start则通过相对跳转
语句将控制权转交给了用户应用程序的_stext。
如果芯片中没有UDF,因为trampoline.x在0x80000000处放置了有效的代码,将系统控制
权直接交给program start,因而加入了trampoline.x的用户应用程序可以同时兼容使用UDF
或者不使用UDF的情况。
这种接力棒式的传递,就是boot.x和trampoline.x的秘密契约。 |
|