Uboot运行分析(三) .

http://blog.csdn.net/yangxingbo0311/article/details/7335996

 

接下来就是start.S了。。本文源码来源于u-boot-1.1.6。

        源码的分析参考网上的诸多博客的整理。如http://home.eeworld.com.cn/my/space.php?uid=135723&do=blog&id=25548。http://www.51hei.com/mcu/1132.html等。


      都说bootloader分为两个阶段。。四极管也来看看这两个阶段都做了什么事情。

一、阶段1

阶段1通常包括以下步骤(以执行的先后顺序)

    1、一些基本硬件初始化工作

    2、为加载映像2准备RAM空间(RAM足够的情况下可以省略)

    3、把映像2拷贝到RAM空间

    4、跳转到映像2的入口点(一般是C入口点)

一般阶段1都会有如下具体工作:

    1、定义ARM各个运行模式

    2 、定义ARM各个运行模式堆栈的大小

    3、根据处理器工作状态确定编译方式

    4、初始化异常中断向量表

    5、禁止看门狗

    6、屏蔽中断

    7、屏蔽子中断

    8、设置时钟,初始化使能SDRAM

    9、为各操作模式设置堆栈指针,将系统模式置为监管模式(SVC)并设置SP

   10、将映像2拷贝到SDRAM的指定处。。。通过跳转进入阶段2

现在看源码分析:

 
 

Uboot start.S分析

四极管 2012-3-8

/*

 *  cpu/s3c24xx/start.S

 *

 *  U-Boot - Startup Code for S3C24XX

 *

 *  Copyright (c) 2006,  Samsung Electronics

 *  All rights reserved.

 *

 *  Based on cpu/arm926ejs/start.S

 *

 * This program is free software; you can redistribute it and/or modify

 * it under the terms of the GNU General Public License version 2 as

 * published by the Free Software Foundation.

 *

 * $Id: start.S,v 1.8 2008/05/23 00:26:34 eyryu Exp $

 */

/*

 *  mod by sc.suh@samsung.com

 *

 *  Our U-Boot Memory Map

 *                                      (offset)

 *       --------------------------     0x04000000

 *       |     Stack     (512KB)  |

 *       --------------------------     0x03f80000

 *       |     Heap       (1MB)   |

 *       --------------------------     0x03e80000

 *       |     IRQ Stack  (4KB)   | <------------------------ if exists

 *       --------------------------     0x03e70000

 *       |     FIQ Stack  (4KB)   | <------------------------ if exists

 *       --------------------------     0x03e60000

 *       |     GBL       (128B)   |

 *       --------------------------     0x03exxxxx

 *       |     BSS and Reserved   |

 *       --------------------------     0x03e40000

 *       |     U-Boot    (256KB)  |

 *       --------------------------     0x03e00000

 */

#include <config.h>

#include <version.h>

#ifdef CONFIG_ENABLE_MMU

#include <asm/proc/domain.h>

#endif

#ifndef CONFIG_ENABLE_MMU

#ifndef CFG_PHY_UBOOT_BASE

#define CFG_PHY_UBOOT_BASE CFG_UBOOT_BASE

#endif

#endif

#define no_compile 0

/********************************************************************

 *

 * Jump vector table as in table 3.1 in [1]

 *

*******************************************************************/

.globl _start

_start:  /*系统复位位置,各个异常向量对应的跳转代码,ARM中规定了异常向量的地址*/

b reset     //复位 0x0

ldr pc, _undefined_instruction //未定义的指令异常 0x4

ldr pc, _software_interrupt  //软件中断异常

ldr pc, _prefetch_abort//预取指令0xC

ldr pc, _data_abort//数据0x10

ldr pc, _not_used //未使用0x14

ldr pc, _irq//慢速中断异常0x18

ldr pc, _fiq//快速中断异常0x1C

/*.word伪操作作用于分配一段字内单元(分配的单元都是字对齐的),并用伪操作中的expr初始化。.long于.int作用与//相同*/

//以下.word 的含义如下:

.Word为GNU ARM汇编特有的伪操作,为分配一段字节内容单元(分配的单元为字对齐的),可以使用.word把标识符作为常量使用,如_irq:.word irq即把fiq存入内存变量_irq中,也即是把fiq放到地址_irq中。

