21ic电子技术开发论坛 已关闭版块 ZLG u-boot学习报告(上)
发新帖我要提问
返回列表
打印
[ZLG-ARM]

u-boot学习报告(上)

[复制链接]
1679|9
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
armqt|  楼主 | 2009-7-9 13:31 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
1.
u-boot简介1.1.
概述U-Boot,全称Universal Boot Loader,是遵循GPL条款的开放源码项目,从FADSROM、8xxROM、PPCBOOT逐步发展演化而来,其源码目录、编译形式与Linux内核很相似。事实上,不少U-Boot源码就是相应Linux内核源程序的简化,尤其是一些设备的驱动程序,从UBoot源码的注释中能体现这一点。但是U-Boot不仅仅支持嵌入式Linux系统的引导,当前,它还支持NetBSD、VxWorks、QNX、RTEMS、ARTOS、LynxOS嵌入式操作系统。其目前要支持的目标操作系统包括OpenBSD、NetBSD、FreeBSD、4.4BSD、Linux、SVR4、Esix、Solaris、Irix、SCO、Dell、NCR、VxWorks、LynxOS、pSOS、QNX、RTEMS和ARTOS。这是U-Boot中Universal的一层含义。另外一层含义则是U-Boot除了支持PowerPC系列的处理器外,还能支持MIPS、x86、ARM、Nios、xScale等诸多常用系列的处理器。这两个特点正是U-Boot项目的开发目标,即支持尽可能多的嵌入式处理器和嵌入式操作系统。就目前来看,U-Boot对PowerPC系列处理器支持最为丰富,对Linux的支持最完善。其它系列的处理器和操作系统基本是在2002年11月PPCBOOT改名为U-Boot后逐步扩充的。从PPCBOOT向U-Boot的顺利过渡,很大程度上归功于U-Boot的维护人,德国DENX软件工程中心的Wolfgang Denk(以下简称W.D)本人精湛的专业水平和持着不懈的努力。当前,U-Boot项目在他的领军下,众多有志于开放源码Bootloader移植工作的嵌入式开发人员,正如火如荼地将各个不同系列嵌入式处理器的移植工作不断展开和深入,以支持更多嵌入式操作系统的装载与引导。
1.2.
U-Boot主要目录结构
board——目标板相关文件,主要包含SDRAM、Flash驱动; 
common——独立于处理器体系结构的通用代码,如 内存大小探测与故障检测; 
cpu——与处理器相关的文件,如mpc8xx子目录下含串口、网口、LCD驱动及中断初始化等文件; 
driver——通用设备驱动,如CFI Flash驱动(目前对Intel Flash支持较好) 
doc——U-Boot的说明文档; 
examples——可在U-Boot下运行的示例程序;如  helloworld.c,timer.c; 
include——U-Boot头文件,configs子目录下与目标板相关的配置头文件是移植过程中经常要修改的文件; 
lib_xxx——处理器体系相关的文件,如lib—ppc,lib_arm目录分别包含与PowerPC、ARM体系结构相关的文件; 
net——与网络功能相关的文件目录,如bootp、nfs、tftp; 
post——上电自检文件目录,尚有待于进一步完善; 
rtc——RTC驱动程序; 
tools——用于创建U-Boot S-RECORD和BIN镜像文件的工具。 
1.3.
U-Boot支持的主要功能U-Boot可支持的主要功能如表1所列。
表格 1
系统引导
 支持NFS挂载、RAMDISK(压缩或非压缩)形式的根文件系统 
 
支持NTS挂载,从Flash中引导压缩或非压缩系统内核
 
基本辅助功能
 强大的操作系统接口功能,可灵活设置、传递多个关键参数给操作系统,适合系统在不同开发阶段的调试要求与产品发布,尤其对Linux支持最为强劲 
 
支持目标板环境参数的多种存储方式,如Flash、NVRAIvl、EEPROM  
 
CRC32校验,可校验Flash中内核、RAMDISK镜像文件是否完好
 
