您的位置 首页 IC

AM335x uboot spl剖析

AM335x uboot spl分析-在335x 中ROM code是第一级的bootlader。mpu上电后将会自动执行这里的代码,完成部分初始化和引导第二级的bootlader,第二级的bootlader引导第三级bootader,在ti官方上对于第二级和第三级的bootlader由uboot提供。

芯片到uboot发动流程

ROM → SPL→ uboot.img

简介

在335x 中ROM code是榜首级的bootlader。mpu上电后将会主动履行这儿的代码,完结部分初始化和引导第二级的bootlader,第二级的bootlader引导第三级bootader,在TI官方上关于第二级和第三级的bootlader由uboot供给。

SPL

To unify all exisTIng implementaTIons for a secondary program loader (SPL) and to allow simply adding of new implementaTIons this generic SPL framework has been created. With this framework almost all source files for a board can be reused. No code duplication or symlinking is necessary anymore.

1》 Basic ARM initialization

2》 UART console initialization

3》 Clocks and DPLL locking (minimal)

4》 SDRAM initialization

5》 Mux (minimal)

6》 BootDevice initialization(based on where we are booting from.MMC1/MMC2/Nand/Onenand)

7》 Bootloading real u-boot from the BootDevice and passing control to it.

uboot spl源代码剖析

  一、makefile剖析

翻开spl文件夹只要一个makefile 可见spl都是复用uboot原先的代码。

首要触及的代码文件为u-boot-2011.09-psp04.06.00.03/arch/arm/cpu/armv7

u-boot-2011.09-psp04.06.00.03/arch/arm/lib

u-boot-2011.09-psp04.06.00.03/drivers

LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot-spl.lds

这个为链接脚本

  二、u-boot-spl.lds

AM335x uboot spl剖析

__start 为程序开端

__image_copy_end

_end

  三、代码解析

__start 为程序开端 (arch/arm/cpu/armv7/start.S)

.globl _start 这是在界说u-boot的发动界说进口点,汇编程序的缺省进口是 start标号,用户也能够在衔接脚本文件顶用ENTRY标志指明其它进口点。

.global是GNU ARM汇编的一个伪操作,声明一个符号可被其他文档引证,相当于声明晰一个全局变量,.globl和.global相同。该部分为处理器的反常处理向量表。地址规模为0x0000 0000 ~ 0x0000 0020,刚好8条指令。

为什么是8条指令呢?这儿来算一算。首要,一条arm指令为32bit(位),0x0000 0020换算成十进制为2^5=32B(字节),而32(B) = 4 * 8(B) = 4 * 8 * 8( bit),所以刚好8条指令(一个字节Byte包含8个位bit)。

下面是在汇编程序种经常会遇到的反常向量表。Arm处理器一般包含复位、未界说指令、SWI、预取停止、数据停止、IRQ、FIQ等反常,其间U-Boot中关于反常向量的界说如下:

_start: b reset

_start 标号标明oot程序从这儿开端履行。

b是不带回来的跳转(bl是带回来的跳转),意思是无条件直接跳转到reset标号出履行程序。b是最简略的分支,一旦遇到一个 b 指令,ARM处理器将当即跳转到给定的地址,从那里持续履行。留意存储在分支指令中的实践的值是相对当时的R15的值的一个偏移量;而不是一个肯定地址。它的值由汇编器来核算,它是 24 位有符号数,左移两位后有符号扩展为32 位,表明的有用偏移为 26 位。

ldr pc, _undefined_instr tion //未界说指令

ldr pc, _software_interrupt //软中止SWI

ldr pc, _prefetch_abort //预取停止

ldr pc, _data_abort //数拜访停止

ldr pc, _not_used

ldr pc, _irq //中止请求IRQ

ldr pc, _fiq //快速中止FIQ

#ifdef CONFIG_SPL_BUILD //该阶段为spl履行下面代码

_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

_pad: .word 0x12345678 /* now 16*4=64 */

#else

_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

_pad: .word 0x12345678 /* now 16*4=64 */

#endif /* CONFIG_SPL_BUILD */

.word为ARM汇编特有的伪操作符,语法如下:

.word {,} …

效果:刺进一个32-bit的数据行列。(与armasm中的DCD功用相同)

.balignl 16,0xdeadbeef

.align伪操效果于表明对齐方法:经过增加填充字节使当时方位满意必定的对齐方法。

接下来是对各个段代码的界说

Rest: (arch/arm/cpu/armv7/start.S)

bl save_boot_params

save_boot_params: (arch/arm/cpu/armv7/ti81xx/lowlevel_init.S)

