从零开始的uboot系统移植5

从零开始的uboot系统移植5

                                                               ---uboot源码分析第一部分start.s上


本总结基于朱有鹏嵌入式大讲坛uboot的移植


我觉得了解uboot最好的方式是学习uboot的源代码0.02,如果你认真的阅读的话,那么你就会发现

以前的uboot写的是非常的“简单”,所有的配置文件都是仅仅用一个条件编译来编写的而且细心的人可以看

到最初的版本仅仅只支持S3C2440和S3c2410,没有所谓的BSS段,到后面uboot越来越大,有了BSS段了,

所有的配置需要使用链接文件了?

为什么,因为每一个开发板都需要有其支持的东西啊,这样我们就可以一个uboot程序可以支持很多开发板啊。


BSS段:

BSS段是用来存放一些未初始化的全局变量等,为啥要放在这里啊?

因为放在一个地方,一下子全部把它全部初始化不好吗?

为什么我们要这样啊?因为uboot是裸机程序啊,并没有操作系统帮你管理内存,

需要你自己去管理内存。BSS段,只读数据段,数据段,代码段,

代码是用来加工数据的!!!


 所有版本的u-boot源代码压缩包都可以在ftp://ftp.denx.de/pub/u-boot/下载。
关于u-boot源代码的信息,看http://www.denx.de/wiki/U-Boot/SourceCode



1、阶段的定义:

第一阶段:

即在内部SRAM运行的阶段,简单的理解为汇编阶段,此阶段主要涉及start.s文件,

在CPU/s5pc11x/目录下面。

第一阶段以ldr    pc   _start_armboot

第二阶段:

即在DDR中运行的阶段,简单的理解为C语言阶段,此阶段主要涉及start_armboot函数,

在uboot/lib_arm/board.c文件的444到908行



2、总结第一阶段的主要完成的任务

2.1、异常向量表的实现;

2.2、设置进入特权模式,即SVC模式;

2.3、检查恢复状态;

2.4、IO状态恢复;

2.5、关闭看门狗;

2.6、一些SRAM,SROM相关的GPIO设置;

2.7、开发板的供电锁存

2.8、时钟的初始化

2.9、DDR的初始化;

2.10、重新设置栈空间;

2.11、uboot的重定位;

2.12、转换表的建立

2.13、使能MMU


3、start.s的分析部分1

#include  <config.h>      

#include  <version.h>

 

#if  defined(CONFIG_ENABLE_MMU)

#include  <asm/proc/domain.h>

#endif

#include  <regs.h>


(1)config.h文件在mkconfig脚本中生成,此文件的内容为#include <configs/x210.h>

(2)Version.h文件中的内容是#include “version_autogeneratied.h”

(3)version_autogeneratied.h生成的代码为#define U_BOOT_VERSION “U-boot 1.3.4”

(4)由于定义了宏CONFIG_ENABLE_MMU,因此包含asm/proc/domain.h,实际包含include/asm-arm/proc-arm/domain.h文件。


4、start.s的解析2

(1)启动代码的16字节头部:

#if defined(CONFIG_EVT1)  && !Defined (CONFIG_FUSED)

   .word  0x2000

   .word  0x0000

   .word  0x0000

   .word  0x0000

#endif

 

1、arm7和arm9的指令集,一个字的类型是32bit

2.word是arm汇编的伪指令,含义是当前地址的值为XX,XX的内容一般为数值或者地址。

如:.word 0x2000表示当前地址的值为0x2000;.word _start 表示当前地址的值为_start。


(2)构建异常向量表

.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

	.balignl 16,0xdeadbeef

1、异常向量表由硬件决定,软件只是参照硬件设计来实现。

2、此向量表只是做到了其中的一点点的部分,并没有做到非常细致的异常处理

3、复位异常处理的代码是reset是一个函数    b   reset

4、上图中的最后一句是让内存以16字节来对齐,如果不对齐,用oxdeadbeef这个数字填充

