AM335x uboot spl分析

嵌入式技术

1332人已加入

描述

芯片到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

__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

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分