u-boot-2014.10移植第7天----深入分析代码(二)

时间:2022-05-25 17:16:55

硬件平台:tq2440

开发环境:Ubuntu-3.11

u-boot版本:2014.10

本文允许转载,请注明出处:http://blog.csdn.net/fulinus


现在从代码的角度来分析启动的流程:

从u-boot.lds文件知:

ENTRY(_start)SECTIONS
{
. = 0x00000000;

. = ALIGN(4);
.text :
{
*(.__image_copy_start)
*(.vectors)
CPUDIR/start.o (.text*)
*(.text*)
}
文件中__image_copy_start位映像文件复制起始地址,它在文件arch/arm/lib/sections.c中如下定义:

char __image_copy_start[0] __attribute__((section(".__image_copy_start")));char __image_copy_end[0] __attribute__((section(".__image_copy_end")));
这个__image_copy_start在文件common/board_r.c中被调用,

static int initr_reloc_global_data(void){#ifdef __ARM__    monitor_flash_len = _end - __image_copy_start;

文件中.vectors(英文矢量)在arch/arm/lib/vectors.S的文件中定义:

.section ".vectors", "x"

.section伪操作
用户可以通过.section伪操作来自定义一个段,格式如下:
  .section section_name [, "flags"[, %type[,flag_specific_arguments]]]
每一个段以段名为开始, 以下一个段名或者文件结尾为结束。这些段都有缺省的标志(flags),连接器可以识别这些标志。(与armasm中的AREA相同)。

下面是ELF格式允许的段标志
<标志> 含义
a 允许段
w 可写段
x 执行段

参考:http://blog.sina.com.cn/s/blog_59b189220100au1k.html

所以x表示可执行段

该段下面就是可执行代码的起始位置:

_start:

通过下面的语句跳转到reset的入口:

b   reset
b汇编指令见:http://blog.chinaunix.net/uid-20799298-id-99633.html

先不跳入reset代码段返回,就会进入:

    ldr pc, _undefined_instruction    ldr pc, _software_interrupt    ldr pc, _prefetch_abort    ldr pc, _data_abort    ldr pc, _not_used    ldr pc, _irq    ldr pc, _fiq

ldr汇编指令见:http://blog.chinaunix.net/uid-28458801-id-4084264.html

举其中一个存储器地址“_undefined_instruction”为例,它定义如下:

    .globl  _undefined_instruction    .globl  _software_interrupt    .globl  _prefetch_abort    .globl  _data_abort    .globl  _not_used    .globl  _irq    .globl  _fiq_undefined_instruction: .word undefined_instruction
undefined_instruction定义如下:

undefined_instruction:    get_bad_stack    bad_save_user_regs    bl  do_undefined_instruction

获取坏掉的栈,保存用户寄存器,有打印信息供开发人员调试,最后就是在死循环了。

下面我们再来看看reset代码段,reset定义在:arch/arm/cpu/arm920t/start.S文件中,reset(英文复位),系统复位时也会从这里开始,处理硬件上的复位,软件复位命令时通过看门狗操作实现。reset开始的代码段实现切换到超级用户模式(SVC 模式),接着是异常重定位异常表:

#if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK)    /*     * relocate exception table     */    ldr r0, =_start    ldr r1, =0x0    mov r2, #16copyex:    subs    r2, r2, #1    ldr r3, [r0], #4    str r3, [r1], #4    bne copyex#endif

CONFIG_AT91RM9200EK宏有定义,

LDR   r0,=label  
如果label是立即数,就把数值赋给r0, 如果lable是标识符,就把label地址的值赋给r0

r0保存了_start表示的地址,r1保存0,r2保存16,r2 = r2-1, subs中的s可以影响CPSR中的条件标志位,将r0地址处的内容读到r3中,再r0 = r0+4,str这条指令将R3中的字数据写入以R1为地址的存储器中,并将新地址R1+4写入R1,bne指令根据CPSR中的条件标志位判断是否跳转,如果subs指令中r2初值为16减为0时即影响了条件标志位,没有影响就跳转到copyex。所以异常重定位就是将__start开始的16个字拷贝到0地址开始的位置中去。

异常重定位结束后就是我们常说的关看门狗、屏蔽中断、设置系统时钟,

# if defined(CONFIG_S3C2400)#  define pWTCON    0x15300000#  define INTMSK    0x14400008  /* Interrupt-Controller base addresses */#  define CLKDIVN   0x14800014  /* clock divisor register */#else#  define pWTCON    0x53000000#  define INTMSK    0x4A000008  /* Interrupt-Controller base addresses */#  define INTSUBMSK 0x4A00001C#  define CLKDIVN   0x4C000014  /* clock divisor register */# endif    ldr r0, =pWTCON    mov r1, #0x0    str r1, [r0]    /*     * mask all IRQs by setting all bits in the INTMR - default     */    mov r1, #0xffffffff    ldr r0, =INTMSK    str r1, [r0]# if defined(CONFIG_S3C2410)    ldr r1, =0x3ff    ldr r0, =INTSUBMSK    str r1, [r0]# endif    /* FCLK:HCLK:PCLK = 1:2:4 */    /* default FCLK is 120 MHz ! */    ldr r0, =CLKDIVN    mov r1, #3    str r1, [r0]#endif  /* CONFIG_S3C24X0 */

下面是:

    /*     * we do sys-critical inits only at reboot,     * not when booting from ram!     */#ifndef CONFIG_SKIP_LOWLEVEL_INIT    bl  cpu_init_crit#endif
从它的注释我们看到只在重启就进行系统临界初始化,我们计入cpu_init_curit查看。

明天再看。