5、学完裸机中的中断向量表可知,这里有类似的操作。


总结:

所谓的异常向量表,听起来好像很牛逼的样子,但是其实就是你的这个程序跑飞了,然后

会进入什么样的状态而已,但是如果没有这个异常状态表,你就很难去跟踪你的程序到底是

哪里出错了,这个中断向量表,这里的异常向量表也包含了中断模式和快速中断的模式;

未定义
软件中断
预处理的指令
数据出错
未使用的代码
普通中断
快速中断
这些异常的模式都代表一条公路,可以同往该去的地方,后面的.word就是对应的地址的代码。

(前面的一段里面有说明)


(3)一些重要的地址值:

_TEXT_BASE:
	.word	TEXT_BASE

.globl _armboot_start      这里相当于定义了一个全局变量_armboot_start
_armboot_start:
	.word _start

/*
 * Note: _armboot_end_data and _armboot_end are defined
 * by the (board-dependent) linker script.
 * _armboot_end_data is the first usable FLASH address after armboot
 */
.globl _armboot_end_data
_armboot_end_data:
	.word armboot_end_data
.globl _armboot_end
_armboot_end:
	.word armboot_end

/*
 * _armboot_real_end is the first usable RAM address behind armboot
 * and the various stacks
 */
.globl _armboot_real_end
_armboot_real_end:
	.word 0x0badc0de

//这里的代码主要定义了两个配置文件,如果定义了中断,那么就需要用到中断的堆栈,否则不能使用中断。

#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

1、_TEXT_BASE(4字节)这个内存地址出的值为TEXT_BASE(即0xc3e00000)。

2、_TEXT_PHY_BASE(4字节)这个内存存放的值为CFG_PHY_UBOOT_BASE(uboot的物理基地址)。

3、CFG_PHY_UBOOT_BASE(定义在x210_sd.h中)为 MEMORY_BASE_ADDRESS + 0x3e00000

在x210_sd.h中有#define MEMORY_BASE_ADDRESS 0x30000000;

因此CFG_PHY_UBOOT_BASE为0x33e00000,这个是uboot在DDR中的物理地址。

4、总结,即标签表示地址,.word后面的表示此内存地址中存储的值。

如_bss_end: .word _end表示地址_bss_end上存放的值是_end。


4、start.s解析3

(1)reset中断处理函数

/*
 * 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

设置寄存器为0xd3的时候,则CPU设置为SVC模式,arm状态,禁止FIQ,IRQ中断。

整个uboot的工作时,CPU一直处于SVC模式。


以下的代码使用的是uboot最早的版本,所以肯定是不完善写的不够好,牛逼的程序,

一般是没有注释的,为什么呢?因为是牛逼的人写的,他认为我们都是懂的,其实我们是

不懂的微笑


(2)关闭看门狗:

此代码主要使用了两个配置选项来选择2440或者2410的代码,这里是uboot最早的代码,

还是十分的简单,没有支持很多的开发板但是已经有配置的思想了。

/* turn off the watchdog */
#if defined(CONFIG_S3C2400)
#define pWTCON		0x15300000
/* Interupt-Controller base addresses */
#define INTMSK		0x14400008
/* clock divisor register */
#define CLKDIVN		0x14800014
#elif defined(CONFIG_S3C2410)
#define pWTCON		0x53000000
/* Interupt-Controller base addresses */
#define INTMSK		0x4A000008
#define INTSUBMSK	0x4A00001C
/* clock divisor register */
#define CLKDIVN		0x4C000014
#endif

	ldr     r0, =pWTCON
	mov     r1, #0x0
	str     r1, [r0]


	/*
	 * mask all IRQs by setting all bits in the INTMR - default
	 */
	mov	r1, #0xffffffff
	ldr	r0, =INTMSK
	str	r1, [r0]
#if defined(CONFIG_S3C2410)
	ldr	r1, =0x3ff
	ldr	r0, =INTSUBMSK
	str	r1, [r0]