设备驱动
 串口、SDRAM、Flash、以太网、LCD、NVRA/vl、EEPROM、键盘、JSB、PCMCIA、PCI、RTC等驱动支持                    
 
上电自检功能
 SDRAM、Flash大小自动检测;SDRAM故障检测:CPLy型号
 
特殊功能
 xⅢ内核引导 
 

2.
u-boot启动过程2.1.
启动模式Boot loader启动模式通常有两种:启动加载模式和下载模式。u-boot作为boot loader的一种也不例外。
启动加载模式:整个系统启动过程是自主的,完全没有人的干预。
下载模式:linux内核在加载时有开发人员控制,通过串口或者网络进行加载的方式。
对于普通用户来说,一般都用在启动加载模式,但是对于开发人员来数,则需要运行在下载模式下,因为开发过程中需要经常更新镜像。为了达到两者兼顾的目的,通常,采用两种模式相结合的方式。复位后,boot loader 首先进行初始化工作,结束后不是立刻加载linux镜像,而是等待一段时间,如果用户有键盘输入,就进入下载模式,否则进入启动加载模式。
2.2.
启动的阶段u-boot启动分为两个阶段。第一阶段主要针对与CPU体系结构和存储设备密切相关部分作一些必要的初始化工作,是一些依赖于CPU结构的代码,为了增加效率以及涉及到处理器的设置,只能采用汇编语言编写。第二阶段主要针对目标板一级的一些初始化工作并且提供一些驱动的支持,用c语言实现。


2.3.
启动代码分析首先我们整体上浏览下u-boot启动代码的流程图。




relocate

 

Stack_setup

 
Start_armboot()

 
Init_sequence[]

……
Getenv()

 
Cpu_init_crit

 
Main_loop()

 
Lowelevel_init.S

 
Reset


 

下面详细分析各个阶段中代码的具体工作。
1. Start.S
源码位置:cpu/arm920t/start.S
运行位置:Flash
描述:一个可执行的映像有且只有一个全局入口。这个入口点为处理器复位取第一条指令的位置。U-boot映像的入口就是start.S。这个可以通过 board/smdk2410/u-boot.lds连接脚本文件决定。

.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

//快速中断向量



_TEXT_BASE:

.word
TEXT_BASE

.globl _armboot_start
_armboot_start:

.word _start

/*

* These are defined in the board-specific linker script.

*/
.globl _bss_start
_bss_start:

.word __bss_start

.globl _bss_end
_bss_end:

.word _end

#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


/*

* the actual reset code

*/

reset:
//复位启动子程序

/* 设置CPU
为SVC32模式
*/

mrs
r0,cpsr

bic
r0,r0,#0x1f

orr
r0,r0,#0xd3

msr
cpsr,r0

/* 关闭看门狗 */
#if defined(CONFIG_S3C2400)
# define pWTCON
0x15300000
# define INTMSK
0x14400008
/* Interupt-Controller base addresses */
# define CLKDIVN
0x14800014
/* clock divisor register */
#elif defined(CONFIG_S3C2410)
# define pWTCON
0x53000000
# define INTMSK
0x4A000008
/* Interupt-Controller base addresses */
# define INTSUBMSK
0x4A00001C
# define CLKDIVN
0x4C000014
/* clock divisor register */
#endif

#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)

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:HCLKCLK = 1:2:4 */

/* default FCLK is 120 MHz ! */

ldr
r0, =CLKDIVN

mov
r1, #3

str
r1, [r0]
#endif
/* CONFIG_S3C2400 || CONFIG_S3C2410 */


/*
关键的初始化代码在系统重启是执行,而在热复位也就是直接从RAM中启动不执行

*/
#ifndef CONFIG_SKIP_LOWLEVEL_INIT

bl
cpu_init_crit
#endif

#ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate:
/* 把u-boot重新定位到RAM

*/

adr
r0, _start

/* 把代码的当前位置也就是需要复制代码的起始地址放到r0 */

