u-boot之start.S分析(一)

      在C语言中,我们只需要找到main函数就找到了程序的入口函数,但是在u-boot初始运行之时,并没有操作系统为我们初始化堆栈,所以它的入口函数是汇编代码。
      我们之前在链接脚本中的代码(.text)段定义了u-boot的启动文件顺序,因此第一个运行的函数必是cpu/s5pc11x/start.o所对应的源文件,而且入口函数是ENTRY(_start)对应的_start
      我们先将u-boot编译一遍再研究其代码

头文件包含

#include <config.h>
#include <version.h>
#if defined(CONFIG_ENABLE_MMU)
#include <asm/proc/domain.h>
#endif
#include <regs.h>

#ifndef CONFIG_ENABLE_MMU
#ifndef CFG_PHY_UBOOT_BASE
#define CFG_PHY_UBOOT_BASE	CFG_UBOOT_BASE
#endif
#endif
  • config.h文件是我们在u-boot之顶层Makefile分析(二)之config.mk文件的生成博文中的config.mk小节中生成的,里面只有一句头文件包含#include <configs/x210_sd.h>
  • version.h文件只有一句头文件包含#include "version_autogenerated.h",这个头文件是我们在 u-boot之顶层Makefile分析(一)博文中的u-boot版本以及环境变量小节中生成的,里面定义了u-boot的版本号,例如#define U_BOOT_VERSION "U-Boot 1.3.4"
  • regs.h文件中定义了开发板相关的寄存器地址

16字节校验位

#if defined(CONFIG_EVT1) && !defined(CONFIG_FUSED)
	.word 0x2000
	.word 0x0
	.word 0x0
	.word 0x0
#endif
  • 我们在include/autoconf.mk文件中找到了CONFIG_EVT1定义而没有找到CONFIG_FUSED定义,因此这个判断语句是成立的
  • 这里定义了16个字节的校验位,这里只是占位符,数据待以后填充。

注意

start.S中并没有直接引用autoconf.mk文件而引用的是x210_sd.h,已知的是autoconf.mk文件的生成过程使用了x210_sd.h头文件,所有在x210_sd.h中使用#define进行的宏定义都能在autoconf.mk中找到。

程序入口与异常向量表

.globl _start
_start: b	reset
	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

_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
  • _start就是整个uboot的入口
  • 类似于_undefined_instruction就是异常处理函数,它们组合起来就是所谓的异常向量表
  • 所有的CPU都有异常向量表,这是CPU设计时就设定好的,是硬件决定的。
  • 当异常发生时,CPU会自动处理(PC跳转到异常向量处处理异常,有时伴有一些辅助动作)
  • 异常向量表是硬件向软件提供的处理异常的支持
  • 程序真正是从b reset开始的

16字节对齐

.balignl 16,0xdeadbeef
  • 这句指令让当前的地址对齐排布,如果不对齐则自动后移,空出来的地方用0xdeadbeef来填充
  • 填充是为了有更高的执行效率或者是硬件的特殊要求

链接地址

_TEXT_BASE:
	.word	TEXT_BASE
  • 这里的TEXT_BASE 就是指定uboot的链接地址

u-boot真正开始

reset:
	/*
	 * set the cpu to SVC32 mode and IRQ & FIQ disable
	 */
	@;mrs	r0,cpsr
	@;bic	r0,r0,#0x1f
	@;orr	r0,r0,#0xd3
	@;msr	cpsr,r0
	msr	cpsr_c, #0xd3		@ I & F disable, Mode: 0x13 - SVC
  • @开头的行是注释
  • 向程序状态寄存器(cpsr)的c位写入0xd3,用来禁用普通中断(IRQ)和快速中断(FIQ)并设置为SVC(超级用户)模式

cpu初始化部分

忽略的部分

#ifndef CONFIG_EVT1
#if 0	
	bl	v7_flush_dcache_all
#else
	bl	disable_l2cache

	mov	r0, #0x0	@ 
	mov	r1, #0x0	@ i	
	mov	r3, #0x0
	mov	r4, #0x0
lp1:
	mov	r2, #0x0	@ j
lp2:	
	mov	r3, r1, LSL #29		@ r3 = r1(i) <<29
	mov	r4, r2, LSL #6		@ r4 = r2(j) <<6
	orr	r4, r4, #0x2		@ r3 = (i<<29)|(j<<6)|(1<<1)
	orr	r3, r3, r4
	mov	r0, r3			@ r0 = r3
	bl	CoInvalidateDCacheIndex
	add	r2, #0x1		@ r2(j)++
	cmp	r2, #1024		@ r2 < 1024
	bne	lp2			@ jump to lp2
	add	r1, #0x1		@ r1(i)++
	cmp	r1, #8			@ r1(i) < 8
	bne	lp1			@ jump to lp1

	bl	set_l2cache_auxctrl
	
	bl	enable_l2cache
#endif
#endif
  • 由于我们定义了CONFIG_EVT1变量,因此此部分不起作用

设置L1,L2 cache和MMU

bl	disable_l2cache
bl	set_l2cache_auxctrl_cycle
bl	enable_l2cache
/*
* 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 12 (Z---) BTB
mcr 	p15, 0, r0, c1, c0, 0
  • 先禁用l2cache
  • 然后再设置
  • 接着再使能
  • 使L1的I和Dcache无效(Icache是指令缓存,Dcache是数据缓存)
  • 关闭MMU
  • 这些都与CPU有关

读取启动信息

/* Read booting information */
ldr	r0, =PRO_ID_BASE
ldr	r1, [r0,#OMR_OFFSET]
bic	r2, r1, #0xffffffc1

/* NAND BOOT */
cmp	r2, #0x0		@ 512B 4-cycle
moveq	r3, #BOOT_NAND

cmp	r2, #0x2		@ 2KB 5-cycle
moveq	r3, #BOOT_NAND

cmp	r2, #0x4		@ 4KB 5-cycle	8-bit ECC
moveq	r3, #BOOT_NAND

cmp	r2, #0x6		@ 4KB 5-cycle	16-bit ECC
moveq	r3, #BOOT_NAND

cmp	r2, #0x8		@ OneNAND Mux
moveq	r3, #BOOT_ONENAND

/* SD/MMC BOOT */
cmp     r2, #0xc
moveq   r3, #BOOT_MMCSD	

/* NOR BOOT */
cmp     r2, #0x14
moveq   r3, #BOOT_NOR	
  • 代码执行完成后r2寄存器中存储了一个数,代表从哪个启动介质启动
  • 将r2和某一个数值进行对比,不同的数据代表不同的启动方式,再将某一个对应的值放于r3寄存器中

设置栈与低层初始化

/*
 * Go setup Memory and board specific bits prior to relocation.
 */

ldr	sp, =0xd0036000 /* end of sram dedicated to u-boot */
sub	sp, sp, #12	/* set stack */
mov	fp, #0

bl	lowlevel_init	/* go setup pll,mux,memory */
  • 第一次设置栈(设置在SRAM中)。当前整个代码还在SRAM中运行,DDR还未被初始化。地址0xd0036000是自己设置的,只给栈用
  • 然后调用lowlevel_init进行低层初始化

注:0xd0036000

这个地址是SoC内部的IROM&IRAM地址,这部分存储不需要初始化,上电就能使用。
在这里插入图片描述
具体的说是在IRAM中,看这个栈的大小为多大。0xd0037fff-0xd0036000=0x1fff,换算成10进制为8191,因此最后为8191/1024~~8K
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贱贱的剑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值