#endif

	/* FCLK:HCLK:PCLK = 1:2:4 */
	/* default FCLK is 120 MHz ! */
	ldr	r0, =CLKDIVN
	mov	r1, #3
	str	r1, [r0]

	/*
	 * we do sys-critical inits only at reboot,
	 * not when booting from ram!
	 */
#ifdef CONFIG_INIT_CRITICAL
	bl	cpu_init_crit
#endif

	/* FCLK:HCLK:PCLK = 1:2:4 */
	/* default FCLK is 120 MHz ! */
	ldr	r0, =CLKDIVN
	mov	r1, #3
	str	r1, [r0]

	/*
	 * we do sys-critical inits only at reboot,
	 * not when booting from ram!
	 */

(3)CPU的初始化的代码:

不用问为什么这么写,没有什么为什么,因为它的用户手册已经规定了使用什么寄存器,

寄存器的地址是什么了。

cpu_init_crit:
	/*
	 * flush v4 I/D caches
	 */
	mov	r0, #0
	mcr	p15, 0, r0, c7, c7, 0	/* flush v3/v4 cache */
	mcr	p15, 0, r0, c8, c7, 0	/* flush v4 TLB */

	/*
	 * disable MMU stuff and caches
	 */
	mrc	p15, 0, r0, c1, c0, 0
	bic	r0, r0, #0x00002300	@ clear bits 13, 9:8 (--V- --RS)
	bic	r0, r0, #0x00000087	@ clear bits 7, 2:0 (B--- -CAM)
	orr	r0, r0, #0x00000002	@ set bit 2 (A) Align
	orr	r0, r0, #0x00001000	@ set bit 12 (I) I-Cache
	mcr	p15, 0, r0, c1, c0, 0


	/*
	 * before relocating, we have to setup RAM timing
	 * because memory timing is board-dependend, you will
	 * find a memsetup.S in your board directory.
	 */
	mov	ip, lr
	bl	memsetup
	mov	lr, ip

	mov	pc, lr


(3)识别并暂存启动介质选项:

   用我的话来说:启动方式有很多种,S3C2440,一般是从NORFLASH中开始启动,然后再把

前4K的内容转移到NANDFLASH。朱有鹏老师使用的210的开发板,比较高级一点,所以有很多方式,

需要识别那些SD卡,NANDFLASH,NORFLASH

Ldr  ro, =PRO_ID_BASE

Ldr  r1,[ro,#OMR_OFFSET]

Bic  r2,r1,#0xffffffc1

3.1、启动介质由SOC的OMO:OM5的引脚的高低电平决定;

由#define PRO_ID_BASE 0xE0000000和#define OMR_OFFSET 0x04得到寄存器0xE000 0004

这个寄存器会根据OM引脚状况,硬件自动设置值。

(3)此三行代码后,r2存储了一个数字,后续通过该数字进行启动介质的判断。

//此处条件编译,删除部分代码

(4)通过判断r2中的值,来确定是从哪里启动的。

如果r2中的值为0xc,那从SD卡启动,然后把#BOOT_MMCSD(#define  BOOT_MMCSD  0x3)赋给r3。

(5)最后两行中,因为有#define INF_REG_BASE 0xE010F000和#define INF_REG3_OFFSET 0x0c,则合成寄存器0xE010F00C,

然后把r3中的值放入其中。


5、start.s解析4

Lowlevel_init函数


1lowlevel_inituboot\board\samsung\x210\lowlevel_init.S中。

2)检查复位状态

因为复杂CPU支持多种复位状态(冷上电、休眠复位等),因此在复位代码中检查复位状态,判断到底是哪一种。

冷上电时DDR需要初始化,而休眠状态下复位不需要再次初始化DDR

3IO状态恢复;

4)关看门狗;

5)一些与SRAMSROM相关的GPIO设置(下图);

(6)开发板的供电锁存(下图)















  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值