_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 /*定义fiq变量到_fiq地址里面去,_fiq地址就是上面对应的,比如_fiq是0x0000 001C*/

.balignl 16,0xdeadbeef

/*对于这句话的理解内容就比较多了。。。。在Nunca Muer to 的空间里面有详细的对比分析。。为了以后难找,我还是把那段话敲出来。。。

先要弄明白.balignl的意思,这个其实应该算是一个伪操作符,伪操作符的意思就是机器码里,并没有一个汇编指令与其对应,是编译器来实现其功能的,.balignl是.balign的变体,.balign的意思是,在以当前地址开始,地址计数器必须是以第一个参数为整数倍的地址为尾,在前面记录一个字节长度的信息,信息内容为第二个参数。

.balignl  8,0xde

它的意思就是在以当前地址开始,在地址为8的倍数的位置的前面填入一个字节内容为0xde的内容。如果当前地址正好是8的倍数,则没有东西被写入到内存。

关于.balignl 16,0xdeadbeef这句,功能说明没有错,就是想在某个位置插入0xdeadbeef这个特殊的内存值。错就错在我对这个16的理解上面,16就是16个字节,这是没有错的,但是这个16的由来,并不是我所理解的至少16个字节,才能在任何情况下保证插入这个特殊的内存值。我在博客留言中回答,举了个例子pc=0x0000007地址,偏移量为8个字节时,这个时候就不够用4个字节的内容了,以此推导出的,至少有16个字节才能保证这个特殊的内存值的插入也是完全错误的。

举个反例,如果给那位网友的解释,那就算有16个字节的偏移量,那如果PC地址为0x000000F时,也只需要一个字符的空间,那这个0xdeadbeef的值是不够的,以此类推,就算这个值为任意一值,按我之前的解释的错误逻辑,也都有不满足的情况,呵呵,所以我之前的推论有误,我现在把16这个值的由来进行说明。

ARM920T处理器核心,支持32与16位两种指令长度,16位的指令叫做thumb指令集,由于我使用的是32位指令集,所有一切都是以32位指令集进行说明。

既然是32位指令集,所以一条指令就占32位,即4个字节,所以在调试器中,地址显示也是4字节一跳的,所以PC的值,也是4字节一跳的,并不存在可能PC的值为0x00000007的情况。

这个地方填16个偏移量,是因为

.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//占四个字节的内存

占了4x8 = 32 字节内存。

_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//占四个字节的内存

占了4X7=28个字节内存。

所以在这个.balignl 16,0xdeadbeef指令之前,一共占了4X15=60个字节的内存,所以本代码的作者当时就简单的在15这个数上,加了一个1,即16,把前面的指针移到地址为64的位置,然后在前面插上了0xdeadbeef这个特殊的值。

我不知道这个地方时作者的一个错误呢,歪打正着呢,还是怎么回事,其实这个偏移量的值有好多种情况,如果说最小值的话,那么也可以写成.balignl 8,0xdeadbeef,也同样可以达到相同的目的,因为60不是8的倍数,但是64是8的倍数(60到64之前都不是8的倍数,同样也不是16的倍数,所以写8和16都可行)如果写8,也正好插入到64前面,也即60这个内存起始地址,如果更大一点儿呢,那么填32也可以达到同样的效果,即.balignl 32,0xdeadbeef,道理同上。当然,不能为4,因为PC值在任何时候,都是4的倍数(64是4的倍数),只要不为0就为4的倍数,呵呵,这个值不行,如果用了这个值,0xdeadbeef永远也插不进去。

*/

/********************************************************************

 *

 * Startup Code (reset vector)

 *

 * do important init only if we don't start from memory!//做一些初始化,如果我们不是SDRAM启动的话

 * setup Memory and board specific bits prior to relocation.

 * relocate armboot to ram //重定位代码到SDRAM中

 * setup stack//设置堆栈空间

 * *******************************************************************/

/*保存变量的数据区*/

_TEXT_BASE:

.word TEXT_BASE  //在TEXT_BASE定义在board\smdk2416、config.mk文件中这段话表示,用户告诉编译器编译地址的起始(或者说可以理解是为加载的地址,这样就能做到编译地址和运行地址的统一了)

