概述
从《链接文件u-boot.lds分析》中我们看到链接脚本的代码段链接的第一个文件是arch/arm/cpu/hi3521a/start.o,也就是说程序运行最开始是从start.S文件开始执行的。
start.S在这里完成uboot的第一阶段的启动,它的内容包括:
- 设置CPU SVC模式
- 关闭mmu和缓存
- 启动流程判断
- 关闭地址重映射
- 使能指令缓存
- 重定向异常向量表到内部RAM
- 重定向uboot到外部DDR
- 设置栈空间
- 清除bss段
- 跳转到C程序入口
1.设置CPU SVC模式
1.1头文件包含
#include <config.h>
#include <version.h>
- 头文件包含,这里的config.h 是/include/config.h
- 这个文件不是原来就有的,是uboot配置的的时候生成的
- 它的内容是:
- #include <config_defaults.h>
- #include <configs/hi3521a.h>
- #include <asm/config.h>
- 这里面都是一些条件编译的宏,根据不同的设备配置不同而不同
- <version.h>。include/version.h中包含了include/version_autogenerated.h,
- 这个头文件就是配置过程中自动生成的。版本号信息来自于Makefile中的配置值
- 在uboot启动过程中会串口打印出uboot的版本号,那个版本号信息就是从这来的。
1.2程序入口
.globl _start
_start: b reset
- 由uboot.lds链接脚本,我们知道整个程序的入口取决于中ENTRY声明的地方。
- 在uboot.lds中有ENTRY(_start),因此_start符号所在的文件就是整个程序的起始文件,_start所在的代码就是整个程序的起始代码。
- .globl XX 语法:给XX外部连接的属性,一般为了在别的文件中引用这个符号
- _start后面加上一个冒号' :',表示_start是一个标号
- _start: b reset 程序开始,跳到reset标号去执行,执行完后不返回
1.3异常向量表的构建
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指令用于从存储器中将一个32位的字数据传送到目的寄存器中。该指令通常用于从存储器中读取32位的字数据到通用寄存器,然后对数据进行处理。当程序计数器PC作为目的寄存器时,指令从存储器中读取的字数据被当作目的地址,从而可以实现程序流程的跳转。
- 以第一个_undefined_instruction为例,就是将地址为_undefined_instruction中的一个word的值,赋值给pc
_undefined_instruction: .word undefined_instruction
_software_interrupt: .word software_interrupt
_prefetch_abort: .word prefetch_abort
_data_abort: .word data_abort
_not_used: .word not_used
_irq: .word irq
_fiq: .word fiq
- 以_undefined_instruction为例,就是,此处分配了一个word=32bit=4字节的地址空间,里面存放的值是undefined_instruction。
- 在后面的代码,我们可以看到,undefined_instruction也是一个标号,即一个地址值,对应着就是在发生“未定义指令”的时候,系统所要去执行的代码。
- 这里定义的中断分别是:
- 未定义指令异常,0x04
- 软中断异常,0x08
- 内存操作异常,0x0c
- 数据异常,0x10
- 未适用,0x14
- 慢速中断异常,0x18
- 快速中断异常,0x1c,
1.4设置标号地址
_pad: .word 0x12345678 /* now 16*4=64 */
- _pad是一个标号,没有看到有地方使用它
__blank_zone_start:
.fill 1024*4,1,0
__blank_zone_end:
- 反复拷贝1个字节的0,拷贝1024*4次,也就是填充4KB的0数据
- 通过反汇编我们知道__blank_zone_start的值为0x80800040,__blank_zone_end的值为0x80801040,可以知道它的范围刚好是0x1000=4096=4KB
.globl _blank_zone_start
_blank_zone_start:
.word __blank_zone_start
.globl _blank_zone_end
_blank_zone_end:
.word __blank_zone_end
- 设置外部引用标号:_blank_zone_start,_blank_zone_end,这样他们就可以在其它汇编和C语言中被调用
.balignl 16,0xdeadbeef
- 设置16字节对齐,如果没有16字节对齐,则使用0xdeadbeef中的数值来填充。这个数值没有什么特别的意义,只是对应英文单词deadbeef(坏牛肉)
_TEXT_BASE:
.word TEXT_BASE
.globl _armboot_start
_armboot_start:
.word _start
- TEXT_BASE就是Makefile配置阶段写入的TEXT_BASE值
- TEXT_BASE = 0x80800000 在/board/hi3521a/config.mk中定义
- 这个是指明链接地址的值,也就是程序应该开始运行的地址,在uboot重定位的时候会使用到。经过链接脚本链接过后_armboot_start的地址与_start的地址都等于0x80800000
/*
* These are defined in the board-specific linker script.
*/
.globl _bss_start
_bss_start:
.word __bss_start
.globl _bss_end
_bss_end:
.word _end
- 这里将bss段的开始地址和结束地址设置一个外部标号,bss段的开始位置和结束位置在这里是不确定的,通过u-boot.lds可知,bss的位置与前面的代码段和数据段的长度有关
- 通过反汇编,我们查看到_bss_start=0x8084abc4,_bss_end=0x8089f700
#ifdef CONFIG_USE_IRQ
/* IRQ stack memory (calculated at run-time) */
.globl IRQ_STACK_START
IRQ_STACK_START:
.word 0x0badc0de
/* IRQ stack memory (calculated at run-time) */
.globl FIQ_STACK_START
FIQ_STACK_START:
.word 0x0badc0de
#endif
- CONFIG_USE_IRQ 在海思设备上并没有使用中断
- 所以上面这段代码无效
_clr_remap_fmc_entry:
.word FMC_TEXT_ADRS + do_clr_remap - TEXT_BASE
- FMC 是flash memory controller
- FMC_TEXT_ADRS=FMC_MEM_BASE=0x14000000
- TEXT_BASE = 0x80800000 在/board/hi3521a/config.mk中定义
- 芯片手册上描述:
- SFC NAND/NOR MEMORY起始地址为0x14000000,大小为16MB
- DDR 存储地址空间起始地址为:0x8000_0000,大小为2GB
- 通过反汇编我们查看到
- do_clr_remap=0x8080113c
- _clr_remap_fmc_entry=0x1400113c
- 这里是指向了SFC NAND/NOR MEMORY地址空间
1.5.设置cpu SVC模式
/*
* the actual reset code
*/
reset:
/*
* set the cpu to SVC32 mode
*/
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd3
msr cpsr,r0
- 将程序状态寄存器(cpsr)的值存到寄存器r0
- 将r0寄存器的低五位清零
- 将r0与0xd3或之后赋值给r0
- 将寄存器r0里的值赋值程序状态寄存器(cpsr)
- 上面的这四句命令是将CPU设置为禁止FIQ IRQ,ARM状态,SVC模式
2.关闭mmu和缓存
/*
* Invalidate L1 I/D
*/
mov r0, #0 @ set up for MCR
mcr p15, 0, r0, c8, c7, 0 @ invalidate TLBs
mcr p15, 0, r0, c7, c5, 0 @ invalidate icache
- 关闭一级缓存的指令和数据缓存功能
/*
* disable MMU stuff and caches
*/
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x00002000 @ clear bits 13 (--V-)
bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM)
orr r0, r0, #0x00000002 @ set bit 1 (--A-) Align
orr r0, r0, #0x00000800 @ set bit 11 (Z---) BTB
mcr p15, 0, r0, c1, c0, 0
- 关闭MMU功能
3.启动流程判断
3.1正常模式流程
/*
* read system register REG_SC_GEN2
* check if ziju flag
*/
ldr r0, =SYS_CTRL_REG_BASE
ldr r1, [r0, #REG_SC_GEN2]
ldr r2, =0x7a696a75 /* magic for "ziju" */
cmp r1, r2
bne normal_start_flow
- 将SYS_CTRL_REG_BASE这个宏表示的值赋值给r0寄存器
- 将r0寄存器的值加上REG_SC_GEN2宏地址上的值赋值给r1寄存器
- 将0x7a696a75 赋值给r2
- 将r1与r2寄存器中的值做对比
- 如果不相等 执行函数normal_start_flow,执行完之后再返回这里
- 如果相等,继续往下执行,将sp寄存器的值赋值给r1寄存器
- 将r1寄存器的值存到r0+REG_SC_GEN2值表示的地址中去
- 这里SYS_CTRL_REG_BASE=0x12050000,REG_SC_GEN2=0x0140,这个寄存器的功能海思的官方手册上并没有给出说明,所以这里不好猜测它主要是做什么的,但是基本上重启都是会进入normal_start_flow模式的。
3.2ziju模式流程
mov r1, sp /* save sp */
str r1, [r0, #REG_SC_GEN2] /* clear ziju flag */
/* init PLL/DDRC/pin mux/... */
ldr r0, _blank_zone_start
ldr r1, _TEXT_BASE
sub r0, r0, r1
ldr r1, =RAM_START_ADRS
add r0, r0, r1
mov r1, #0x0 /* flags: 0->normal 1->pm */
bl init_registers /* init PLL/DDRC/... */
/* after ziju, we need ddr traning */
#ifdef CONFIG_DDR_TRAINING_V2
ldr sp, =STACK_TRAINING
ldr r0, =REG_BASE_SCTL
bl start_ddr_training /* DDR training */
#endif
ldr r0, =SYS_CTRL_REG_BASE
ldr r1, [r0, #REG_SC_GEN2]
mov sp, r1 /* restore sp */
ldr r1, [r0, #REG_SC_GEN3]
mov pc, r1 /* return to bootrom */
nop
nop
nop
nop
nop
nop
nop
nop
b . /* bug here */
- 海思在u-boot-2010.06archarmincludeasmarch-hi3521aplatform.h中有定义:
- #define REG_SC_GEN0 0x0138
- #define REG_SC_GEN1 0x013c
- #define REG_SC_GEN2 0x0140
- #define REG_SC_GEN3 0x0144
- #define REG_SC_GEN4 0x0148
- 但是海思的用户手册上并没有给出这几个寄存器的描述,因此从代码上并不能知道面的自举操作实现了些什么功能。
- 从代码上来猜测,RAM_START_ADRS是内部SRAM的开始地址,__blank_zone_start的大小是4K,在hi3520dv400上这个值是5k。
- 综上猜测,这里的ziju模式应该是使用HiBurn进行uboot升级的时候,先将4K或是5k的uboot代码下载到内部SRAM,然后再通过下载的前面一点点uboot代码,初始化ddr,初始化DDR之后,再将所有的uboot程序下载到ddr中,从ddr中使用命令进行uboot烧入flash的操作。
通过这里也可以分析出两个问题:
- 使用hiburn升级uboot的时候,如果只升级了4~5k程序(通过进度判断)就提示失败,那有可能是ddr初始化失败了。
- 所升级的uboot程序对DDR的操作有问题,导致DDR不能正常被初始化。
3.3.正常启动
normal_start_flow:
@if running not boot from spi/nand/ddr ram,
@we skipping boot_type checking.
mov r0, pc, lsr#24
cmp r0, #0x0
bne do_clr_remap
- 将PC寄存器的值逻辑右移24位,然后再赋值给r0寄存器
- 将r0寄存器的值与0做对比
- 如果r0寄存器的值不等于零,则执行do_clr_remap函数,执行完后不返回。
- 海思hi3521a的uboot有三种种启动方式:
- spi nor/nand flash
- 内部RAM
- 外部DDR启动
- PC指针地址逻辑右移24位等于0,也就是只有PC指针的地址小于或等于0x8FFFFF时才成立,这种情况应该只有在内部RAM中运行才会出现。
- 正常启动的时候,海思hi3521a芯片这里的PC指针是指向spi flash的地址空间范围0x1400_0000-0x1400_FFFF。
3.4检查启动类型
check_boot_type:
ldr r0, =SYS_CTRL_REG_BASE
ldr r0, [r0, #REG_SYSSTAT]
mov r6, r0, lsr#4
and r6, #0x1
cmp r6, #0 @ [4] = 0 FMC /* spi nor | spi nand */
ldreq pc, _clr_remap_fmc_entry
@otherwise, [31]=1 means boot from bootrom, err
beq bug
- 通过SYSSTAT寄存器的bootrom_sel控制启动类型。
- 如果是spi nor或是spi nand 启动,程序会进入到这里执行,如果是bootrom启动则不会。
- 正常这里应该是不会进来执行的。
4.关闭地址重映射
do_clr_remap:
/* do clear remap */
ldr r4, =SYS_CTRL_REG_BASE
ldr r0, [r4, #REG_SC_CTRL]
@Set clear remap bit.
orr r0, #(1<<8)
str r0, [r4, #REG_SC_CTRL]
- 将SYS_CTRL_REG_BASE内存地址的值赋值给r4寄存器
- 将r4加REG_SC_CTRL表示的地址的值赋值给r0寄存器
- 将(1<<8)赋值给与r0或之后赋值给r0寄存器
- 将r0寄存器的值存到r4加REG_SC_CTRL的地址表示的地址中
- SYS_CTRL_REG_BASE=0x12050000;REG_SC_CTRL=0 表示hi3521a中的SC_CTRL系统控制寄存器,该寄存器的第8位为地址重映射清除选择位(remapclear):
- 0:保持 Remap 状态。
- 1:清除 Remap。
- 地址重映射时: 0x00000000地址指向启动地址空间。
- 地址重映射撤销后:0x00000000地址空间指向片内 RAM
- 上面的代码是清除重映射。
/*
* Set ACTLR.SMP to 1
* This is a bug on Cortex-A7 MPCORE. see buglist of Cortex-A7
* The D-caches are disabled when ACTLR.SMP is set to 0 regardless of
* the value of the cache enable bit. so we must set SMP bit of ACTLR
* register before enable D-cache
*/
mrc p15, 0, r0, c1, c0, 1
orr r0, #(1 << 6)
mcr p15, 0, r0, c1, c0, 1
- 修复一个Cortex-A7的BUG,具体内容不用管它
5.使能指令缓存
@enable I-Cache now
mrc p15, 0, r0, c1, c0, 0
orr r0, r0, #0x00001000 /* set bit 12 (I) I-Cache */
mcr p15, 0, r0, c1, c0, 0
isb
- 使能指令缓存
@Check wether I'm running in dynamic mem bank
mov r0, pc, lsr#28
cmp r0, #8
bleq relocate
- 将PC寄存器的值逻辑右移28位后赋值给r0寄存器
- 将pc寄存器的值与8相比较
- 如果PC寄存器的值与8相等,调到relocate执行,执行结束后返回到这里
- 这里是判断是否是在DDR中运行,因为DDR的地址空间是0x8000_0000到0xFFFF_FFFF的范围,uboot的运行地址一定在0x8000_0000~0x8FFF_FFFF,所以逻辑右移28位之后就一定是等于8
- 在这里如果是正常启动,PC值是在0x14000000开始的16M地址空间
- 最后的那个跳转函数不会执行。
6.重定向异常向量表到内部RAM
ldr r0, _blank_zone_start
ldr r1, _TEXT_BASE
sub r0, r0, r1
adrl r1, _start
add r0, r0, r1
mov r1, #0 /* flags: 0->normal 1->pm */
bl init_registers
- 将_blank_zone_start地址的值读入到r0寄存器
- 将_TEXT_BASE地址的值读入到r1寄存器
- 将r1-r0的值存入r0
- 将_start地址的值读入到r1
- 将r1+r0的值存入r0
- 将0赋值给r1
- 跳转到init_registers去执行,执行完返回
- _blank_zone_start和_TEXT_BASE用的是远连接,正常启动时:
- blank_zone_start=0x80800040_TEXT_BASE=0x80800000
- _start使用的是中长度寻址,实际正常启动时_start的地址范围在0x1400_0000之后的16M之内
- 这一段的作用是:如果不是从内存启动,那么需要为uboot重定向到DDR做准备。
- 假如是flash正常启动,在执行上面代码之后,r0寄存器中的地址是指向flash中异常中断结束的地址,r1寄存器的值为0,
- init_registers标号是在lowlevel_init.S文件中定义的,是一些比较底层的初始化,官方没有给出说明,看不懂 -_- 略过~
#ifdef CONFIG_DDR_TRAINING_V2
ldr sp, =STACK_TRAINING
ldr r0, =REG_BASE_SCTL
bl start_ddr_training /* DDR training */
#endif
- CONFIG_DDR_TRAINING_V2=1 该功能有使能
- STACK_TRAINING=0x04014000 数据手册查不到
- REG_BASE_SCTL=0x12050000 系统控制寄存器
- start_ddr_training 是一个C语言函数,定义在lowlevel_init_v300.c
- DDR training:DR布线,完全按等长约束就没有ddr training的说法。当布线去掉等长约束或放宽约束条件,就要做ddr training,以保证时序的完整性,使信号的建立&保持时间窗口一致。ddr training是调整Addr/Cmd信号对CLK,DQ信号对DQS的延时。由于没做等长约束,信号有长,有短,就会导致信号有快,慢之差(信号在1000mil走线耗时约160~180ps,相对FR-4的板材),ddr training就是找到一套参数,使信号的建立与保持时间充足。并保存且写到配置中。
6.1重定向异常向量表
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate:
@copy arm exception table in 0 address
adrl r0, _start
mov r1, #0
mov r2, #0x100 /* copy arm Exception table to 0 addr */
add r2, r0, r2
- 将_start的地址值赋值给r0寄存器
- 将r1寄存器的值设置为0
- 将r2寄存器的值设置为0x100
- 将r2寄存器的值加r0寄存器的值赋值给r2
- 注意:
- 这里的_start,在正常启动的时候,_start的地址是0x1400_0000,是flash的地址空间,r1是0地址,在地址重映射时,地址指向启动空间,地址重映射撤销后:此地址
- 空间指向片内 RAM。前面我们取消了地址映射,这里应该是指向片内RAM
copy_exception_table:
ldmia r0!, {r3 - r10}
stmia r1!, {r3 - r10}
cmp r0, r2
ble copy_exception_table
- 从R0所指的源数据区装载8个字数据到r3-R10中,每次装载1个字后R0中地址加1,最后更新R0中地址
- 将R3-R10的8个字数据存入R1所指的目的数据区,每次装载1个字后R1中地址加1,最后更新R1中地址
- 如果r0与r2寄存器数值表示的地址小于或者等于则循环执行copy_exception_table函数
- 这里是从r0开始的地址拷贝0x100个字节到r1的地址中去,由于r0,r1寄存器的地址这里会自动加以,所以最终会出现r0大于r2结束循环
- 注意:ble是指Branch if Less than or Equal,即小于或等于跳转;
- 上面这一段实现的功能就是,将_start开始的100字节复制到地址为0的内部RAM中去.从反汇编中可以知道,异常向量表的地址是存在开始的0x00~0x40的空间,这里实际是将异常向量表赋值到片内RAM中去了。
7.重定向uboot到外部DDR
@ relocate U-Boot to RAM
adrl r0, _start @ r0 <- current position of code
ldr r1, _TEXT_BASE @ test if we run from flash or RAM
cmp r0, r1 @ don't reloc during debug
beq stack_setup
- 将_start的地址复制给r0寄存器
- 将_TEXT_BASE的地址赋值给r1寄存器
- 比较r0与r1寄存器里的地址是否相同
- 如果相同跳转到stack_setup去执行,执行完返回。
- _start的地址使用的是adrl来加载,实际该值是flash的指令地址,也就是0x14000000
- _TEXT_BASE的地址使用的是ldr来加载,正常启动时这个值就是我们连接的起始地址0x80800000
- 只有从外部DDR启动的时候r0才会与r1相等,其它时候不会相等。
- 正常启动执行到这里r0=0x14000000,r1=0x80800000
ldr r2, _armboot_start
ldr r3, _bss_start
sub r2, r3, r2 @ r2 <- size of armboot
add r2, r0, r2 @ r2 <- source end address
- 将_armboot_start标号表示的地址赋值给r2寄存器
- 将_bss_start标号的地址赋值给r3寄存器
- 将r3减r2地址的值赋值给r2
- 将r0加r2的值赋值给r2
- _armboot_start和_bss_start使用的都是ldr加载,
- _armboot_start=0x80800000,_bss_start=0x8084abc4(该值通过反汇编查询得到)
- 正常启动到这里寄存器r2的值为r2=0x14000000+(0x8084abc4-0x80800000)
- r2的地址实际表示flash中uboot bss段的开始地址(重定向时不需要bss段)。
copy_loop: @ copy 32 bytes at a time
ldmia r0!, {r3 - r10} @ copy from source address [r0]
stmia r1!, {r3 - r10} @ copy to target address [r1]
cmp r0, r2 @ until source end addreee [r2]
ble copy_loop
#endif /* CONFIG_SKIP_RELOCATE_UBOOT */
- r0=0x14000000,r1=0x80800000,与上面复制异常中断表到内部RAM中类似,这里是将flash中的uboot(除了bss段)全部复制到外部的DDR中去
8.设置栈空间
/* Set up the stack */
stack_setup:
ldr r0, _TEXT_BASE @ upper 128 KiB: relocated uboot
sub r0, r0, #CONFIG_SYS_MALLOC_LEN @ malloc area
sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE @ bdinfo
- _TEXT_BASE 代码启动地址
- CONFIG_SYS_MALLOC_LEN = 0x40000 +128*1024 = (256+128)*1024 = 384KB
- CONFIG_SYS_GBL_DATA_SIZE=128 Byte
#ifdef CONFIG_USE_IRQ
sub r0, r0, #(CONFIG_STACKSIZE_IRQ + CONFIG_STACKSIZE_FIQ)
#endif
- 在hi3521a中CONFIG_USE_IRQ没有被定义
sub sp, r0, #12 @ leave 3 words for abort-stack
and sp, sp, #~7 @ 8 byte alinged for (ldr/str)d
- r0=0x80800000 - 0x60000(384K) - 0x80(byte)
- sp=r0 - sp
- 设置sp 8字节对齐
9.清除bss段
/* Clear BSS (if any). Is below tx (watch load addr - need space) */
clear_bss:
ldr r0, _bss_start @ find start of bss segment
ldr r1, _bss_end @ stop here
mov r2, #0x0 @ clear value
- 将bss段的开始位置放到r0寄存器中
- 将bss段的结束位置放到r1寄存器中
- 将数值0放置到r2寄存器
clbss_l:
str r2, [r0] @ clear BSS location
cmp r0, r1 @ are we at the end yet
add r0, r0, #4 @ increment clear index pointer
bne clbss_l @ keep clearing till at end
- 将r2寄存器的值(0)保存到r0寄存器所指向的地址中去
- 比较r0与r1寄存器中的值是否相等
- 将r0寄存器的值加4(地址加4字节)
- 如果r0与r1表示的地址不相等,则循环到clbss_l处执行
- 这一段代码的作用是:使用0填充_bss_start开始到_bss_end结束的地址空间。
10.跳转到C程序入口
ldr pc, _start_armboot @ jump to C code
_start_armboot: .word start_armboot
- 跳转到C语言阶段
- start_armboot 函数是在arch/arm/lib/board.c 中被定义的
- 注意这里使用ldr来跳转,这是个长跳转,由原来的spi flash 中运行直接跳转到外部DDR中运行,uboot后面都是在DDR中运行。
bug:
nop
nop
nop
nop
nop
nop
nop
nop
b . /* bug here */
- bug 标号定义,b.表示运行到最后进入了死循环。
uboot的第一阶段启动到这里就结束了,后面调用C语言实现第二阶段的启动,在start.S 文件后面的汇编代码是一些异常中断的处理定义,这里不再介绍。其它内容可以参考博客《序言与目录》
致谢:
本文内容有参考下列内容:
- https://re-eject.gbadev.org/files/GasARMRef.pdf
- https://www.crifan.com/files/doc/docbook/uboot_starts_analysis/release/webhelp/
----------------------------------------------------------------2022.08.28----------------------------------------------------------------
新的文章|公|内容和附件工程文件
已更新|众|在博客首页和:
|号|:liwen01
----------------------------------------------------------------2022.08.28----------------------------------------------------------------
最后
以上就是包容服饰为你收集整理的海思(Hi3521a)uboot详细分析(5)——uboot启动第一阶段start.S文件分析1.设置CPU SVC模式 2.关闭mmu和缓存3.启动流程判断4.关闭地址重映射5.使能指令缓存6.重定向异常向量表到内部RAM7.重定向uboot到外部DDR8.设置栈空间9.清除bss段10.跳转到C程序入口致谢:的全部内容,希望文章能够帮你解决海思(Hi3521a)uboot详细分析(5)——uboot启动第一阶段start.S文件分析1.设置CPU SVC模式 2.关闭mmu和缓存3.启动流程判断4.关闭地址重映射5.使能指令缓存6.重定向异常向量表到内部RAM7.重定向uboot到外部DDR8.设置栈空间9.清除bss段10.跳转到C程序入口致谢:所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复