#ifdef CONFIG_SPL_BUILD

ldr r4, =ti81xx_boot_device

//ti81xx_boot_device = BOOT_DEVICE_NAND

//发动方法

ldr r5, [r0, #BOOT_DEVICE_OFFSET]

and r5, r5, #BOOT_DEVICE_MASK

str r5, [r4]

#endif

bx lr

回到reset:(arch/arm/cpu/armv7/start.S)

//设置cpu的作业形式设置CPU的状况类型为SVC特权形式

mrs r0, cpsr

bic r0, r0, #0x1f

orr r0, r0, #0xd3

msr cpsr,r0

cpu_init_crit: (arch/arm/cpu/armv7/start.S)

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

mcr p15, 0, r0, c7, c5, 6 @ invalidate BP array

mcr p15, 0, r0, c7, c10, 4 @ DSB

mcr p15, 0, r0, c7, c5, 4 @ ISB

//封闭mmu 缓存

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

#ifdef CONFIG_SYS_ICACHE_OFF

bic r0, r0, #0x00001000 @ clear bit 12 (I) I-cache

#else

orr r0, r0, #0x00001000 @ set bit 12 (I) I-cache

#endif

mcr p15, 0, r0, c1, c0, 0

//调用初始化函数

mov ip, lr @ persevere link reg across call

bl lowlevel_init @ go setup pll,mux,memory

lowlevel_init:(arch/arm/cpu/armv7/ti81xx/lowlevel.S)

/* The link register is saved in ip by start.S */

mov r6, ip

/* check if we are already running from RAM */

ldr r2, _lowlevel_init

_TEXT_BASE:

.word CONFIG_SYS_TEXT_BASE /* Load address (RAM) */

#define CONFIG_SYS_TEXT_BASE 0x80800000

SDRAM的前8MB作为spl的bss段然后前64bytes做为u-boot.img的头

ldr r3, _TEXT_BASE

sub r4, r2, r3

sub r0, pc, r4

//设置仓库指针

/* require dummy instr or subtract pc by 4 instead i‘m doing stack init */

ldr sp, SRAM_STACK

mark1:

ldr r5, _mark1

sub r5, r5, r2 /* bytes between mark1 and lowlevel_init */

sub r0, r0, r5 /* r0 《- _start w.r.t current place of execution */

mov r10, #0x0 /* r10 has in_ddr used by s_init() */

ands r0, r0, #0xC0000000 /* MSB 2 bits 《》 0 then we are in ocmc or DDR */

cmp r0, #0x80000000

bne s_init_start

mov r10, #0x01

b s_init_start

s_init_start:(arch/arm/cpu/armv7/ti81xx/lowlevel.S)

mov r0, r10 /* passing in_ddr in r0 */

bl s_init

初始化pll mux memery

/* back to arch calling code */

mov pc, r6

call_board_init_f:(arch/arm/cpu/armv7/start.s)

//设置仓库指针,并调用board_init_f

ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)

bic sp, sp, #7 /* 8-byte alignment for ABI compliance */

ldr r0,=0x00000000

bl board_init_f

void board_init_f(ulong dummy)

『u-boot-2011.09-psp04.06.00.03/arch/arm/cpu/armv7/omap-common/spl.c』

调用relocate_code(CONFIG_SPL_STACK, &gdata, CONFIG_SPL_TEXT_BASE);

这儿使用了 CONFIG_SPL_STACK

#define CONFIG_SPL_STACK LOW_LEVEL_SRAM_STACK

#define LOW_LEVEL_SRAM_STACK (SRAM0_START + SRAM0_SIZE – 4)

gdata 为.bss 前一段的空间描绘镜像头

#define CONFIG_SPL_TEXT_BASE 0x402F0400

relocate_code: (arch/arm/cpu/armv7/start.s)

重载定位代码

jump_2_ram: (arch/arm/cpu/armv7/start.s)

跳转到spl的第二阶段

board_init_r:(u-boot-2011.09-psp04.06.00.03/arch/arm/cpu/armv7/omap-common/spl.c)

初始化时钟: timer_init()

i2c 初始化: i2c_init();

获取发动方法 omap_boot_device();

判别发动方法从不同的当地装载镜像

从mmc 中装载镜像 spl_mmc_load_image();

从nand 中装载镜像 spl_nand_load_image();

uart 中装载镜像 spl_ymodem_load_image();

判别镜像类型

跳转到镜像中履行镜像 jump_to_image_no_args();

装载镜像 将会从装备的存储介质中读取数据 及uboot镜像

然后跳转到uboot中履行uboot

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/bandaoti/102976.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部