/*

 * 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

/*上面这些代码,主要保存一些全局变量,用于BOOT程序从FLASH拷贝到RAM,或者其他的使用。还有一些变量的值是通过连接脚本得到的,比如TEXT_BASE位于/u-boot-1.1.6/board/xxx(开发板目录名称)/config.mk文件里,_bss_start、_end位于/u-boot-1.1.6/board/xxx(开发板目录名称)/u-boot.lds文件里,具体值是由编译器算出来的。

*/

/*

 * the actual reset code  //系统复位代码。系统一上电,就跳转到这里运行

 */

reset:

/*

 * set the cpu to SVC32 mode //svc为操作系统保护模式

 */

mrs r0,cpsr  //取得当前程序状态寄存器cpsr到r0

bic r0,r0,#0x1f //这里是位清除指令,把中断全部清除,只置位模式控制位。为中断提供服务的通常是0S,设备驱动程序的责任,因此在Bootloader的执行过程中可以不必响应任何中断。

orr r0,r0,#0xd3 //计算为超级保护模式

msr cpsr,r0//设置cpsr为超级保护模式

/*以上设置的作用:

设置CPU运行在SVC32模式,ARM共有7种模式:

用户模式(usr):arm处理器正常的程序执行状态

快速中断模式(fiq):用于高速数据传输或通道处理

超级保护模式(svc):操作系统使用的保护模式

数据访问终止模式(abt):当数据或指令预终止时进入该模式,可用于虚拟存储及存储保护

系统模式(sys):运行具有特殊的操作系统任务

未定义指令中止模式(uud):当未定义的指令执行时进入该模式。可用于支持硬件协处理器的软件仿真。

通过设置ARM的CPSR寄存器,让CPU运行在操作系统保护模式,为后面进行其他操作做好准备工作。

*/

#if defined(CONFIG_S3C2443) ||defined(CONFIG_S3C2450) || defined(CONFIG_S3C2416)

/*

 * Retention IO power will be turen off whel sleep mode,

 * but, when wakeup process starts, User should write '1'

 * produce power on retention IO. PM check

 */

ldr r0, =0x4c00006c

ldr r1, =0x4c000064

ldr r2, [r0]

tst  r2, #0x8

ldreq r2, [r1]

orreq r2, r2, #0x10000  /* (1<<16) */

streq r2, [r1]

#endif

/*

 * we do sys-critical inits only at reboot,

 * not when booting from ram!

 */

/*

1、关闭MMU和CPU内部指令/数据(I/D)cache

2、设置CPU的速度和时钟频率

3、RAM初始化

*/

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

/*

MCR指令用于将ARM处理器寄存器中的数据传输到协处理器寄存器中,格式为:

MCR 协处理器编码 ,协处理器操作码 1,源寄存器,目的寄存器1,目的寄存器2,协处理器操作码2。

其中协处理器操作码1和协处理器操作码2为协处理器将要执行的操作,源寄存器为ARM处理器的寄存器,目的寄存器1和目的寄存器2均为协处理器的寄存器。

*/

/*

 * disable MMU stuff and caches禁止MMU和chache

 */

mrc p15, 0, r0, c1, c0, 0 //先把c1和c0寄存器的各位置0(r0=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

/*

  * led GPH12 on

 */

#ifdef no_comiple

test1:

mov r1,#0x56000000

add r1,r1,#0x20 // set offset address

ldr r2,=(1<<6)

