【一】Uboot-2017.11源码分析启动过程之汇编部分

来源:互联网 发布:你别无选择 知乎 编辑:程序博客网 时间:2024/05/29 02:11

1 设置中断向量表

CPU在上电后,首先从0x0000 0000地址开始执行程序,uboot编译后,在程序的起始地址处存放了中断向量表,该部分代码为汇编语言写的,代码存储于arch\arm\cpu\armv7目录下的start.S中,如下所示:

/*************************************************************************

 *

 * Startup Code (reset vector)

 *

 * Do important init only if we don't startfrom memory!

 * Setup memory and board specific bits priorto relocation.

 * Relocate armboot to ram. Setup stack.

 *

 *************************************************************************/

.globl reset

         .globl save_boot_params_ret

#ifdefCONFIG_ARMV7_LPAE

         .global        switch_to_hypervisor_ret

#endif

reset:

         /* Allow the board to save importantregisters */

         b       save_boot_params

save_boot_params_ret:

#ifdefCONFIG_ARMV7_LPAE

/*

 * check for Hypervisor support

 */

         mrc   p15,0, r0, c0, c1, 1                @ readID_PFR1

         and    r0,r0, #CPUID_ARM_VIRT_MASK    @ maskvirtualization bits

         cmp   r0,#(1 << CPUID_ARM_VIRT_SHIFT)

         beq    switch_to_hypervisor

switch_to_hypervisor_ret:

#endif

第32行,程序一开始声明了三个全局的三个标签reset,ave_boot_params_ret,switch_to_hypervisor_ret,接着开始执行reset标签处的代码,即b         save_boot_params,跳转至save_boot_params处,如下所示:

/*************************************************************************

 *

 * void save_boot_params(u32 r0, u32 r1, u32r2, u32 r3)

 *     __attribute__((weak));

 *

 * Stack pointer is not yet initialized at thismoment

 * Don't save anything to stack even ifcompiled with -O0

 *

 *************************************************************************/

ENTRY(save_boot_params)

         b       save_boot_params_ret           @ back to my caller

ENDPROC(save_boot_params)

         .weak         save_boot_params

#ifdefCONFIG_ARMV7_LPAE

ENTRY(switch_to_hypervisor)

         b       switch_to_hypervisor_ret

ENDPROC(switch_to_hypervisor)

         .weak         switch_to_hypervisor

#endif

第115行,在save_boot_params调用了save_boot_params_ret函数,该函数在此处声明为弱函数,当外部有同名函数时,则调用外部的同名函数。再接着判断是否支持Hypervisor功能,如果支持,则调用switch_to_hypervisor函数,同样该函数在此处声明为弱函数。

第56行,如下所示,关闭FIQ和IRQ中断,除非在HYP模式下,否则设置CPU为SVC32模式,

/*

 *disable interrupts (FIQ and IRQ), also set the cpu to SVC32 mode,

 * exceptif in HYP mode already

 */

mrs   r0,cpsr

and    r1,r0, #0x1f                 @ mask mode bits

teq     r1,#0x1a             @ test for HYP mode

bicne r0,r0, #0x1f                 @ clear all modebits

orrne r0,r0, #0x13                 @ set SVC mode

orr     r0,r0, #0xc0                 @ disable FIQand IRQ

msr   cpsr,r0

第69行,如下所示,设置中断向量表,如果定义了要编译SPL,则将中断向量表地址写入协处理器CP15寄存器中,

/*

 * Setup vector:

 * (OMAP4 spl TEXT_BASE is not 32 byte aligned.

 * Continue to use ROM code vector only inOMAP4 spl)

 */

#if!(defined(CONFIG_OMAP44XX) && defined(CONFIG_SPL_BUILD))

/* Set V=0 in CP15 SCTLR register - for VBAR topoint to vector */

mrc   p15,0, r0, c1, c0, 0       @ Read CP15 SCTLRRegister

bic     r0,#CR_V          @ V = 0

mcr   p15,0, r0, c1, c0, 0       @ Write CP15 SCTLRRegister

 