ldr
r1, _TEXT_BASE
/* 测试启动从Flash还是RAM */

cmp
r0, r1
/* 比较r0和r1,调试的时候也就是都是从RAM启动*/
beq
stack_setup
/*的情况下,不需要重定位,跳过重定位代码 */
       

ldr
r2, _armboot_start
/*准备重新定位代码,得到_armboot_start的位置*/

ldr
r3, _bss_start
/*得到_bss_start的位置*/

sub
r2, r3, r2

/*r2为arm_boot的大小
*/

add
r2, r0, r2

/* r2得到需要复制代码的末尾地址 */

copy_loop:
/* 重新定位代码,也就是执行从代码从flash到RAM的拷贝工作*/

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


/* 初始化堆栈
*/
stack_setup:

ldr
r0, _TEXT_BASE
/* 上面128KiB是重定位后的u-boot
*/

sub
r0, r0, #CFG_MALLOC_LEN

/*向下是内存分配空间
*/

sub
r0, r0, #CFG_GBL_DATA_SIZE 
/*然后是bdinfo结构体地址空间
*/
#ifdef CONFIG_USE_IRQ

sub
r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif

sub
sp, r0, #12
/* 为abort-stack预留3个字
*/

clear_bss:

ldr
r0, _bss_start
/* 找到bss 段起始地址
*/

ldr
r1, _bss_end
/* bss段的末尾地址
*/

mov 
r2, #0x00000000
/* 清零
*/

clbss_l:str
r2, [r0]
/* bss段地址空间循环清零
*/

add
r0, r0, #4

cmp
r0, r1

ble
clbss_l

/* 跳转到start_armboot函数入口, _start_armboot字保存函数的入口地址 */

ldr
pc, _start_armboot

_start_armboot:
.word start_armboot


#ifndef CONFIG_SKIP_LOWLEVEL_INIT
cpu_init_crit:
/*关键的初始化程序 */

/*


初始化CACHE


*/

mov
r0, #0

mcr
p15, 0, r0, c7, c7, 0
/* flush v3/v4 cache */

mcr
p15, 0, r0, c8, c7, 0
/* flush v4 TLB */


/*


* 关闭MMU 和 CACHE


*/

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 lowlevel_init.S in your board directory.


*/

mov
ip, lr

bl
lowlevel_init

mov
lr, ip

mov
pc, lr
#endif /* CONFIG_SKIP_LOWLEVEL_INIT */

/*

*************************************************************************

*

* 中断向量

*

*************************************************************************

*/

@
@ IRQ stack frame.
@
#define S_FRAME_SIZE
72

#define S_OLD_R0
68
#define S_PSR
64
#define S_PC
60
#define S_LR
56
#define S_SP
52

#define S_IP
48
#define S_FP
44
#define S_R10
40
#define S_R9
36
#define S_R8
32
#define S_R7
28
#define S_R6
24
#define S_R5
20
#define S_R4
16
#define S_R3
12
#define S_R2
8
#define S_R1
4
#define S_R0
0

#define MODE_SVC 0x13
#define I_BIT
0x80

/*

* use bad_save_user_regs for abort/prefetch/undef/swi ...

* use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling

*/


.macro
bad_save_user_regs

sub
sp, sp, #S_FRAME_SIZE

stmia
sp, {r0 - r12}
@ Calling r0-r12

ldr
r2, _armboot_start

sub
r2, r2, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)

sub
r2, r2, #(CFG_GBL_DATA_SIZE+8)
@ set base 2 words into abort stack

ldmia
r2, {r2 - r3}
@ get pc, cpsr

add
r0, sp, #S_FRAME_SIZE
@ restore sp_SVC


add
r5, sp, #S_SP

mov
r1, lr

stmia
r5, {r0 - r3}
@ save sp_SVC, lr_SVC, pc, cpsr

mov
r0, sp

.endm


.macro
irq_save_user_regs

