uboot的函数入口要查看链接脚本中ENTTRY的入口参数,我们这里的链接脚本在board/samsung/x210/u-boot.lds,这个文件里面的开头有一句
ENTRY(_start),所以uboot的入口就是在_start这个标识的地方。

 * Base codes by scsuh (sc.suh)

 */

//x210_sd.h对开发板的宏定义配置文件,这个文件会被用来生成一个autoconfig.mk文件,这个文件会被主Makefile引入,指导整个编译过程

#include //config.h文件在incline目录下,这个文件不是源码中本身存在的,而是配置过程中自动生成的(mkconfig脚本),这个文件的内容是#include,包含x21_sd.h这个头文件。这个文件里面是很多宏定义

#include  //include/version.h包含了include/version_autogenerated.h,这个头文件是配置过程自动生成的。

这个头文件的内容是uboot的版本号。这个版本号在uboot启动时会被打印出来

#if defined(CONFIG_ENABLE_MMU)

#include   //asm/proc实际上是一个连接符号,因此实际包含的文件是include/asm-arm/proc-armv/domain.h。在mkconfig中,根据传入的6个参数,产生了很多链接符号,这些链接符号就是为了移植性而出现的。这样可以通过不同的配置得到不同的头文件。

#endif

#include 



/*

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

 *

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

 *

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

 */


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


/*

.word 汇编伪指令,定义四字节的变量,值就是 0x2000,地址就是当前的地址。相当于是一个数组  0x2000  0x0   0x0   0x0 共16字节为后面计算校验和填充占位,这16字节的占位是为了保证正式的p_w_picpath的头部确实有16字节,

*/

    .word 0x2000 

    .word 0x0  

    .word 0x0  //但是这16字节的内容是不对的,需要后面去计算校验和,然后重新填充

    .word 0x0

#endif


.globl _start

_start: b    reset 

/*

异常向量的构建,异常向量表中的每一种异常都需要处理,但是我们在uboot中并未非常细致的处理各种异常,原因是uboot执行的时间很短,异常比较少,如果发生异常,重启即可。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  

/*

意思是,如果当前地址不对齐则自动向后走地址直到对齐,并且向后走的那些内存要用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

/*

 mkconfig中提到的那个链接时指定uboot的链接地址(值就是0xc3e00000这是一个虚拟地址)

这两行相当于是一个指针,指针名为TEXT_BASE,所以我们后面可以直接ld TEXT_BASE   来使用TEXT_BASE  这个值,源代码中和配置Makefile中很多变量是可以互相运送的,简单来说有些符号的值可以从Makefile中传递到源代码中。

_TEXT_BASE:  

    .word    TEXT_BASE


_TEXT_BASE:一个标识符号,类似一个指针

   .word :相当于一个四字节的变量

TEXT_BASE :一个值

这样将来我们使用lds去加载_TEXT_BASE这个标识的时候就可以直接加载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  //33e00000  uboot在DDR中的物理地址


.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


/*

 * the actual reset code  真正的复位代码

 */


reset:

    /*

     * set the cpu to SVC32 mode and IRQ & FIQ disable

     */

    msr    cpsr_c, #0xd3    

/*

 I & F disable, Mode: 0x13 - SVC,C位也就是I F mode 这三位(0-7这个8位)

0xd3=11010011,对应到这8位分别 I=1 F=1 T=0 mode=0x13 对应为SVC模式。ARMCPU在复位时默认是工作在SVC模式下的,这里只是为了保险起见,在软件上再次将其设置为SVC模式。整个uboot启动过程中都是工作在SVC模式。

在我们的cpsr寄存器的C位写上0xd3

cpsr:程序状态寄存器,

*/


/*

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

 *

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


    bl    disable_l2cache     //禁止L2 cache


    bl    set_l2cache_auxctrl_cycle  //l2 cache相关的初始化


    bl    enable_l2cache   //使能l2 cache


       /*

        * Invalidate L1 I/D     //刷新l1 cache 的icache 和dchahce

        */

        mov    r0, #0                  @ set up for MCR

        mcr    p15, 0, r0, c8, c7, 0   @ invalidate TLBs

        mcr    p15, 0, r0, c7, c5, 0   @ invalidate icache


       /*

        * disable MMU stuff and caches  //关闭 MMU

        */

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

        bic    r0, r0, #0x00002000     @ clear bits 13 (--V-)

        bic    r0, r0, #0x00000007     @ clear bits 2:0 (-CAM)

        orr    r0, r0, #0x00000002     @ set bit 1 (--A-) Align

        orr    r0, r0, #0x00000800     @ set bit 12 (Z---) BTB

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

