root/arch/nios2/kernel/head.S
/*
 * Copyright (C) 2009 Wind River Systems Inc
 *   Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com
 * Copyright (C) 2004 Microtronix Datacom Ltd
 * Copyright (C) 2001 Vic Phillips, Microtronix Datacom Ltd.
 *
 * Based on head.S for Altera's Excalibur development board with nios processor
 *
 * Based on the following from the Excalibur sdk distribution:
 *      NA_MemoryMap.s, NR_JumpToStart.s, NR_Setup.s, NR_CWPManager.s
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License. See the file "COPYING" in the main directory of this archive
 * for more details.
 */

#include <linux/init.h>
#include <linux/linkage.h>
#include <asm/thread_info.h>
#include <asm/processor.h>
#include <asm/cache.h>
#include <asm/page.h>
#include <asm/asm-offsets.h>
#include <asm/asm-macros.h>

/*
 * ZERO_PAGE is a special page that is used for zero-initialized
 * data and COW.
 */
.data
.global empty_zero_page
.align 12
empty_zero_page:
        .space  PAGE_SIZE

/*
 * This global variable is used as an extension to the nios'
 * STATUS register to emulate a user/supervisor mode.
 */
        .data
        .align  2
        .set noat

        .global _current_thread
_current_thread:
        .long   0
/*
 * Input(s): passed from u-boot
 *   r4 - Optional pointer to a board information structure.
 *   r5 - Optional pointer to the physical starting address of the init RAM
 *        disk.
 *   r6 - Optional pointer to the physical ending address of the init RAM
 *        disk.
 *   r7 - Optional pointer to the physical starting address of any kernel
 *        command-line parameters.
 */

/*
 * First executable code - detected and jumped to by the ROM bootstrap
 * if the code resides in flash (looks for "Nios" at offset 0x0c from
 * the potential executable image).
 */
        __HEAD
ENTRY(_start)
        wrctl   status, r0              /* Disable interrupts */

        /* Initialize all cache lines within the instruction cache */
        movia   r1, NIOS2_ICACHE_SIZE
        movui   r2, NIOS2_ICACHE_LINE_SIZE

icache_init:
        initi   r1
        sub     r1, r1, r2
        bgt     r1, r0, icache_init
        br      1f

        /*
         * This is the default location for the exception handler. Code in jump
         * to our handler
         */
ENTRY(exception_handler_hook)
        movia   r24, inthandler
        jmp     r24

ENTRY(fast_handler)
        nextpc et
helper:
        stw     r3, r3save - helper(et)

        rdctl   r3 , pteaddr
        srli    r3, r3, 12
        slli    r3, r3, 2
        movia   et, pgd_current

        ldw     et, 0(et)
        add     r3, et, r3
        ldw     et, 0(r3)

        rdctl   r3, pteaddr
        andi    r3, r3, 0xfff
        add     et, r3, et
        ldw     et, 0(et)
        wrctl   tlbacc, et
        nextpc  et
helper2:
        ldw     r3, r3save - helper2(et)
        subi    ea, ea, 4
        eret
r3save:
        .word 0x0
ENTRY(fast_handler_end)

1:
        /*
         * After the instruction cache is initialized, the data cache must
         * also be initialized.
         */
        movia   r1, NIOS2_DCACHE_SIZE
        movui   r2, NIOS2_DCACHE_LINE_SIZE

dcache_init:
        initd   0(r1)
        sub     r1, r1, r2
        bgt     r1, r0, dcache_init

        nextpc  r1                      /* Find out where we are */
chkadr:
        movia   r2, chkadr
        beq     r1, r2,finish_move      /* We are running in RAM done */
        addi    r1, r1,(_start - chkadr)        /* Source */
        movia   r2, _start              /* Destination */
        movia   r3, __bss_start         /* End of copy */

loop_move:                              /* r1: src, r2: dest, r3: last dest */
        ldw     r8, 0(r1)               /* load a word from [r1] */
        stw     r8, 0(r2)               /* store a word to dest [r2] */
        flushd  0(r2)                   /* Flush cache for safety */
        addi    r1, r1, 4               /* inc the src addr */
        addi    r2, r2, 4               /* inc the dest addr */
        blt     r2, r3, loop_move

        movia   r1, finish_move         /* VMA(_start)->l1 */
        jmp     r1                      /* jmp to _start */

finish_move:

        /* Mask off all possible interrupts */
        wrctl   ienable, r0

        /* Clear .bss */
        movia   r2, __bss_start
        movia   r1, __bss_stop
1:
        stb     r0, 0(r2)
        addi    r2, r2, 1
        bne     r1, r2, 1b

        movia   r1, init_thread_union   /* set stack at top of the task union */
        addi    sp, r1, THREAD_SIZE
        movia   r2, _current_thread     /* Remember current thread */
        stw     r1, 0(r2)

        movia   r1, nios2_boot_init     /* save args r4-r7 passed from u-boot */
        callr   r1

        movia   r1, start_kernel        /* call start_kernel as a subroutine */
        callr   r1

        /* If we return from start_kernel, break to the oci debugger and
         * buggered we are.
         */
        break

        /* End of startup code */
.set at