sub
sp, sp, #S_FRAME_SIZE

stmia
sp, {r0 - r12}
@ Calling r0-r12

add
r8, sp, #S_PC

stmdb
r8, {sp, lr}^
@ Calling SP, LR

str
lr, [r8, #0]
@ Save calling PC

mrs
r6, spsr

str
r6, [r8, #4]
@ Save CPSR

str
r0, [r8, #8]
@ Save OLD_R0

mov
r0, sp

.endm


.macro
irq_restore_user_regs

ldmia
sp, {r0 - lr}^
@ Calling r0 - lr

mov
r0, r0

ldr
lr, [sp, #S_PC]
@ Get PC

add
sp, sp, #S_FRAME_SIZE

subs
pc, lr, #4
@ return & move spsr_svc into cpsr

.endm


.macro get_bad_stack

ldr
r13, _armboot_start
@ setup our mode stack

sub
r13, r13, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)

sub
r13, r13, #(CFG_GBL_DATA_SIZE+8) @ reserved a couple spots in abort stack


str
lr, [r13]
@ save caller lr / spsr

mrs
lr, spsr

str
lr, [r13, #4]


mov
r13, #MODE_SVC
@ prepare SVC-Mode

@ msr
spsr_c, r13

msr
spsr, r13

mov
lr, pc

movs
pc, lr

.endm


.macro get_irq_stack
@ setup IRQ stack

ldr
sp, IRQ_STACK_START

.endm


.macro get_fiq_stack
@ setup FIQ stack

ldr
sp, FIQ_STACK_START

.endm

/*

*异常向量

*/

.align
5
undefined_instruction:

get_bad_stack

bad_save_user_regs

bl 
do_undefined_instruction


.align
5
software_interrupt:

get_bad_stack

bad_save_user_regs

bl 
do_software_interrupt


.align
5
prefetch_abort:

get_bad_stack

bad_save_user_regs

bl 
do_prefetch_abort


.align
5
data_abort:

get_bad_stack

bad_save_user_regs

bl 
do_data_abort


.align
5
not_used:

get_bad_stack

bad_save_user_regs

bl 
do_not_used

#ifdef CONFIG_USE_IRQ


.align
5
irq:

get_irq_stack

irq_save_user_regs

bl 
do_irq

irq_restore_user_regs


.align
5
fiq:

get_fiq_stack

/* someone ought to write a more effiction fiq_save_user_regs */

irq_save_user_regs

bl 
do_fiq

irq_restore_user_regs

#else


.align
5
irq:

get_bad_stack

bad_save_user_regs

bl 
do_irq


.align
5
fiq:

get_bad_stack

bad_save_user_regs

bl 
do_fiq

#endif

相关帖子

沙发
tmake| | 2009-7-9 13:45 | 只看该作者

好长啊!你要把代码全贴上估计还得好几页!

使用特权

评论回复
板凳
lpc2410| | 2009-7-9 14:04 | 只看该作者

很详细

使用特权

评论回复
地板
armqt|  楼主 | 2009-7-24 18:05 | 只看该作者

共同学习

使用特权

评论回复
5
bespecial| | 2009-11-21 17:59 | 只看该作者
学习一下 标记

使用特权

评论回复
6
linhai1986| | 2009-11-21 21:39 | 只看该作者
不错,写的很详细

使用特权

评论回复
7
linhai1986| | 2009-11-21 21:39 | 只看该作者
赞一个:)

使用特权

评论回复
8
LIU_XF| | 2009-11-21 21:42 | 只看该作者
学习一下,做个标记

非常感谢楼主分享

使用特权

评论回复
9
xiaoxin1986| | 2009-11-22 00:20 | 只看该作者
好长啊

使用特权

评论回复
10
xiaoxin1986| | 2009-11-22 00:20 | 只看该作者
赞一下LZ

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

31

主题

150

帖子

0

粉丝
关闭 热门推荐
快速回复 在线客服 返回列表 返回顶部