Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1152574
  • 博文数量: 101
  • 博客积分: 110
  • 博客等级: 民兵
  • 技术积分: 1842
  • 用 户 组: 普通用户
  • 注册时间: 2012-08-24 13:26
个人简介

专注linux

文章分类

全部博文(101)

文章存档

2017年(2)

2016年(12)

2015年(17)

2014年(41)

2013年(27)

2012年(3)

分类: IT业界

2014-11-22 22:37:06

闲来无事,研究下Uboot的启动代码。整理份笔记,也供大家分享学习。

Uboot的起始函数位于start.s中,属于板级代码,就从这里开始喽。。。

 

.globl _start

_start: b reset

/*

一上来就跳转到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

_pad:

.word 0x12345678 /* now 16*4=64 */

.global _end_vect

_end_vect:

 

.balignl 16,0xdeadbeef

/*

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

 *

 * Startup Code (reset vector)

 *

 * do important init only if we don't start from memory!

 * setup Memory and board specific bits prior to relocation.

 * relocate armboot to ram

 * setup stack

 *

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

 */

 

_TEXT_BASE:

.word TEXT_BASE

 

/*

 * Below variable is very important because we use MMU in U-Boot.

 * Without it, we cannot run code correctly before MMU is ON.

 * by scsuh.

 */

_TEXT_PHY_BASE:

.word CFG_PHY_UBOOT_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:

/*

 * set the cpu to SVC32 mode

 */

mrs r0,cpsr  /* 取出cpsr中的内容 */

bic r0,r0,#0x1f /* 清除 bit[4:0] */

orr r0,r0,#0xd3 /* 设置 bit[4:0] 为管理模式,关闭irqfiq*/

msr cpsr,r0 /* 写入cpsr */


即设置了M[4:0]b10011,为管理模式。具体模式可参考下图。


/*

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

 *

 * CPU_init_critical registers

 *

 * setup important registers

 * setup memory timing

 *

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

 */

         /*

         * we do sys-critical inits only at reboot,

         * not when booting from ram!

         */

cpu_init_crit:

/*

刷新命令和数据缓冲。mcr命令用于向协处理器写入数据。

格式:MCR{cond} P15,,,,,

P15是协处理器,Rd为普通寄存器(源寄存器),CRnp15协处理器的一个寄存器(32位)。mcr p15, 0, r0, c7, c7, 0是什么意思呢?从下面图中可以找到答案:Invalidate Both Caches


*/

/*

 * flush v4 I/D caches

 */

mov r0, #0  /* r00 */

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为从协处理器的寄存器中读取数据。

bic将操作数1的相应为清除。下图为p15协处理器c1寄存器的位图。

 */


mrc p15, 0, r0, c1, c0, 0

bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)

/* 参考上图可知,此句关闭VRS。这些位是什么意思呢? 

:决定了异常矢量的位置。

普通异常矢量。矢量基地址寄存器决定了地址范围。

高异常矢量。地方范围:0xFFFF0000-0xFFFF001C

RROM保护使能。如果设置了此位,不会影响已经在TLB中的访问权限。

关闭ROM保护

开启ROM保护

SMMU保护使能。如果设置了此位,不会影响已经在TLB中的访问权限。

关闭MMU保护

开启MMU保护

*/

bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)

/* 

B:大小端位

小端

大端

C:级别1数据缓冲位

关闭

开启

A:检测数据对齐位

关闭检测

开启检测

MMMU使能位

关闭MMU

开启MMU  

 */

orr r0, r0, #0x00000002 @ set bit 2 (A) Align /* 开启对齐检测 */

orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache /* 开启1级指令缓冲 */

mcr p15, 0, r0, c1, c0, 0 /* p15的控制寄存器 */

 

/* Peri port setup */

ldr r0, =0x70000000      /* 0x70000000装入r0中 */

orr r0, r0, #0x13 /* 设置bit[4:0] 0b10011 */

mcr p15,0,r0,c15,c2,4    @ 256M(0x70000000-0x7fffffff) 

/* 

  上句,设置Peripheral Port Memory Remap。如下图,设置了size。那size有是怎么一回事呢?

 */


/* 

  参照下图中的值,即可对应其含义。

 */


#ifdef CONFIG_BOOT_ONENAND

ldr r0, =0x70000000 @ onenand controller setup

orr r0, r0, #0x100000

ldr r1, =0x4000

orr r1, r1, #0xe0

str r1, [r0]

 

#if defined(CONFIG_S3C6410) || defined(CONFIG_S3C6430)

orr r0, r0, #300 @ disable watchdog

mov r1, #1

str r1, [r0]

 

mov r1, #0x23000000 @ start buffer register

orr r1, r1, #0x30000

orr r1, r1, #0xc800

#else

mov r1, =0x20000000 @ start buffer register

orr r1, r1, #0xc30000

orr r1, r1, #0xc800

#endif

 

sub r0, r1, #0x0400 @ start address1 register

 

