/*
 * 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.
 *
 * Copyright (C) 1994, 1995 Waldorf Electronics
 * Written by Ralf Baechle and Andreas Busse
 * Copyright (C) 1995 - 1999 Ralf Baechle
 * Copyright (C) 1996 Paul M. Antoine
 * Modified for DECStation and hence R3000 support by Paul M. Antoine
 * Further modifications by David S. Miller and Harald Koerfgen
 * Copyright (C) 1999 Silicon Graphics, Inc.
 *
 *  Kevin Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
 *  Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
 */
#include <linux/config.h>
#include <linux/init.h>
#include <linux/threads.h>

#include <asm/asm.h>
#include <asm/current.h>
#include <asm/offset.h>
#include <asm/processor.h>
#include <asm/regdef.h>
#include <asm/cachectl.h>
#include <asm/mipsregs.h>
#include <asm/stackframe.h>
#include <asm/bootinfo.h>

		__INIT

	.text
	/*
	 * Reserved space for exception handlers.
	 * Necessary for machines which link their kernels at KSEG0.
	 */
	.fill	0x280

	/* Cache Error */
	LEAF(except_vec2_generic)
		.set	noreorder
	.set	noat
	.set    mips0
	/*
	 * This is a very bad place to be.  Our cache error
	 * detection has triggered.  If we have write-back data
	 * in the cache, we may not be able to recover.  As a
	 * first-order desperate measure, turn off KSEG0 cacheing.
	 */
	mfc0	k0,CP0_CONFIG
	li	k1,~CONF_CM_CMASK
	and	k0,k0,k1
	ori	k0,k0,CONF_CM_UNCACHED
	mtc0	k0,CP0_CONFIG
	/* Give it a few cycles to sink in... */
	nop
	nop
	nop

	j	cache_parity_error
	nop
	END(except_vec2_generic)

	.set	at

	/*
	 * Special interrupt vector for embedded MIPS.  This is a
	 * dedicated interrupt vector which reduces interrupt processing
	 * overhead.  The jump instruction will be inserted here at
		 * initialization time.  This handler may only be 8 bytes in
		 * size!
	 */
	NESTED(except_vec4, 0, sp)
1:	j	1b			/* Dummy, will be replaced */
	 nop
	END(except_vec4)

	/*
	 * SBDDP EJTAG debug exception handler.
	 * The EJTAG debug exception entry point is 0xbfc00480, which
	 * normally is in the boot PROM, so the boot PROM must do a
	 * unconditional jump to this vector.
	 */	
	NESTED(except_vec_ejtag_debug, 0, sp)
	j	ejtag_debug_handler
	 nop
	END(except_vec_ejtag_debug)

	/*
	 * EJTAG debug exception handler.
	 */
	NESTED(ejtag_debug_handler, PT_SIZE, sp)
	.set	noat
	.set	noreorder
	SAVE_ALL
#if !defined(CONFIG_NO_PRINTK)
	PRINT("SDBBP EJTAG debug exception - not handled yet, just ignored!\n");
#endif /*--- #if !defined(CONFIG_NO_PRINTK) ---*/
	mfc0	k0, $23         # Get EJTAG Debug register.
	mfc0    k1, $24         # Get DEPC register.
	bgez	k0, 1f
	 addiu	k1, k1, 4	# SBDDP inst. in delay slot.
	addiu	k1, k1, 4
1:	mtc0	k1, $24
	RESTORE_ALL
	.word	0x4200001f      # deret, return EJTAG debug exception.
	 nop
	.set	at
	END(ejtag_debug_handler)

#ifdef CONFIG_CPU_LX45XXX
/*
 * Lexra specific vectored interrupt handlers
 */
		.org	0x700
		NESTED(lx_int_vec8, 0, sp)
		j	lx_vec_handle_int
		nop
		END(lx_int_vec8)

		NESTED(lx_int_vec9, 0, sp)
		j	lx_vec_handle_int
		nop
		END(lx_int_vec9)	

		NESTED(lx_int_vec10, 0, sp)
		j	lx_vec_handle_int
		nop
		END(lx_int_vec10)	

		NESTED(lx_int_vec11, 0, sp)
		j	lx_vec_handle_int
		nop
		END(lx_int_vec11)	

		NESTED(lx_int_vec12, 0, sp)
		j	lx_vec_handle_int
		nop
		END(lx_int_vec12)	

		NESTED(lx_int_vec13, 0, sp)
		j	lx_vec_handle_int
		nop
		END(lx_int_vec13)	

		NESTED(lx_int_vec14, 0, sp)
		j	lx_vec_handle_int
		nop
		END(lx_int_vec14)	

		NESTED(lx_int_vec15, 0, sp)
		j	lx_vec_handle_int
		nop
		END(lx_int_vec15)	
 
 	.org	0x800
#endif		

		/*
 * Kernel entry point
 */
NESTED(kernel_entry, 16, sp)
	.set	noreorder
	/* The following two symbols are used for kernel profiling. */
	EXPORT(stext)
	EXPORT(_stext)

	/*
	 * Stack for kernel and init, current variable
	 */
	la	$28, init_task_union
	addiu	t0, $28, KERNEL_STACK_SIZE-32
	subu	sp, t0, 4*SZREG

	sw	t0, kernelsp
	/* The firmware/bootloader passes argc/argp/envp
	 * to us as arguments.  But clear bss first because
	 * the romvec and other important info is stored there
	 * by prom_init().
	 */
	la	t0, _edata
	sw	zero, (t0)
	la	t1, (_end - 4)
1:
	addiu	t0, 4
	bne	t0, t1, 1b
	 sw	zero, (t0)

	jal	init_arch
	 nop
	END(kernel_entry)


#ifdef CONFIG_SMP

/*
 * SMP slave cpus entry point.  Board specific code
 * for bootstrap calls this function after setting up
 * the stack and gp registers. 
 */
	LEAF(smp_bootstrap)
	.set push
	.set noreorder
	mtc0	zero, CP0_WIRED
	CLI
	mfc0	t0, CP0_STATUS
	li	t1, ~(ST0_CU1|ST0_CU2|ST0_CU3|ST0_BEV); 
	and	t0, t1
	or	t0, (ST0_CU0|ST0_KX|ST0_SX|ST0_FR);
	addiu	a0, zero, 0
	jal	start_secondary
         mtc0	t0, CP0_STATUS
	.set pop
	END(smp_bootstrap)
#endif
	

/*
 * This buffer is reserved for the use of the cache error handler.
 */
		.data
		EXPORT(cache_error_buffer)
		.fill	32*4,1,0

		__FINIT

		.comm	kernelsp, NR_CPUS * 8, 8
		.comm	pgd_current, NR_CPUS * 8, 8

		.text
		.org	0x1000
EXPORT(swapper_pg_dir)

		.org	0x2000
EXPORT(empty_bad_page)

		.org	0x3000
EXPORT(empty_bad_page_table)

		.org	0x4000
EXPORT(invalid_pte_table)

		.org	0x5000
/*
 * Odd MIPS as behaviour but no bug - this label is required to keep as from
 * trying to be too clever ...
 */
dummy:

/*
 * Align to 8kb boundary for init_task_union which follows in the
 * .text segment.
 */
#if CONFIG_KERNEL_STACK_SIZE_SHIFT == 1
		.align	13
#endif
#if CONFIG_KERNEL_STACK_SIZE_SHIFT == 2
		.align	14
#endif
#if CONFIG_KERNEL_STACK_SIZE_SHIFT == 3
		.align	15
#endif
