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