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