/* Set vector address in CP15 VBAR register */

ldr     r0,=_start

mcr   p15,0, r0, c12, c0, 0     @Set VBAR

#endif

第81行,如下所示,判断是否跳过LOWLEVEL_INIT的初始化和LOWLEVEL_INIT_ONLY,不跳过则分别调用cpu_init_cp15和cpu_init_crit,执行完成这两个函数后,则跳转至_main函数中。

/* the mask ROM code should have PLL and othersstable */

#ifndefCONFIG_SKIP_LOWLEVEL_INIT

bl      cpu_init_cp15

#ifndefCONFIG_SKIP_LOWLEVEL_INIT_ONLY

bl      cpu_init_crit

#endif

#endif

 

bl      _main

在cpu_init_cp15函数中,完成了关闭L1 I/D,MMU和caches,开启I-cache,除非定义了CONFIG_SYS_ICACHE_OFF则不开启。

在cpu_init_crit函数中,第317行,跳转至lowlevel_init函数,该函数定义于不同board的不同的初始化函数中。

#if!defined(CONFIG_SKIP_LOWLEVEL_INIT) && \

!defined(CONFIG_SKIP_LOWLEVEL_INIT_ONLY)

/*************************************************************************

 *

 * CPU_init_critical registers

 *

 * setup important registers

 * setup memory timing

 *

 *************************************************************************/

ENTRY(cpu_init_crit)

/*

 * Jumpto board specific initialization...

 * TheMask ROM will have already initialized

 * basicmemory. Go here to bump up clock rate and handle

 * wakeup conditions.

 */

b       lowlevel_init                 @ go setup pll,mux,memory

ENDPROC(cpu_init_crit)

#endif

lowlevel_init函数实现于board\samsung\smdkc100目录下的lowlevel.S中,第19行,这该函数中,主要实现了如下功能:

a、    关闭看门狗;

b、   设置SRAM;

c、    设置三组中断源;

d、   关闭所有中断;

e、    设置所有中断为IRQ;

f、    清除中断挂起位;

g、   调用uart_asm_init函数;

h、   调用tzpc_asm_init函数;

i、     初始化内核和总线的时钟。

第124行,在uart_asm_init函数中,初始化了UART的引脚;第136行,在tzpc_asm_init函数中,初始化了TZPC。

_main函数实现于arch\arm\lib目录下的crt0.S中,在第67行,指定了ENTRY(_main)入口函数名为,该函数主要实现了初始化C语言的运行环境以及调用board_init_f(0)函数。

接下来详细介绍下该函数的具体实现:

#ifdefined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)

   ldr     r0,=(CONFIG_SPL_STACK)

#else

   ldr     r0,=(CONFIG_SYS_INIT_SP_ADDR)

#endif

   bic     r0,r0, #7    /* 8-byte alignment for ABIcompliance */

   mov  sp,r0

   bl      board_init_f_alloc_reserve

   mov  sp,r0

   /* set up gd here, outside any C code */

   mov  r9,r0

   bl      board_init_f_init_reserve

 

   mov  r0,#0

   bl      board_init_f

首先判断是否定义了CONFIG_SPL_BUILD和CONFIG_SPL_STACK两个宏定义,如果有,则完成以下操作:

加载CONFIG_SPL_STACK宏的数据到r0寄存器,否则使用CONFIG_SYS_INIT_SP_ADDR这个宏定义,再通过mov sp, r0设置好堆栈,接着调用board_init_f_alloc_reserve函数,紧接着调用board_init_f_init_reserve函数,再接着r0寄存器赋值为0,并调用board_init_f函数,传入的参数为r0,即传入0作为参数。

如果没有定义CONFIG_SPL_BUILD,则完成如下操作:

#if !defined(CONFIG_SPL_BUILD)

 

