U-boot第一阶段分析
来源:互联网 发布:安卓app源码 编辑:程序博客网 时间:2024/05/11 05:03
u-boot是在单板刚启动的时候执行的一段程序。其作用是将内核从flash、硬盘等介质上拷贝到内存中,并传递给内核一些启动参数并跳转到内核去执行。
由于u-boot的代码非常的依赖于不同的体系结构。对u-boot的分析也只能提炼出不同体系结构的共性,做相应的总结。总的说来,u-boot所做到工作分为两个阶段。第一个阶段是将u-boot第二阶段的代码拷贝到ram空间,跳转到第二阶段代码执行。第二阶段是将内核代码拷贝到ram并跳转到内核去执行。
具体执行过程中做到操作如下
· 第一阶段的功能
1. 硬件设备初始化
2. 加载U-Boot第二阶段代码到RAM空间
3. 设置好栈
4. 跳转到第二阶段代码入口
· 第二阶段的功能
5. 初始化本阶段使用的硬件设备
6. 检测系统内存映射
7. 将内核从Flash读取到RAM中
8. 为内核设置启动参数
9. 调用内核
下面以ARM9 u-boot执行过程做一个分析,之后如果有时间再继续分析mips架构的u-boot执行过程,由于u-boot中涉及到许多汇编和体系结构的知识,对我们学习不同的体系结构有很大的帮助。如果相关知识不熟悉,阅读代码的时候会遇到很多疑惑。
第一阶段--硬件设备初始
.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
地址
异常
进入模式
描述
0x00000000
复位
管理模式
复位电平效时,产生复位异常,程序跳转到复位处理程序处执行
0x00000004
未定义指令
未定义模式
遇到不能处理的指令时,产生未定义指令异常
0x00000008
软件中断
管理模式
执行SWI指令产生,用于用户模式下的程序调用特权操作指令
0x0000000c
预存指令
中止模式
处理器预取指令的地址不存在,或该地址不允许当前指令访问,产生指令预取中止异常
0x00000010
数据操作
中止模式
处理器数据访问指令的地址不存在,或该地址不允许当前指令访问时,产生数据中止异常
0x00000014
未使用
未使用
未使用
0x00000018
IRQ
IRQ
外部中断请求效,且CPSR中的I位为0时,产生IRQ异常
0x0000001c
FIQ
FIQ
快速中断请求引脚效,且CPSR中的F位为0时,产生FIQ异常
在之前的文章中曾经提及过arm处理器有8中运行方式,上电后,cpu首先跳转到0x00000000 地址开始执行
reset:
/*
* set the cpu to SVC32 mode
*/
mrs r0,cpsr
bic r0,r0,#0x1f
orr r0,r0,#0xd3
msr cpsr,r0
mrs r0,cpsr //将当前cpsr的状态为保存到r0中。
bic r0,r0,#0x1f //bic,位清零指令。0x1f=00011111,相当于清除低5位。
刚好是模式位。
orr r0,r0,#0xd3 //或指令。置模式位。0xd3=11010011以及设置5,6,7位的
状态位。禁止FIQ,IRQ,处于arm状态。低5位为10011,则对应超级用户态。msr cpsr,r0 //在将r0中的值赋给状态寄存器cps
/* turn off the watchdog */
#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 INTMOD 0X4A000004
# 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
关闭禁止各个中断
#ifdef CONFIG_S3C2440
#define MPLLCON 0x4c000004
#define UPLLCON 0x4c000008
ldr r0, =CLKDIVN
mov r1, #5
str r1, [r0]
ldr r0, =MPLLCON
ldr r1, =0x7f021
str r1, [r0]
ldr r0, =UPLLCON
ldr r1, =0x38022
str r1, [r0]
#else
/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
#endif
设置cpu各个模块的主频大小
#endif /* CONFIG_S3C2400 || CONFIG_S3C2410 */
/*
* we do sys-critical inits only at reboot,
* not when booting from ram!
*/
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
adr r0, _start /* r0 <- current position of code */
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
cmp r0, r1 /* don't reloc during debug */
blne cpu_init_crit
#endif
如果cpu还是在flash或者step stone的内存中运行的话,跳转到cpu_init_crit运行
cpu_init_crit清空I cache和D cache并清空掉TLB表项,暂时关闭MMU,跳转到lowlevel_init对ram控制寄存器进行初始化
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
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 lowlevel_init.S in your board directory.
*/
mov ip, lr
bl lowlevel_init
mov lr, ip
mov pc, lr
#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
设置堆栈指针
stack_setup:
ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
sub r0, r0, #CFG_MALLOC_LEN
设置堆栈指针
stack_setup:
ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
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 /* leave 3 words for abort-stack */
设置cpu的时钟
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl clock_init
#endif
#define S3C2410_MPLL_200MHZ ((0x5c<<12)|(0x04<<4)|(0x00))
#define S3C2410_UPLL_48MHZ ((0x28<<12)|(0x01<<4)|(0x02))
#define S3C2410_CLKDIV 0x03 /* FCLK:HCLK:PCLK = 1:2:4 */
void clock_init(void)
{
S3C24X0_CLOCK_POWER *clk_power = (S3C24X0_CLOCK_POWER *)0x4C000000;
/* support both of S3C2410 and S3C2440, by www.arm9.net */
if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002))
{
/* FCLK:HCLK:PCLK = 1:2:4 */
clk_power->CLKDIVN = S3C2410_CLKDIV;
/* change to asynchronous bus mod */
__asm__( "mrc p15, 0, r1, c1, c0, 0\n" /* read ctrl register */
"orr r1, r1, #0xc0000000\n" /* Asynchronous */
"mcr p15, 0, r1, c1, c0, 0\n" /* write ctrl register */
:::"r1"
);
/* to reduce PLL lock time, adjust the LOCKTIME register */
clk_power->LOCKTIME = 0xFFFFFFFF;
/* configure UPLL */
clk_power->UPLLCON = S3C2410_UPLL_48MHZ;
/* some delay between MPLL and UPLL */
delay (4000);
/* configure MPLL */
clk_power->MPLLCON = S3C2410_MPLL_200MHZ;
/* some delay between MPLL and UPLL */
delay (8000);
}
else
{
/* FCLK:HCLK:PCLK = 1:4:8 */
clk_power->CLKDIVN = S3C2440_CLKDIV;
/* change to asynchronous bus mod */
__asm__( "mrc p15, 0, r1, c1, c0, 0\n" /* read ctrl register */
"orr r1, r1, #0xc0000000\n" /* Asynchronous */
"mcr p15, 0, r1, c1, c0, 0\n" /* write ctrl register */
:::"r1"
);
/* to reduce PLL lock time, adjust the LOCKTIME register */
clk_power->LOCKTIME = 0xFFFFFFFF;
/* configure UPLL */
clk_power->UPLLCON = S3C2440_UPLL_48MHZ;
/* some delay between MPLL and UPLL */
delay (4000);
/* configure MPLL */
clk_power->MPLLCON = S3C2440_MPLL_400MHZ;
/* some delay between MPLL and UPLL */
delay (8000);
}
}
硬件初始化完成,堆栈设置完成,之后将u-boot第二阶段的代码拷贝到内存
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate: /* relocate U-Boot to RAM */
adr r0, _start /* r0 <- current position of code */
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
cmp r0, r1 /* don't reloc during debug */
beq clear_bss
ldr r2, _armboot_start
ldr r3, _bss_start
sub r2, r3, r2 /* r2 <- size of armboot */
#if 1
bl CopyCode2Ram /* r0: source, r1: dest, r2: size */
#else
add r2, r0, r2 /* r2 <- source end address */
copy_loop:
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
#endif /* CONFIG_SKIP_RELOCATE_UBOOT */
上面的代码过程是,首先看uboot是不是已经在内存中运行了,如果是这样直接将bss区间置0就可以了,如果不是运行在内存中设置
r0 为flash起始位置
r1 为希望将u-boot拷贝到的ram位置
r2 u-boot代码段的长度
int CopyCode2Ram(unsigned long start_addr, unsigned char *buf, int size)
{
unsigned int *pdwDest;
unsigned int *pdwSrc;
int i;
if (bBootFrmNORFlash())
{
pdwDest = (unsigned int *)buf;
pdwSrc = (unsigned int *)start_addr;
/* 从 NOR Flash启动 */
for (i = 0; i < size / 4; i++)
{
pdwDest[i] = pdwSrc[i];
}
return 0;
}
else
{
/* 初始化NAND Flash */
nand_init_ll();
/* 从 NAND Flash启动 */
nand_read_ll(buf, start_addr, (size + NAND_BLOCK_MASK)&~(NAND_BLOCK_MASK));
return 0;
}
}
将bss区域清0
clear_bss:
ldr r0, _bss_start /* find start of bss segment */
ldr r1, _bss_end /* stop here */
mov r2, #0x00000000 /* clear */
clbss_l:str r2, [r0] /* clear loop... */
add r0, r0, #4
cmp r0, r1
ble clbss_l
跳转到内存中执行u-boot的第二阶段过程
ldr pc, _start_armboot
- U-boot第一阶段分析
- U-boot第一阶段分析
- U-Boot 第一阶段代码分析
- 图解U-Boot:第一阶段源码分析
- U-boot启动第一阶段详细分析
- 图解U-Boot:第一阶段源码分析
- U-Boot启动第一阶段代码分析
- U-Boot启动第一阶段代码分析
- 图解U-Boot:第一阶段源码分析
- u-boot第一阶段start.S分析
- U-Boot启动第一阶段代码分析
- u-boot第一阶段程序分析小结
- U-BOOT第一阶段程序分析(1)
- U-BOOT第一阶段程序分析(2)
- U-Boot启动第一阶段代码分析
- U-boot-1.1.6第一阶段源码分析
- 图解U-Boot:第一阶段源码分析
- U-Boot启动第一阶段代码分析
- poj 3264 Balanced Lineup
- 用户层调试
- Android Application Thread CPU GC Operatiing and OOM Question 0603-随手笔记
- XPath in SimpleXML
- 《C#程序设计》 第五次作业:开源项目“网页正文提取”的理解
- U-boot第一阶段分析
- C++实现PING命令
- opengl函数
- Spring mvc原理
- googlemock
- 确定有穷自动机测试代码
- iOS开发(Objective-C)常用库索引
- ExtJs中Ext.Ajax.request()跟getForm().submit()得用法
- Archlinux 下的 mariadb 和 jdbc