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