176 lines
4.0 KiB
ArmAsm
176 lines
4.0 KiB
ArmAsm
|
/*
|
||
|
* 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
|