/*

 * Set up intermediate environment (new sp andgd) and call

 * relocate_code(addr_moni). Trick here is thatwe'll return

 * 'here' but relocated.

 */

 

   ldr     r0,[r9, #GD_START_ADDR_SP] /* sp =gd->start_addr_sp */

   bic     r0,r0, #7    /* 8-byte alignment for ABIcompliance */

   mov  sp,r0

   ldr     r9,[r9, #GD_BD]                  /* r9 =gd->bd */

   sub    r9,r9, #GD_SIZE                  /* new GD isbelow bd */

 

   adr    lr,here

   ldr     r0,[r9, #GD_RELOC_OFF]          /* r0 =gd->reloc_off */

   add    lr,lr, r0

#ifdefined(CONFIG_CPU_V7M)

   orr     lr,#1                             /* Asrequired by Thumb-only */

#endif

   ldr     r0,[r9, #GD_RELOCADDR]                 /* r0= gd->relocaddr */

   b       relocate_code

here:

/*

 * now relocate vectors

 */

 

   bl      relocate_vectors

 

/* Set up final(full) environment */

 

   bl      c_runtime_cpu_setup    /* we still call old routine here */

#endif

加载GD_START_ADDR_SP宏定义的至作为堆栈地址,即sp =gd->start_addr_sp,此处会用到几个外部定义的宏GD_BD、GD_SIZE、GD_RELOC_OFF、GD_RELOCADDR,接着调用relocate_code函数,再紧接着调用了relocate_vectors重定向了中断向量表,最后调用了c_runtime_cpu_setup完成没有使用SPL情况下,C语言运行环境的搭建。

#if!defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_FRAMEWORK)

# ifdefCONFIG_SPL_BUILD

   /* Use a DRAM stack for the rest of SPL, ifrequested */

   bl      spl_relocate_stack_gd

   cmp   r0,#0

   movne        sp,r0

   movne        r9,r0

# endif

   ldr     r0,=__bss_start  /* this is auto-relocated!*/

 

#ifdefCONFIG_USE_ARCH_MEMSET

   ldr     r3,=__bss_end             /* this isauto-relocated! */

   mov  r1,#0x00000000          /* prepare zero toclear BSS */

 

   subs  r2,r3, r0              /* r2 = memset len */

   bl      memset

#else

   ldr     r1,=__bss_end             /* this isauto-relocated! */

   mov  r2,#0x00000000          /* prepare zero toclear BSS */

 

clbss_l:cmp   r0, r1                   /*while not at end of BSS */

#ifdefined(CONFIG_CPU_V7M)

   itt      lo

#endif

   strlo  r2,[r0]                 /* clear 32-bit BSSword */

   addlo r0,r0, #4             /* move to next */

   blo    clbss_l

#endif         

#if ! defined(CONFIG_SPL_BUILD)

                         blcoloured_LED_init

                         blred_led_on

#endif

第122行,如上所示,如果没有定义CONFIG_SPL_BUILD这个宏,或定义了CONFIG_SPL_FRAMEWORK,则完成以上操作,具体为如果定义了CONFIG_SPL_BUILD,则将调用spl_relocate_stack_gd函数,如果有需要的话,可以使用DRAM的栈。紧接着对bss段进行初始化为0。再接着判断如果没有定义CONFIG_SPL_BUILD这个宏,则调用coloured_LED_init和red_led_on两个函数。

第155行,如下所示,最后调用board_init_r这个函数,这个函数GD_RELOCADDR这个宏定义作为函数的第二个参数。

   /* call board_init_r(gd_t *id, ulongdest_addr) */

   mov    r0, r9                  /* gd_t */

   ldr     r1,[r9, #GD_RELOCADDR]        /* dest_addr */

   /* call board_init_r */

#ifCONFIG_IS_ENABLED(SYS_THUMB_BUILD)

   ldr     lr,=board_init_r  /* this is auto-relocated!*/

   bx     lr

#else

   ldr     pc,=board_init_r /* this is auto-relocated!*/

#endif

   /* we should not return here. */

#endif

 

ENDPROC(_main)

至此,uboot启动过程的汇编部分到此结束,下一步则分析C语言部分的代码。

 

原创粉丝点击