str     r2,[r1,#0x0] // set GPC3 as output

ldr  r2,=(0<<6)

str r2,[r1,#0x8] // disable pull-up/down

ldr r2,=(1<<3)

str r2,[r1,#0x4] // output low level

#endif 

#ifdef CONFIG_ONENAND

/*

 * With this check, we can change boot sequence as we want in run-time. * XXX: must modify to use "swp" not "ldr and str".

 */

check_onenand_boot:

mov r0, #0x1e400 /* check OneNAND via start buffer reg */

ldr r1, =0xfffffffe /* very tweaky and may occur bugs */

ldr r2, =0x00000f02

ldr r3, [r0]

str r1, [r0]

ldr r1, [r0]

str r3, [r0]

cmp r1, r2

bne 1024f

/* OneNAND is detected as boot device

 * So, load <0x400 ~ 0xc00> to DataRam0

 */

fill_onenand_dr:

mov r2, #0

ldr r3, =0x0001e200

ldr r5, =0x0002 /* 0x400 ~ 0x800 */

ldr r6, =0x0001e400

ldr r7, =0x0802 /* fill 1KB in DR0 */

100: strh r2, [r3] /* block = 0, data buffer = 0 */

strh r2, [r3, #0x2] /* block = 0, data buffer = 0 */

strh r5, [r3, #0xe] /* set page, sector addr */

strh r7, [r6] /* set start buffer and count */

strh r2, [r6, #0x82] /* reset int status */

strh r2, [r6, #0x40] /* send LOAD command */

1: ldrh r8, [r6, #0x82] /* check int status */

tst r8, #(1<<15)

beq 1b

tst r5, #4;

ldr r5, =0x0004 /* 0x800 ~ 0xc00 */

add r7, r7, #0x0200 /* fill next 1KB 0x0a02 */

beq 100b

b 1024f

.ltorg /* without it, variables may go too far. */

1024:

#endif

/*

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

 */

bl lowlevel_init /* go setup pll,mux,memory */

/*进入lowlevel_init,这里主要是初始化存储寄存器,S3C2416的是Bank0-Bank6,比如位宽等,这个要根据自己的板子来进行响应的配置,比如网卡放在几个Bank,位宽多少,SDRAM放在那里,多大等。位于board/smdk2416/lowlevel_init.S:用于完成芯片存储器的初始化,执行完成后返回*/

#ifdef CONFIG_S3C2442

#ifdef CONFIG_PM

@ Check if this is a wake-up from sleep

ldr r1, PMST_ADDR

ldr r0, [r1]

tst r0, #0x8 @ PMST_SMR

bne WakeupStart

#endif

#endif

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

 */

check_boot_device:

ldr r0, =0xff000fff

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_MOVINAND

ldr sp, _TEXT_PHY_BASE

bl movi_bl2_copy

b after_copy

#endif

/* check boot device is nand or nor */

ldr r0, =0x00000000

ldr r3, [r0]

ldr r1, =0xfffffffe

str r1, [r0]

ldr r2, [r0]

str r3, [r0]

cmp r1, r2

#if defined(CONFIG_S3C2450) || defined(CONFIG_S3C2416)

/* Now iROM on 2450 is not support eFuse */

#if 1

b nand_copy

#else

beq nand_copy

#endif

#else

beq nand_copy

#endif

#ifdef CONFIG_ONENAND

ldr r3, [r0, #0x400]

ldr r1, =0xfffffffe

str r1, [r0, #0x400]

ldr r2, [r0, #0x400]

str r3, [r0, #0x400]

cmp r1, r2

beq jump_to_onenand

#endif

/* nor copy */

relocate: /* relocate U-Boot to RAM     */

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

//取得_start的地址到r0。如果是在flash中运行,则_start的值就是0,如果是在RAM中运行,则_start=_TEXT_BASE=TEXT_BASE=0X33F80000。

(_TEXT_BASE在board/smdk2416/config.mk中定义)

@ ldr r1, _TEXT_BASE//把_TEXT_BASE地址处的值_TEXT_BASE,也就是BOOT在RAM中运行地址移到r1。测试时在flash还是在ARM

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

ldr r2, _armboot_start /*把_armboot_start 地址处的值也就是_start绝对地址(也就是在内存中的地址,这个绝对地址是在Link的时候确定的,如0x81008000)移到r2*/

ldr r3, _bss_start /*把_bss_start地址处的值也就是_bss_start绝对地址(也即在内存中的地址,这个绝对地址是在Link的时候确定的)移到r3*/

sub r2, r3, r2 /* r2 <- size of armboot*//*计算引导代码大小并存放到r2*/

add r2, r0, r2 /* r2 <- source end address*//*计算引导代码最后相对地址并存入R2*/

copy_loop:  //重定位代码

ldmia r0!, {r3-r10} /* copy from source address [r0]    */

/*从源地址[r0]读取32个字节到寄存器,并更新r0*/

stmia r1!, {r3-r10} /* copy to   target address [r1]    */

/*拷贝寄存器R3-R10的32个字节值保存到[r1]指明的地址,并更新R1的值*/

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

/*循环拷贝,直到把所有的引导代码移植到内存*/

ble copy_loop

b after_copy

nand_copy:

mov r0, #0x1000

bl copy_from_nand

#ifdef CONFIG_ONENAND

b after_copy

jump_to_onenand:

bl temp_copy_onenand

onenand_copy:

mov r0, #0x400

bl copy_from_nand

#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

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

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

#endif

/* Set up the stack*/

//初始化堆栈,为第二阶段的C语言做准备

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

//数据段_bss_start ßà_bss_end的初始化

clear_bss:

ldr r0, _bss_start /* find start of bss segment*/

/*把_bss_start地址处存储的绝对地址移到r0*/

ldr r1, _bss_end /* stop here*/

/*把_bss_end 的地址处存储的绝对地址移到R1*/

mov  r2, #0x00000000 /* clear*/

//初始化直接使用汉字,一次就是64个位

clbss_l:str r2, [r0] /* clear loop...*/

/*str指令用于从源寄存器中r2将一个32位的字数据传送到寄存器[r0]*/

add r0, r0, #4

cmp r0, r1

ble clbss_l /*小于或者等于跳转*/

ldr pc, _start_armboot  //跳转到stage2

/*

Stage1 到此结束,然后开始stage2。也就是跳转到u-boot-1.1.6/board.c àstart_armboot中运行。把_start_armboot地址处的值也就是_start_armboot绝对地址移植到PC。

*/

_start_armboot:

.word start_armboot

#ifdef CONFIG_ENABLE_MMU

_mmu_table_base:

.word mmu_table

#endif

#ifdef CONFIG_ONENAND

temp_copy_onenand:

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

ldr r1, _TEXT_PHY_BASE /* test if we run from flash or RAM */

ldr r2, =0xbff

1: 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 1b

adr r0, onenand_copy

ldr r1, _TEXT_PHY_BASE

add r0, r0, r1

mov pc, r0

.ltorg

#endif

/*

 * copy U-Boot to SDRAM and jump to ram (from NAND or OneNAND)

 * r0: size to be compared

 */

.globl copy_from_nand

copy_from_nand:

mov r10, lr /* save return address */

mov r9, r0

/* get ready to call C functions */

ldr sp, _TEXT_PHY_BASE /* setup temp stack pointer */

sub sp, sp, #12

mov fp, #0 /* no previous frame, so fp=0 */

#ifdef CONFIG_ONENAND

cmp r9, #0x1000

bne 2f

bl copy_uboot_to_ram

b 3f

2: bl onenand_cp

#else

mov r9, #0x1000

bl copy_uboot_to_ram

#endif

3: tst  r0, #0x0

bne copy_failed

#if defined(CONFIG_S3C2450) || defined(CONFIG_S3C2416)

/* Confirm Booting Status NAND Booting or iROM NAND*/

ldr r6, =0x40008000

ldr r7, =0x24564236

swp r8, r7, [r6]

swp r5, r8, [r6]

cmp r7, r5

/* If compare value is same between r7 and r5, Booting Device is iROM */

beq 444f

mov r0, #0 /* NAND Booting */

b 555f

444:

mov r0, #0x40000000 /* iROM booting */

#else

mov r0, #0

#endif

555:

ldr r1, _TEXT_PHY_BASE

1: ldr r3, [r0], #4

ldr r4, [r1], #4

teq r3, r4

bne compare_failed /* not matched */

subs r9, r9, #4

bne 1b

4: mov lr, r10 /* all is OK */

mov pc, lr

copy_failed:

nop /* copy from nand failed */

b copy_failed

compare_failed:

nop /* compare failed */

b compare_failed

/*

 * we assume that cache operation is done before. (eg. cleanup_before_linux())

 * actually, we don't need to do anything about cache if not use d-cache in U-Boot

 * So, in this function we clean only MMU. by scsuh

 *

 * void theLastJump(void *kernel, int arch_num, uint boot_params);

 */

#ifdef CONFIG_ENABLE_MMU

.globl theLastJump

theLastJump:

mov r9, r0

ldr r3, =0xfff00000

ldr r4, _TEXT_PHY_BASE

adr r5, phy_last_jump

bic r5, r5, r3

orr r5, r5, r4

mov pc, r5

phy_last_jump:

/*

 * disable MMU stuff

 */

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

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

mov r0, #0

mov pc, r9

#endif

//以下是一些中断的定义和处理

/*******************************************************************

 *

 * Interrupt handling

 *

********************************************************************/

@

@ 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

@ carve out a frame on current user stack

sub sp, sp, #S_FRAME_SIZE

stmia sp, {r0 - r12} @ Save user registers (now in svc mode) 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

@ get values for "aborted" pc and cpsr (into parm regs)

ldmia r2, {r2 - r3}

add r0, sp, #S_FRAME_SIZE @ grab pointer to old stack

add r5, sp, #S_SP

mov r1, lr

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

mov r0, sp @ save current stack into r0 (param register)

.endm

.macro irq_save_user_regs

sub sp, sp, #S_FRAME_SIZE

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

@ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good.

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 in position 0 of saved stack

mrs lr, spsr @ get the spsr

str lr, [r13, #4] @ save spsr in position 1 of saved stack

mov r13, #MODE_SVC @ prepare SVC-Mode

@ msr spsr_c, r13

msr spsr, r13 @ switch modes, make sure moves will execute

mov lr, pc @ capture return pc

movs pc, lr @ jump to next instruction & switch modes.

.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

/*

 * exception handlers

 */

.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

#ifdef CONFIG_PM

.align 4

PMCTL1_ADDR: .long 0x56000080

PMST_ADDR: .long 0x4C000068

PMSR0_ADDR: .long 0x560000B8

GPBCON: .long 0x56000010

GPBDAT: .long 0x56000014

GPFCON_reg: .long 0x56000050

GPFDAT_reg: .long 0x56000054

.align 5

sleep_setting:

@ prepare the SDRAM self-refresh mode

ldr r0, =0x48000024 @ REFRESH Register

ldr r1, [r0]

orr r1, r1,#(1<<22) @ self-refresh bit set

@ prepare MISCCR[19:17]=111b to make SDRAM signals(SCLK0,SCLK1,SCKE) protected

ldr r2,=0x56000080 @ MISCCR Register

ldr r3,[r2]

orr r3,r3,#((1<<17)|(1<<18)|(1<<19))

@ prepare the Power_Off mode bit in CLKCON Register

ldr r4,=0x4c00000c @ CLKCON Register

ldr r5,=(1<<3)

b   set_sdram_refresh

.align 5

set_sdram_refresh:

str r1,[r0]             @ SDRAM self-refresh enable

@ wait until SDRAM into self-refresh

mov r1, #64

1:  subs    r1, r1, #1

bne 1b

@ set the MISCCR & CLKCON register for power off

str r3,[r2]

str r5,[r4]

nop                 @ waiting for power off

nop

nop

b   .

.align 5

WakeupStart:

@ Clear sleep reset bit

ldr r0, PMST_ADDR

mov r1, #(1<<1) @ PMST_SMR

str r1, [r0]

@ Release the SDRAM signal protections

ldr r0, PMCTL1_ADDR

ldr r1, [r0]

bic r1, r1, #((1<<17)|(1<<18)|(1<<19))  @ (SCLKE | SCLK1 | SCLK0)

str r1, [r0]

@ Max1718_Set();  @for case 135 i.e 300MHz operation

@ GPBCON = (GPBCON & ~((3 << 20) | (3 << 16) | (3 << 14))) | (1 << 20) | (1 << 16) | (1 << 14);

ldr r1, GPBCON

ldr r0, [r1]

bic r0, r0, #( (3 << 20) | (3 << 16) | (3 << 14) )

orr r0, r0, #( (1 << 20) | (1 << 16) | (1 << 14) )

str r0, [r1]

// GPB7, 8, 10 : Output

@ GPFCON = (GPFCON & ~(0xff << 8)) | (0x55 << 8); // GPF4~7: Output , shared with LED4~7

ldr r1, GPFCON_reg

ldr r0, [r1]

bic r0, r0, #( (0xff << 8) )

orr r0, r0, #( (0x55 << 8) )

str r0, [r1]

@ GPBDAT = (GPBDAT & ~(1 << 7)) | (0 << 7);   //D4

ldr r1, GPBDAT

ldr r0, [r1]

bic r0, r0, #( (1 << 7) )

orr r0, r0, #( (0 << 7) )

str r0, [r1]

@ GPFDAT = (GPFDAT & ~(0xf << 4)) | (1 << 7) | (0 << 6) | (0 << 5) | (0 << 4);    //D3~0

ldr r1, GPFDAT_reg

ldr r0, [r1]

bic r0, r0, #( (0xf << 4) )

orr r0, r0, #( (1 << 7) | (0 << 6) | (0 << 5) | (0 << 4) ) @D3~0

str r0, [r1]

@ Go...

ldr r0, PMSR0_ADDR  @ read a return address

ldr r1, [r0]

mov pc, r1

nop

nop

1:  b   1b      @ infinite loop

#endif

对于UBOOT的relocate代码的深入理解。可以看看http://www.51hei.com/mcu/1131.html的解析。。我也把他记下来,以便以后自己复习。

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     stack_setup

     最初看到这个代码的时候,发现功能还是很简单的,就是判断uboot是放在哪里的,flash? or SDRAM?如果放在SDRAM中,就不需要再把uboot代码从flash中搬移到SDRAM中,直接跳到stack_setup;如果是放在flash里的话,则要把代码从flash中搬移到指定的SDRAM地址(TEXT_BASE)中。细看之下,又发现了点问题:它是怎么知道uboot到底放在哪呢;又要把uboot放到SDRAM的什么地址去呢,也即TEXT_BASE是多少。

    先说TEXT_BASE吧。TEXT_BASE在功能上是指示uboot将要SDRAM中存放的起始地址。(理解这个很重要)在uboot\cpu\s3c44b0\start.S中有如下声明和定义:_TEXT_BASE:。word TEXT_BASE 而在uboot\board\B2\config.mk文件中有如下赋值:TEXT_BASE = 0x0c100000。在基于dave\B2板子的uboot是把uboot放在SDRAM中的0x0c100000处的。(点击浏览下一页个人暂时认为这个TEXT_BASE应该是可以修改的,比如TEXT_BASE=0x0c100004)再说这个_start:当uboot在flash中运行的时候,_start是程序的开始,也即地址0。而当uboot在SDRAM的时候,这个_start应该是多少呢??经过反复想,点击浏览下一页反复想之后,才发现,这个_start就应该是TEXT_BASE。

 由于_start是整个uboot的开头处,所以_start在uboot中的偏移地址_start_offset=0,这个无疑义。当uboot在flash中的时候,_start=0x00000000很好理解:flash映射起始地址为0x00000000。uboot放在flash当中的话,uboot起始地址就应该为0x00000000,而_start在uboot中的偏移地址为0,所以_start的绝对物理地址就应该是0x00000000。当uboot处于SDRAM中的时候,_start=??那么它为什么又会等于TEXT_BASE=0x0c1000000呢???原因就在于,我们要把(注意:是将要把,打算把)uboot搬到TEXT_BASE=0x0c100000(这个位置属于SDRAM的映射)处。那么uboot的绝对地址就应该是TEXT_BASE,而_start在uboot中的偏移地址是0,所以_start的绝对地址就是TEXT_BASE+0=TEXT_BASE。在ldr r1,_TEXT_BASE执行之后,r1=TEXT_BASE的;而adr r0,_start执行之后呢??adr指令是基于PC的相对寻址,执行之后r0=PC+_star_offset=PC。如果uboot放在SDRAM中的话,那么_start的绝对地址是TEXT_BASE,也即PC=TEXT_BASE。

 至此,才明白了是如何判断是否要进行代码搬移的。

   总结:开始一直以为,uboot在SDRAM中的话,其开始地址应该是SDRAM的映射开始地址,即0x0c000000,也即_start的绝对地址应该是0x0c000000。后来才发现,uboot放在SDRAM中的位置是由程序控制的,即放在TEXT_BASE处。这才明白上面那几行代码是怎么回事了~~~

 话外音::突然间想到---TEXT_BASE是uboot在SDRAM的开始处,所以在SDRAM中的时候_start=TEXT_BASE。只有这样才能判断正确~~


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值