//总结:上面5步都是和CPU和MMU有关的,不用去细看,大概知道即可


        /* Read booting information */ 

/*

启动介质的选择也就是芯片的OM5-OM0这6个引脚的电平高低来决定的,对应的寄存为0xE0000004,这个寄存器的值会根据OM引脚上的电平高低而自动设置,我们通过读这个寄存器的值就可以确定是从哪种介质启动(Nand,SD卡还是其他)。

*/

        ldr    r0, =PRO_ID_BASE     //0xE0000000

        ldr    r1, [r0,#OMR_OFFSET]   //0x04      r1 0xE0000004

        bic    r2, r1, #0xffffffc1  

/*

r2 里面存放的就是这个值,如下所示,根据r2的值来确定启动方式。bic 位清除 将r1的和 #0xffffffc1的反码进行按位与,得到的值写入r1寄存器中。

*/


    /* NAND BOOT */

    cmp    r2, #0x0        @ 512B 4-cycle

    moveq    r3, #BOOT_NAND


    cmp    r2, #0x2        @ 2KB 5-cycle

    moveq    r3, #BOOT_NAND


    cmp    r2, #0x4        @ 4KB 5-cycle    8-bit ECC

    moveq    r3, #BOOT_NAND


    cmp    r2, #0x6        @ 4KB 5-cycle    16-bit ECC

    moveq    r3, #BOOT_NAND


    cmp    r2, #0x8        @ OneNAND Mux

    moveq    r3, #BOOT_ONENAND


    /* SD/MMC BOOT */

    cmp     r2, #0xc

    moveq   r3, #BOOT_MMCSD  

/*

BOOT_MMCSD  实际是一个宏,值是0x03,也就是将0x03放到r3中以备后用(判断从哪个通道启动)

*/

    /* NOR BOOT */

    cmp     r2, #0x14

    moveq   r3, #BOOT_NOR    


    /* Uart BOOTONG failed */

    cmp     r2, #(0x1<<4)

    moveq   r3, #BOOT_SEC_DEV


    ldr    r0, =INF_REG_BASE

    str    r3, [r0, #INF_REG3_OFFSET]       

//将我们的r3,也就是BOOT_MMCSD 的值放到[r0, #INF_REG3_OFFSET]中保存,后用


    /*

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

     */

    ldr    sp, =0xd0036000 /* end of sram dedicated to u-boot */

//设置栈,记住SP5PV210是满减栈,也就是入栈时向下延伸

    sub    sp, sp, #12    /* set stack */

    mov    fp, #0

/*

第一次设置栈,因为当前整个代码还在SRAM(96KB)中运行,此时DDR还未被初始化,还不能使用,所以设置的栈也是在SRAM中的。栈地址0xd0036000 是自己指定的,指定的原则是这个空间只能给栈用,不会被别人占用。

*/

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

/*

底层初始化,也就是CPU里面的东西,这里需要调用函数,所以需要栈,故上面要把栈设置好。在调用函数之前初始化栈,主要原因是在被调用的函数内还有再次调用函数,而BL只会将返回地址存储到LR中,但是我们只有一个LR,所以在第二层调用函数前要先将LR入栈,否则函数返回时第一层的返回地址就丢了。

这个函数的位置:lowlevel_init.S (i:\windows_share\uboot\board\samsung\x210):lowlevel_init

总结:lowlevel_init.S这个文件主要做了以下事情

检查复位状态   IO恢复  关看门狗   开发板的供电锁存   时钟初始化  DDR初始化  串口初始化并打印'O'  tzpc初始化    打印'K'

*/

    /* To hold max8698 output before releasing power on switch,

     * set PS_HOLD signal to high

/*

      开发板供电锁存,(第二次),其实没意义,因为在lowlevel_init 已经做了,但是做两次也不会出错(可能是移植的人没注意)

*/

    ldr    r0, =0xE010E81C  /* PS_HOLD_CONTROL register */

    ldr    r1, =0x00005301     /* PS_HOLD output high    */

    str    r1, [r0]


    /* get ready to call C functions

/*

 设置DDR中的栈,之前设置的是SRAM中的栈,因为那个时候DDR还没有初始化,所以在SRAM中分配了一部分的内存供给栈使用,现在DDR已经被初始化,所以需要把栈挪移到DDR上。

*/

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

    sub    sp, sp, #12

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


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

     */

/*

再次判断运行位置是在SRAM还是DDR,本次判断的目的不同,之前在lowlevel_inti判断是为了判断是否执行时钟初始化和DDR初始化,这里再次判断是为了判断是否要进行重定位。

在我们冷启动的时候,uboot的第一部分(BL1)开机自动从SD卡加载到SRAM中正在运行,uboot的第二部分(BL2:整个uboot)还在SD卡中,运行到这里时uboot的第一阶段即将结束,但是在结束之前要将第二部分加载到DDR的链接地址处(也就是33e00000)。

*/

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


#if defined(CONFIG_EVT1)

    /* If BL1 was copied from SD/MMC CH2 */

    ldr    r0, =0xD0037488 

/*

这个内存地址的值是被硬件自动设置的,硬件根据SD//卡在哪个通道中,会将这个地址的内容设置为相应的值

*/

    ldr    r1, [r0] 

  //譬如我们从SD0通道启动时,这个值为EB000000;从SD2通道/启动时这个值为EB20000

    ldr    r2, =0xEB200000

    cmp    r1, r2

    beq     mmcsd_boot

/*

如果相等则直接执行mmcsd_boot  

如果我们不是从外部的SD卡启动,而是从内部的iNand启动,则不会相等那么就会往下执行

*/

#endif

//这里其实也是在判断从哪里启动

    ldr    r0, =INF_REG_BASE  

    ldr    r1, [r0, #INF_REG3_OFFSET] 

//读取[r0, #INF_REG3_OFFSET]中的值(这个值我们在之前已经根据启动通道设置好了

    cmp    r1, #BOOT_NAND        /* 0x0 => boot device is nand */

    beq    nand_boot

    cmp    r1, #BOOT_ONENAND    /* 0x1 => boot device is onenand */

    beq    onenand_boot

    cmp     r1, #BOOT_MMCSD 

/*

通过前面的分析可知即使没有上面那部分,最终还是会进入到(如果是SD卡启动)mmcsd_boot这个函数中去

*/

    beq     mmcsd_boot             //进行重定位,具体单参照mmcsd_boot

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

mmcsd_boot:

#if DELETE

    ldr     sp, _TEXT_PHY_BASE      

    sub     sp, sp, #12

    mov     fp, #0

#endif

    bl      movi_bl2_copy   

// 跳转到这个函数,这个函数是一个语言函数,在uboot/cpu/s5pc11x/movi.c中, 在这个函数里面通过一定的宏定义和判断最终调用copy_bl2(2, MOVI_BL2_POS, MOVI_BL2_BLKCNT,CFG_PHY_UBOOT_BASE, 0);函数来完成重定位

参数分析:

2:通道号。2表示SD通道2也就是外部的SD卡,0表示通道0,也就是内部iNand

MOVI_BL2_POS:BL2在SD卡中的开始的扇区号,这个必须和在SD卡烧录uboot时的相同

MOVI_BL2_BLKCNT:uboot的长度占用的扇区数(这里我们定义的uboot是2K)

CFG_PHY_UBOOT_BASE:重定位时将uboot的BL2复制到DDR中的起始地址,其实就是33e00020。


    b       after_copy

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

    cmp     r1, #BOOT_NOR

    beq     nor_boot

    cmp     r1, #BOOT_SEC_DEV

    beq     mmcsd_boot


nand_boot:

    mov    r0, #0x1000

    bl    copy_from_nand

    b    after_copy


onenand_boot:

    bl    onenand_bl2_copy

    b    after_copy


mmcsd_boot:

#if DELETE

    ldr     sp, _TEXT_PHY_BASE      

    sub     sp, sp, #12

    mov     fp, #0

#endif

    bl      movi_bl2_copy

    b       after_copy


nor_boot:

    bl      read_hword

    b       after_copy



after_copy:   //重定位完成


//虚拟地址映射

#if defined(CONFIG_ENABLE_MMU)

enable_mmu:

    /* enable domain access */

    ldr    r5, =0x0000ffff

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

//mrc :读CP15协处理器里面的寄存器   mcr:写CP15协处理器里面的寄存器


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

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

    nop

    nop

    nop

    nop

#endif


skip_hw_init:

    /* Set up the stack    

/*

第三次设置栈 ,这次设置栈还是在DDR中,之前虽然已经在DDR中已经设置过一次栈了,但是本次设置栈的目的是将栈是将栈放在比较合适(安全,紧凑而不浪费内存的地方。

我们实际将栈设置在uboot起始地址(33e00000)上方2MB(341FFFFF)大小的地方,实际供栈使用的空间为2M-200K(uboot大小)-0x1000)                       

*/

stack_setup:

#if defined(CONFIG_MEMORY_UPPER_CODE)

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

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

#if defined(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:  //清bss段,BSS段主要用来存放未初始化的全局变量和未初始化的局部静态变量

    ldr    r0, _bss_start        /* find start of bss segment        */注意这里表示bss段开头和结尾的符号的bss_start 和bss_start是从我们的链接脚本u-boot.lds中得来的

    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

/* 

uboot第一阶段的最后一句话:指针指向_start_armboot这个C语言函数,这个函数就是我们uboot的第二阶段,所以这句代码的作用就是将uboot第二阶段执行的函数地址给PC,实际上就是用一个远跳转直接跳转到DDR中的第二节点开始地址处。

远跳转的含义就是这句话加载的地址和当前运行地址无关,而和链接地址有关,因此这个远跳可以实现从SRAM中的第一阶段跳转到DDR中的第二阶段

总结:uboot第一阶段做的事情

1 构建异常向量表  2 设置CPU为SVC模式   

3 进入low_lever_init.S  

(1)关看门狗 (2 )开icache  (3)开发板供电自锁  (4)根据判断当前执行的位置在SRAM还是DDR来判断是否初始化时钟和DDR (5)串口初始化并打印'OK'

4 DDR重定位,将SD卡中的uboot搬移到DDR中

5 建立虚拟地址映射表并开启MMU

6 跳转到第二阶段

*/

_start_armboot:

    .word start_armboot


#if defined(CONFIG_ENABLE_MMU)

_mmu_table_base:

    .word mmu_table

#endif


/*

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

 * r0: size to be compared

 * Load 1'st 2blocks to RAM because U-boot's size is larger than 1block(128k) size

 */

    .globl copy_from_nand

copy_from_nand:

    push    {lr}        /* save return address */


    mov    r9, r0


    mov    r9, #0x100        /* Compare about 8KB */

    bl    copy_uboot_to_ram

    tst     r0, #0x0

    bne    copy_failed


#if defined(CONFIG_EVT1)

    ldr    r0, =0xd0020000

#else    

    ldr    r0, =0xd0030000

#endif

    ldr    r1, _TEXT_PHY_BASE    /* 0x23e00000 */


#if !defined(CONFIG_SECURE_BOOT)

1:    ldr    r3, [r0], #4

    ldr    r4, [r1], #4

    teq    r3, r4

    bne    compare_failed    /* not matched */

    subs    r9, r9, #4

    bne    1b

#endif

    pop    {pc}        /* all is OK */


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);

 */

#if defined(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

    sub    sp, sp, #S_FRAME_SIZE        @ carve out a frame on current user stack

    stmia    sp, {r0 - r12}            @ Save user registers (now in svc mode) r0-r12


    ldr    r2, _armboot_start

    sub    r2, r2, #(CFG_MALLOC_LEN)

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

    ldmia    r2, {r2 - r3}            @ get values for "aborted" pc and cpsr (into parm regs)

    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

    add    r8, sp, #S_PC            @ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good.

    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 (enter in banked mode)

    sub    r13, r13, #(CFG_MALLOC_LEN)    @ move past malloc pool

    sub    r13, r13, #(CFG_GBL_DATA_SIZE+8) @ move to reserved a couple spots for 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_bad_stack_swi

    sub    r13, r13, #4            @ space on current stack for scratch reg.

    str    r0, [r13]            @ save R0's value.

    ldr    r0, _armboot_start        @ get data regions start

    sub    r0, r0, #(CFG_MALLOC_LEN)    @ move past malloc pool

    sub    r0, r0, #(CFG_GBL_DATA_SIZE+8)    @ move past gbl and a couple spots for abort stack

    str    lr, [r0]            @ save caller lr in position 0 of saved stack

    mrs    r0, spsr            @ get the spsr

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

    ldr    r0, [r13]            @ restore r0

    add    r13, r13, #4            @ pop stack entry

    .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_swi

    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


#if defined(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

    .align 5

.global arm_cache_flush

arm_cache_flush:

       mcr     p15, 0, r1, c7, c5, 0           @ invalidate I cache

       mov     pc, lr                          @ back to caller


/*

 *     v7_flush_dcache_all()

 *

 *     Flush the whole D-cache.

 *

 *     Corrupted registers: r0-r5, r7, r9-r11

 *

 *     - mm    - mm_struct describing address space

 */

       .align 5

.global v7_flush_dcache_all

v7_flush_dcache_all:


    ldr    r0, =0xffffffff

    mrc    p15, 1, r0, c0, c0, 1         @ Read CLIDR

    ands    r3, r0, #0x7000000

    mov    r3, r3, LSR #23               @ Cache level value (naturally aligned)

    beq     Finished

    mov    r10, #0

Loop1:         

    add    r2, r10, r10, LSR #1          @ Work out 3xcachelevel

    mov    r1, r0, LSR r2                @ bottom 3 bits are the Ctype for this level

    and    r1, r1, #7                    @ get those 3 bits alone

    cmp    r1, #2

    blt    Skip                           @ no cache or only instruction cache at this level

    mcr    p15, 2, r10, c0, c0, 0         @ write the Cache Size selection register

    mov    r1, #0

    mcr    p15, 0, r1, c7, c5, 4         @ PrefetchFlush to sync the change to the CacheSizeID reg

    mrc    p15, 1, r1, c0, c0, 0         @ reads current Cache Size ID register

    and    r2, r1, #0x7                   @ extract the line length field

    add    r2, r2, #4                    @ add 4 for the line length offset (log2 16 bytes)

    ldr    r4, =0x3FF

    ands    r4, r4, r1, LSR #3           @ R4 is the max number on the way size (right aligned)

    clz    r5, r4                        @ R5 is the bit position of the way size increment

    ldr    r7, =0x00007FFF

    ands    r7, r7, r1, LSR #13          @ R7 is the max number of the index size (right aligned)

Loop2:         

    mov    r9, r4                          @ R9 working copy of the max way size (right aligned)

Loop3:         

    orr    r11, r10, r9, LSL r5            @ factor in the way number and cache number into R11

    orr    r11, r11, r7, LSL r2            @ factor in the index number

    mcr    p15, 0, r11, c7, c6, 2         @ invalidate by set/way

    subs    r9, r9, #1                     @ decrement the way number

    bge    Loop3

    subs    r7, r7, #1                     @ decrement the index

    bge    Loop2

Skip:          

    add    r10, r10, #2                    @ increment the cache number

    cmp    r3, r10

    bgt    Loop1

Finished:

    mov    pc, lr


       .align  5

.global disable_l2cache

disable_l2cache:

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

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

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

    mov    pc, lr



       .align  5

.global enable_l2cache

enable_l2cache:

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

    orr     r0, r0, #(1<<1)

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

    mov     pc, lr


       .align  5

.global set_l2cache_auxctrl

set_l2cache_auxctrl:

    mov    r0, #0x0

    mcr     p15, 1, r0, c9, c0, 2

    mov     pc, lr


       .align  5

.global set_l2cache_auxctrl_cycle

set_l2cache_auxctrl_cycle:

    mrc     p15, 1, r0, c9, c0, 2

    bic     r0, r0, #(0x1<<29)

    bic     r0, r0, #(0x1<<21)

    bic     r0, r0, #(0x7<<6)

    bic     r0, r0, #(0x7<<0)

    mcr     p15, 1, r0, c9, c0, 2

    mov     pc,lr


    .align 5

CoInvalidateDCacheIndex:

    ;/* r0 = index */

    mcr     p15, 0, r0, c7, c6, 2

    mov     pc,lr



#if defined(CONFIG_INTEGRATOR) && defined(CONFIG_ARCH_CINTEGRATOR)

/* Use the IntegratorCP function from board/integratorcp/platform.S */

#elif defined(CONFIG_S5PC11X)

/* For future usage of S3C64XX*/

#else

    .align    5

.globl reset_cpu

reset_cpu:

    ldr    r1, rstctl    /* get addr for global reset reg */

    mov    r3, #0x2    /* full reset pll+mpu */

    str    r3, [r1]    /* force reset */

    mov    r0, r0

_loop_forever:

    b    _loop_forever

rstctl:

    .word    PM_RSTCTRL_WKUP


#endif