ldr r2, [r1, #0x84] @ ecc bypass

orr r2, r2, #0x100

str r2, [r1, #0x84]

 

mov r3, #0x0 @ DFS, FBA

str r3, [r0, #0x00]

str r3, [r0, #0x04] @ select dataram for DDP as 0

 

mov r4, #0x104 @ interrupt register

mov r5, #0x0002 @ FPA, FSA

mov r6, #0x0800 @ BSA

 

onenand_bl1_load:

str r5, [r0, #0x1c] @ save FPA, FSA

orr r6, r6, #0x02 @ BSC

str r6, [r1, #0x00] @ save BSA, BSC

str r3, [r1, r4] @ clear interrupt

str r3, [r1, #0x80] @ write load command

 

mov r7, #0x100 @ need small delay

 

onenand_wait_loop1:

subs r7, r7, #0x1

bne onenand_wait_loop1

 

add r5, r5, #0x2 @ next FPA, FSA

sub r6, r6, #0x2

add r6, r6, #0x200 @ next BSA

cmp r5, #0x8

bne onenand_bl1_load

#endif

/* 上面这一段我想比较简单,我就不多说了。大家可以耐下心来仔细研究即可看明白。 */

/*

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

 */

bl lowlevel_init /* go setup pll,mux,memory */ /* 此函数不在此文件中,先不说。后续文章中会有提及。 */

 

/* when we already run in ram, we don't need to relocate U-Boot.

 * and actually, memory controller must be configured before U-Boot

 * is running in ram.

 */

 ldr r0, =0xff000fff

/* 查看uboot是否已经在内存中 */

bic r1, pc, r0 /* r0 <- current base addr of code */

ldr r2, _TEXT_BASE /* r1 <- original base addr in ram */

bic r2, r2, r0 /* r0 <- current base addr of code */

cmp     r1, r2                  /* compare r0, r1                  */

beq     after_copy /* r0 == r1 then skip flash copy   */

 

#ifdef CONFIG_BOOT_NOR /* relocate U-Boot to RAM */

adr r0, _start /* r0 <- current position of code   */

ldr r1, _TEXT_PHY_BASE /* r1 <- destination                */

ldr r2, _armboot_start

ldr r3, _bss_start

sub r2, r3, r2 /* r2 <- size of armboot            */

add r2, r0, r2 /* r2 <- source end address         */

/* 循环去copy */

nor_copy_loop:

ldmia r0!, {r3-r10} /* copy from source address [r0]    *//* 每次会copy一段内存到r3-r10 */

stmia r1!, {r3-r10} /* copy to   target address [r1]    *//* copy r3-r10 寄存器内容到 r1所指内存 */

cmp r0, r2 /* until source end addreee [r2]    */

ble nor_copy_loop

b after_copy

#endif

 

after_copy:

#ifdef CONFIG_ENABLE_MMU

enable_mmu:

/* enable domain access */

ldr r5, =0x0000ffff

mcr p15, 0, r5, c3, c0, 0 @ load domain access register

/* 

这里又涉及另一个寄存器c3(Domain Access Control)


开启D0-D7的域访问权限。

 */

 

/* Set the TTB register */

ldr r0, _mmu_table_base

ldr r1, =CFG_PHY_UBOOT_BASE

ldr r2, =0xfff00000

bic r0, r0, r2

orr r1, r0, r1

mcr p15, 0, r1, c2, c0, 0

/* 

c2 寄存器(Translation Table Base Register 0)


上图为c3的位格式。

 */

/* Enable the MMU */

mmu_on:

mrc p15, 0, r0, c1, c0, 0

orr r0, r0, #1 /* Set CR_M to enable MMU */

mcr p15, 0, r0, c1, c0, 0

nop

nop

nop

Nop

/* 上面这段也很简单了,在前面的设置中有提及。打开MMU */

#endif

 

skip_hw_init:

/* Set up the stack */

stack_setup:

#ifdef CONFIG_MEMORY_UPPER_CODE

ldr sp, =(CFG_UBOOT_BASE + CFG_UBOOT_SIZE - 0xc)

#else

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

 

#endif

 

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

/* 上面这段程序,应该不用再解释了吧,英语注释已经很详尽了。 */

ldr pc, _start_armboot /* 跳转至start_armboot 函数。此函数为C函数。 */

 

_start_armboot:

.word start_armboot

 

#ifdef CONFIG_ENABLE_MMU

_mmu_table_base:

.word mmu_table

#endif

 

目前的学习,不要太拘于细节,要从大体着手,把整体的流程捋清楚。有时间可以再回头研究细节。如果在初学阶段就研究那么细的话,很容易半途而废,挫折太多,使得自己对自己都没有了信心。我就是这样学习的,如果大家还有什么好的观点,不妨拿出来,与大家分享。

 

关于ARM相关的,希望大家能下一本ARM1174的参考手册。网上有很多,可以找来看看,或者去ARM的官方网站中找,也是很容易找到的。如果还是没有找到,也可以在下面的连接中去下载一份(需要csdn账户)。

阅读(3300) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~