接下来就以阅读ARM体系结构的启动文件为线索来修改我们的新平台。我们的做法是:逐段分析启动文件代码,采用“源码”字样指定是启动文件中的源代码,采用“说明”字样指定此处是我对源代码的理解和补充说明;在涉及到需要移植的代码的时候,我们马上将这部分代码展开细化,把具体的移植工作马上落实好.落实的方法:如果是简单的一段代码或注释搞定的,我们就原地了结。如果涉及的内容多,我们就用单独的章节来具体说明。考虑到自己是新手,所以我会尽量将一些对我来说是新知识的地方也附带提出来。
启动文件位于:hal\arm\arch\v3_0\src\vectors.S
//==========================================================================
【源码】
#include "arm.inc"
#ifdef __thumb__
// Switch to thumb mode
#define THUMB_MODE(_r_, _l_) \
ldr _r_,=_l_ ## f+1 ;\ //将后面标号_l_的地址加1赋给_r_
bx _r_ ;\ //跳转到_l_,以thumb模式开始运行
.pool ;\
.code 16 ;\
.thumb_func ;\
_l_:
// Call thumb function from ARM mode, return to ARM
// mode afterwards
#define THUMB_CALL(_r_, _l_, _f_) \
ldr _r_,=_f_+1 ;\ //将子函数_f_的地址加1赋给_r_
mov lr,pc ;\ //将指令“ldr _r_,=_l_ ## f “的地址赋给lr寄存器,在子函数中,会有一条指令将lr的值赋给PC实现函数返回。
bx _r_ ;\ //调用子函数_f_
.pool ;\
.code 16 ;\
.thumb_func ;\
ldr _r_,=_l_ ## f ;\ //返回到arm模式
bx _r_ ;\
.pool ;\
.code 32 ;\
_l_:
// Switch to ARM mode
#define ARM_MODE(_r_, _l_) \
ldr _r_,=_l_ ## f ;\ //将标号_l_的地址赋给_r_
bx _r_ ;\ //跳转到_l_,以arm模式继续运行
.pool ;\
.code 32 ;\
_l_:
// Function definition, start executing body in ARM mode
#define FUNC_START_ARM(_name_, _r_) \
.code 16 ;\
.thumb_func ;\
.globl _name_ ;\
.type _name_, function ;\
_name_: ;\
ldr _r_,=_name_ ## _ARM ;\
bx _r_ ;\
.code 32 ;\
_name_ ## _ARM:
#else
// Switch to thumb mode
#define THUMB_MODE(_r_, _l_)
// Call ARM function
#define THUMB_CALL(_r_, _l_, _f_) \
bl _f_
// Switch to ARM mode
#define ARM_MODE(_r_, _l_)
// Function definition, start executing body in ARM mode
#define FUNC_START_ARM(_name_, _r_) \
.globl _name_; \
.type _name_, function ;\
_name_:
#endif
【说明】
thumb和ARM模式的切换:采用bx指令,当跳转的目的地址的最低位为1时,切换到thumb模式,否则切换到arm模式
【源码】
#define PTR(name) \
.##name: .word name
// CYGHWR_HAL_ROM_VADDR is used when compiling for a different location
// from the base of ROM. hal_platform_setup.h might define it. For
// example, if flash is from 0x50000000 upwards (as on SA11x0), and we are
// to execute at 0x50040000, then we want the reset vector to point to
// 0x0004pqrs - the unmapped ROM address of the code - rather than
// 0x0000pqrs, which is the offset into our flash block.
//
// But usually it's not defined, so the behaviour is the obvious.
#ifndef UNMAPPED //如果没有定义UNMAPPED宏
#ifdef CYGHWR_HAL_ARM_HAS_MMU //如果有MMU,需要定义宏CYGHWR_HAL_ROM_VADDR
# ifndef CYGHWR_HAL_ROM_VADDR //如果没有定义宏CYGHWR_HAL_ROM_VADDR,则在下面定义它
# define CYGHWR_HAL_ROM_VADDR __exception_handlers //原来CYGHWR_HAL_ROM_VADDR等于__exception_handlers
# endif
# define UNMAPPED(x) ((x)-CYGHWR_HAL_ROM_VADDR) //等ARM有MMU时,UNMAPPED(x)得到x到__exception_handlers的偏移地址
#else
# define UNMAPPED(x) (x) //如果没有MMU,则UNMAPPED(x)得到的地址就是x
#endif
#endif
#define UNMAPPED_PTR(name) \
.##name: .word UNMAPPED(name)
// .file "vectors.S"
// CYGHWR_LED_MACRO can be defined in hal_platform_setup.h. It's free to
// use r0+r1. Argument is in "\x" - cannot use macro arguments since the
// macro may contain #-chars and use of arguments cause these to be
// interpreted as CPP stringify operators.
// See example in PID hal_platform_setup.h.
#ifndef CYGHWR_LED_MACRO
#define CYGHWR_LED_MACRO
#endif
.macro LED x
CYGHWR_LED_MACRO
.endm
【源码】
// Hardware exception vectors.
// This entire section will be copied to the vector table base (by default at
// location 0x0000) at startup time.
//
#ifndef CYGHWR_HAL_VECTOR_TABLE_BASE
# define CYGHWR_HAL_VECTOR_TABLE_BASE 0x0
#endif /* ifdef CYGHWR_HAL_VECTOR_TABLE_BASE */
.code 32
.section ".vectors","ax"
// This macro allows platforms to add their own code at the very start of
// the image. This may be required in some circumstances where eCos ROM
// based code does not run immediately upon reset and/or when some sort of
// special header is required at the start of the image.
#ifdef PLATFORM_PREAMBLE
PLATFORM_PREAMBLE
#endif
【说明】
1.CYGHWR_HAL_VECTOR_TABLE_BASE 说明硬件向量表的基址是可以指定的,默认值是0X00
2. .code伪操作用来用来选择ARM或者Thumb指令集,16指的是Thumb指令集,32是ARM指令集。
3. .section伪操作定义段,这里".vectors”是段名,后面"ax”是段权限标志:a 允许段w 可写段x 执行段
4.PLATFORM_PREAMBLE宏定义是为了满足特殊平台的特殊功能扩展而提出的。如果定义了这个宏,那么接下来的向量表就不是位于ROM的起始位置了。
【源码】
.global __exception_handlers
__exception_handlers:
#ifdef CYGSEM_HAL_ROM_RESET_USES_JUMP //如果程序代码的复位向量表已经位于硬件复位地址,则可以定义此宏
// Assumption: ROM code has these vectors at the hardware reset address.
// A simple jump removes any address-space dependencies [i.e. safer]
b reset_vector // 0x00
#else
ldr pc,.reset_vector // 0x00
#endif
ldr pc,.undefined_instruction // 0x04
ldr pc,.software_interrupt // 0x08 start && software int
ldr pc,.abort_prefetch // 0x0C
ldr pc,.abort_data // 0x10
#ifdef CYGNUM_HAL_ARM_VECTOR_0x14
.word CYGNUM_HAL_ARM_VECTOR_0x14
#else
.word 0 // unused
#endif
ldr pc,.IRQ // 0x18
ldr pc,.FIQ // 0x1C
【说明】
1. .global 定义一个全局的符号,类似C语言里的extern
2. 如果reset_vector的地址与__exception_handlers的地址偏移在正负32M之间,那么可以定义CYGSEM_HAL_ROM_RESET_USES_JUMP这个宏。
3. 我们知道ARM中断向量表里0x00000014是缺失的,所以在这里你可以通过定义CYGNUM_HAL_ARM_VECTOR_0x14 来用作其它用途。
4..word:用法1----分配4字节空间存储后面标识符的值; 用法2----如果后面接常数,则是分配4字节空间存储常数,上面属用法2。
5.ldr指令:注意伪指令和加载指令的区别:伪指令的形式:ldr rd ,=const/label,当const/label在指令范围之内是,汇编器直接产生一条MOV或MVN指令,当不在指令范围内,则汇编器将常量放入文字池,并产生一条相对偏移的指令:ldr rd,[PC,offset_to_litpool].这种用法中,编程者一定要确保在正负4K内有合适的文字池。加载指令的形式:ldr rd,label,此时label必须在当前指令的正负4K范围之内。上面程序中ldr是做加载指令使用,其实上面中断向量表也可以用伪指令实现,只是要考虑在指令范围内分配文字池。
【源码】
// The layout of these pointers should match the vector table above since
// they are copied in pairs.
.global vectors
vectors:
UNMAPPED_PTR(reset_vector) // 0x20
PTR(undefined_instruction) // 0x24
PTR(software_interrupt) // 0x28
PTR(abort_prefetch) // 0x2C
PTR(abort_data) // 0x30
.word 0 // 0x34
PTR(IRQ) // 0x38
PTR(FIQ) // 0x3c
#ifdef CYGSEM_HAL_ARM_PID_ANGEL_BOOT
PTR(start) // This is copied to 0x28 for bootup // 0x40
#endif
// location 0x40 is used for storing DRAM size if known
// for some platforms.
【说明】
1.这里的表格与上面的中断向量表是配置使用的,这里保存了中断处理程序的入口地址
2.这里用到前面定义的宏:#define PTR(name) \
.##name: .word name
宏定义里##的几种使用形式:第一种:字串##参数,表示当前参数与前面字串连接;第二种:参数##字串:表示当前参数与后面的字串连接;
第三种:字串1##参数##字串2:表示将当前参数嵌入到字串1和字串2的中间。
【源码】
// "Vectors" - fixed location data items
// This section contains any data which might be shared between
// an eCos application and any other environment, e.g. the debug
// ROM.
//
.section ".fixed_vectors"
// Interrupt/exception VSR pointers
.globl hal_vsr_table
hal_vsr_table:
.rept 8
.long 0
.endr
.globl hal_dram_size
hal_dram_size:
.long 0
// what, if anything, hal_dram_type means is up to the platform
.globl hal_dram_type
hal_dram_type:
.long 0
.balign 16
#ifdef CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT
// Vectors used to communicate between eCos and ROM environments
.globl hal_virtual_vector_table
hal_virtual_vector_table:
.rept CYGNUM_CALL_IF_TABLE_SIZE
.long 0
.endr
#endif
#ifdef CYGHWR_HAL_ARM_ICE_THREAD_SUPPORT
.balign 16 // Should be at 0x50
ice_thread_vector:
.long 0 // Must be 'MICE'
.long 0 // Pointer to thread support vector
.long 0 // eCos executing flag
.long 0 // Must be 'GDB '
#endif // CYGHWR_HAL_ARM_ICE_THREAD_SUPPORT
.balign 32
// Other vectors - this may include "fixed" locations
#ifdef PLATFORM_VECTORS
PLATFORM_VECTORS
#endif
【说明】
1.. Rept重复定义伪指令,是对后面的语句进行指定次数的操作,比如:
.rept 8
.long 0
.endr
是指重复定义8个4字节数据,初始化为0
2..long:定义4字节数据
3..balign 指定字节对齐方式
4.从上面的数据定义,我们就知道这是在内存中特定位置开辟一片固定的存储空间来保存一些变量。所以这个段在链接时肯定定位在RAM中。
【源码】
.text
// Startup code which will get the machine into supervisor mode
.global reset_vector
.type reset_vector,function
reset_vector:
PLATFORM_SETUP1 // Early stage platform initialization
// which can set DRAM size at 0x40
// see
【说明】
1..text:定义代码段
2..type 用来指定一个符号的类型是函数类型或者是对象类型
3.PLATFORM_SETUP1平台初始化宏定义,这是我们移植工作的重点之一,请参考《在imx27ads上移植ecos3.0的redboot(四)》
********************************************************************************************
《在imx27ads上移植ecos3.0的redboot(四)》整理中
********************************************************************************************