【一】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语言部分的代码。
- 【一】Uboot-2017.11源码分析启动过程之汇编部分
- UBOOT源码分析1-汇编部分
- uboot分析之uboot启动过程分析
- uboot一之启动过程
- uboot 的启动过程及工作原理 汇编部分
- uboot内核启动过程源码分析
- uboot源码及启动过程分析
- uboot源码分析-第一阶段(汇编部分)
- uboot源码分析-第一阶段(汇编部分)
- uboot移植之启动过程--汇编过程start.s
- uboot学习笔记(三)启动源码分析之第二阶段(c语言部分)
- linux源码分析--内核启动之(2)Image内核启动(汇编部分)
- BF533之UBOOT启动过程分析
- skyeye之uboot启动过程分析
- 4412uboot启动过程分析之二
- UBOOT启动过程分析
- Uboot启动分析之stage1-Nand-Flash启动部分详解
- uboot 源码分析一
- 利用itex操作从数据库导出大量数据-功能汇总(一)
- HTML中(块级元素和非块级元素的区别)
- python基础-ElementTree、minidom解析xml
- ccf201612-2
- 重新认识HashMap
- 【一】Uboot-2017.11源码分析启动过程之汇编部分
- Android多渠道SDK开发心得
- ubuntu使用vim编辑器异常
- 设计模式—依赖倒转原则
- ubuntu 16.04 LTS
- windows卸载系统补丁
- Android 适配器 adapter 初探
- 2014-04-03-editplus,快速编译运行,注册激活
- 单链表,双链表,循环链表的区别