[PATCH] xtensa: Architecture support for Tensilica Xtensa Part 3

The attached patches provides part 3 of an architecture implementation for the
Tensilica Xtensa CPU series.

Signed-off-by: Chris Zankel <chris@zankel.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
diff --git a/arch/xtensa/kernel/Makefile b/arch/xtensa/kernel/Makefile
new file mode 100644
index 0000000..d573017
--- /dev/null
+++ b/arch/xtensa/kernel/Makefile
@@ -0,0 +1,18 @@
+#
+# Makefile for the Linux/Xtensa kernel.
+#
+
+extra-y := head.o vmlinux.lds
+
+
+obj-y := align.o entry.o irq.o coprocessor.o process.o ptrace.o semaphore.o  \
+	 setup.o signal.o syscalls.o time.o traps.o vectors.o platform.o  \
+	 pci-dma.o
+
+## windowspill.o
+
+obj-$(CONFIG_KGDB) += xtensa-stub.o
+obj-$(CONFIG_PCI) += pci.o
+obj-$(CONFIG_MODULES) += xtensa_ksyms.o module.o
+
+
diff --git a/arch/xtensa/kernel/align.S b/arch/xtensa/kernel/align.S
new file mode 100644
index 0000000..74b1e90
--- /dev/null
+++ b/arch/xtensa/kernel/align.S
@@ -0,0 +1,459 @@
+/*
+ * arch/xtensa/kernel/align.S
+ *
+ * Handle unalignment exceptions in kernel space.
+ *
+ * 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) 2001 - 2005 Tensilica, Inc.
+ *
+ * Rewritten by Chris Zankel <chris@zankel.net>
+ *
+ * Based on work from Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
+ * and Marc Gauthier <marc@tensilica.com, marc@alimni.uwaterloo.ca>
+ */
+
+#include <linux/linkage.h>
+#include <asm/ptrace.h>
+#include <asm/ptrace.h>
+#include <asm/current.h>
+#include <asm/offsets.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/thread_info.h>
+
+#if XCHAL_UNALIGNED_LOAD_EXCEPTION || XCHAL_UNALIGNED_STORE_EXCEPTION
+
+/*  First-level exception handler for unaligned exceptions.
+ *
+ *  Note: This handler works only for kernel exceptions.  Unaligned user
+ *        access should get a seg fault.
+ */
+
+/* Big and little endian 16-bit values are located in
+ * different halves of a register.  HWORD_START helps to
+ * abstract the notion of extracting a 16-bit value from a
+ * register.
+ * We also have to define new shifting instructions because
+ * lsb and msb are on 'opposite' ends in a register for
+ * different endian machines.
+ *
+ * Assume a memory region in ascending address:
+ *   	0 1 2 3|4 5 6 7
+ *
+ * When loading one word into a register, the content of that register is:
+ *  LE	3 2 1 0, 7 6 5 4
+ *  BE  0 1 2 3, 4 5 6 7
+ *
+ * Masking the bits of the higher/lower address means:
+ *  LE  X X 0 0, 0 0 X X
+ *  BE	0 0 X X, X X 0 0
+ *
+ * Shifting to higher/lower addresses, means:
+ *  LE  shift left / shift right
+ *  BE  shift right / shift left
+ *
+ * Extracting 16 bits from a 32 bit reg. value to higher/lower address means:
+ *  LE  mask 0 0 X X / shift left
+ *  BE  shift left / mask 0 0 X X
+ */
+
+#define UNALIGNED_USER_EXCEPTION
+
+#if XCHAL_HAVE_BE
+
+#define HWORD_START	16
+#define	INSN_OP0	28
+#define	INSN_T		24
+#define	INSN_OP1	16
+
+.macro __src_b	r, w0, w1;	src	\r, \w0, \w1;	.endm
+.macro __ssa8	r;		ssa8b	\r;		.endm
+.macro __ssa8r	r;		ssa8l	\r;		.endm
+.macro __sh	r, s;		srl	\r, \s;		.endm
+.macro __sl	r, s;		sll	\r, \s;		.endm
+.macro __exth	r, s;		extui	\r, \s, 0, 16;	.endm
+.macro __extl	r, s;		slli	\r, \s, 16;	.endm
+
+#else
+
+#define HWORD_START	0
+#define	INSN_OP0	0
+#define	INSN_T		4
+#define	INSN_OP1	12
+
+.macro __src_b	r, w0, w1;	src	\r, \w1, \w0;	.endm
+.macro __ssa8	r;		ssa8l	\r;		.endm
+.macro __ssa8r	r;		ssa8b	\r;		.endm
+.macro __sh	r, s;		sll	\r, \s;		.endm
+.macro __sl	r, s;		srl	\r, \s;		.endm
+.macro __exth	r, s;		slli	\r, \s, 16;	.endm
+.macro __extl	r, s;		extui	\r, \s, 0, 16;	.endm
+
+#endif
+
+/*
+ *	xxxx xxxx = imm8 field
+ *	     yyyy = imm4 field
+ *	     ssss = s field
+ *	     tttt = t field
+ *
+ *	       		 16		    0
+ *		          -------------------
+ *	L32I.N		  yyyy ssss tttt 1000
+ *	S32I.N	          yyyy ssss tttt 1001
+ *
+ *	       23			    0
+ *		-----------------------------
+ *	res	          0000           0010
+ *	L16UI	xxxx xxxx 0001 ssss tttt 0010
+ *	L32I	xxxx xxxx 0010 ssss tttt 0010
+ *	XXX	          0011 ssss tttt 0010
+ *	XXX	          0100 ssss tttt 0010
+ *	S16I	xxxx xxxx 0101 ssss tttt 0010
+ *	S32I	xxxx xxxx 0110 ssss tttt 0010
+ *	XXX	          0111 ssss tttt 0010
+ *	XXX	          1000 ssss tttt 0010
+ *	L16SI	xxxx xxxx 1001 ssss tttt 0010
+ *	XXX	          1010           0010
+ *      **L32AI	xxxx xxxx 1011 ssss tttt 0010 unsupported
+ *	XXX	          1100           0010
+ *	XXX	          1101           0010
+ *	XXX	          1110           0010
+ *	**S32RI	xxxx xxxx 1111 ssss tttt 0010 unsupported
+ *		-----------------------------
+ *                           ^         ^    ^
+ *    sub-opcode (NIBBLE_R) -+         |    |
+ *       t field (NIBBLE_T) -----------+    |
+ *  major opcode (NIBBLE_OP0) --------------+
+ */
+
+#define OP0_L32I_N	0x8		/* load immediate narrow */
+#define OP0_S32I_N	0x9		/* store immediate narrow */
+#define OP1_SI_MASK	0x4		/* OP1 bit set for stores */
+#define OP1_SI_BIT	2		/* OP1 bit number for stores */
+
+#define OP1_L32I	0x2
+#define OP1_L16UI	0x1
+#define OP1_L16SI	0x9
+#define OP1_L32AI	0xb
+
+#define OP1_S32I	0x6
+#define OP1_S16I	0x5
+#define OP1_S32RI	0xf
+
+/*
+ * Entry condition:
+ *
+ *   a0:	trashed, original value saved on stack (PT_AREG0)
+ *   a1:	a1
+ *   a2:	new stack pointer, original in DEPC
+ *   a3:	dispatch table
+ *   depc:	a2, original value saved on stack (PT_DEPC)
+ *   excsave_1:	a3
+ *
+ *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
+ *	     <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
+ */
+
+
+ENTRY(fast_unaligned)
+
+	/* Note: We don't expect the address to be aligned on a word
+	 *       boundary. After all, the processor generated that exception
+	 *       and it would be a hardware fault.
+	 */
+
+	/* Save some working register */
+
+	s32i	a4, a2, PT_AREG4
+	s32i	a5, a2, PT_AREG5
+	s32i	a6, a2, PT_AREG6
+	s32i	a7, a2, PT_AREG7
+	s32i	a8, a2, PT_AREG8
+
+	rsr	a0, DEPC
+	xsr	a3, EXCSAVE_1
+	s32i	a0, a2, PT_AREG2
+	s32i	a3, a2, PT_AREG3
+
+	/* Keep value of SAR in a0 */
+
+	rsr	a0, SAR
+	rsr	a8, EXCVADDR		# load unaligned memory address
+
+	/* Now, identify one of the following load/store instructions.
+	 *
+	 * The only possible danger of a double exception on the
+	 * following l32i instructions is kernel code in vmalloc
+	 * memory. The processor was just executing at the EPC_1
+	 * address, and indeed, already fetched the instruction.  That
+	 * guarantees a TLB mapping, which hasn't been replaced by
+	 * this unaligned exception handler that uses only static TLB
+	 * mappings. However, high-level interrupt handlers might
+	 * modify TLB entries, so for the generic case, we register a
+	 * TABLE_FIXUP handler here, too.
+	 */
+
+	/* a3...a6 saved on stack, a2 = SP */
+
+	/* Extract the instruction that caused the unaligned access. */
+
+	rsr	a7, EPC_1	# load exception address
+	movi	a3, ~3
+	and	a3, a3, a7	# mask lower bits
+
+	l32i	a4, a3, 0	# load 2 words
+	l32i	a5, a3, 4
+
+	__ssa8	a7
+	__src_b	a4, a4, a5	# a4 has the instruction
+
+	/* Analyze the instruction (load or store?). */
+
+	extui	a5, a4, INSN_OP0, 4	# get insn.op0 nibble
+
+#if XCHAL_HAVE_NARROW
+	_beqi	a5, OP0_L32I_N, .Lload	# L32I.N, jump
+	addi	a6, a5, -OP0_S32I_N
+	_beqz	a6, .Lstore		# S32I.N, do a store
+#endif
+	/* 'store indicator bit' not set, jump */
+	_bbci.l	a4, OP1_SI_BIT + INSN_OP1, .Lload
+
+	/* Store: Jump to table entry to get the value in the source register.*/
+
+.Lstore:movi	a5, .Lstore_table	# table
+	extui	a6, a4, INSN_T, 4	# get source register
+	addx8	a5, a6, a5
+	jx	a5			# jump into table
+
+	/* Invalid instruction, CRITICAL! */
+.Linvalid_instruction_load:
+	j	.Linvalid_instruction
+
+	/* Load: Load memory address. */
+
+.Lload: movi	a3, ~3
+	and	a3, a3, a8		# align memory address
+
+	__ssa8	a8
+#ifdef UNALIGNED_USER_EXCEPTION
+	addi	a3, a3, 8
+	l32e	a5, a3, -8
+	l32e	a6, a3, -4
+#else
+	l32i	a5, a3, 0
+	l32i	a6, a3, 4
+#endif
+	__src_b	a3, a5, a6		# a3 has the data word
+
+#if XCHAL_HAVE_NARROW
+	addi	a7, a7, 2		# increment PC (assume 16-bit insn)
+
+	extui	a5, a4, INSN_OP0, 4
+	_beqi	a5, OP0_L32I_N, 1f	# l32i.n: jump
+
+	addi	a7, a7, 1
+#else
+	addi	a7, a7, 3
+#endif
+
+	extui	a5, a4, INSN_OP1, 4
+	_beqi	a5, OP1_L32I, 1f	# l32i: jump
+
+	extui	a3, a3, 0, 16		# extract lower 16 bits
+	_beqi	a5, OP1_L16UI, 1f
+	addi	a5, a5, -OP1_L16SI
+	_bnez	a5, .Linvalid_instruction_load
+
+	/* sign extend value */
+
+	slli	a3, a3, 16
+	srai	a3, a3, 16
+
+	/* Set target register. */
+
+1:
+
+#if XCHAL_HAVE_LOOP
+	rsr	a3, LEND		# check if we reached LEND
+	bne	a7, a3, 1f
+	rsr	a3, LCOUNT		# and LCOUNT != 0
+	beqz	a3, 1f
+	addi	a3, a3, -1		# decrement LCOUNT and set
+	rsr	a7, LBEG		# set PC to LBEGIN
+	wsr	a3, LCOUNT
+#endif
+
+1:	wsr	a7, EPC_1		# skip load instruction
+	extui	a4, a4, INSN_T, 4	# extract target register
+	movi	a5, .Lload_table
+	addx8	a4, a4, a5
+	jx	a4			# jump to entry for target register
+
+	.align	8
+.Lload_table:
+	s32i	a3, a2, PT_AREG0;	_j .Lexit;	.align 8
+	mov	a1, a3;			_j .Lexit;	.align 8 # fishy??
+	s32i	a3, a2, PT_AREG2;	_j .Lexit;	.align 8
+	s32i	a3, a2, PT_AREG3;	_j .Lexit;	.align 8
+	s32i	a3, a2, PT_AREG4;	_j .Lexit;	.align 8
+	s32i	a3, a2, PT_AREG5;	_j .Lexit;	.align 8
+	s32i	a3, a2, PT_AREG6;	_j .Lexit;	.align 8
+	s32i	a3, a2, PT_AREG7;	_j .Lexit;	.align 8
+	s32i	a3, a2, PT_AREG8;	_j .Lexit;	.align 8
+	mov	a9, a3		;	_j .Lexit;	.align 8
+	mov	a10, a3		;	_j .Lexit;	.align 8
+	mov	a11, a3		;	_j .Lexit;	.align 8
+	mov	a12, a3		;	_j .Lexit;	.align 8
+	mov	a13, a3		;	_j .Lexit;	.align 8
+	mov	a14, a3		;	_j .Lexit;	.align 8
+	mov	a15, a3		;	_j .Lexit;	.align 8
+
+.Lstore_table:
+	l32i	a3, a2, PT_AREG0;	_j 1f;	.align 8
+	mov	a3, a1;			_j 1f;	.align 8	# fishy??
+	l32i	a3, a2, PT_AREG2;	_j 1f;	.align 8
+	l32i	a3, a2, PT_AREG3;	_j 1f;	.align 8
+	l32i	a3, a2, PT_AREG4;	_j 1f;	.align 8
+	l32i	a3, a2, PT_AREG5;	_j 1f;	.align 8
+	l32i	a3, a2, PT_AREG6;	_j 1f;	.align 8
+	l32i	a3, a2, PT_AREG7;	_j 1f;	.align 8
+	l32i	a3, a2, PT_AREG8;	_j 1f;	.align 8
+	mov	a3, a9		;	_j 1f;	.align 8
+	mov	a3, a10		;	_j 1f;	.align 8
+	mov	a3, a11		;	_j 1f;	.align 8
+	mov	a3, a12		;	_j 1f;	.align 8
+	mov	a3, a13		;	_j 1f;	.align 8
+	mov	a3, a14		;	_j 1f;	.align 8
+	mov	a3, a15		;	_j 1f;	.align 8
+
+1: 	# a7: instruction pointer, a4: instruction, a3: value
+
+	movi	a6, 0			# mask: ffffffff:00000000
+
+#if XCHAL_HAVE_NARROW
+	addi	a7, a7, 2		# incr. PC,assume 16-bit instruction
+
+	extui	a5, a4, INSN_OP0, 4	# extract OP0
+	addi	a5, a5, -OP0_S32I_N
+	_beqz	a5, 1f			# s32i.n: jump
+
+	addi	a7, a7, 1		# increment PC, 32-bit instruction
+#else
+	addi	a7, a7, 3		# increment PC, 32-bit instruction
+#endif
+
+	extui	a5, a4, INSN_OP1, 4	# extract OP1
+	_beqi	a5, OP1_S32I, 1f	# jump if 32 bit store
+	_bnei	a5, OP1_S16I, .Linvalid_instruction_store
+
+	movi	a5, -1
+	__extl	a3, a3			# get 16-bit value
+	__exth	a6, a5			# get 16-bit mask ffffffff:ffff0000
+
+	/* Get memory address */
+
+1:
+#if XCHAL_HAVE_LOOP
+	rsr	a3, LEND		# check if we reached LEND
+	bne	a7, a3, 1f
+	rsr	a3, LCOUNT		# and LCOUNT != 0
+	beqz	a3, 1f
+	addi	a3, a3, -1		# decrement LCOUNT and set
+	rsr	a7, LBEG		# set PC to LBEGIN
+	wsr	a3, LCOUNT
+#endif
+
+1:	wsr	a7, EPC_1		# skip store instruction
+	movi	a4, ~3
+	and	a4, a4, a8		# align memory address
+
+	/* Insert value into memory */
+
+	movi	a5, -1			# mask: ffffffff:XXXX0000
+#ifdef UNALIGNED_USER_EXCEPTION
+	addi	a4, a4, 8
+#endif
+
+	__ssa8r a8
+	__src_b	a7, a5, a6		# lo-mask  F..F0..0 (BE) 0..0F..F (LE)
+	__src_b	a6, a6, a5		# hi-mask  0..0F..F (BE) F..F0..0 (LE)
+#ifdef UNALIGNED_USER_EXCEPTION
+	l32e	a5, a4, -8
+#else
+	l32i	a5, a4, 0		# load lower address word
+#endif
+	and	a5, a5, a7		# mask
+	__sh	a7, a3 			# shift value
+	or	a5, a5, a7		# or with original value
+#ifdef UNALIGNED_USER_EXCEPTION
+	s32e	a5, a4, -8
+	l32e	a7, a4, -4
+#else
+	s32i	a5, a4, 0		# store
+	l32i	a7, a4, 4		# same for upper address word
+#endif
+	__sl	a5, a3
+	and	a6, a7, a6
+	or	a6, a6, a5
+#ifdef UNALIGNED_USER_EXCEPTION
+	s32e	a6, a4, -4
+#else
+	s32i	a6, a4, 4
+#endif
+
+	/* Done. restore stack and return */
+
+.Lexit:
+	movi	a4, 0
+	rsr	a3, EXCSAVE_1
+	s32i	a4, a3, EXC_TABLE_FIXUP
+
+	/* Restore working register */
+
+	l32i	a7, a2, PT_AREG7
+	l32i	a6, a2, PT_AREG6
+	l32i	a5, a2, PT_AREG5
+	l32i	a4, a2, PT_AREG4
+	l32i	a3, a2, PT_AREG3
+
+	/* restore SAR and return */
+
+	wsr	a0, SAR
+	l32i	a0, a2, PT_AREG0
+	l32i	a2, a2, PT_AREG2
+	rfe
+
+	/* We cannot handle this exception. */
+
+	.extern _kernel_exception
+.Linvalid_instruction_store:
+.Linvalid_instruction:
+
+	/* Restore a4...a8 and SAR, set SP, and jump to default exception. */
+
+	l32i	a8, a2, PT_AREG8
+	l32i	a7, a2, PT_AREG7
+	l32i	a6, a2, PT_AREG6
+	l32i	a5, a2, PT_AREG5
+	l32i	a4, a2, PT_AREG4
+	wsr	a0, SAR
+	mov	a1, a2
+
+	rsr	a0, PS
+        bbsi.l  a2, PS_UM_SHIFT, 1f     # jump if user mode
+
+	movi	a0, _kernel_exception
+	jx	a0
+
+1:	movi	a0, _user_exception
+	jx	a0
+
+
+#endif /* XCHAL_UNALIGNED_LOAD_EXCEPTION || XCHAL_UNALIGNED_STORE_EXCEPTION */
+
diff --git a/arch/xtensa/kernel/asm-offsets.c b/arch/xtensa/kernel/asm-offsets.c
new file mode 100644
index 0000000..840cd9a
--- /dev/null
+++ b/arch/xtensa/kernel/asm-offsets.c
@@ -0,0 +1,94 @@
+/*
+ * arch/xtensa/kernel/asm-offsets.c
+ *
+ * Generates definitions from c-type structures used by assembly sources.
+ *
+ * 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) 2005 Tensilica Inc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ */
+
+#include <asm/processor.h>
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/stddef.h>
+#include <linux/thread_info.h>
+#include <linux/ptrace.h>
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+
+#define DEFINE(sym, val) asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+#define BLANK() asm volatile("\n->" : : )
+
+int main(void)
+{
+	/* struct pt_regs */
+	DEFINE(PT_PC, offsetof (struct pt_regs, pc));
+	DEFINE(PT_PS, offsetof (struct pt_regs, ps));
+	DEFINE(PT_DEPC, offsetof (struct pt_regs, depc));
+	DEFINE(PT_EXCCAUSE, offsetof (struct pt_regs, exccause));
+	DEFINE(PT_EXCVADDR, offsetof (struct pt_regs, excvaddr));
+	DEFINE(PT_DEBUGCAUSE, offsetof (struct pt_regs, debugcause));
+	DEFINE(PT_WMASK, offsetof (struct pt_regs, wmask));
+	DEFINE(PT_LBEG, offsetof (struct pt_regs, lbeg));
+	DEFINE(PT_LEND, offsetof (struct pt_regs, lend));
+	DEFINE(PT_LCOUNT, offsetof (struct pt_regs, lcount));
+	DEFINE(PT_SAR, offsetof (struct pt_regs, sar));
+	DEFINE(PT_SYSCALL, offsetof (struct pt_regs, syscall));
+	DEFINE(PT_AREG, offsetof (struct pt_regs, areg[0]));
+	DEFINE(PT_AREG0, offsetof (struct pt_regs, areg[0]));
+	DEFINE(PT_AREG1, offsetof (struct pt_regs, areg[1]));
+	DEFINE(PT_AREG2, offsetof (struct pt_regs, areg[2]));
+	DEFINE(PT_AREG3, offsetof (struct pt_regs, areg[3]));
+	DEFINE(PT_AREG4, offsetof (struct pt_regs, areg[4]));
+	DEFINE(PT_AREG5, offsetof (struct pt_regs, areg[5]));
+	DEFINE(PT_AREG6, offsetof (struct pt_regs, areg[6]));
+	DEFINE(PT_AREG7, offsetof (struct pt_regs, areg[7]));
+	DEFINE(PT_AREG8, offsetof (struct pt_regs, areg[8]));
+	DEFINE(PT_AREG9, offsetof (struct pt_regs, areg[9]));
+	DEFINE(PT_AREG10, offsetof (struct pt_regs, areg[10]));
+	DEFINE(PT_AREG11, offsetof (struct pt_regs, areg[11]));
+	DEFINE(PT_AREG12, offsetof (struct pt_regs, areg[12]));
+	DEFINE(PT_AREG13, offsetof (struct pt_regs, areg[13]));
+	DEFINE(PT_AREG14, offsetof (struct pt_regs, areg[14]));
+	DEFINE(PT_AREG15, offsetof (struct pt_regs, areg[15]));
+	DEFINE(PT_WINDOWBASE, offsetof (struct pt_regs, windowbase));
+	DEFINE(PT_WINDOWSTART, offsetof(struct pt_regs, windowstart));
+	DEFINE(PT_SIZE, sizeof(struct pt_regs));
+	DEFINE(PT_AREG_END, offsetof (struct pt_regs, areg[XCHAL_NUM_AREGS]));
+	DEFINE(PT_USER_SIZE, offsetof(struct pt_regs, areg[XCHAL_NUM_AREGS]));
+	BLANK();
+
+	/* struct task_struct */
+	DEFINE(TASK_PTRACE, offsetof (struct task_struct, ptrace));
+	DEFINE(TASK_MM, offsetof (struct task_struct, mm));
+	DEFINE(TASK_ACTIVE_MM, offsetof (struct task_struct, active_mm));
+	DEFINE(TASK_PID, offsetof (struct task_struct, pid));
+	DEFINE(TASK_THREAD, offsetof (struct task_struct, thread));
+	DEFINE(TASK_THREAD_INFO, offsetof (struct task_struct, thread_info));
+	DEFINE(TASK_STRUCT_SIZE, sizeof (struct task_struct));
+	BLANK();
+
+	/* struct thread_info (offset from start_struct) */
+	DEFINE(THREAD_RA, offsetof (struct task_struct, thread.ra));
+	DEFINE(THREAD_SP, offsetof (struct task_struct, thread.sp));
+	DEFINE(THREAD_CP_SAVE, offsetof (struct task_struct, thread.cp_save));
+	DEFINE(THREAD_CURRENT_DS, offsetof (struct task_struct, thread.current_ds));
+	BLANK();
+
+	/* struct mm_struct */
+	DEFINE(MM_USERS, offsetof(struct mm_struct, mm_users));
+	DEFINE(MM_PGD, offsetof (struct mm_struct, pgd));
+	DEFINE(MM_CONTEXT, offsetof (struct mm_struct, context));
+	BLANK();
+	DEFINE(PT_SINGLESTEP_BIT, PT_SINGLESTEP_BIT);
+	return 0;
+}
+
+
diff --git a/arch/xtensa/kernel/coprocessor.S b/arch/xtensa/kernel/coprocessor.S
new file mode 100644
index 0000000..356192a
--- /dev/null
+++ b/arch/xtensa/kernel/coprocessor.S
@@ -0,0 +1,201 @@
+/*
+ * arch/xtensa/kernel/coprocessor.S
+ *
+ * Xtensa processor configuration-specific table of coprocessor and
+ * other custom register layout information.
+ *
+ * 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) 2003 - 2005 Tensilica Inc.
+ *
+ * Marc Gauthier <marc@tensilica.com> <marc@alumni.uwaterloo.ca>
+ */
+
+/*
+ * This module contains a table that describes the layout of the various
+ * custom registers and states associated with each coprocessor, as well
+ * as those not associated with any coprocessor ("extra state").
+ * This table is included with core dumps and is available via the ptrace
+ * interface, allowing the layout of such register/state information to
+ * be modified in the kernel without affecting the debugger.  Each
+ * register or state is identified using a 32-bit "libdb target number"
+ * assigned when the Xtensa processor is generated.
+ */
+
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <asm/processor.h>
+
+#if XCHAL_HAVE_CP
+
+#define CP_LAST ((XCHAL_CP_MAX - 1) * COPROCESSOR_INFO_SIZE)
+
+ENTRY(release_coprocessors)
+
+	entry	a1, 16
+						# a2: task
+	movi	a3, 1 << XCHAL_CP_MAX 		# a3: coprocessor-bit
+	movi	a4, coprocessor_info+CP_LAST	# a4: owner-table
+						# a5: tmp
+	movi	a6, 0				# a6: 0
+	rsil	a7, LOCKLEVEL			# a7: PS
+
+1:	/* Check if task is coprocessor owner of coprocessor[i]. */
+
+	l32i	a5, a4, COPROCESSOR_INFO_OWNER
+	srli	a3, a3, 1
+	beqz	a3, 1f
+	addi	a4, a4, -8
+	beq	a2, a5, 1b
+
+	/* Found an entry: Clear entry CPENABLE bit to disable CP. */
+
+	rsr	a5, CPENABLE
+	s32i	a6, a4, COPROCESSOR_INFO_OWNER
+	xor	a5, a3, a5
+	wsr	a5, CPENABLE
+
+	bnez	a3, 1b
+
+1:	wsr	a7, PS
+	rsync
+	retw
+
+
+ENTRY(disable_coprocessor)
+	entry	sp, 16
+	rsil	a7, LOCKLEVEL
+	rsr	a3, CPENABLE
+	movi	a4, 1
+	ssl	a2
+	sll	a4, a4
+	and	a4, a3, a4
+	xor	a3, a3, a4
+	wsr	a3, CPENABLE
+	wsr	a7, PS
+	rsync
+	retw
+
+ENTRY(enable_coprocessor)
+	entry	sp, 16
+	rsil	a7, LOCKLEVEL
+	rsr	a3, CPENABLE
+	movi	a4, 1
+	ssl	a2
+	sll	a4, a4
+	or	a3, a3, a4
+	wsr	a3, CPENABLE
+	wsr	a7, PS
+	rsync
+	retw
+
+#endif
+
+ENTRY(save_coprocessor_extra)
+	entry	sp, 16
+	xchal_extra_store_funcbody
+	retw
+
+ENTRY(restore_coprocessor_extra)
+	entry	sp, 16
+	xchal_extra_load_funcbody
+	retw
+
+ENTRY(save_coprocessor_registers)
+	entry	sp, 16
+	xchal_cpi_store_funcbody
+	retw
+
+ENTRY(restore_coprocessor_registers)
+	entry	sp, 16
+	xchal_cpi_load_funcbody
+	retw
+
+
+/*
+ *  The Xtensa compile-time HAL (core.h) XCHAL_*_SA_CONTENTS_LIBDB macros
+ *  describe the contents of coprocessor & extra save areas in terms of
+ *  undefined CONTENTS_LIBDB_{SREG,UREG,REGF} macros.  We define these
+ *  latter macros here; they expand into a table of the format we want.
+ *  The general format is:
+ *
+ *	CONTENTS_LIBDB_SREG(libdbnum, offset, size, align, rsv1, name, sregnum,
+ *			    bitmask, rsv2, rsv3)
+ *	CONTENTS_LIBDB_UREG(libdbnum, offset, size, align, rsv1, name, uregnum,
+ *			    bitmask, rsv2, rsv3)
+ *	CONTENTS_LIBDB_REGF(libdbnum, offset, size, align, rsv1, name, index,
+ *			    numentries, contentsize, regname_base,
+ *			    regfile_name, rsv2, rsv3)
+ *
+ *  For this table, we only care about the <libdbnum>, <offset> and <size>
+ *  fields.
+ */
+
+/*  Map all XCHAL CONTENTS macros to the reg_entry asm macro defined below:  */
+
+#define CONTENTS_LIBDB_SREG(libdbnum,offset,size,align,rsv1,name,sregnum,     \
+			    bitmask, rsv2, rsv3)			      \
+		reg_entry libdbnum, offset, size ;
+#define CONTENTS_LIBDB_UREG(libdbnum,offset,size,align,rsv1,name,uregnum,     \
+			    bitmask, rsv2, rsv3)			      \
+		reg_entry libdbnum, offset, size ;
+#define CONTENTS_LIBDB_REGF(libdbnum, offset, size, align, rsv1, name, index, \
+			    numentries, contentsize, regname_base,	      \
+			    regfile_name, rsv2, rsv3)			      \
+		reg_entry libdbnum, offset, size ;
+
+/* A single table entry: */
+	.macro	reg_entry	libdbnum, offset, size
+	 .ifne	(__last_offset-(__last_group_offset+\offset))
+	  /* padding entry */
+	  .word	(0xFC000000+__last_offset-(__last_group_offset+\offset))
+	 .endif
+	 .word	\libdbnum				/* actual entry */
+	 .set	__last_offset, __last_group_offset+\offset+\size
+	.endm	/* reg_entry */
+
+
+/* Table entry that marks the beginning of a group (coprocessor or "extra"): */
+	.macro	reg_group	cpnum, num_entries, align
+	 .set	__last_group_offset, (__last_offset + \align- 1) & -\align
+	 .ifne	\num_entries
+	  .word	0xFD000000+(\cpnum<<16)+\num_entries
+	 .endif
+	.endm	/* reg_group */
+
+/*
+ * Register info tables.
+ */
+
+	.section .rodata, "a"
+	.globl	_xtensa_reginfo_tables
+	.globl	_xtensa_reginfo_table_size
+	.align	4
+_xtensa_reginfo_table_size:
+	.word	_xtensa_reginfo_table_end - _xtensa_reginfo_tables
+
+_xtensa_reginfo_tables:
+	.set	__last_offset, 0
+	reg_group 0xFF, XCHAL_EXTRA_SA_CONTENTS_LIBDB_NUM, XCHAL_EXTRA_SA_ALIGN
+	XCHAL_EXTRA_SA_CONTENTS_LIBDB
+	reg_group 0, XCHAL_CP0_SA_CONTENTS_LIBDB_NUM, XCHAL_CP0_SA_ALIGN
+	XCHAL_CP0_SA_CONTENTS_LIBDB
+	reg_group 1, XCHAL_CP1_SA_CONTENTS_LIBDB_NUM, XCHAL_CP1_SA_ALIGN
+	XCHAL_CP1_SA_CONTENTS_LIBDB
+	reg_group 2, XCHAL_CP2_SA_CONTENTS_LIBDB_NUM, XCHAL_CP2_SA_ALIGN
+	XCHAL_CP2_SA_CONTENTS_LIBDB
+	reg_group 3, XCHAL_CP3_SA_CONTENTS_LIBDB_NUM, XCHAL_CP3_SA_ALIGN
+	XCHAL_CP3_SA_CONTENTS_LIBDB
+	reg_group 4, XCHAL_CP4_SA_CONTENTS_LIBDB_NUM, XCHAL_CP4_SA_ALIGN
+	XCHAL_CP4_SA_CONTENTS_LIBDB
+	reg_group 5, XCHAL_CP5_SA_CONTENTS_LIBDB_NUM, XCHAL_CP5_SA_ALIGN
+	XCHAL_CP5_SA_CONTENTS_LIBDB
+	reg_group 6, XCHAL_CP6_SA_CONTENTS_LIBDB_NUM, XCHAL_CP6_SA_ALIGN
+	XCHAL_CP6_SA_CONTENTS_LIBDB
+	reg_group 7, XCHAL_CP7_SA_CONTENTS_LIBDB_NUM, XCHAL_CP7_SA_ALIGN
+	XCHAL_CP7_SA_CONTENTS_LIBDB
+	.word	0xFC000000	/* invalid register number,marks end of table*/
+_xtensa_reginfo_table_end:
+
diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S
new file mode 100644
index 0000000..c64a01f
--- /dev/null
+++ b/arch/xtensa/kernel/entry.S
@@ -0,0 +1,1996 @@
+/*
+ * arch/xtensa/kernel/entry.S
+ *
+ * Low-level exception handling
+ *
+ * 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) 2004-2005 by Tensilica Inc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ *
+ */
+
+#include <linux/linkage.h>
+#include <asm/offsets.h>
+#include <asm/processor.h>
+#include <asm/thread_info.h>
+#include <asm/uaccess.h>
+#include <asm/unistd.h>
+#include <asm/ptrace.h>
+#include <asm/current.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/signal.h>
+#include <xtensa/coreasm.h>
+
+/* Unimplemented features. */
+
+#undef SIGNAL_HANDLING_IN_DOUBLE_EXCEPTION
+#undef KERNEL_STACK_OVERFLOW_CHECK
+#undef PREEMPTIBLE_KERNEL
+#undef ALLOCA_EXCEPTION_IN_IRAM
+
+/* Not well tested.
+ *
+ * - fast_coprocessor
+ */
+
+/*
+ * Macro to find first bit set in WINDOWBASE from the left + 1
+ *
+ * 100....0 -> 1
+ * 010....0 -> 2
+ * 000....1 -> WSBITS
+ */
+
+	.macro ffs_ws bit mask
+
+#if XCHAL_HAVE_NSA
+	nsau    \bit, \mask			# 32-WSBITS ... 31 (32 iff 0)
+	addi    \bit, \bit, WSBITS - 32 + 1   	# uppest bit set -> return 1
+#else
+	movi    \bit, WSBITS
+#if WSBITS > 16
+	_bltui  \mask, 0x10000, 99f
+	addi    \bit, \bit, -16
+	extui   \mask, \mask, 16, 16
+#endif
+#if WSBITS > 8
+99:	_bltui  \mask, 0x100, 99f
+	addi    \bit, \bit, -8
+	srli    \mask, \mask, 8
+#endif
+99:	_bltui  \mask, 0x10, 99f
+	addi    \bit, \bit, -4
+	srli    \mask, \mask, 4
+99:	_bltui  \mask, 0x4, 99f
+	addi    \bit, \bit, -2
+	srli    \mask, \mask, 2
+99:	_bltui  \mask, 0x2, 99f
+	addi    \bit, \bit, -1
+99:
+
+#endif
+	.endm
+
+/* ----------------- DEFAULT FIRST LEVEL EXCEPTION HANDLERS ----------------- */
+
+/*
+ * First-level exception handler for user exceptions.
+ * Save some special registers, extra states and all registers in the AR
+ * register file that were in use in the user task, and jump to the common
+ * exception code.
+ * We save SAR (used to calculate WMASK), and WB and WS (we don't have to
+ * save them for kernel exceptions).
+ *
+ * Entry condition for user_exception:
+ *
+ *   a0:	trashed, original value saved on stack (PT_AREG0)
+ *   a1:	a1
+ *   a2:	new stack pointer, original value in depc
+ *   a3:	dispatch table
+ *   depc:	a2, original value saved on stack (PT_DEPC)
+ *   excsave1:	a3
+ *
+ *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
+ *	     <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
+ *
+ * Entry condition for _user_exception:
+ *
+ *   a0-a3 and depc have been saved to PT_AREG0...PT_AREG3 and PT_DEPC
+ *   excsave has been restored, and
+ *   stack pointer (a1) has been set.
+ *
+ * Note: _user_exception might be at an odd adress. Don't use call0..call12
+ */
+
+ENTRY(user_exception)
+
+	/* Save a2, a3, and depc, restore excsave_1 and set SP. */
+
+	xsr	a3, EXCSAVE_1
+	rsr	a0, DEPC
+	s32i	a1, a2, PT_AREG1
+	s32i	a0, a2, PT_AREG2
+	s32i	a3, a2, PT_AREG3
+	mov	a1, a2
+
+	.globl _user_exception
+_user_exception:
+
+	/* Save SAR and turn off single stepping */
+
+	movi	a2, 0
+	rsr	a3, SAR
+	wsr	a2, ICOUNTLEVEL
+	s32i	a3, a1, PT_SAR
+
+	/* Rotate ws so that the current windowbase is at bit0. */
+	/* Assume ws = xxwww1yyyy. Rotate ws right, so that a2 = yyyyxxwww1 */
+
+	rsr	a2, WINDOWBASE
+	rsr	a3, WINDOWSTART
+	ssr	a2
+	s32i	a2, a1, PT_WINDOWBASE
+	s32i	a3, a1, PT_WINDOWSTART
+	slli	a2, a3, 32-WSBITS
+	src	a2, a3, a2
+	srli	a2, a2, 32-WSBITS
+	s32i	a2, a1, PT_WMASK	# needed for restoring registers
+
+	/* Save only live registers. */
+
+	_bbsi.l	a2, 1, 1f
+	s32i	a4, a1, PT_AREG4
+	s32i	a5, a1, PT_AREG5
+	s32i	a6, a1, PT_AREG6
+	s32i	a7, a1, PT_AREG7
+	_bbsi.l	a2, 2, 1f
+	s32i	a8, a1, PT_AREG8
+	s32i	a9, a1, PT_AREG9
+	s32i	a10, a1, PT_AREG10
+	s32i	a11, a1, PT_AREG11
+	_bbsi.l	a2, 3, 1f
+	s32i	a12, a1, PT_AREG12
+	s32i	a13, a1, PT_AREG13
+	s32i	a14, a1, PT_AREG14
+	s32i	a15, a1, PT_AREG15
+	_bnei	a2, 1, 1f		# only one valid frame?
+
+	/* Only one valid frame, skip saving regs. */
+
+	j	2f
+
+	/* Save the remaining registers.
+	 * We have to save all registers up to the first '1' from
+	 * the right, except the current frame (bit 0).
+	 * Assume a2 is:  001001000110001
+	 * All regiser frames starting from the top fiel to the marked '1'
+	 * must be saved.
+	 */
+
+1:	addi	a3, a2, -1		# eliminate '1' in bit 0: yyyyxxww0
+	neg	a3, a3			# yyyyxxww0 -> YYYYXXWW1+1
+	and	a3, a3, a2		# max. only one bit is set
+
+	/* Find number of frames to save */
+
+	ffs_ws	a0, a3			# number of frames to the '1' from left
+
+	/* Store information into WMASK:
+	 * bits 0..3: xxx1 masked lower 4 bits of the rotated windowstart,
+	 * bits 4...: number of valid 4-register frames
+	 */
+
+	slli	a3, a0, 4		# number of frames to save in bits 8..4
+	extui	a2, a2, 0, 4		# mask for the first 16 registers
+	or	a2, a3, a2
+	s32i	a2, a1, PT_WMASK	# needed when we restore the reg-file
+
+	/* Save 4 registers at a time */
+
+1:	rotw	-1
+	s32i	a0, a5, PT_AREG_END - 16
+	s32i	a1, a5, PT_AREG_END - 12
+	s32i	a2, a5, PT_AREG_END - 8
+	s32i	a3, a5, PT_AREG_END - 4
+	addi	a0, a4, -1
+	addi	a1, a5, -16
+	_bnez	a0, 1b
+
+	/* WINDOWBASE still in SAR! */
+
+	rsr	a2, SAR			# original WINDOWBASE
+	movi	a3, 1
+	ssl	a2
+	sll	a3, a3
+	wsr	a3, WINDOWSTART		# set corresponding WINDOWSTART bit
+	wsr	a2, WINDOWBASE		# and WINDOWSTART
+	rsync
+
+	/* We are back to the original stack pointer (a1) */
+
+2:
+#if XCHAL_EXTRA_SA_SIZE
+
+	/* For user exceptions, save the extra state into the user's TCB.
+	 * Note: We must assume that xchal_extra_store_funcbody destroys a2..a15
+	 */
+
+	GET_CURRENT(a2,a1)
+	addi	a2, a2, THREAD_CP_SAVE
+	xchal_extra_store_funcbody
+#endif
+
+	/* Now, jump to the common exception handler. */
+
+	j	common_exception
+
+
+/*
+ * First-level exit handler for kernel exceptions
+ * Save special registers and the live window frame.
+ * Note: Even though we changes the stack pointer, we don't have to do a
+ *	 MOVSP here, as we do that when we return from the exception.
+ *	 (See comment in the kernel exception exit code)
+ *
+ * Entry condition for kernel_exception:
+ *
+ *   a0:	trashed, original value saved on stack (PT_AREG0)
+ *   a1:	a1
+ *   a2:	new stack pointer, original in DEPC
+ *   a3:	dispatch table
+ *   depc:	a2, original value saved on stack (PT_DEPC)
+ *   excsave_1:	a3
+ *
+ *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
+ *	     <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
+ *
+ * Entry condition for _kernel_exception:
+ *
+ *   a0-a3 and depc have been saved to PT_AREG0...PT_AREG3 and PT_DEPC
+ *   excsave has been restored, and
+ *   stack pointer (a1) has been set.
+ *
+ * Note: _kernel_exception might be at an odd adress. Don't use call0..call12
+ */
+
+ENTRY(kernel_exception)
+
+	/* Save a0, a2, a3, DEPC and set SP. */
+
+	xsr	a3, EXCSAVE_1		# restore a3, excsave_1
+	rsr	a0, DEPC		# get a2
+	s32i	a1, a2, PT_AREG1
+	s32i	a0, a2, PT_AREG2
+	s32i	a3, a2, PT_AREG3
+	mov	a1, a2
+
+	.globl _kernel_exception
+_kernel_exception:
+
+	/* Save SAR and turn off single stepping */
+
+	movi	a2, 0
+	rsr	a3, SAR
+	wsr	a2, ICOUNTLEVEL
+	s32i	a3, a1, PT_SAR
+
+	/* Rotate ws so that the current windowbase is at bit0. */
+	/* Assume ws = xxwww1yyyy. Rotate ws right, so that a2 = yyyyxxwww1 */
+
+	rsr	a2, WINDOWBASE		# don't need to save these, we only
+	rsr	a3, WINDOWSTART		# need shifted windowstart: windowmask
+	ssr	a2
+	slli	a2, a3, 32-WSBITS
+	src	a2, a3, a2
+	srli	a2, a2, 32-WSBITS
+	s32i	a2, a1, PT_WMASK	# needed for kernel_exception_exit
+
+	/* Save only the live window-frame */
+
+	_bbsi.l	a2, 1, 1f
+	s32i	a4, a1, PT_AREG4
+	s32i	a5, a1, PT_AREG5
+	s32i	a6, a1, PT_AREG6
+	s32i	a7, a1, PT_AREG7
+	_bbsi.l	a2, 2, 1f
+	s32i	a8, a1, PT_AREG8
+	s32i	a9, a1, PT_AREG9
+	s32i	a10, a1, PT_AREG10
+	s32i	a11, a1, PT_AREG11
+	_bbsi.l	a2, 3, 1f
+	s32i	a12, a1, PT_AREG12
+	s32i	a13, a1, PT_AREG13
+	s32i	a14, a1, PT_AREG14
+	s32i	a15, a1, PT_AREG15
+
+1:
+
+#ifdef KERNEL_STACK_OVERFLOW_CHECK
+
+	/*  Stack overflow check, for debugging  */
+	extui	a2, a1, TASK_SIZE_BITS,XX
+	movi	a3, SIZE??
+	_bge	a2, a3, out_of_stack_panic
+
+#endif
+
+/*
+ * This is the common exception handler.
+ * We get here from the user exception handler or simply by falling through
+ * from the kernel exception handler.
+ * Save the remaining special registers, switch to kernel mode, and jump
+ * to the second-level exception handler.
+ *
+ */
+
+common_exception:
+
+	/* Save EXCVADDR, DEBUGCAUSE, and PC, and clear LCOUNT */
+
+	rsr	a2, DEBUGCAUSE
+	rsr	a3, EPC_1
+	s32i	a2, a1, PT_DEBUGCAUSE
+	s32i	a3, a1, PT_PC
+
+	rsr	a3, EXCVADDR
+	movi	a2, 0
+	s32i	a3, a1, PT_EXCVADDR
+	xsr	a2, LCOUNT
+	s32i	a2, a1, PT_LCOUNT
+
+	/* It is now save to restore the EXC_TABLE_FIXUP variable. */
+
+	rsr	a0, EXCCAUSE
+	movi	a3, 0
+	rsr	a2, EXCSAVE_1
+	s32i	a0, a1, PT_EXCCAUSE
+	s32i	a3, a2, EXC_TABLE_FIXUP
+
+	/* All unrecoverable states are saved on stack, now, and a1 is valid,
+	 * so we can allow exceptions and interrupts (*) again.
+	 * Set PS(EXCM = 0, UM = 0, RING = 0, OWB = 0, WOE = 1, INTLEVEL = X)
+	 *
+	 * (*) We only allow interrupts if PS.INTLEVEL was not set to 1 before
+	 *     (interrupts disabled) and if this exception is not an interrupt.
+	 */
+
+	rsr	a3, PS
+	addi	a0, a0, -4
+	movi	a2, 1
+	extui	a3, a3, 0, 1		# a3 = PS.INTLEVEL[0]
+	moveqz	a3, a2, a0		# a3 = 1 iff interrupt exception
+	movi	a2, PS_WOE_MASK
+	or	a3, a3, a2
+	rsr	a0, EXCCAUSE
+	xsr	a3, PS
+
+	s32i	a3, a1, PT_PS		# save ps
+
+	/* Save LBEG, LEND */
+
+	rsr	a2, LBEG
+	rsr	a3, LEND
+	s32i	a2, a1, PT_LBEG
+	s32i	a3, a1, PT_LEND
+
+	/* Go to second-level dispatcher. Set up parameters to pass to the
+	 * exception handler and call the exception handler.
+	 */
+
+	movi	a4, exc_table
+	mov	a6, a1			# pass stack frame
+	mov	a7, a0			# pass EXCCAUSE
+	addx4	a4, a0, a4
+	l32i	a4, a4, EXC_TABLE_DEFAULT		# load handler
+
+	/* Call the second-level handler */
+
+	callx4	a4
+
+	/* Jump here for exception exit */
+
+common_exception_return:
+
+	/* Jump if we are returning from kernel exceptions. */
+
+1:	l32i	a3, a1, PT_PS
+	_bbsi.l	a3, PS_UM_SHIFT, 2f
+	j	kernel_exception_exit
+
+	/* Specific to a user exception exit:
+	 * We need to check some flags for signal handling and rescheduling,
+	 * and have to restore WB and WS, extra states, and all registers
+	 * in the register file that were in use in the user task.
+	 */
+
+2:	wsr	a3, PS		/* disable interrupts */
+
+	/* Check for signals (keep interrupts disabled while we read TI_FLAGS)
+	 * Note: PS.INTLEVEL = 0, PS.EXCM = 1
+	 */
+
+	GET_THREAD_INFO(a2,a1)
+	l32i	a4, a2, TI_FLAGS
+
+	/* Enable interrupts again.
+	 * Note: When we get here, we certainly have handled any interrupts.
+	 *       (Hint: There is only one user exception frame on stack)
+	 */
+
+	movi	a3, PS_WOE_MASK
+
+	_bbsi.l	a4, TIF_NEED_RESCHED, 3f
+	_bbci.l	a4, TIF_SIGPENDING, 4f
+
+#ifndef SIGNAL_HANDLING_IN_DOUBLE_EXCEPTION
+	l32i	a4, a1, PT_DEPC
+	bgeui	a4, VALID_DOUBLE_EXCEPTION_ADDRESS, 4f
+#endif
+
+	/* Reenable interrupts and call do_signal() */
+
+	wsr	a3, PS
+	movi	a4, do_signal	# int do_signal(struct pt_regs*, sigset_t*)
+	mov	a6, a1
+	movi	a7, 0
+	callx4	a4
+	j	1b
+
+3:	/* Reenable interrupts and reschedule */
+
+	wsr	a3, PS
+	movi	a4, schedule	# void schedule (void)
+	callx4	a4
+	j	1b
+
+	/* Restore the state of the task and return from the exception. */
+
+
+	/* If we are returning from a user exception, and the process
+	 * to run next has PT_SINGLESTEP set, we want to setup
+	 * ICOUNT and ICOUNTLEVEL to step one instruction.
+	 * PT_SINGLESTEP is set by sys_ptrace (ptrace.c)
+	 */
+
+4:	/* a2 holds GET_CURRENT(a2,a1)  */
+
+	l32i	a3, a2, TI_TASK
+	l32i	a3, a3, TASK_PTRACE
+	bbci.l	a3, PT_SINGLESTEP_BIT, 1f # jump if single-step flag is not set
+
+	movi	a3, -2			# PT_SINGLESTEP flag is set,
+	movi	a4, 1			# icountlevel of 1 means it won't
+	wsr	a3, ICOUNT		# start counting until after rfe
+	wsr	a4, ICOUNTLEVEL		# so setup icount & icountlevel.
+	isync
+
+1:
+
+#if XCHAL_EXTRA_SA_SIZE
+
+	/* For user exceptions, restore the extra state from the user's TCB. */
+
+	/* Note: a2 still contains GET_CURRENT(a2,a1) */
+	addi	a2, a2, THREAD_CP_SAVE
+	xchal_extra_load_funcbody
+
+	/* We must assume that xchal_extra_store_funcbody destroys
+	 * registers a2..a15.  FIXME, this list can eventually be
+	 * reduced once real register requirements of the macro are
+	 * finalized. */
+
+#endif /* XCHAL_EXTRA_SA_SIZE */
+
+
+	/* Switch to the user thread WINDOWBASE. Save SP temporarily in DEPC */
+
+	l32i	a2, a1, PT_WINDOWBASE
+	l32i	a3, a1, PT_WINDOWSTART
+	wsr	a1, DEPC		# use DEPC as temp storage
+	wsr	a3, WINDOWSTART		# restore WINDOWSTART
+	ssr	a2			# preserve user's WB in the SAR
+	wsr	a2, WINDOWBASE		# switch to user's saved WB
+	rsync
+	rsr	a1, DEPC		# restore stack pointer
+	l32i	a2, a1, PT_WMASK	# register frames saved (in bits 4...9)
+	rotw	-1			# we restore a4..a7
+	_bltui	a6, 16, 1f		# only have to restore current window?
+
+	/* The working registers are a0 and a3.  We are restoring to
+	 * a4..a7.  Be careful not to destroy what we have just restored.
+	 * Note: wmask has the format YYYYM:
+	 *       Y: number of registers saved in groups of 4
+	 *       M: 4 bit mask of first 16 registers
+	 */
+
+	mov	a2, a6
+	mov	a3, a5
+
+2:	rotw	-1			# a0..a3 become a4..a7
+	addi	a3, a7, -4*4		# next iteration
+	addi	a2, a6, -16		# decrementing Y in WMASK
+	l32i	a4, a3, PT_AREG_END + 0
+	l32i	a5, a3, PT_AREG_END + 4
+	l32i	a6, a3, PT_AREG_END + 8
+	l32i	a7, a3, PT_AREG_END + 12
+	_bgeui	a2, 16, 2b
+
+	/* Clear unrestored registers (don't leak anything to user-land */
+
+1:	rsr	a0, WINDOWBASE
+	rsr	a3, SAR
+	sub	a3, a0, a3
+	beqz	a3, 2f
+	extui	a3, a3, 0, WBBITS
+
+1:	rotw	-1
+	addi	a3, a7, -1
+	movi	a4, 0
+	movi	a5, 0
+	movi	a6, 0
+	movi	a7, 0
+	bgei	a3, 1, 1b
+
+	/* We are back were we were when we started.
+	 * Note: a2 still contains WMASK (if we've returned to the original
+	 *	 frame where we had loaded a2), or at least the lower 4 bits
+	 *	 (if we have restored WSBITS-1 frames).
+	 */
+
+2:	j	common_exception_exit
+
+	/* This is the kernel exception exit.
+	 * We avoided to do a MOVSP when we entered the exception, but we
+	 * have to do it here.
+	 */
+
+kernel_exception_exit:
+
+	/* Disable interrupts (a3 holds PT_PS) */
+
+	wsr	a3, PS
+
+#ifdef PREEMPTIBLE_KERNEL
+
+#ifdef CONFIG_PREEMPT
+
+	/*
+	 * Note: We've just returned from a call4, so we have
+	 * at least 4 addt'l regs.
+	 */
+
+	/* Check current_thread_info->preempt_count */
+
+	GET_THREAD_INFO(a2)
+	l32i	a3, a2, TI_PREEMPT
+	bnez	a3, 1f
+
+	l32i	a2, a2, TI_FLAGS
+
+1:
+
+#endif
+
+#endif
+
+	/* Check if we have to do a movsp.
+	 *
+	 * We only have to do a movsp if the previous window-frame has
+	 * been spilled to the *temporary* exception stack instead of the
+	 * task's stack. This is the case if the corresponding bit in
+	 * WINDOWSTART for the previous window-frame was set before
+	 * (not spilled) but is zero now (spilled).
+	 * If this bit is zero, all other bits except the one for the
+	 * current window frame are also zero. So, we can use a simple test:
+	 * 'and' WINDOWSTART and WINDOWSTART-1:
+	 *
+	 *  (XXXXXX1[0]* - 1) AND XXXXXX1[0]* = XXXXXX0[0]*
+	 *
+	 * The result is zero only if one bit was set.
+	 *
+	 * (Note: We might have gone through several task switches before
+	 *        we come back to the current task, so WINDOWBASE might be
+	 *        different from the time the exception occurred.)
+	 */
+
+	/* Test WINDOWSTART before and after the exception.
+	 * We actually have WMASK, so we only have to test if it is 1 or not.
+	 */
+
+	l32i	a2, a1, PT_WMASK
+	_beqi	a2, 1, common_exception_exit	# Spilled before exception,jump
+
+	/* Test WINDOWSTART now. If spilled, do the movsp */
+
+	rsr     a3, WINDOWSTART
+	addi	a0, a3, -1
+	and     a3, a3, a0
+	_bnez	a3, common_exception_exit
+
+	/* Do a movsp (we returned from a call4, so we have at least a0..a7) */
+
+	addi    a0, a1, -16
+	l32i    a3, a0, 0
+	l32i    a4, a0, 4
+	s32i    a3, a1, PT_SIZE+0
+	s32i    a4, a1, PT_SIZE+4
+	l32i    a3, a0, 8
+	l32i    a4, a0, 12
+	s32i    a3, a1, PT_SIZE+8
+	s32i    a4, a1, PT_SIZE+12
+
+	/* Common exception exit.
+	 * We restore the special register and the current window frame, and
+	 * return from the exception.
+	 *
+	 * Note: We expect a2 to hold PT_WMASK
+	 */
+
+common_exception_exit:
+
+	_bbsi.l	a2, 1, 1f
+	l32i	a4,  a1, PT_AREG4
+	l32i	a5,  a1, PT_AREG5
+	l32i	a6,  a1, PT_AREG6
+	l32i	a7,  a1, PT_AREG7
+	_bbsi.l	a2, 2, 1f
+	l32i	a8,  a1, PT_AREG8
+	l32i	a9,  a1, PT_AREG9
+	l32i	a10, a1, PT_AREG10
+	l32i	a11, a1, PT_AREG11
+	_bbsi.l	a2, 3, 1f
+	l32i	a12, a1, PT_AREG12
+	l32i	a13, a1, PT_AREG13
+	l32i	a14, a1, PT_AREG14
+	l32i	a15, a1, PT_AREG15
+
+	/* Restore PC, SAR */
+
+1:	l32i	a2, a1, PT_PC
+	l32i	a3, a1, PT_SAR
+	wsr	a2, EPC_1
+	wsr	a3, SAR
+
+	/* Restore LBEG, LEND, LCOUNT */
+
+	l32i	a2, a1, PT_LBEG
+	l32i	a3, a1, PT_LEND
+	wsr	a2, LBEG
+	l32i	a2, a1, PT_LCOUNT
+	wsr	a3, LEND
+	wsr	a2, LCOUNT
+
+	/* Check if it was double exception. */
+
+	l32i	a0, a1, PT_DEPC
+	l32i	a3, a1, PT_AREG3
+	l32i	a2, a1, PT_AREG2
+	_bgeui	a0, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f
+
+	/* Restore a0...a3 and return */
+
+	l32i	a0, a1, PT_AREG0
+	l32i	a1, a1, PT_AREG1
+	rfe
+
+1:	wsr	a0, DEPC
+	l32i	a0, a1, PT_AREG0
+	l32i	a1, a1, PT_AREG1
+	rfde
+
+/*
+ * Debug exception handler.
+ *
+ * Currently, we don't support KGDB, so only user application can be debugged.
+ *
+ * When we get here,  a0 is trashed and saved to excsave[debuglevel]
+ */
+
+ENTRY(debug_exception)
+
+	rsr	a0, EPS + XCHAL_DEBUGLEVEL
+	bbsi.l	a0, PS_EXCM_SHIFT, 1f	# exception mode
+
+	/* Set EPC_1 and EXCCAUSE */
+
+	wsr	a2, DEPC		# save a2 temporarily
+	rsr	a2, EPC + XCHAL_DEBUGLEVEL
+	wsr	a2, EPC_1
+
+	movi	a2, EXCCAUSE_MAPPED_DEBUG
+	wsr	a2, EXCCAUSE
+
+	/* Restore PS to the value before the debug exc but with PS.EXCM set.*/
+
+	movi	a2, 1 << PS_EXCM_SHIFT
+	or	a2, a0, a2
+	movi	a0, debug_exception	# restore a3, debug jump vector
+	wsr	a2, PS
+	xsr	a0, EXCSAVE + XCHAL_DEBUGLEVEL
+
+	/* Switch to kernel/user stack, restore jump vector, and save a0 */
+
+	bbsi.l	a2, PS_UM_SHIFT, 2f	# jump if user mode
+
+	addi	a2, a1, -16-PT_SIZE	# assume kernel stack
+	s32i	a0, a2, PT_AREG0
+	movi	a0, 0
+	s32i	a1, a2, PT_AREG1
+	s32i	a0, a2, PT_DEPC		# mark it as a regular exception
+	xsr	a0, DEPC
+	s32i	a3, a2, PT_AREG3
+	s32i	a0, a2, PT_AREG2
+	mov	a1, a2
+	j	_kernel_exception
+
+2:	rsr	a2, EXCSAVE_1
+	l32i	a2, a2, EXC_TABLE_KSTK	# load kernel stack pointer
+	s32i	a0, a2, PT_AREG0
+	movi	a0, 0
+	s32i	a1, a2, PT_AREG1
+	s32i	a0, a2, PT_DEPC
+	xsr	a0, DEPC
+	s32i	a3, a2, PT_AREG3
+	s32i	a0, a2, PT_AREG2
+	mov	a1, a2
+	j	_user_exception
+
+	/* Debug exception while in exception mode. */
+1:	j	1b	// FIXME!!
+
+
+/*
+ * We get here in case of an unrecoverable exception.
+ * The only thing we can do is to be nice and print a panic message.
+ * We only produce a single stack frame for panic, so ???
+ *
+ *
+ * Entry conditions:
+ *
+ *   - a0 contains the caller address; original value saved in excsave1.
+ *   - the original a0 contains a valid return address (backtrace) or 0.
+ *   - a2 contains a valid stackpointer
+ *
+ * Notes:
+ *
+ *   - If the stack pointer could be invalid, the caller has to setup a
+ *     dummy stack pointer (e.g. the stack of the init_task)
+ *
+ *   - If the return address could be invalid, the caller has to set it
+ *     to 0, so the backtrace would stop.
+ *
+ */
+	.align 4
+unrecoverable_text:
+	.ascii "Unrecoverable error in exception handler\0"
+
+ENTRY(unrecoverable_exception)
+
+	movi	a0, 1
+	movi	a1, 0
+
+	wsr	a0, WINDOWSTART
+	wsr	a1, WINDOWBASE
+	rsync
+
+	movi	a1, PS_WOE_MASK | 1
+	wsr	a1, PS
+	rsync
+
+	movi	a1, init_task
+	movi	a0, 0
+	addi	a1, a1, PT_REGS_OFFSET
+
+	movi	a4, panic
+	movi	a6, unrecoverable_text
+
+	callx4	a4
+
+1:	j	1b
+
+
+/* -------------------------- FAST EXCEPTION HANDLERS ----------------------- */
+
+/*
+ * Fast-handler for alloca exceptions
+ *
+ *  The ALLOCA handler is entered when user code executes the MOVSP
+ *  instruction and the caller's frame is not in the register file.
+ *  In this case, the caller frame's a0..a3 are on the stack just
+ *  below sp (a1), and this handler moves them.
+ *
+ *  For "MOVSP <ar>,<as>" without destination register a1, this routine
+ *  simply moves the value from <as> to <ar> without moving the save area.
+ *
+ * Entry condition:
+ *
+ *   a0:	trashed, original value saved on stack (PT_AREG0)
+ *   a1:	a1
+ *   a2:	new stack pointer, original in DEPC
+ *   a3:	dispatch table
+ *   depc:	a2, original value saved on stack (PT_DEPC)
+ *   excsave_1:	a3
+ *
+ *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
+ *	     <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
+ */
+
+#if XCHAL_HAVE_BE
+#define _EXTUI_MOVSP_SRC(ar)	extui ar, ar, 4, 4
+#define _EXTUI_MOVSP_DST(ar)	extui ar, ar, 0, 4
+#else
+#define _EXTUI_MOVSP_SRC(ar)	extui ar, ar, 0, 4
+#define _EXTUI_MOVSP_DST(ar)	extui ar, ar, 4, 4
+#endif
+
+ENTRY(fast_alloca)
+
+	/* We shouldn't be in a double exception. */
+
+	l32i	a0, a2, PT_DEPC
+	_bgeui	a0, VALID_DOUBLE_EXCEPTION_ADDRESS, .Lunhandled_double
+
+	rsr	a0, DEPC		# get a2
+	s32i	a4, a2, PT_AREG4	# save a4 and
+	s32i	a0, a2, PT_AREG2	# a2 to stack
+
+	/* Exit critical section. */
+
+	movi	a0, 0
+	s32i	a0, a3, EXC_TABLE_FIXUP
+
+	/* Restore a3, excsave_1 */
+
+	xsr	a3, EXCSAVE_1		# make sure excsave_1 is valid for dbl.
+	rsr	a4, EPC_1		# get exception address
+	s32i	a3, a2, PT_AREG3	# save a3 to stack
+
+#ifdef ALLOCA_EXCEPTION_IN_IRAM
+#error	iram not supported
+#else
+	/* Note: l8ui not allowed in IRAM/IROM!! */
+	l8ui	a0, a4, 1		# read as(src) from MOVSP instruction
+#endif
+	movi	a3, .Lmovsp_src
+	_EXTUI_MOVSP_SRC(a0)		# extract source register number
+	addx8	a3, a0, a3
+	jx	a3
+
+.Lunhandled_double:
+	wsr	a0, EXCSAVE_1
+	movi	a0, unrecoverable_exception
+	callx0	a0
+
+	.align 8
+.Lmovsp_src:
+	l32i	a3, a2, PT_AREG0;	_j 1f;	.align 8
+	mov	a3, a1;			_j 1f;	.align 8
+	l32i	a3, a2, PT_AREG2;	_j 1f;	.align 8
+	l32i	a3, a2, PT_AREG3;	_j 1f;	.align 8
+	l32i	a3, a2, PT_AREG4;	_j 1f;	.align 8
+	mov	a3, a5;			_j 1f;	.align 8
+	mov	a3, a6;			_j 1f;	.align 8
+	mov	a3, a7;			_j 1f;	.align 8
+	mov	a3, a8;			_j 1f;	.align 8
+	mov	a3, a9;			_j 1f;	.align 8
+	mov	a3, a10;		_j 1f;	.align 8
+	mov	a3, a11;		_j 1f;	.align 8
+	mov	a3, a12;		_j 1f;	.align 8
+	mov	a3, a13;		_j 1f;	.align 8
+	mov	a3, a14;		_j 1f;	.align 8
+	mov	a3, a15;		_j 1f;	.align 8
+
+1:
+
+#ifdef ALLOCA_EXCEPTION_IN_IRAM
+#error	iram not supported
+#else
+	l8ui	a0, a4, 0		# read ar(dst) from MOVSP instruction
+#endif
+	addi	a4, a4, 3		# step over movsp
+	_EXTUI_MOVSP_DST(a0)		# extract destination register
+	wsr	a4, EPC_1		# save new epc_1
+
+	_bnei	a0, 1, 1f		# no 'movsp a1, ax': jump
+
+        /* Move the save area. This implies the use of the L32E
+	 * and S32E instructions, because this move must be done with
+	 * the user's PS.RING privilege levels, not with ring 0
+	 * (kernel's) privileges currently active with PS.EXCM
+	 * set. Note that we have stil registered a fixup routine with the
+	 * double exception vector in case a double exception occurs.
+	 */
+
+	/* a0,a4:avail a1:old user stack a2:exc. stack a3:new user stack. */
+
+	l32e	a0, a1, -16
+	l32e	a4, a1, -12
+	s32e	a0, a3, -16
+	s32e	a4, a3, -12
+	l32e	a0, a1, -8
+	l32e	a4, a1, -4
+	s32e	a0, a3, -8
+	s32e	a4, a3, -4
+
+	/* Restore stack-pointer and all the other saved registers. */
+
+	mov	a1, a3
+
+	l32i	a4, a2, PT_AREG4
+	l32i	a3, a2, PT_AREG3
+	l32i	a0, a2, PT_AREG0
+	l32i	a2, a2, PT_AREG2
+	rfe
+
+	/*  MOVSP <at>,<as>  was invoked with <at> != a1.
+	 *  Because the stack pointer is not being modified,
+	 *  we should be able to just modify the pointer
+	 *  without moving any save area.
+	 *  The processor only traps these occurrences if the
+	 *  caller window isn't live, so unfortunately we can't
+	 *  use this as an alternate trap mechanism.
+	 *  So we just do the move.  This requires that we
+	 *  resolve the destination register, not just the source,
+	 *  so there's some extra work.
+	 *  (PERHAPS NOT REALLY NEEDED, BUT CLEANER...)
+	 */
+
+	/* a0 dst-reg, a1 user-stack, a2 stack, a3 value of src reg. */
+
+1:	movi	a4, .Lmovsp_dst
+	addx8	a4, a0, a4
+	jx	a4
+
+	.align 8
+.Lmovsp_dst:
+	s32i	a3, a2, PT_AREG0;	_j 1f;	.align 8
+	mov	a1, a3;			_j 1f;	.align 8
+	s32i	a3, a2, PT_AREG2;	_j 1f;	.align 8
+	s32i	a3, a2, PT_AREG3;	_j 1f;	.align 8
+	s32i	a3, a2, PT_AREG4;	_j 1f;	.align 8
+	mov	a5, a3;			_j 1f;	.align 8
+	mov	a6, a3;			_j 1f;	.align 8
+	mov	a7, a3;			_j 1f;	.align 8
+	mov	a8, a3;			_j 1f;	.align 8
+	mov	a9, a3;			_j 1f;	.align 8
+	mov	a10, a3;		_j 1f;	.align 8
+	mov	a11, a3;		_j 1f;	.align 8
+	mov	a12, a3;		_j 1f;	.align 8
+	mov	a13, a3;		_j 1f;	.align 8
+	mov	a14, a3;		_j 1f;	.align 8
+	mov	a15, a3;		_j 1f;	.align 8
+
+1:	l32i	a4, a2, PT_AREG4
+	l32i	a3, a2, PT_AREG3
+	l32i	a0, a2, PT_AREG0
+	l32i	a2, a2, PT_AREG2
+	rfe
+
+
+/*
+ * fast system calls.
+ *
+ * WARNING:  The kernel doesn't save the entire user context before
+ * handling a fast system call.  These functions are small and short,
+ * usually offering some functionality not available to user tasks.
+ *
+ * BE CAREFUL TO PRESERVE THE USER'S CONTEXT.
+ *
+ * Entry condition:
+ *
+ *   a0:	trashed, original value saved on stack (PT_AREG0)
+ *   a1:	a1
+ *   a2:	new stack pointer, original in DEPC
+ *   a3:	dispatch table
+ *   depc:	a2, original value saved on stack (PT_DEPC)
+ *   excsave_1:	a3
+ */
+
+ENTRY(fast_syscall_kernel)
+
+	/* Skip syscall. */
+
+	rsr	a0, EPC_1
+	addi	a0, a0, 3
+	wsr	a0, EPC_1
+
+	l32i	a0, a2, PT_DEPC
+	bgeui	a0, VALID_DOUBLE_EXCEPTION_ADDRESS, fast_syscall_unrecoverable
+
+	rsr	a0, DEPC			# get syscall-nr
+	_beqz	a0, fast_syscall_spill_registers
+
+	addi	a0, a0, -__NR_sysxtensa
+	_beqz	a0, fast_syscall_sysxtensa
+
+	j	kernel_exception
+
+
+ENTRY(fast_syscall_user)
+
+	/* Skip syscall. */
+
+	rsr	a0, EPC_1
+	addi	a0, a0, 3
+	wsr	a0, EPC_1
+
+	l32i	a0, a2, PT_DEPC
+	bgeui	a0, VALID_DOUBLE_EXCEPTION_ADDRESS, fast_syscall_unrecoverable
+
+	rsr	a0, DEPC			# get syscall-nr
+	_beqz	a0, fast_syscall_spill_registers
+
+	addi	a0, a0, -__NR_sysxtensa
+	_beqz	a0, fast_syscall_sysxtensa
+
+	j	user_exception
+
+ENTRY(fast_syscall_unrecoverable)
+
+        /* Restore all states. */
+
+        l32i    a0, a2, PT_AREG0        # restore a0
+        xsr     a2, DEPC                # restore a2, depc
+        rsr     a3, EXCSAVE_1
+
+        wsr     a0, EXCSAVE_1
+        movi    a0, unrecoverable_exception
+        callx0  a0
+
+
+
+/*
+ * sysxtensa syscall handler
+ *
+ * int sysxtensa (XTENSA_ATOMIC_SET, ptr, val, unused);
+ * int sysxtensa (XTENSA_ATOMIC_ADD, ptr, val, unused);
+ * int sysxtensa (XTENSA_ATOMIC_EXG_ADD, ptr, val, unused);
+ * int sysxtensa (XTENSA_ATOMIC_CMP_SWP, ptr, oldval, newval);
+ * a2                    a6              a3    a4      a5
+ *
+ * Entry condition:
+ *
+ *   a0:	trashed, original value saved on stack (PT_AREG0)
+ *   a1:	a1
+ *   a2:	new stack pointer, original in DEPC
+ *   a3:	dispatch table
+ *   depc:	a2, original value saved on stack (PT_DEPC)
+ *   excsave_1:	a3
+ *
+ *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
+ *	     <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
+ *
+ * Note: we don't have to save a2; a2 holds the return value
+ *
+ * We use the two macros TRY and CATCH:
+ *
+ * TRY	 adds an entry to the __ex_table fixup table for the immediately
+ *	 following instruction.
+ *
+ * CATCH catches any exception that occurred at one of the preceeding TRY
+ *       statements and continues from there
+ *
+ * Usage TRY	l32i	a0, a1, 0
+ *		<other code>
+ *	 done:	rfe
+ *	 CATCH	<set return code>
+ *		j done
+ */
+
+#define TRY								\
+	.section __ex_table, "a";					\
+	.word	66f, 67f;						\
+	.text;								\
+66:
+
+#define CATCH								\
+67:
+
+ENTRY(fast_syscall_sysxtensa)
+
+	_beqz	a6, 1f
+	_blti	a6, SYSXTENSA_COUNT, 2f
+
+1:	j	user_exception
+
+2:	xsr	a3, EXCSAVE_1		# restore a3, excsave1
+	s32i	a7, a2, PT_AREG7
+
+	movi	a7, 4			# sizeof(unsigned int)
+	verify_area a3, a7, a0, a2, .Leac
+
+	_beqi	a6, SYSXTENSA_ATOMIC_SET, .Lset
+	_beqi	a6, SYSXTENSA_ATOMIC_EXG_ADD, .Lexg
+	_beqi	a6, SYSXTENSA_ATOMIC_ADD, .Ladd
+
+	/* Fall through for SYSXTENSA_ATOMIC_CMP_SWP */
+
+.Lswp:	/* Atomic compare and swap */
+
+TRY	l32i	a7, a3, 0		# read old value
+	bne	a7, a4, 1f		# same as old value? jump
+	s32i	a5, a3, 0		# different, modify value
+	movi	a7, 1			# and return 1
+	j	.Lret
+
+1:	movi	a7, 0			# same values: return 0
+	j	.Lret
+
+.Ladd:	/* Atomic add */
+.Lexg:	/* Atomic (exchange) add */
+
+TRY	l32i	a7, a3, 0
+	add	a4, a4, a7
+	s32i	a4, a3, 0
+	j	.Lret
+
+.Lset:	/* Atomic set */
+
+TRY	l32i	a7, a3, 0		# read old value as return value
+	s32i	a4, a3, 0		# write new value
+
+.Lret:	mov	a0, a2
+	mov	a2, a7
+	l32i	a7, a0, PT_AREG7
+	l32i	a3, a0, PT_AREG3
+	l32i	a0, a0, PT_AREG0
+	rfe
+
+CATCH
+.Leac:	movi	a7, -EFAULT
+	j	.Lret
+
+
+
+/* fast_syscall_spill_registers.
+ *
+ * Entry condition:
+ *
+ *   a0:	trashed, original value saved on stack (PT_AREG0)
+ *   a1:	a1
+ *   a2:	new stack pointer, original in DEPC
+ *   a3:	dispatch table
+ *   depc:	a2, original value saved on stack (PT_DEPC)
+ *   excsave_1:	a3
+ *
+ * Note: We assume the stack pointer is EXC_TABLE_KSTK in the fixup handler.
+ * Note: We don't need to save a2 in depc (return value)
+ */
+
+ENTRY(fast_syscall_spill_registers)
+
+	/* Register a FIXUP handler (pass current wb as a parameter) */
+
+	movi	a0, fast_syscall_spill_registers_fixup
+	s32i	a0, a3, EXC_TABLE_FIXUP
+	rsr	a0, WINDOWBASE
+	s32i	a0, a3, EXC_TABLE_PARAM
+
+	/* Save a3 and SAR on stack. */
+
+	rsr	a0, SAR
+	xsr	a3, EXCSAVE_1		# restore a3 and excsave_1
+	s32i	a0, a2, PT_AREG4	# store SAR to PT_AREG4
+	s32i	a3, a2, PT_AREG3
+
+	/* The spill routine might clobber a7, a11, and a15. */
+
+	s32i	a7, a2, PT_AREG5
+	s32i	a11, a2, PT_AREG6
+	s32i	a15, a2, PT_AREG7
+
+	call0	_spill_registers	# destroys a3, DEPC, and SAR
+
+	/* Advance PC, restore registers and SAR, and return from exception. */
+
+	l32i	a3, a2, PT_AREG4
+	l32i	a0, a2, PT_AREG0
+	wsr	a3, SAR
+	l32i	a3, a2, PT_AREG3
+
+	/* Restore clobbered registers. */
+
+	l32i	a7, a2, PT_AREG5
+	l32i	a11, a2, PT_AREG6
+	l32i	a15, a2, PT_AREG7
+
+	movi	a2, 0
+	rfe
+
+/* Fixup handler.
+ *
+ * We get here if the spill routine causes an exception, e.g. tlb miss.
+ * We basically restore WINDOWBASE and WINDOWSTART to the condition when
+ * we entered the spill routine and jump to the user exception handler.
+ *
+ * a0: value of depc, original value in depc
+ * a2: trashed, original value in EXC_TABLE_DOUBLE_SAVE
+ * a3: exctable, original value in excsave1
+ */
+
+fast_syscall_spill_registers_fixup:
+
+	rsr	a2, WINDOWBASE	# get current windowbase (a2 is saved)
+	xsr	a0, DEPC	# restore depc and a0
+	ssl	a2		# set shift (32 - WB)
+
+	/* We need to make sure the current registers (a0-a3) are preserved.
+	 * To do this, we simply set the bit for the current window frame
+	 * in WS, so that the exception handlers save them to the task stack.
+	 */
+
+	rsr	a3, EXCSAVE_1	# get spill-mask
+	slli	a2, a3, 1	# shift left by one
+
+	slli	a3, a2, 32-WSBITS
+	src	a2, a2, a3	# a1 = xxwww1yyxxxwww1yy......
+	wsr	a2, WINDOWSTART	# set corrected windowstart
+
+	movi	a3, exc_table
+	l32i	a2, a3, EXC_TABLE_DOUBLE_SAVE	# restore a2
+	l32i	a3, a3, EXC_TABLE_PARAM	# original WB (in user task)
+
+	/* Return to the original (user task) WINDOWBASE.
+	 * We leave the following frame behind:
+	 * a0, a1, a2	same
+	 * a3:		trashed (saved in excsave_1)
+	 * depc:	depc (we have to return to that address)
+	 * excsave_1:	a3
+	 */
+
+	wsr	a3, WINDOWBASE
+	rsync
+
+	/* We are now in the original frame when we entered _spill_registers:
+	 *  a0: return address
+	 *  a1: used, stack pointer
+	 *  a2: kernel stack pointer
+	 *  a3: available, saved in EXCSAVE_1
+	 *  depc: exception address
+	 *  excsave: a3
+	 * Note: This frame might be the same as above.
+	 */
+
+#ifdef SIGNAL_HANDLING_IN_DOUBLE_EXCEPTION
+	/* Restore registers we precautiously saved.
+	 * We have the value of the 'right' a3
+	 */
+
+	l32i	a7, a2, PT_AREG5
+	l32i	a11, a2, PT_AREG6
+	l32i	a15, a2, PT_AREG7
+#endif
+
+	/* Setup stack pointer. */
+
+	addi	a2, a2, -PT_USER_SIZE
+	s32i	a0, a2, PT_AREG0
+
+	/* Make sure we return to this fixup handler. */
+
+	movi	a3, fast_syscall_spill_registers_fixup_return
+	s32i	a3, a2, PT_DEPC		# setup depc
+
+	/* Jump to the exception handler. */
+
+	movi	a3, exc_table
+	rsr	a0, EXCCAUSE
+        addx4   a0, a0, a3              	# find entry in table
+        l32i    a0, a0, EXC_TABLE_FAST_USER     # load handler
+        jx      a0
+
+fast_syscall_spill_registers_fixup_return:
+
+	/* When we return here, all registers have been restored (a2: DEPC) */
+
+	wsr	a2, DEPC		# exception address
+
+	/* Restore fixup handler. */
+
+	xsr	a3, EXCSAVE_1
+	movi	a2, fast_syscall_spill_registers_fixup
+	s32i	a2, a3, EXC_TABLE_FIXUP
+	rsr	a2, WINDOWBASE
+	s32i	a2, a3, EXC_TABLE_PARAM
+	l32i	a2, a3, EXC_TABLE_KSTK
+
+#ifdef SIGNAL_HANDLING_IN_DOUBLE_EXCEPTION
+	/* Save registers again that might be clobbered. */
+
+	s32i	a7, a2, PT_AREG5
+	s32i	a11, a2, PT_AREG6
+	s32i	a15, a2, PT_AREG7
+#endif
+
+	/* Load WB at the time the exception occurred. */
+
+	rsr	a3, SAR			# WB is still in SAR
+	neg	a3, a3
+	wsr	a3, WINDOWBASE
+	rsync
+
+	/* Restore a3 and return. */
+
+	movi	a3, exc_table
+	xsr	a3, EXCSAVE_1
+
+	rfde
+
+
+/*
+ * spill all registers.
+ *
+ * This is not a real function. The following conditions must be met:
+ *
+ *  - must be called with call0.
+ *  - uses DEPC, a3 and SAR.
+ *  - the last 'valid' register of each frame are clobbered.
+ *  - the caller must have registered a fixup handler
+ *    (or be inside a critical section)
+ *  - PS_EXCM must be set (PS_WOE cleared?)
+ */
+
+ENTRY(_spill_registers)
+
+	/*
+	 * Rotate ws so that the current windowbase is at bit 0.
+	 * Assume ws = xxxwww1yy (www1 current window frame).
+	 * Rotate ws right so that a2 = yyxxxwww1.
+	 */
+
+	wsr	a2, DEPC		# preserve a2
+	rsr	a2, WINDOWBASE
+	rsr	a3, WINDOWSTART
+	ssr	a2			# holds WB
+	slli	a2, a3, WSBITS
+	or	a3, a3, a2		# a2 = xxxwww1yyxxxwww1yy
+	srl	a3, a3
+
+	/* We are done if there are no more than the current register frame. */
+
+	extui	a3, a3, 1, WSBITS-2	# a3 = 0yyxxxwww
+	movi	a2, (1 << (WSBITS-1))
+	_beqz	a3, .Lnospill		# only one active frame? jump
+
+	/* We want 1 at the top, so that we return to the current windowbase */
+
+	or	a3, a3, a2		# 1yyxxxwww
+
+	/* Skip empty frames - get 'oldest' WINDOWSTART-bit. */
+
+	wsr	a3, WINDOWSTART		# save shifted windowstart
+	neg	a2, a3
+	and	a3, a2, a3		# first bit set from right: 000010000
+
+	ffs_ws	a2, a3			# a2: shifts to skip empty frames
+	movi	a3, WSBITS
+	sub	a2, a3, a2		# WSBITS-a2:number of 0-bits from right
+	ssr	a2			# save in SAR for later.
+
+	rsr	a3, WINDOWBASE
+	add	a3, a3, a2
+	rsr	a2, DEPC		# restore a2
+	wsr	a3, WINDOWBASE
+	rsync
+
+	rsr	a3, WINDOWSTART
+	srl	a3, a3			# shift windowstart
+
+	/* WB is now just one frame below the oldest frame in the register
+	   window. WS is shifted so the oldest frame is in bit 0, thus, WB
+	   and WS differ by one 4-register frame. */
+
+	/* Save frames. Depending what call was used (call4, call8, call12),
+	 * we have to save 4,8. or 12 registers.
+	 */
+
+	_bbsi.l	a3, 1, .Lc4
+	_bbsi.l	a3, 2, .Lc8
+
+	/* Special case: we have a call12-frame starting at a4. */
+
+	_bbci.l	a3, 3, .Lc12	# bit 3 shouldn't be zero! (Jump to Lc12 first)
+
+	s32e	a4, a1, -16	# a1 is valid with an empty spill area
+	l32e	a4, a5, -12
+	s32e	a8, a4, -48
+	mov	a8, a4
+	l32e	a4, a1, -16
+	j	.Lc12c
+
+.Lloop: _bbsi.l	a3, 1, .Lc4
+	_bbci.l	a3, 2, .Lc12
+
+.Lc8:	s32e	a4, a13, -16
+	l32e	a4, a5, -12
+	s32e	a8, a4, -32
+	s32e	a5, a13, -12
+	s32e	a6, a13, -8
+	s32e	a7, a13, -4
+	s32e	a9, a4, -28
+	s32e	a10, a4, -24
+	s32e	a11, a4, -20
+
+	srli	a11, a3, 2		# shift windowbase by 2
+	rotw	2
+	_bnei	a3, 1, .Lloop
+
+.Lexit: /* Done. Do the final rotation, set WS, and return. */
+
+	rotw	1
+	rsr	a3, WINDOWBASE
+	ssl	a3
+	movi	a3, 1
+	sll	a3, a3
+	wsr	a3, WINDOWSTART
+
+.Lnospill:
+	jx	a0
+
+.Lc4:	s32e	a4, a9, -16
+	s32e	a5, a9, -12
+	s32e	a6, a9, -8
+	s32e	a7, a9, -4
+
+	srli	a7, a3, 1
+	rotw	1
+	_bnei	a3, 1, .Lloop
+	j	.Lexit
+
+.Lc12:	_bbci.l	a3, 3, .Linvalid_mask	# bit 2 shouldn't be zero!
+
+	/* 12-register frame (call12) */
+
+	l32e	a2, a5, -12
+	s32e	a8, a2, -48
+	mov	a8, a2
+
+.Lc12c: s32e	a9, a8, -44
+	s32e	a10, a8, -40
+	s32e	a11, a8, -36
+	s32e	a12, a8, -32
+	s32e	a13, a8, -28
+	s32e	a14, a8, -24
+	s32e	a15, a8, -20
+	srli	a15, a3, 3
+
+	/* The stack pointer for a4..a7 is out of reach, so we rotate the
+	 * window, grab the stackpointer, and rotate back.
+	 * Alternatively, we could also use the following approach, but that
+	 * makes the fixup routine much more complicated:
+	 * rotw	1
+	 * s32e	a0, a13, -16
+	 * ...
+	 * rotw 2
+	 */
+
+	rotw	1
+	mov	a5, a13
+	rotw	-1
+
+	s32e	a4, a9, -16
+	s32e	a5, a9, -12
+	s32e	a6, a9, -8
+	s32e	a7, a9, -4
+
+	rotw	3
+
+	_beqi	a3, 1, .Lexit
+	j	.Lloop
+
+.Linvalid_mask:
+
+	/* We get here because of an unrecoverable error in the window
+	 * registers. If we are in user space, we kill the application,
+	 * however, this condition is unrecoverable in kernel space.
+	 */
+
+	rsr	a0, PS
+	_bbci.l	a0, PS_UM_SHIFT, 1f
+
+ 	/* User space: Setup a dummy frame and kill application.
+	 * Note: We assume EXC_TABLE_KSTK contains a valid stack pointer.
+	 */
+
+	movi	a0, 1
+	movi	a1, 0
+
+	wsr	a0, WINDOWSTART
+	wsr	a1, WINDOWBASE
+	rsync
+
+	movi	a0, 0
+
+	movi	a3, exc_table
+	l32i	a1, a3, EXC_TABLE_KSTK
+	wsr	a3, EXCSAVE_1
+
+	movi	a4, PS_WOE_MASK | 1
+	wsr	a4, PS
+	rsync
+
+	movi	a6, SIGSEGV
+	movi	a4, do_exit
+	callx4	a4
+
+1:	/* Kernel space: PANIC! */
+
+	wsr	a0, EXCSAVE_1
+	movi	a0, unrecoverable_exception
+	callx0	a0		# should not return
+1:	j	1b
+
+/*
+ * We should never get here. Bail out!
+ */
+
+ENTRY(fast_second_level_miss_double_kernel)
+
+1:	movi	a0, unrecoverable_exception
+	callx0	a0		# should not return
+1:	j	1b
+
+/* First-level entry handler for user, kernel, and double 2nd-level
+ * TLB miss exceptions.  Note that for now, user and kernel miss
+ * exceptions share the same entry point and are handled identically.
+ *
+ * An old, less-efficient C version of this function used to exist.
+ * We include it below, interleaved as comments, for reference.
+ *
+ * Entry condition:
+ *
+ *   a0:	trashed, original value saved on stack (PT_AREG0)
+ *   a1:	a1
+ *   a2:	new stack pointer, original in DEPC
+ *   a3:	dispatch table
+ *   depc:	a2, original value saved on stack (PT_DEPC)
+ *   excsave_1:	a3
+ *
+ *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
+ *	     <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
+ */
+
+ENTRY(fast_second_level_miss)
+
+	/* Save a1. Note: we don't expect a double exception. */
+
+	s32i	a1, a2, PT_AREG1
+
+	/* We need to map the page of PTEs for the user task.  Find
+	 * the pointer to that page.  Also, it's possible for tsk->mm
+	 * to be NULL while tsk->active_mm is nonzero if we faulted on
+	 * a vmalloc address.  In that rare case, we must use
+	 * active_mm instead to avoid a fault in this handler.  See
+	 *
+	 * http://mail.nl.linux.org/linux-mm/2002-08/msg00258.html
+	 *   (or search Internet on "mm vs. active_mm")
+	 *
+	 *	if (!mm)
+	 *		mm = tsk->active_mm;
+	 *	pgd = pgd_offset (mm, regs->excvaddr);
+	 *	pmd = pmd_offset (pgd, regs->excvaddr);
+	 *	pmdval = *pmd;
+	 */
+
+	GET_CURRENT(a1,a2)
+	l32i	a0, a1, TASK_MM		# tsk->mm
+	beqz	a0, 9f
+
+8:	rsr	a1, EXCVADDR		# fault address
+	_PGD_OFFSET(a0, a1, a1)
+	l32i	a0, a0, 0		# read pmdval
+	//beqi	a0, _PAGE_USER, 2f
+	beqz	a0, 2f
+
+	/* Read ptevaddr and convert to top of page-table page.
+	 *
+	 * 	vpnval = read_ptevaddr_register() & PAGE_MASK;
+	 * 	vpnval += DTLB_WAY_PGTABLE;
+	 *	pteval = mk_pte (virt_to_page(pmd_val(pmdval)), PAGE_KERNEL);
+	 *	write_dtlb_entry (pteval, vpnval);
+	 *
+	 * The messy computation for 'pteval' above really simplifies
+	 * into the following:
+	 *
+	 * pteval = ((pmdval - PAGE_OFFSET) & PAGE_MASK) | PAGE_KERNEL
+	 */
+
+	movi	a1, -PAGE_OFFSET
+	add	a0, a0, a1		# pmdval - PAGE_OFFSET
+	extui	a1, a0, 0, PAGE_SHIFT	# ... & PAGE_MASK
+	xor	a0, a0, a1
+
+
+	movi	a1, PAGE_DIRECTORY
+	or	a0, a0, a1		# ... | PAGE_DIRECTORY
+
+	rsr	a1, PTEVADDR
+	srli	a1, a1, PAGE_SHIFT
+	slli	a1, a1, PAGE_SHIFT	# ptevaddr & PAGE_MASK
+	addi	a1, a1, DTLB_WAY_PGTABLE	# ... + way_number
+
+	wdtlb	a0, a1
+	dsync
+
+	/* Exit critical section. */
+
+	movi	a0, 0
+	s32i	a0, a3, EXC_TABLE_FIXUP
+
+	/* Restore the working registers, and return. */
+
+	l32i	a0, a2, PT_AREG0
+	l32i	a1, a2, PT_AREG1
+	l32i	a2, a2, PT_DEPC
+	xsr	a3, EXCSAVE_1
+
+	bgeui	a2, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f
+
+	/* Restore excsave1 and return. */
+
+	rsr	a2, DEPC
+	rfe
+
+	/* Return from double exception. */
+
+1:	xsr	a2, DEPC
+	esync
+	rfde
+
+9:	l32i	a0, a1, TASK_ACTIVE_MM	# unlikely case mm == 0
+	j	8b
+
+2:	/* Invalid PGD, default exception handling */
+
+	rsr	a1, DEPC
+	xsr	a3, EXCSAVE_1
+	s32i	a1, a2, PT_AREG2
+	s32i	a3, a2, PT_AREG3
+	mov	a1, a2
+
+	rsr	a2, PS
+	bbsi.l	a2, PS_UM_SHIFT, 1f
+	j	_kernel_exception
+1:	j	_user_exception
+
+
+/*
+ * StoreProhibitedException
+ *
+ * Update the pte and invalidate the itlb mapping for this pte.
+ *
+ * Entry condition:
+ *
+ *   a0:	trashed, original value saved on stack (PT_AREG0)
+ *   a1:	a1
+ *   a2:	new stack pointer, original in DEPC
+ *   a3:	dispatch table
+ *   depc:	a2, original value saved on stack (PT_DEPC)
+ *   excsave_1:	a3
+ *
+ *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
+ *	     <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
+ */
+
+ENTRY(fast_store_prohibited)
+
+	/* Save a1 and a4. */
+
+	s32i	a1, a2, PT_AREG1
+	s32i	a4, a2, PT_AREG4
+
+	GET_CURRENT(a1,a2)
+	l32i	a0, a1, TASK_MM		# tsk->mm
+	beqz	a0, 9f
+
+8:	rsr	a1, EXCVADDR		# fault address
+	_PGD_OFFSET(a0, a1, a4)
+	l32i	a0, a0, 0
+	//beqi	a0, _PAGE_USER, 2f	# FIXME use _PAGE_INVALID
+	beqz	a0, 2f
+
+	_PTE_OFFSET(a0, a1, a4)
+	l32i	a4, a0, 0		# read pteval
+	movi	a1, _PAGE_VALID | _PAGE_RW
+	bnall	a4, a1, 2f
+
+	movi	a1, _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_WRENABLE
+	or	a4, a4, a1
+	rsr	a1, EXCVADDR
+	s32i	a4, a0, 0
+
+	/* We need to flush the cache if we have page coloring. */
+#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
+	dhwb	a0, 0
+#endif
+	pdtlb	a0, a1
+	beqz	a0, 1f
+	idtlb	a0		// FIXME do we need this?
+	wdtlb	a4, a0
+1:
+
+	/* Exit critical section. */
+
+	movi	a0, 0
+	s32i	a0, a3, EXC_TABLE_FIXUP
+
+	/* Restore the working registers, and return. */
+
+	l32i	a4, a2, PT_AREG4
+	l32i	a1, a2, PT_AREG1
+	l32i	a0, a2, PT_AREG0
+	l32i	a2, a2, PT_DEPC
+
+	/* Restore excsave1 and a3. */
+
+	xsr	a3, EXCSAVE_1
+	bgeui	a2, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f
+
+	rsr	a2, DEPC
+	rfe
+
+	/* Double exception. Restore FIXUP handler and return. */
+
+1:	xsr	a2, DEPC
+	esync
+	rfde
+
+9:	l32i	a0, a1, TASK_ACTIVE_MM	# unlikely case mm == 0
+	j	8b
+
+2:	/* If there was a problem, handle fault in C */
+
+	rsr	a4, DEPC	# still holds a2
+	xsr	a3, EXCSAVE_1
+	s32i	a4, a2, PT_AREG2
+	s32i	a3, a2, PT_AREG3
+	l32i	a4, a2, PT_AREG4
+	mov	a1, a2
+
+	rsr	a2, PS
+	bbsi.l	a2, PS_UM_SHIFT, 1f
+	j	_kernel_exception
+1:	j	_user_exception
+
+
+#if XCHAL_EXTRA_SA_SIZE
+
+#warning fast_coprocessor untested
+
+/*
+ * Entry condition:
+ *
+ *   a0:	trashed, original value saved on stack (PT_AREG0)
+ *   a1:	a1
+ *   a2:	new stack pointer, original in DEPC
+ *   a3:	dispatch table
+ *   depc:	a2, original value saved on stack (PT_DEPC)
+ *   excsave_1:	a3
+ *
+ *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
+ *	     <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
+ */
+
+ENTRY(fast_coprocessor_double)
+	wsr	a0, EXCSAVE_1
+	movi	a0, unrecoverable_exception
+	callx0	a0
+
+ENTRY(fast_coprocessor)
+
+	/* Fatal if we are in a double exception. */
+
+	l32i	a0, a2, PT_DEPC
+	_bgeui	a0, VALID_DOUBLE_EXCEPTION_ADDRESS, fast_coprocessor_double
+
+	/* Save some registers a1, a3, a4, SAR */
+
+	xsr	a3, EXCSAVE_1
+	s32i	a3, a2, PT_AREG3
+	rsr	a3, SAR
+	s32i	a4, a2, PT_AREG4
+	s32i	a1, a2, PT_AREG1
+	s32i	a5, a1, PT_AREG5
+	s32i	a3, a2, PT_SAR
+	mov	a1, a2
+
+	/* Currently, the HAL macros only guarantee saving a0 and a1.
+	 * These can and will be refined in the future, but for now,
+	 * just save the remaining registers of a2...a15.
+	 */
+	s32i	a6, a1, PT_AREG6
+	s32i	a7, a1, PT_AREG7
+	s32i	a8, a1, PT_AREG8
+	s32i	a9, a1, PT_AREG9
+	s32i	a10, a1, PT_AREG10
+	s32i	a11, a1, PT_AREG11
+	s32i	a12, a1, PT_AREG12
+	s32i	a13, a1, PT_AREG13
+	s32i	a14, a1, PT_AREG14
+	s32i	a15, a1, PT_AREG15
+
+	/* Find coprocessor number. Subtract first CP EXCCAUSE from EXCCAUSE */
+
+	rsr	a0, EXCCAUSE
+	addi	a3, a0, -XCHAL_EXCCAUSE_COPROCESSOR0_DISABLED
+
+	/* Set corresponding CPENABLE bit */
+
+	movi	a4, 1
+	ssl	a3			# SAR: 32 - coprocessor_number
+	rsr	a5, CPENABLE
+	sll	a4, a4
+	or	a4, a5, a4
+	wsr	a4, CPENABLE
+	rsync
+	movi	a5, coprocessor_info	# list of owner and offset into cp_save
+	addx8	a0, a4, a5		# entry for CP
+
+	bne	a4, a5, .Lload		# bit wasn't set before, cp not in use
+
+	/* Now compare the current task with the owner of the coprocessor.
+	 * If they are the same, there is no reason to save or restore any
+	 * coprocessor state. Having already enabled the coprocessor,
+	 * branch ahead to return.
+	 */
+	GET_CURRENT(a5,a1)
+	l32i	a4, a0, COPROCESSOR_INFO_OWNER	# a4: current owner for this CP
+	beq	a4, a5, .Ldone
+
+	/* Find location to dump current coprocessor state:
+	 *  task_struct->task_cp_save_offset + coprocessor_offset[coprocessor]
+	 *
+	 * Note: a0 pointer to the entry in the coprocessor owner table,
+	 *	 a3 coprocessor number,
+         *	 a4 current owner of coprocessor.
+	 */
+	l32i	a5, a0, COPROCESSOR_INFO_OFFSET
+	addi	a2, a4, THREAD_CP_SAVE
+	add	a2, a2, a5
+
+	/* Store current coprocessor states. (a5 still has CP number) */
+
+	xchal_cpi_store_funcbody
+
+	/* The macro might have destroyed a3 (coprocessor number), but
+	 * SAR still has 32 - coprocessor_number!
+	 */
+	movi	a3, 32
+	rsr	a4, SAR
+	sub	a3, a3, a4
+
+.Lload:	/* A new task now owns the corpocessors. Save its TCB pointer into
+	 * the coprocessor owner table.
+	 *
+	 * Note: a0 pointer to the entry in the coprocessor owner table,
+	 *	 a3 coprocessor number.
+	 */
+	GET_CURRENT(a4,a1)
+	s32i	a4, a0, 0
+
+	/* Find location from where to restore the current coprocessor state.*/
+
+	l32i	a5, a0, COPROCESSOR_INFO_OFFSET
+	addi	a2, a4, THREAD_CP_SAVE
+	add	a2, a2, a4
+
+	xchal_cpi_load_funcbody
+
+	/* We must assume that the xchal_cpi_store_funcbody macro destroyed
+	 * registers a2..a15.
+	 */
+
+.Ldone:	l32i	a15, a1, PT_AREG15
+	l32i	a14, a1, PT_AREG14
+	l32i	a13, a1, PT_AREG13
+	l32i	a12, a1, PT_AREG12
+	l32i	a11, a1, PT_AREG11
+	l32i	a10, a1, PT_AREG10
+	l32i	a9, a1, PT_AREG9
+	l32i	a8, a1, PT_AREG8
+	l32i	a7, a1, PT_AREG7
+	l32i	a6, a1, PT_AREG6
+	l32i	a5, a1, PT_AREG5
+	l32i	a4, a1, PT_AREG4
+	l32i	a3, a1, PT_AREG3
+	l32i	a2, a1, PT_AREG2
+	l32i	a0, a1, PT_AREG0
+	l32i	a1, a1, PT_AREG1
+
+	rfe
+
+#endif /* XCHAL_EXTRA_SA_SIZE */
+
+/*
+ * Task switch.
+ *
+ * struct task*  _switch_to (struct task* prev, struct task* next)
+ *         a2                              a2                 a3
+ */
+
+ENTRY(_switch_to)
+
+	entry	a1, 16
+
+	mov	a4, a3			# preserve a3
+
+	s32i	a0, a2, THREAD_RA	# save return address
+	s32i	a1, a2, THREAD_SP	# save stack pointer
+
+	/* Disable ints while we manipulate the stack pointer; spill regs. */
+
+	movi	a5, PS_EXCM_MASK | LOCKLEVEL
+	xsr	a5, PS
+	rsr	a3, EXCSAVE_1
+	rsync
+	s32i	a3, a3, EXC_TABLE_FIXUP	/* enter critical section */
+
+	call0	_spill_registers
+
+	/* Set kernel stack (and leave critical section)
+	 * Note: It's save to set it here. The stack will not be overwritten
+	 *       because the kernel stack will only be loaded again after
+	 *       we return from kernel space.
+	 */
+
+	l32i	a0, a4, TASK_THREAD_INFO
+	rsr	a3, EXCSAVE_1		# exc_table
+	movi	a1, 0
+	addi	a0, a0, PT_REGS_OFFSET
+	s32i	a1, a3, EXC_TABLE_FIXUP
+	s32i	a0, a3, EXC_TABLE_KSTK
+
+	/* restore context of the task that 'next' addresses */
+
+	l32i	a0, a4, THREAD_RA	/* restore return address */
+	l32i	a1, a4, THREAD_SP	/* restore stack pointer */
+
+	wsr	a5, PS
+	rsync
+
+	retw
+
+
+ENTRY(ret_from_fork)
+
+	/* void schedule_tail (struct task_struct *prev)
+	 * Note: prev is still in a6 (return value from fake call4 frame)
+	 */
+	movi	a4, schedule_tail
+	callx4	a4
+
+	movi	a4, do_syscall_trace
+	callx4	a4
+
+	j	common_exception_return
+
+
+
+/*
+ * Table of syscalls
+ */
+
+.data
+.align  4
+.global sys_call_table
+sys_call_table:
+
+#define SYSCALL(call, narg) .word call
+#include "syscalls.h"
+
+/*
+ * Number of arguments of each syscall
+ */
+
+.global sys_narg_table
+sys_narg_table:
+
+#undef SYSCALL
+#define SYSCALL(call, narg) .byte narg
+#include "syscalls.h"
+
diff --git a/arch/xtensa/kernel/head.S b/arch/xtensa/kernel/head.S
new file mode 100644
index 0000000..6e9b522
--- /dev/null
+++ b/arch/xtensa/kernel/head.S
@@ -0,0 +1,237 @@
+/*
+ * arch/xtensa/kernel/head.S
+ *
+ * Xtensa Processor startup code.
+ *
+ * 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) 2001 - 2005 Tensilica Inc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ * Marc Gauthier <marc@tensilica.com, marc@alumni.uwaterloo.ca>
+ * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
+ * Kevin Chea
+ */
+
+#include <xtensa/cacheasm.h>
+#include <linux/config.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+
+/*
+ * This module contains the entry code for kernel images. It performs the
+ * minimal setup needed to call the generic C routines.
+ *
+ * Prerequisites:
+ *
+ * - The kernel image has been loaded to the actual address where it was
+ *   compiled to.
+ * - a2 contains either 0 or a pointer to a list of boot parameters.
+ *   (see setup.c for more details)
+ *
+ */
+
+	.macro	iterate	from, to , cmd
+		.ifeq	((\to - \from) & ~0xfff)
+			\cmd	\from
+			iterate "(\from+1)", \to, \cmd
+		.endif
+	.endm
+
+/*
+ *  _start
+ *
+ *  The bootloader passes a pointer to a list of boot parameters in a2.
+ */
+
+	/* The first bytes of the kernel image must be an instruction, so we
+	 * manually allocate and define the literal constant we need for a jx
+	 * instruction.
+	 */
+
+	.section .head.text, "ax"
+	.globl _start
+_start:	_j	2f
+	.align	4
+1:	.word	_startup
+2:	l32r	a0, 1b
+	jx	a0
+
+	.text
+	.align 4
+_startup:
+
+	/* Disable interrupts and exceptions. */
+
+	movi	a0, XCHAL_PS_EXCM_MASK
+	wsr	a0, PS
+
+	/* Preserve the pointer to the boot parameter list in EXCSAVE_1 */
+
+	wsr	a2, EXCSAVE_1
+
+	/* Start with a fresh windowbase and windowstart.  */
+
+	movi	a1, 1
+	movi	a0, 0
+	wsr	a1, WINDOWSTART
+	wsr	a0, WINDOWBASE
+	rsync
+
+	/* Set a0 to 0 for the remaining initialization. */
+
+	movi	a0, 0
+
+	/* Clear debugging registers. */
+
+#if XCHAL_HAVE_DEBUG
+	wsr	a0, IBREAKENABLE
+	wsr	a0, ICOUNT
+	movi	a1, 15
+	wsr	a0, ICOUNTLEVEL
+
+	.macro reset_dbreak num
+	wsr	a0, DBREAKC + \num
+	.endm
+
+        iterate 0, XCHAL_NUM_IBREAK-1, reset_dbreak
+#endif
+
+	/* Clear CCOUNT (not really necessary, but nice) */
+
+	wsr	a0, CCOUNT	# not really necessary, but nice
+
+	/* Disable zero-loops. */
+
+#if XCHAL_HAVE_LOOPS
+	wsr	a0, LCOUNT
+#endif
+
+	/* Disable all timers. */
+
+	.macro	reset_timer	num
+	wsr	a0, CCOMPARE_0 + \num
+	.endm
+	iterate	0, XCHAL_NUM_TIMERS-1, reset_timer
+
+	/* Interrupt initialization. */
+
+	movi	a2, XCHAL_INTTYPE_MASK_SOFTWARE | XCHAL_INTTYPE_MASK_EXTERN_EDGE
+	wsr	a0, INTENABLE
+	wsr	a2, INTCLEAR
+
+	/* Disable coprocessors. */
+
+#if XCHAL_CP_NUM > 0
+	wsr	a0, CPENABLE
+#endif
+
+	/* Set PS.INTLEVEL=1, PS.WOE=0, kernel stack, PS.EXCM=0
+	 *
+	 * Note: PS.EXCM must be cleared before using any loop
+	 *	 instructions; otherwise, they are silently disabled, and
+	 * 	 at most one iteration of the loop is executed.
+	 */
+
+	movi	a1, 1
+	wsr	a1, PS
+	rsync
+
+	/*  Initialize the caches.
+	 *  Does not include flushing writeback d-cache.
+	 *  a6, a7 are just working registers (clobbered).
+	 */
+
+	icache_reset  a2, a3
+	dcache_reset  a2, a3
+
+	/* Unpack data sections
+	 *
+	 * The linker script used to build the Linux kernel image
+	 * creates a table located at __boot_reloc_table_start
+	 * that contans the information what data needs to be unpacked.
+	 *
+	 * Uses a2-a7.
+	 */
+
+	movi	a2, __boot_reloc_table_start
+	movi	a3, __boot_reloc_table_end
+
+1:	beq	a2, a3, 3f	# no more entries?
+	l32i	a4, a2, 0	# start destination (in RAM)
+	l32i	a5, a2, 4	# end desination (in RAM)
+	l32i	a6, a2, 8	# start source (in ROM)
+	addi	a2, a2, 12	# next entry
+	beq	a4, a5, 1b	# skip, empty entry
+	beq	a4, a6, 1b	# skip, source and dest. are the same
+
+2:	l32i	a7, a6, 0	# load word
+	addi	a6, a6, 4
+	s32i	a7, a4, 0	# store word
+	addi	a4, a4, 4
+	bltu	a4, a5, 2b
+	j	1b
+
+3:
+	/* All code and initialized data segments have been copied.
+	 * Now clear the BSS segment.
+	 */
+
+	movi	a2, _bss_start	# start of BSS
+	movi	a3, _bss_end	# end of BSS
+
+1:	addi	a2, a2, 4
+	s32i	a0, a2, 0
+	blt	a2, a3, 1b
+
+#if XCHAL_DCACHE_IS_WRITEBACK
+
+	/* After unpacking, flush the writeback cache to memory so the
+	 * instructions/data are available.
+	 */
+
+	dcache_writeback_all	a2, a3
+#endif
+
+	/* Setup stack and enable window exceptions (keep irqs disabled) */
+
+	movi	a1, init_thread_union
+	addi	a1, a1, KERNEL_STACK_SIZE
+
+	movi	a2, 0x00040001		# WOE=1, INTLEVEL=1, UM=0
+	wsr	a2, PS			# (enable reg-windows; progmode stack)
+	rsync
+
+	/* Set up EXCSAVE[DEBUGLEVEL] to point to the Debug Exception Handler.*/
+
+	movi	a2, debug_exception
+	wsr	a2, EXCSAVE + XCHAL_DEBUGLEVEL
+
+	/* Set up EXCSAVE[1] to point to the exc_table. */
+
+	movi	a6, exc_table
+	xsr	a6, EXCSAVE_1
+
+	/* init_arch kick-starts the linux kernel */
+
+	movi	a4, init_arch
+	callx4	a4
+
+	movi	a4, start_kernel
+	callx4	a4
+
+should_never_return:
+	j	should_never_return
+
+	/* Define some common data structures here.  We define them
+	 * here in this assembly file due to their unusual alignment
+	 * requirements.
+	 */
+
+	.comm   swapper_pg_dir,PAGE_SIZE,PAGE_SIZE
+	.comm	empty_bad_page_table,PAGE_SIZE,PAGE_SIZE
+	.comm	empty_bad_page,PAGE_SIZE,PAGE_SIZE
+	.comm	empty_zero_page,PAGE_SIZE,PAGE_SIZE
+
diff --git a/arch/xtensa/kernel/irq.c b/arch/xtensa/kernel/irq.c
new file mode 100644
index 0000000..4cbf6d9
--- /dev/null
+++ b/arch/xtensa/kernel/irq.c
@@ -0,0 +1,192 @@
+/*
+ * linux/arch/xtensa/kernel/irq.c
+ *
+ * Xtensa built-in interrupt controller and some generic functions copied
+ * from i386.
+ *
+ * Copyright (C) 2002 - 2005 Tensilica, Inc.
+ * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
+ *
+ *
+ * Chris Zankel <chris@zankel.net>
+ * Kevin Chea
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel_stat.h>
+
+#include <asm/uaccess.h>
+#include <asm/platform.h>
+
+static void enable_xtensa_irq(unsigned int irq);
+static void disable_xtensa_irq(unsigned int irq);
+static void mask_and_ack_xtensa(unsigned int irq);
+static void end_xtensa_irq(unsigned int irq);
+
+static unsigned int cached_irq_mask;
+
+atomic_t irq_err_count;
+
+/*
+ * 'what should we do if we get a hw irq event on an illegal vector'.
+ * each architecture has to answer this themselves.
+ */
+void ack_bad_irq(unsigned int irq)
+{
+          printk("unexpected IRQ trap at vector %02x\n", irq);
+}
+
+/*
+ * do_IRQ handles all normal device IRQ's (the special
+ * SMP cross-CPU interrupts have their own specific
+ * handlers).
+ */
+
+unsigned int  do_IRQ(int irq, struct pt_regs *regs)
+{
+	irq_enter();
+
+#ifdef CONFIG_DEBUG_STACKOVERFLOW
+	/* Debugging check for stack overflow: is there less than 1KB free? */
+	{
+		unsigned long sp;
+
+		__asm__ __volatile__ ("mov %0, a1\n" : "=a" (sp));
+		sp &= THREAD_SIZE - 1;
+
+		if (unlikely(sp < (sizeof(thread_info) + 1024)))
+			printk("Stack overflow in do_IRQ: %ld\n",
+			       sp - sizeof(struct thread_info));
+	}
+#endif
+
+	__do_IRQ(irq, regs);
+
+	irq_exit();
+
+	return 1;
+}
+
+/*
+ * Generic, controller-independent functions:
+ */
+
+int show_interrupts(struct seq_file *p, void *v)
+{
+	int i = *(loff_t *) v, j;
+	struct irqaction * action;
+	unsigned long flags;
+
+	if (i == 0) {
+		seq_printf(p, "           ");
+		for (j=0; j<NR_CPUS; j++)
+			if (cpu_online(j))
+				seq_printf(p, "CPU%d       ",j);
+		seq_putc(p, '\n');
+	}
+
+	if (i < NR_IRQS) {
+		spin_lock_irqsave(&irq_desc[i].lock, flags);
+		action = irq_desc[i].action;
+		if (!action)
+			goto skip;
+		seq_printf(p, "%3d: ",i);
+#ifndef CONFIG_SMP
+		seq_printf(p, "%10u ", kstat_irqs(i));
+#else
+		for (j = 0; j < NR_CPUS; j++)
+			if (cpu_online(j))
+				seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
+#endif
+		seq_printf(p, " %14s", irq_desc[i].handler->typename);
+		seq_printf(p, "  %s", action->name);
+
+		for (action=action->next; action; action = action->next)
+			seq_printf(p, ", %s", action->name);
+
+		seq_putc(p, '\n');
+skip:
+		spin_unlock_irqrestore(&irq_desc[i].lock, flags);
+	} else if (i == NR_IRQS) {
+		seq_printf(p, "NMI: ");
+		for (j = 0; j < NR_CPUS; j++)
+			if (cpu_online(j))
+				seq_printf(p, "%10u ", nmi_count(j));
+		seq_putc(p, '\n');
+		seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
+	}
+	return 0;
+}
+/* shutdown is same as "disable" */
+#define shutdown_xtensa_irq disable_xtensa_irq
+
+static unsigned int startup_xtensa_irq(unsigned int irq)
+{
+	enable_xtensa_irq(irq);
+	return 0;               /* never anything pending */
+}
+
+static struct hw_interrupt_type xtensa_irq_type = {
+	"Xtensa-IRQ",
+	startup_xtensa_irq,
+	shutdown_xtensa_irq,
+	enable_xtensa_irq,
+	disable_xtensa_irq,
+	mask_and_ack_xtensa,
+	end_xtensa_irq
+};
+
+static inline void mask_irq(unsigned int irq)
+{
+	cached_irq_mask &= ~(1 << irq);
+	set_sr (cached_irq_mask, INTENABLE);
+}
+
+static inline void unmask_irq(unsigned int irq)
+{
+	cached_irq_mask |= 1 << irq;
+	set_sr (cached_irq_mask, INTENABLE);
+}
+
+static void disable_xtensa_irq(unsigned int irq)
+{
+	unsigned long flags;
+	local_save_flags(flags);
+	mask_irq(irq);
+	local_irq_restore(flags);
+}
+
+static void enable_xtensa_irq(unsigned int irq)
+{
+	unsigned long flags;
+	local_save_flags(flags);
+	unmask_irq(irq);
+	local_irq_restore(flags);
+}
+
+static void mask_and_ack_xtensa(unsigned int irq)
+{
+        disable_xtensa_irq(irq);
+}
+
+static void end_xtensa_irq(unsigned int irq)
+{
+        enable_xtensa_irq(irq);
+}
+
+
+void __init init_IRQ(void)
+{
+	int i;
+
+	for (i=0; i < XTENSA_NR_IRQS; i++)
+		irq_desc[i].handler = &xtensa_irq_type;
+
+	cached_irq_mask = 0;
+
+	platform_init_irq();
+}
diff --git a/arch/xtensa/kernel/module.c b/arch/xtensa/kernel/module.c
new file mode 100644
index 0000000..d1683cf
--- /dev/null
+++ b/arch/xtensa/kernel/module.c
@@ -0,0 +1,78 @@
+/*
+ * arch/xtensa/kernel/platform.c
+ *
+ * Module support.
+ *
+ * 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) 2001 - 2005 Tensilica Inc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleloader.h>
+#include <linux/elf.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/cache.h>
+
+LIST_HEAD(module_buf_list);
+
+void *module_alloc(unsigned long size)
+{
+  panic("module_alloc not implemented");
+}
+
+void module_free(struct module *mod, void *module_region)
+{
+  panic("module_free not implemented");
+}
+
+int module_frob_arch_sections(Elf32_Ehdr *hdr,
+    			      Elf32_Shdr *sechdrs,
+			      char *secstrings,
+			      struct module *me)
+{
+  panic("module_frob_arch_sections not implemented");
+}
+
+int apply_relocate(Elf32_Shdr *sechdrs,
+    		   const char *strtab,
+		   unsigned int symindex,
+		   unsigned int relsec,
+		   struct module *module)
+{
+  panic ("apply_relocate not implemented");
+}
+
+int apply_relocate_add(Elf32_Shdr *sechdrs,
+		       const char *strtab,
+		       unsigned int symindex,
+		       unsigned int relsec,
+		       struct module *module)
+{
+  panic("apply_relocate_add not implemented");
+}
+
+int module_finalize(const Elf_Ehdr *hdr,
+    		    const Elf_Shdr *sechdrs,
+		    struct module *me)
+{
+  panic ("module_finalize not implemented");
+}
+
+void module_arch_cleanup(struct module *mod)
+{
+  panic("module_arch_cleanup not implemented");
+}
+
+struct bug_entry *module_find_bug(unsigned long bugaddr)
+{
+  panic("module_find_bug not implemented");
+}
diff --git a/arch/xtensa/kernel/pci-dma.c b/arch/xtensa/kernel/pci-dma.c
new file mode 100644
index 0000000..84fde25
--- /dev/null
+++ b/arch/xtensa/kernel/pci-dma.c
@@ -0,0 +1,73 @@
+/*
+ * arch/xtensa/pci-dma.c
+ *
+ * DMA coherent memory allocation.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * Copyright (C) 2002 - 2005 Tensilica Inc.
+ *
+ * Based on version for i386.
+ *
+ * Chris Zankel <chris@zankel.net>
+ * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <asm/cacheflush.h>
+
+/*
+ * Note: We assume that the full memory space is always mapped to 'kseg'
+ *	 Otherwise we have to use page attributes (not implemented).
+ */
+
+void *
+dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, int gfp)
+{
+	void *ret;
+
+	/* ignore region speicifiers */
+	gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
+
+	if (dev == NULL || (*dev->dma_mask < 0xffffffff))
+		gfp |= GFP_DMA;
+	ret = (void *)__get_free_pages(gfp, get_order(size));
+
+	if (ret != NULL) {
+		memset(ret, 0, size);
+		*handle = virt_to_bus(ret);
+	}
+	return (void*) BYPASS_ADDR((unsigned long)ret);
+}
+
+void dma_free_coherent(struct device *hwdev, size_t size,
+			 void *vaddr, dma_addr_t dma_handle)
+{
+	free_pages(CACHED_ADDR((unsigned long)vaddr), get_order(size));
+}
+
+
+void consistent_sync(void *vaddr, size_t size, int direction)
+{
+	switch (direction) {
+	case PCI_DMA_NONE:
+		BUG();
+	case PCI_DMA_FROMDEVICE:        /* invalidate only */
+		__invalidate_dcache_range((unsigned long)vaddr,
+				          (unsigned long)size);
+		break;
+
+	case PCI_DMA_TODEVICE:          /* writeback only */
+	case PCI_DMA_BIDIRECTIONAL:     /* writeback and invalidate */
+		__flush_invalidate_dcache_range((unsigned long)vaddr,
+				    		(unsigned long)size);
+		break;
+	}
+}
diff --git a/arch/xtensa/kernel/pci.c b/arch/xtensa/kernel/pci.c
new file mode 100644
index 0000000..d29a816
--- /dev/null
+++ b/arch/xtensa/kernel/pci.c
@@ -0,0 +1,563 @@
+/*
+ * arch/xtensa/pcibios.c
+ *
+ * PCI bios-type initialisation for PCI machines
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * Copyright (C) 2001-2005 Tensilica Inc.
+ *
+ * Based largely on work from Cort (ppc/kernel/pci.c)
+ * IO functions copied from sparc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/bootmem.h>
+
+#include <asm/pci-bridge.h>
+#include <asm/platform.h>
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+/* PCI Controller */
+
+
+/*
+ * pcibios_alloc_controller
+ * pcibios_enable_device
+ * pcibios_fixups
+ * pcibios_align_resource
+ * pcibios_fixup_bus
+ * pcibios_setup
+ * pci_bus_add_device
+ * pci_mmap_page_range
+ */
+
+struct pci_controller* pci_ctrl_head;
+struct pci_controller** pci_ctrl_tail = &pci_ctrl_head;
+
+static int pci_bus_count;
+
+static void pcibios_fixup_resources(struct pci_dev* dev);
+
+#if 0 // FIXME
+struct pci_fixup pcibios_fixups[] = {
+	{ DECLARE_PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources },
+	{ 0 }
+};
+#endif
+
+void
+pcibios_update_resource(struct pci_dev *dev, struct resource *root,
+			struct resource *res, int resource)
+{
+	u32 new, check, mask;
+	int reg;
+	struct pci_controller* pci_ctrl = dev->sysdata;
+
+	new = res->start;
+	if (pci_ctrl && res->flags & IORESOURCE_IO) {
+		new -= pci_ctrl->io_space.base;
+	}
+	new |= (res->flags & PCI_REGION_FLAG_MASK);
+	if (resource < 6) {
+		reg = PCI_BASE_ADDRESS_0 + 4*resource;
+	} else if (resource == PCI_ROM_RESOURCE) {
+		res->flags |= PCI_ROM_ADDRESS_ENABLE;
+		reg = dev->rom_base_reg;
+	} else {
+	/* Somebody might have asked allocation of a non-standard resource */
+		return;
+	}
+
+	pci_write_config_dword(dev, reg, new);
+	pci_read_config_dword(dev, reg, &check);
+	mask = (new & PCI_BASE_ADDRESS_SPACE_IO) ?
+		PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK;
+
+	if ((new ^ check) & mask) {
+		printk(KERN_ERR "PCI: Error while updating region "
+		       "%s/%d (%08x != %08x)\n", dev->slot_name, resource,
+		       new, check);
+	}
+}
+
+/*
+ * We need to avoid collisions with `mirrored' VGA ports
+ * and other strange ISA hardware, so we always want the
+ * addresses to be allocated in the 0x000-0x0ff region
+ * modulo 0x400.
+ *
+ * Why? Because some silly external IO cards only decode
+ * the low 10 bits of the IO address. The 0x00-0xff region
+ * is reserved for motherboard devices that decode all 16
+ * bits, so it's ok to allocate at, say, 0x2800-0x28ff,
+ * but we want to try to avoid allocating at 0x2900-0x2bff
+ * which might have be mirrored at 0x0100-0x03ff..
+ */
+void
+pcibios_align_resource(void *data, struct resource *res, unsigned long size,
+    		       unsigned long align)
+{
+	struct pci_dev *dev = data;
+
+	if (res->flags & IORESOURCE_IO) {
+		unsigned long start = res->start;
+
+		if (size > 0x100) {
+			printk(KERN_ERR "PCI: I/O Region %s/%d too large"
+			       " (%ld bytes)\n", dev->slot_name,
+			       dev->resource - res, size);
+		}
+
+		if (start & 0x300) {
+			start = (start + 0x3ff) & ~0x3ff;
+			res->start = start;
+		}
+	}
+}
+
+int
+pcibios_enable_resources(struct pci_dev *dev, int mask)
+{
+	u16 cmd, old_cmd;
+	int idx;
+	struct resource *r;
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	old_cmd = cmd;
+	for(idx=0; idx<6; idx++) {
+		r = &dev->resource[idx];
+		if (!r->start && r->end) {
+			printk (KERN_ERR "PCI: Device %s not available because "
+				"of resource collisions\n", dev->slot_name);
+			return -EINVAL;
+		}
+		if (r->flags & IORESOURCE_IO)
+			cmd |= PCI_COMMAND_IO;
+		if (r->flags & IORESOURCE_MEM)
+			cmd |= PCI_COMMAND_MEMORY;
+	}
+	if (dev->resource[PCI_ROM_RESOURCE].start)
+		cmd |= PCI_COMMAND_MEMORY;
+	if (cmd != old_cmd) {
+		printk("PCI: Enabling device %s (%04x -> %04x)\n",
+			dev->slot_name, old_cmd, cmd);
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	}
+	return 0;
+}
+
+struct pci_controller * __init pcibios_alloc_controller(void)
+{
+	struct pci_controller *pci_ctrl;
+
+	pci_ctrl = (struct pci_controller *)alloc_bootmem(sizeof(*pci_ctrl));
+	memset(pci_ctrl, 0, sizeof(struct pci_controller));
+
+	*pci_ctrl_tail = pci_ctrl;
+	pci_ctrl_tail = &pci_ctrl->next;
+
+	return pci_ctrl;
+}
+
+static int __init pcibios_init(void)
+{
+	struct pci_controller *pci_ctrl;
+	struct pci_bus *bus;
+	int next_busno = 0, i;
+
+	printk("PCI: Probing PCI hardware\n");
+
+	/* Scan all of the recorded PCI controllers.  */
+	for (pci_ctrl = pci_ctrl_head; pci_ctrl; pci_ctrl = pci_ctrl->next) {
+		pci_ctrl->last_busno = 0xff;
+		bus = pci_scan_bus(pci_ctrl->first_busno, pci_ctrl->ops,
+				   pci_ctrl);
+		if (pci_ctrl->io_resource.flags) {
+			unsigned long offs;
+
+			offs = (unsigned long)pci_ctrl->io_space.base;
+			pci_ctrl->io_resource.start += offs;
+			pci_ctrl->io_resource.end += offs;
+			bus->resource[0] = &pci_ctrl->io_resource;
+		}
+		for (i = 0; i < 3; ++i)
+			if (pci_ctrl->mem_resources[i].flags)
+				bus->resource[i+1] =&pci_ctrl->mem_resources[i];
+		pci_ctrl->bus = bus;
+		pci_ctrl->last_busno = bus->subordinate;
+		if (next_busno <= pci_ctrl->last_busno)
+			next_busno = pci_ctrl->last_busno+1;
+	}
+	pci_bus_count = next_busno;
+
+	return platform_pcibios_fixup();
+}
+
+subsys_initcall(pcibios_init);
+
+void __init pcibios_fixup_bus(struct pci_bus *bus)
+{
+	struct pci_controller *pci_ctrl = bus->sysdata;
+	struct resource *res;
+	unsigned long io_offset;
+	int i;
+
+	io_offset = (unsigned long)pci_ctrl->io_space.base;
+	if (bus->parent == NULL) {
+		/* this is a host bridge - fill in its resources */
+		pci_ctrl->bus = bus;
+
+		bus->resource[0] = res = &pci_ctrl->io_resource;
+		if (!res->flags) {
+			if (io_offset)
+				printk (KERN_ERR "I/O resource not set for host"
+					" bridge %d\n", pci_ctrl->index);
+			res->start = 0;
+			res->end = IO_SPACE_LIMIT;
+			res->flags = IORESOURCE_IO;
+		}
+		res->start += io_offset;
+		res->end += io_offset;
+
+		for (i = 0; i < 3; i++) {
+			res = &pci_ctrl->mem_resources[i];
+			if (!res->flags) {
+				if (i > 0)
+					continue;
+				printk(KERN_ERR "Memory resource not set for "
+				       "host bridge %d\n", pci_ctrl->index);
+				res->start = 0;
+				res->end = ~0U;
+				res->flags = IORESOURCE_MEM;
+			}
+			bus->resource[i+1] = res;
+		}
+	} else {
+		/* This is a subordinate bridge */
+		pci_read_bridge_bases(bus);
+
+		for (i = 0; i < 4; i++) {
+			if ((res = bus->resource[i]) == NULL || !res->flags)
+				continue;
+			if (io_offset && (res->flags & IORESOURCE_IO)) {
+				res->start += io_offset;
+				res->end += io_offset;
+			}
+		}
+	}
+}
+
+char __init *pcibios_setup(char *str)
+{
+	return str;
+}
+
+/* the next one is stolen from the alpha port... */
+
+void __init
+pcibios_update_irq(struct pci_dev *dev, int irq)
+{
+	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+}
+
+int pcibios_enable_device(struct pci_dev *dev, int mask)
+{
+	u16 cmd, old_cmd;
+	int idx;
+	struct resource *r;
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	old_cmd = cmd;
+	for (idx=0; idx<6; idx++) {
+		r = &dev->resource[idx];
+		if (!r->start && r->end) {
+			printk(KERN_ERR "PCI: Device %s not available because "
+			       "of resource collisions\n", dev->slot_name);
+			return -EINVAL;
+		}
+		if (r->flags & IORESOURCE_IO)
+			cmd |= PCI_COMMAND_IO;
+		if (r->flags & IORESOURCE_MEM)
+			cmd |= PCI_COMMAND_MEMORY;
+	}
+	if (cmd != old_cmd) {
+		printk("PCI: Enabling device %s (%04x -> %04x)\n",
+		       dev->slot_name, old_cmd, cmd);
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_PROC_FS
+
+/*
+ * Return the index of the PCI controller for device pdev.
+ */
+
+int
+pci_controller_num(struct pci_dev *dev)
+{
+	struct pci_controller *pci_ctrl = (struct pci_controller*) dev->sysdata;
+	return pci_ctrl->index;
+}
+
+#endif /* CONFIG_PROC_FS */
+
+
+static void
+pcibios_fixup_resources(struct pci_dev *dev)
+{
+	struct pci_controller* pci_ctrl = (struct pci_controller *)dev->sysdata;
+	int i;
+	unsigned long offset;
+
+	if (!pci_ctrl) {
+		printk(KERN_ERR "No pci_ctrl for PCI dev %s!\n",dev->slot_name);
+		return;
+	}
+	for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+		struct resource *res = dev->resource + i;
+		if (!res->start || !res->flags)
+			continue;
+		if (res->end == 0xffffffff) {
+			DBG("PCI:%s Resource %d [%08lx-%08lx] is unassigned\n",
+			    dev->slot_name, i, res->start, res->end);
+			res->end -= res->start;
+			res->start = 0;
+			continue;
+		}
+		offset = 0;
+		if (res->flags & IORESOURCE_IO)
+			offset = (unsigned long) pci_ctrl->io_space.base;
+		else if (res->flags & IORESOURCE_MEM)
+			offset = (unsigned long) pci_ctrl->mem_space.base;
+
+		if (offset != 0) {
+			res->start += offset;
+			res->end += offset;
+#ifdef DEBUG
+			printk("Fixup res %d (%lx) of dev %s: %lx -> %lx\n",
+			       i, res->flags, dev->slot_name,
+			       res->start - offset, res->start);
+#endif
+		}
+	}
+}
+
+/*
+ * Platform support for /proc/bus/pci/X/Y mmap()s,
+ * modelled on the sparc64 implementation by Dave Miller.
+ *  -- paulus.
+ */
+
+/*
+ * Adjust vm_pgoff of VMA such that it is the physical page offset
+ * corresponding to the 32-bit pci bus offset for DEV requested by the user.
+ *
+ * Basically, the user finds the base address for his device which he wishes
+ * to mmap.  They read the 32-bit value from the config space base register,
+ * add whatever PAGE_SIZE multiple offset they wish, and feed this into the
+ * offset parameter of mmap on /proc/bus/pci/XXX for that device.
+ *
+ * Returns negative error code on failure, zero on success.
+ */
+static __inline__ int
+__pci_mmap_make_offset(struct pci_dev *dev, struct vm_area_struct *vma,
+		       enum pci_mmap_state mmap_state)
+{
+	struct pci_controller *pci_ctrl = (struct pci_controller*) dev->sysdata;
+	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+	unsigned long io_offset = 0;
+	int i, res_bit;
+
+	if (pci_ctrl == 0)
+		return -EINVAL;		/* should never happen */
+
+	/* If memory, add on the PCI bridge address offset */
+	if (mmap_state == pci_mmap_mem) {
+		res_bit = IORESOURCE_MEM;
+	} else {
+		io_offset = (unsigned long)pci_ctrl->io_space.base;
+		offset += io_offset;
+		res_bit = IORESOURCE_IO;
+	}
+
+	/*
+	 * Check that the offset requested corresponds to one of the
+	 * resources of the device.
+	 */
+	for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
+		struct resource *rp = &dev->resource[i];
+		int flags = rp->flags;
+
+		/* treat ROM as memory (should be already) */
+		if (i == PCI_ROM_RESOURCE)
+			flags |= IORESOURCE_MEM;
+
+		/* Active and same type? */
+		if ((flags & res_bit) == 0)
+			continue;
+
+		/* In the range of this resource? */
+		if (offset < (rp->start & PAGE_MASK) || offset > rp->end)
+			continue;
+
+		/* found it! construct the final physical address */
+		if (mmap_state == pci_mmap_io)
+			offset += pci_ctrl->io_space.start - io_offset;
+		vma->vm_pgoff = offset >> PAGE_SHIFT;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+/*
+ * Set vm_flags of VMA, as appropriate for this architecture, for a pci device
+ * mapping.
+ */
+static __inline__ void
+__pci_mmap_set_flags(struct pci_dev *dev, struct vm_area_struct *vma,
+		     enum pci_mmap_state mmap_state)
+{
+	vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
+}
+
+/*
+ * Set vm_page_prot of VMA, as appropriate for this architecture, for a pci
+ * device mapping.
+ */
+static __inline__ void
+__pci_mmap_set_pgprot(struct pci_dev *dev, struct vm_area_struct *vma,
+		      enum pci_mmap_state mmap_state, int write_combine)
+{
+	int prot = pgprot_val(vma->vm_page_prot);
+
+	/* Set to write-through */
+	prot &= ~_PAGE_NO_CACHE;
+#if 0
+	if (!write_combine)
+		prot |= _PAGE_WRITETHRU;
+#endif
+	vma->vm_page_prot = __pgprot(prot);
+}
+
+/*
+ * Perform the actual remap of the pages for a PCI device mapping, as
+ * appropriate for this architecture.  The region in the process to map
+ * is described by vm_start and vm_end members of VMA, the base physical
+ * address is found in vm_pgoff.
+ * The pci device structure is provided so that architectures may make mapping
+ * decisions on a per-device or per-bus basis.
+ *
+ * Returns a negative error code on failure, zero on success.
+ */
+int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
+			enum pci_mmap_state mmap_state,
+			int write_combine)
+{
+	int ret;
+
+	ret = __pci_mmap_make_offset(dev, vma, mmap_state);
+	if (ret < 0)
+		return ret;
+
+	__pci_mmap_set_flags(dev, vma, mmap_state);
+	__pci_mmap_set_pgprot(dev, vma, mmap_state, write_combine);
+
+	ret = io_remap_page_range(vma, vma->vm_start, vma->vm_pgoff<<PAGE_SHIFT,
+			       vma->vm_end - vma->vm_start, vma->vm_page_prot);
+
+	return ret;
+}
+
+/*
+ * This probably belongs here rather than ioport.c because
+ * we do not want this crud linked into SBus kernels.
+ * Also, think for a moment about likes of floppy.c that
+ * include architecture specific parts. They may want to redefine ins/outs.
+ *
+ * We do not use horroble macroses here because we want to
+ * advance pointer by sizeof(size).
+ */
+void outsb(unsigned long addr, const void *src, unsigned long count) {
+        while (count) {
+                count -= 1;
+                writeb(*(const char *)src, addr);
+                src += 1;
+                addr += 1;
+        }
+}
+
+void outsw(unsigned long addr, const void *src, unsigned long count) {
+        while (count) {
+                count -= 2;
+                writew(*(const short *)src, addr);
+                src += 2;
+                addr += 2;
+        }
+}
+
+void outsl(unsigned long addr, const void *src, unsigned long count) {
+        while (count) {
+                count -= 4;
+                writel(*(const long *)src, addr);
+                src += 4;
+                addr += 4;
+        }
+}
+
+void insb(unsigned long addr, void *dst, unsigned long count) {
+        while (count) {
+                count -= 1;
+                *(unsigned char *)dst = readb(addr);
+                dst += 1;
+                addr += 1;
+        }
+}
+
+void insw(unsigned long addr, void *dst, unsigned long count) {
+        while (count) {
+                count -= 2;
+                *(unsigned short *)dst = readw(addr);
+                dst += 2;
+                addr += 2;
+        }
+}
+
+void insl(unsigned long addr, void *dst, unsigned long count) {
+        while (count) {
+                count -= 4;
+                /*
+                 * XXX I am sure we are in for an unaligned trap here.
+                 */
+                *(unsigned long *)dst = readl(addr);
+                dst += 4;
+                addr += 4;
+        }
+}
+
+
+
diff --git a/arch/xtensa/kernel/platform.c b/arch/xtensa/kernel/platform.c
new file mode 100644
index 0000000..cf13627
--- /dev/null
+++ b/arch/xtensa/kernel/platform.c
@@ -0,0 +1,49 @@
+/*
+ * arch/xtensa/kernel/platform.c
+ *
+ * Default platform functions.
+ *
+ * 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) 2005 Tensilica Inc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/time.h>
+#include <asm/platform.h>
+#include <asm/timex.h>
+
+#define _F(r,f,a,b)							\
+	r __platform_##f a b;                                   	\
+	r platform_##f a __attribute__((weak, alias("__platform_"#f)))
+
+/*
+ * Default functions that are used if no platform specific function is defined.
+ * (Please, refer to include/asm-xtensa/platform.h for more information)
+ */
+
+_F(void, setup, (char** cmd), { });
+_F(void, init_irq, (void), { });
+_F(void, restart, (void), { while(1); });
+_F(void, halt, (void), { while(1); });
+_F(void, power_off, (void), { while(1); });
+_F(void, idle, (void), { __asm__ __volatile__ ("waiti 0" ::: "memory"); });
+_F(void, heartbeat, (void), { });
+_F(int,  pcibios_fixup, (void), { return 0; });
+_F(int, get_rtc_time, (time_t* t), { return 0; });
+_F(int, set_rtc_time, (time_t t), { return 0; });
+
+#if CONFIG_XTENSA_CALIBRATE_CCOUNT
+_F(void, calibrate_ccount, (void),
+{
+  printk ("ERROR: Cannot calibrate cpu frequency! Assuming 100MHz.\n");
+  ccount_per_jiffy = 100 * (1000000UL/HZ);
+});
+#endif
+
diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c
new file mode 100644
index 0000000..4099703
--- /dev/null
+++ b/arch/xtensa/kernel/process.c
@@ -0,0 +1,482 @@
+// TODO	verify coprocessor handling
+/*
+ * arch/xtensa/kernel/process.c
+ *
+ * Xtensa Processor version.
+ *
+ * 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) 2001 - 2005 Tensilica Inc.
+ *
+ * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
+ * Chris Zankel <chris@zankel.net>
+ * Marc Gauthier <marc@tensilica.com, marc@alumni.uwaterloo.ca>
+ * Kevin Chea
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/elf.h>
+#include <linux/init.h>
+#include <linux/prctl.h>
+#include <linux/init_task.h>
+#include <linux/module.h>
+#include <linux/mqueue.h>
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/platform.h>
+#include <asm/mmu.h>
+#include <asm/irq.h>
+#include <asm/atomic.h>
+#include <asm/offsets.h>
+#include <asm/coprocessor.h>
+
+extern void ret_from_fork(void);
+
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
+static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
+struct mm_struct init_mm = INIT_MM(init_mm);
+EXPORT_SYMBOL(init_mm);
+
+union thread_union init_thread_union
+	__attribute__((__section__(".data.init_task"))) =
+{ INIT_THREAD_INFO(init_task) };
+
+struct task_struct init_task = INIT_TASK(init_task);
+EXPORT_SYMBOL(init_task);
+
+struct task_struct *current_set[NR_CPUS] = {&init_task, };
+
+
+#if XCHAL_CP_NUM > 0
+
+/*
+ * Coprocessor ownership.
+ */
+
+coprocessor_info_t coprocessor_info[] = {
+	{ 0, XTENSA_CPE_CP0_OFFSET },
+	{ 0, XTENSA_CPE_CP1_OFFSET },
+	{ 0, XTENSA_CPE_CP2_OFFSET },
+	{ 0, XTENSA_CPE_CP3_OFFSET },
+	{ 0, XTENSA_CPE_CP4_OFFSET },
+	{ 0, XTENSA_CPE_CP5_OFFSET },
+	{ 0, XTENSA_CPE_CP6_OFFSET },
+	{ 0, XTENSA_CPE_CP7_OFFSET },
+};
+
+#endif
+
+/*
+ * Powermanagement idle function, if any is provided by the platform.
+ */
+
+void cpu_idle(void)
+{
+  	local_irq_enable();
+
+	/* endless idle loop with no priority at all */
+	while (1) {
+		while (!need_resched())
+			platform_idle();
+		preempt_enable();
+		schedule();
+	}
+}
+
+/*
+ * Free current thread data structures etc..
+ */
+
+void exit_thread(void)
+{
+	release_coprocessors(current);	/* Empty macro if no CPs are defined */
+}
+
+void flush_thread(void)
+{
+	release_coprocessors(current);	/* Empty macro if no CPs are defined */
+}
+
+/*
+ * Copy thread.
+ *
+ * The stack layout for the new thread looks like this:
+ *
+ *	+------------------------+ <- sp in childregs (= tos)
+ *	|       childregs        |
+ *	+------------------------+ <- thread.sp = sp in dummy-frame
+ *	|      dummy-frame       |    (saved in dummy-frame spill-area)
+ *	+------------------------+
+ *
+ * We create a dummy frame to return to ret_from_fork:
+ *   a0 points to ret_from_fork (simulating a call4)
+ *   sp points to itself (thread.sp)
+ *   a2, a3 are unused.
+ *
+ * Note: This is a pristine frame, so we don't need any spill region on top of
+ *       childregs.
+ */
+
+int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+		unsigned long unused,
+                struct task_struct * p, struct pt_regs * regs)
+{
+	struct pt_regs *childregs;
+	unsigned long tos;
+	int user_mode = user_mode(regs);
+
+	/* Set up new TSS. */
+	tos = (unsigned long)p->thread_info + THREAD_SIZE;
+	if (user_mode)
+		childregs = (struct pt_regs*)(tos - PT_USER_SIZE);
+	else
+		childregs = (struct pt_regs*)tos - 1;
+
+	*childregs = *regs;
+
+	/* Create a call4 dummy-frame: a0 = 0, a1 = childregs. */
+	*((int*)childregs - 3) = (unsigned long)childregs;
+	*((int*)childregs - 4) = 0;
+
+	childregs->areg[1] = tos;
+	childregs->areg[2] = 0;
+	p->set_child_tid = p->clear_child_tid = NULL;
+	p->thread.ra = MAKE_RA_FOR_CALL((unsigned long)ret_from_fork, 0x1);
+	p->thread.sp = (unsigned long)childregs;
+	if (user_mode(regs)) {
+
+		int len = childregs->wmask & ~0xf;
+		childregs->areg[1] = usp;
+		memcpy(&childregs->areg[XCHAL_NUM_AREGS - len/4],
+		       &regs->areg[XCHAL_NUM_AREGS - len/4], len);
+
+		if (clone_flags & CLONE_SETTLS)
+			childregs->areg[2] = childregs->areg[6];
+
+	} else {
+		/* In kernel space, we start a new thread with a new stack. */
+		childregs->wmask = 1;
+	}
+	return 0;
+}
+
+
+/*
+ * Create a kernel thread
+ */
+
+int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+{
+	long retval;
+	__asm__ __volatile__
+		("mov           a5, %4\n\t" /* preserve fn in a5 */
+		 "mov           a6, %3\n\t" /* preserve and setup arg in a6 */
+		 "movi		a2, %1\n\t" /* load __NR_clone for syscall*/
+		 "mov		a3, sp\n\t" /* sp check and sys_clone */
+		 "mov		a4, %5\n\t" /* load flags for syscall */
+		 "syscall\n\t"
+		 "beq		a3, sp, 1f\n\t" /* branch if parent */
+		 "callx4	a5\n\t"     /* call fn */
+		 "movi		a2, %2\n\t" /* load __NR_exit for syscall */
+		 "mov		a3, a6\n\t" /* load fn return value */
+		 "syscall\n"
+		 "1:\n\t"
+		 "mov		%0, a2\n\t" /* parent returns zero */
+		 :"=r" (retval)
+		 :"i" (__NR_clone), "i" (__NR_exit),
+		 "r" (arg), "r" (fn),
+		 "r" (flags | CLONE_VM)
+		 : "a2", "a3", "a4", "a5", "a6" );
+	return retval;
+}
+
+
+/*
+ * These bracket the sleeping functions..
+ */
+
+unsigned long get_wchan(struct task_struct *p)
+{
+	unsigned long sp, pc;
+	unsigned long stack_page = (unsigned long) p->thread_info;
+	int count = 0;
+
+	if (!p || p == current || p->state == TASK_RUNNING)
+		return 0;
+
+	sp = p->thread.sp;
+	pc = MAKE_PC_FROM_RA(p->thread.ra, p->thread.sp);
+
+	do {
+		if (sp < stack_page + sizeof(struct task_struct) ||
+		    sp >= (stack_page + THREAD_SIZE) ||
+		    pc == 0)
+			return 0;
+		if (!in_sched_functions(pc))
+			return pc;
+
+		/* Stack layout: sp-4: ra, sp-3: sp' */
+
+		pc = MAKE_PC_FROM_RA(*(unsigned long*)sp - 4, sp);
+		sp = *(unsigned long *)sp - 3;
+	} while (count++ < 16);
+	return 0;
+}
+
+/*
+ * do_copy_regs() gathers information from 'struct pt_regs' and
+ * 'current->thread.areg[]' to fill in the xtensa_gregset_t
+ * structure.
+ *
+ * xtensa_gregset_t and 'struct pt_regs' are vastly different formats
+ * of processor registers.  Besides different ordering,
+ * xtensa_gregset_t contains non-live register information that
+ * 'struct pt_regs' does not.  Exception handling (primarily) uses
+ * 'struct pt_regs'.  Core files and ptrace use xtensa_gregset_t.
+ *
+ */
+
+void do_copy_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs,
+		   struct task_struct *tsk)
+{
+	int i, n, wb_offset;
+
+	elfregs->xchal_config_id0 = XCHAL_HW_CONFIGID0;
+	elfregs->xchal_config_id1 = XCHAL_HW_CONFIGID1;
+
+	__asm__ __volatile__ ("rsr  %0, 176\n" : "=a" (i));
+ 	elfregs->cpux = i;
+	__asm__ __volatile__ ("rsr  %0, 208\n" : "=a" (i));
+ 	elfregs->cpuy = i;
+
+	/* Note:  PS.EXCM is not set while user task is running; its
+	 * being set in regs->ps is for exception handling convenience.
+	 */
+
+	elfregs->pc		= regs->pc;
+	elfregs->ps		= (regs->ps & ~XCHAL_PS_EXCM_MASK);
+	elfregs->exccause	= regs->exccause;
+	elfregs->excvaddr	= regs->excvaddr;
+	elfregs->windowbase	= regs->windowbase;
+	elfregs->windowstart	= regs->windowstart;
+	elfregs->lbeg		= regs->lbeg;
+	elfregs->lend		= regs->lend;
+	elfregs->lcount		= regs->lcount;
+	elfregs->sar		= regs->sar;
+	elfregs->syscall	= regs->syscall;
+
+	/* Copy register file.
+	 * The layout looks like this:
+	 *
+	 * |  a0 ... a15  | Z ... Z |  arX ... arY  |
+	 *  current window  unused    saved frames
+	 */
+
+	memset (elfregs->ar, 0, sizeof(elfregs->ar));
+
+	wb_offset = regs->windowbase * 4;
+	n = (regs->wmask&1)? 4 : (regs->wmask&2)? 8 : (regs->wmask&4)? 12 : 16;
+
+	for (i = 0; i < n; i++)
+		elfregs->ar[(wb_offset + i) % XCHAL_NUM_AREGS] = regs->areg[i];
+
+	n = (regs->wmask >> 4) * 4;
+
+	for (i = XCHAL_NUM_AREGS - n; n > 0; i++, n--)
+		elfregs->ar[(wb_offset + i) % XCHAL_NUM_AREGS] = regs->areg[i];
+}
+
+void xtensa_elf_core_copy_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs)
+{
+	do_copy_regs ((xtensa_gregset_t *)elfregs, regs, current);
+}
+
+
+/* The inverse of do_copy_regs().  No error or sanity checking. */
+
+void do_restore_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs,
+		      struct task_struct *tsk)
+{
+	int i, n, wb_offset;
+
+	/* Note:  PS.EXCM is not set while user task is running; it
+	 * needs to be set in regs->ps is for exception handling convenience.
+	 */
+
+	regs->pc		= elfregs->pc;
+	regs->ps		= (elfregs->ps | XCHAL_PS_EXCM_MASK);
+	regs->exccause		= elfregs->exccause;
+	regs->excvaddr		= elfregs->excvaddr;
+	regs->windowbase	= elfregs->windowbase;
+	regs->windowstart	= elfregs->windowstart;
+	regs->lbeg		= elfregs->lbeg;
+	regs->lend		= elfregs->lend;
+	regs->lcount		= elfregs->lcount;
+	regs->sar		= elfregs->sar;
+	regs->syscall	= elfregs->syscall;
+
+	/* Clear everything. */
+
+	memset (regs->areg, 0, sizeof(regs->areg));
+
+	/* Copy regs from live window frame. */
+
+	wb_offset = regs->windowbase * 4;
+	n = (regs->wmask&1)? 4 : (regs->wmask&2)? 8 : (regs->wmask&4)? 12 : 16;
+
+	for (i = 0; i < n; i++)
+		regs->areg[(wb_offset+i) % XCHAL_NUM_AREGS] = elfregs->ar[i];
+
+	n = (regs->wmask >> 4) * 4;
+
+	for (i = XCHAL_NUM_AREGS - n; n > 0; i++, n--)
+		regs->areg[(wb_offset+i) % XCHAL_NUM_AREGS] = elfregs->ar[i];
+}
+
+/*
+ * do_save_fpregs() gathers information from 'struct pt_regs' and
+ * 'current->thread' to fill in the elf_fpregset_t structure.
+ *
+ * Core files and ptrace use elf_fpregset_t.
+ */
+
+void do_save_fpregs (elf_fpregset_t *fpregs, struct pt_regs *regs,
+		     struct task_struct *tsk)
+{
+#if XCHAL_HAVE_CP
+
+	extern unsigned char	_xtensa_reginfo_tables[];
+	extern unsigned		_xtensa_reginfo_table_size;
+	int i;
+	unsigned long flags;
+
+	/* Before dumping coprocessor state from memory,
+	 * ensure any live coprocessor contents for this
+	 * task are first saved to memory:
+	 */
+	local_irq_save(flags);
+
+	for (i = 0; i < XCHAL_CP_MAX; i++) {
+		if (tsk == coprocessor_info[i].owner) {
+			enable_coprocessor(i);
+			save_coprocessor_registers(
+			    tsk->thread.cp_save+coprocessor_info[i].offset,i);
+			disable_coprocessor(i);
+		}
+	}
+
+	local_irq_restore(flags);
+
+	/* Now dump coprocessor & extra state: */
+	memcpy((unsigned char*)fpregs,
+		_xtensa_reginfo_tables, _xtensa_reginfo_table_size);
+	memcpy((unsigned char*)fpregs + _xtensa_reginfo_table_size,
+		tsk->thread.cp_save, XTENSA_CP_EXTRA_SIZE);
+#endif
+}
+
+/*
+ * The inverse of do_save_fpregs().
+ * Copies coprocessor and extra state from fpregs into regs and tsk->thread.
+ * Returns 0 on success, non-zero if layout doesn't match.
+ */
+
+int  do_restore_fpregs (elf_fpregset_t *fpregs, struct pt_regs *regs,
+		        struct task_struct *tsk)
+{
+#if XCHAL_HAVE_CP
+
+	extern unsigned char	_xtensa_reginfo_tables[];
+	extern unsigned		_xtensa_reginfo_table_size;
+	int i;
+	unsigned long flags;
+
+	/* Make sure save area layouts match.
+	 * FIXME:  in the future we could allow restoring from
+	 * a different layout of the same registers, by comparing
+	 * fpregs' table with _xtensa_reginfo_tables and matching
+	 * entries and copying registers one at a time.
+	 * Not too sure yet whether that's very useful.
+	 */
+
+	if( memcmp((unsigned char*)fpregs,
+		_xtensa_reginfo_tables, _xtensa_reginfo_table_size) ) {
+	    return -1;
+	}
+
+	/* Before restoring coprocessor state from memory,
+	 * ensure any live coprocessor contents for this
+	 * task are first invalidated.
+	 */
+
+	local_irq_save(flags);
+
+	for (i = 0; i < XCHAL_CP_MAX; i++) {
+		if (tsk == coprocessor_info[i].owner) {
+			enable_coprocessor(i);
+			save_coprocessor_registers(
+			    tsk->thread.cp_save+coprocessor_info[i].offset,i);
+			coprocessor_info[i].owner = 0;
+			disable_coprocessor(i);
+		}
+	}
+
+	local_irq_restore(flags);
+
+	/*  Now restore coprocessor & extra state:  */
+
+	memcpy(tsk->thread.cp_save,
+		(unsigned char*)fpregs + _xtensa_reginfo_table_size,
+		XTENSA_CP_EXTRA_SIZE);
+#endif
+	return 0;
+}
+/*
+ * Fill in the CP structure for a core dump for a particular task.
+ */
+
+int
+dump_task_fpu(struct pt_regs *regs, struct task_struct *task, elf_fpregset_t *r)
+{
+/* see asm/coprocessor.h for this magic number 16 */
+#if TOTAL_CPEXTRA_SIZE > 16
+	do_save_fpregs (r, regs, task);
+
+	/*  For now, bit 16 means some extra state may be present:  */
+// FIXME!! need to track to return more accurate mask
+	return 0x10000 | XCHAL_CP_MASK;
+#else
+	return 0;	/* no coprocessors active on this processor */
+#endif
+}
+
+/*
+ * Fill in the CP structure for a core dump.
+ * This includes any FPU coprocessor.
+ * Here, we dump all coprocessors, and other ("extra") custom state.
+ *
+ * This function is called by elf_core_dump() in fs/binfmt_elf.c
+ * (in which case 'regs' comes from calls to do_coredump, see signals.c).
+ */
+int  dump_fpu(struct pt_regs *regs, elf_fpregset_t *r)
+{
+	return dump_task_fpu(regs, current, r);
+}
diff --git a/arch/xtensa/kernel/ptrace.c b/arch/xtensa/kernel/ptrace.c
new file mode 100644
index 0000000..9ef07a4
--- /dev/null
+++ b/arch/xtensa/kernel/ptrace.c
@@ -0,0 +1,407 @@
+// TODO some minor issues
+/*
+ * 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) 2001 - 2005  Tensilica Inc.
+ *
+ * Joe Taylor	<joe@tensilica.com, joetylr@yahoo.com>
+ * Chris Zankel <chris@zankel.net>
+ * Scott Foehner<sfoehner@yahoo.com>,
+ * Kevin Chea
+ * Marc Gauthier<marc@tensilica.com> <marc@alumni.uwaterloo.ca>
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/security.h>
+
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/ptrace.h>
+#include <asm/elf.h>
+
+#define TEST_KERNEL	// verify kernel operations FIXME: remove
+
+
+/*
+ * Called by kernel/ptrace.c when detaching..
+ *
+ * Make sure single step bits etc are not set.
+ */
+
+void ptrace_disable(struct task_struct *child)
+{
+	/* Nothing to do.. */
+}
+
+int sys_ptrace(long request, long pid, long addr, long data)
+{
+	struct task_struct *child;
+	int ret = -EPERM;
+
+	lock_kernel();
+
+#if 0
+	if ((int)request != 1)
+	printk("ptrace(r=%d,pid=%d,addr=%08lx,data=%08lx)\n",
+	       (int) request, (int) pid, (unsigned long) addr,
+	       (unsigned long) data);
+#endif
+
+	if (request == PTRACE_TRACEME) {
+
+		/* Are we already being traced? */
+
+		if (current->ptrace & PT_PTRACED)
+			goto out;
+
+		if ((ret = security_ptrace(current->parent, current)))
+			goto out;
+
+		/* Set the ptrace bit in the process flags. */
+
+		current->ptrace |= PT_PTRACED;
+		ret = 0;
+		goto out;
+	}
+
+	ret = -ESRCH;
+	read_lock(&tasklist_lock);
+	child = find_task_by_pid(pid);
+	if (child)
+		get_task_struct(child);
+	read_unlock(&tasklist_lock);
+	if (!child)
+		goto out;
+
+	ret = -EPERM;
+	if (pid == 1)		/* you may not mess with init */
+		goto out;
+
+	if (request == PTRACE_ATTACH) {
+		ret = ptrace_attach(child);
+		goto out_tsk;
+	}
+
+	if ((ret = ptrace_check_attach(child, request == PTRACE_KILL)) < 0)
+		goto out_tsk;
+
+	switch (request) {
+	case PTRACE_PEEKTEXT: /* read word at location addr. */
+	case PTRACE_PEEKDATA:
+	{
+		unsigned long tmp;
+		int copied;
+
+		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+		ret = -EIO;
+		if (copied != sizeof(tmp))
+			break;
+		ret = put_user(tmp,(unsigned long *) data);
+
+		goto out;
+	}
+
+	/* Read the word at location addr in the USER area.  */
+
+	case PTRACE_PEEKUSR:
+		{
+		struct pt_regs *regs;
+		unsigned long tmp;
+
+		regs = xtensa_pt_regs(child);
+		tmp = 0;  /* Default return value. */
+
+		switch(addr) {
+
+		case REG_AR_BASE ... REG_AR_BASE + XCHAL_NUM_AREGS - 1:
+			{
+			int ar = addr - REG_AR_BASE - regs->windowbase * 4;
+			ar &= (XCHAL_NUM_AREGS - 1);
+			if (ar < 16 && ar + (regs->wmask >> 4) * 4 >= 0)
+				tmp = regs->areg[ar];
+			else
+				ret = -EIO;
+			break;
+			}
+		case REG_A_BASE ... REG_A_BASE + 15:
+			tmp = regs->areg[addr - REG_A_BASE];
+			break;
+		case REG_PC:
+			tmp = regs->pc;
+			break;
+		case REG_PS:
+			/* Note:  PS.EXCM is not set while user task is running;
+			 * its being set in regs is for exception handling
+			 * convenience.  */
+			tmp = (regs->ps & ~XCHAL_PS_EXCM_MASK);
+			break;
+		case REG_WB:
+			tmp = regs->windowbase;
+			break;
+		case REG_WS:
+			tmp = regs->windowstart;
+			break;
+		case REG_LBEG:
+			tmp = regs->lbeg;
+			break;
+		case REG_LEND:
+			tmp = regs->lend;
+			break;
+		case REG_LCOUNT:
+			tmp = regs->lcount;
+			break;
+		case REG_SAR:
+			tmp = regs->sar;
+			break;
+		case REG_DEPC:
+			tmp = regs->depc;
+			break;
+		case REG_EXCCAUSE:
+			tmp = regs->exccause;
+			break;
+		case REG_EXCVADDR:
+			tmp = regs->excvaddr;
+			break;
+		case SYSCALL_NR:
+			tmp = regs->syscall;
+			break;
+		default:
+			tmp = 0;
+			ret = -EIO;
+			goto out;
+		}
+		ret = put_user(tmp, (unsigned long *) data);
+		goto out;
+		}
+
+	case PTRACE_POKETEXT: /* write the word at location addr. */
+	case PTRACE_POKEDATA:
+		if (access_process_vm(child, addr, &data, sizeof(data), 1)
+		    == sizeof(data))
+			break;
+		ret = -EIO;
+		goto out;
+
+	case PTRACE_POKEUSR:
+		{
+		struct pt_regs *regs;
+		regs = xtensa_pt_regs(child);
+
+		switch (addr) {
+		case REG_AR_BASE ... REG_AR_BASE + XCHAL_NUM_AREGS - 1:
+			{
+			int ar = addr - REG_AR_BASE - regs->windowbase * 4;
+			if (ar < 16 && ar + (regs->wmask >> 4) * 4 >= 0)
+				regs->areg[ar & (XCHAL_NUM_AREGS - 1)] = data;
+			else
+				ret = -EIO;
+			break;
+			}
+		case REG_A_BASE ... REG_A_BASE + 15:
+			regs->areg[addr - REG_A_BASE] = data;
+			break;
+		case REG_PC:
+			regs->pc = data;
+			break;
+		case SYSCALL_NR:
+			regs->syscall = data;
+			break;
+#ifdef TEST_KERNEL
+		case REG_WB:
+			regs->windowbase = data;
+			break;
+		case REG_WS:
+			regs->windowstart = data;
+			break;
+#endif
+
+		default:
+			/* The rest are not allowed. */
+			ret = -EIO;
+			break;
+		}
+		break;
+		}
+
+	/* continue and stop at next (return from) syscall */
+	case PTRACE_SYSCALL:
+	case PTRACE_CONT: /* restart after signal. */
+	{
+		ret = -EIO;
+		if ((unsigned long) data > _NSIG)
+			break;
+		if (request == PTRACE_SYSCALL)
+			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+		else
+			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+		child->exit_code = data;
+		/* Make sure the single step bit is not set. */
+		child->ptrace &= ~PT_SINGLESTEP;
+		wake_up_process(child);
+		ret = 0;
+		break;
+	}
+
+	/*
+	 * make the child exit.  Best I can do is send it a sigkill.
+	 * perhaps it should be put in the status that it wants to
+	 * exit.
+	 */
+	case PTRACE_KILL:
+		ret = 0;
+		if (child->state == EXIT_ZOMBIE)	/* already dead */
+			break;
+		child->exit_code = SIGKILL;
+		child->ptrace &= ~PT_SINGLESTEP;
+		wake_up_process(child);
+		break;
+
+	case PTRACE_SINGLESTEP:
+		ret = -EIO;
+		if ((unsigned long) data > _NSIG)
+			break;
+		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+		child->ptrace |= PT_SINGLESTEP;
+		child->exit_code = data;
+		wake_up_process(child);
+		ret = 0;
+		break;
+
+	case PTRACE_GETREGS:
+	{
+		/* 'data' points to user memory in which to write.
+		 * Mainly due to the non-live register values, we
+		 * reformat the register values into something more
+		 * standard.  For convenience, we use the handy
+		 * elf_gregset_t format. */
+
+		xtensa_gregset_t format;
+		struct pt_regs *regs = xtensa_pt_regs(child);
+
+		do_copy_regs (&format, regs, child);
+
+		/* Now, copy to user space nice and easy... */
+		ret = 0;
+		if (copy_to_user((void *)data, &format, sizeof(elf_gregset_t)))
+			ret = -EFAULT;
+		break;
+	}
+
+	case PTRACE_SETREGS:
+	{
+		/* 'data' points to user memory that contains the new
+		 * values in the elf_gregset_t format. */
+
+		xtensa_gregset_t format;
+		struct pt_regs *regs = xtensa_pt_regs(child);
+
+		if (copy_from_user(&format,(void *)data,sizeof(elf_gregset_t))){
+			ret = -EFAULT;
+			break;
+		}
+
+		/* FIXME: Perhaps we want some sanity checks on
+		 * these user-space values?  See ARM version.  Are
+		 * debuggers a security concern? */
+
+		do_restore_regs (&format, regs, child);
+
+		ret = 0;
+		break;
+	}
+
+	case PTRACE_GETFPREGS:
+	{
+		/* 'data' points to user memory in which to write.
+		 * For convenience, we use the handy
+		 * elf_fpregset_t format. */
+
+		elf_fpregset_t fpregs;
+		struct pt_regs *regs = xtensa_pt_regs(child);
+
+		do_save_fpregs (&fpregs, regs, child);
+
+		/* Now, copy to user space nice and easy... */
+		ret = 0;
+		if (copy_to_user((void *)data, &fpregs, sizeof(elf_fpregset_t)))
+			ret = -EFAULT;
+
+		break;
+	}
+
+	case PTRACE_SETFPREGS:
+	{
+		/* 'data' points to user memory that contains the new
+		 * values in the elf_fpregset_t format.
+		 */
+		elf_fpregset_t fpregs;
+		struct pt_regs *regs = xtensa_pt_regs(child);
+
+		ret = 0;
+		if (copy_from_user(&fpregs, (void *)data, sizeof(elf_fpregset_t))) {
+			ret = -EFAULT;
+			break;
+		}
+
+		if (do_restore_fpregs (&fpregs, regs, child))
+			ret = -EIO;
+		break;
+	}
+
+	case PTRACE_GETFPREGSIZE:
+		/* 'data' points to 'unsigned long' set to the size
+		 * of elf_fpregset_t
+		 */
+		ret = put_user(sizeof(elf_fpregset_t), (unsigned long *) data);
+		break;
+
+	case PTRACE_DETACH: /* detach a process that was attached. */
+		ret = ptrace_detach(child, data);
+		break;
+
+	default:
+		ret = ptrace_request(child, request, addr, data);
+		goto out;
+	}
+out_tsk:
+	put_task_struct(child);
+out:
+	unlock_kernel();
+	return ret;
+}
+
+void do_syscall_trace(void)
+{
+	if (!test_thread_flag(TIF_SYSCALL_TRACE))
+		return;
+
+	if (!(current->ptrace & PT_PTRACED))
+		return;
+
+	/*
+	 * The 0x80 provides a way for the tracing parent to distinguish
+	 * between a syscall stop and SIGTRAP delivery
+	 */
+	ptrace_notify(SIGTRAP|((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0));
+
+	/*
+	 * this isn't the same as continuing with a signal, but it will do
+	 * for normal use.  strace only continues with a signal if the
+	 * stopping signal is not SIGTRAP.  -brl
+	 */
+	if (current->exit_code) {
+		send_sig(current->exit_code, current, 1);
+		current->exit_code = 0;
+	}
+}
diff --git a/arch/xtensa/kernel/semaphore.c b/arch/xtensa/kernel/semaphore.c
new file mode 100644
index 0000000..d40f4b1
--- /dev/null
+++ b/arch/xtensa/kernel/semaphore.c
@@ -0,0 +1,226 @@
+/*
+ * arch/xtensa/kernel/semaphore.c
+ *
+ * Generic semaphore code. Buyer beware. Do your own specific changes
+ * in <asm/semaphore-helper.h>
+ *
+ * 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) 2001 - 2005 Tensilica Inc.
+ *
+ * Joe Taylor	<joe@tensilica.com, joetylr@yahoo.com>
+ * Chris Zankel	<chris@zankel.net>
+ * Marc Gauthier<marc@tensilica.com, marc@alumni.uwaterloo.ca>
+ * Kevin Chea
+ */
+
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/init.h>
+#include <asm/semaphore.h>
+#include <asm/errno.h>
+
+/*
+ * These two _must_ execute atomically wrt each other.
+ */
+
+static __inline__ void wake_one_more(struct semaphore * sem)
+{
+	atomic_inc((atomic_t *)&sem->sleepers);
+}
+
+static __inline__ int waking_non_zero(struct semaphore *sem)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&semaphore_wake_lock, flags);
+	if (sem->sleepers > 0) {
+		sem->sleepers--;
+		ret = 1;
+	}
+	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+	return ret;
+}
+
+/*
+ * waking_non_zero_interruptible:
+ *	1	got the lock
+ *	0	go to sleep
+ *	-EINTR	interrupted
+ *
+ * We must undo the sem->count down_interruptible() increment while we are
+ * protected by the spinlock in order to make atomic this atomic_inc() with the
+ * atomic_read() in wake_one_more(), otherwise we can race. -arca
+ */
+
+static __inline__ int waking_non_zero_interruptible(struct semaphore *sem,
+						struct task_struct *tsk)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&semaphore_wake_lock, flags);
+	if (sem->sleepers > 0) {
+		sem->sleepers--;
+		ret = 1;
+	} else if (signal_pending(tsk)) {
+		atomic_inc(&sem->count);
+		ret = -EINTR;
+	}
+	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+	return ret;
+}
+
+/*
+ * waking_non_zero_trylock:
+ *	1	failed to lock
+ *	0	got the lock
+ *
+ * We must undo the sem->count down_trylock() increment while we are
+ * protected by the spinlock in order to make atomic this atomic_inc() with the
+ * atomic_read() in wake_one_more(), otherwise we can race. -arca
+ */
+
+static __inline__ int waking_non_zero_trylock(struct semaphore *sem)
+{
+	unsigned long flags;
+	int ret = 1;
+
+	spin_lock_irqsave(&semaphore_wake_lock, flags);
+	if (sem->sleepers <= 0)
+		atomic_inc(&sem->count);
+	else {
+		sem->sleepers--;
+		ret = 0;
+	}
+	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+	return ret;
+}
+
+spinlock_t semaphore_wake_lock;
+
+/*
+ * Semaphores are implemented using a two-way counter:
+ * The "count" variable is decremented for each process
+ * that tries to sleep, while the "waking" variable is
+ * incremented when the "up()" code goes to wake up waiting
+ * processes.
+ *
+ * Notably, the inline "up()" and "down()" functions can
+ * efficiently test if they need to do any extra work (up
+ * needs to do something only if count was negative before
+ * the increment operation.
+ *
+ * waking_non_zero() (from asm/semaphore.h) must execute
+ * atomically.
+ *
+ * When __up() is called, the count was negative before
+ * incrementing it, and we need to wake up somebody.
+ *
+ * This routine adds one to the count of processes that need to
+ * wake up and exit.  ALL waiting processes actually wake up but
+ * only the one that gets to the "waking" field first will gate
+ * through and acquire the semaphore.  The others will go back
+ * to sleep.
+ *
+ * Note that these functions are only called when there is
+ * contention on the lock, and as such all this is the
+ * "non-critical" part of the whole semaphore business. The
+ * critical part is the inline stuff in <asm/semaphore.h>
+ * where we want to avoid any extra jumps and calls.
+ */
+
+void __up(struct semaphore *sem)
+{
+	wake_one_more(sem);
+	wake_up(&sem->wait);
+}
+
+/*
+ * Perform the "down" function.  Return zero for semaphore acquired,
+ * return negative for signalled out of the function.
+ *
+ * If called from __down, the return is ignored and the wait loop is
+ * not interruptible.  This means that a task waiting on a semaphore
+ * using "down()" cannot be killed until someone does an "up()" on
+ * the semaphore.
+ *
+ * If called from __down_interruptible, the return value gets checked
+ * upon return.  If the return value is negative then the task continues
+ * with the negative value in the return register (it can be tested by
+ * the caller).
+ *
+ * Either form may be used in conjunction with "up()".
+ *
+ */
+
+#define DOWN_VAR				\
+	struct task_struct *tsk = current;	\
+	wait_queue_t wait;			\
+	init_waitqueue_entry(&wait, tsk);
+
+#define DOWN_HEAD(task_state)						\
+									\
+									\
+	tsk->state = (task_state);					\
+	add_wait_queue(&sem->wait, &wait);				\
+									\
+	/*								\
+	 * Ok, we're set up.  sem->count is known to be less than zero	\
+	 * so we must wait.						\
+	 *								\
+	 * We can let go the lock for purposes of waiting.		\
+	 * We re-acquire it after awaking so as to protect		\
+	 * all semaphore operations.					\
+	 *								\
+	 * If "up()" is called before we call waking_non_zero() then	\
+	 * we will catch it right away.  If it is called later then	\
+	 * we will have to go through a wakeup cycle to catch it.	\
+	 *								\
+	 * Multiple waiters contend for the semaphore lock to see	\
+	 * who gets to gate through and who has to wait some more.	\
+	 */								\
+	for (;;) {
+
+#define DOWN_TAIL(task_state)			\
+		tsk->state = (task_state);	\
+	}					\
+	tsk->state = TASK_RUNNING;		\
+	remove_wait_queue(&sem->wait, &wait);
+
+void __sched __down(struct semaphore * sem)
+{
+	DOWN_VAR
+	DOWN_HEAD(TASK_UNINTERRUPTIBLE)
+	if (waking_non_zero(sem))
+		break;
+	schedule();
+	DOWN_TAIL(TASK_UNINTERRUPTIBLE)
+}
+
+int __sched __down_interruptible(struct semaphore * sem)
+{
+	int ret = 0;
+	DOWN_VAR
+	DOWN_HEAD(TASK_INTERRUPTIBLE)
+
+	ret = waking_non_zero_interruptible(sem, tsk);
+	if (ret)
+	{
+		if (ret == 1)
+			/* ret != 0 only if we get interrupted -arca */
+			ret = 0;
+		break;
+	}
+	schedule();
+	DOWN_TAIL(TASK_INTERRUPTIBLE)
+	return ret;
+}
+
+int __down_trylock(struct semaphore * sem)
+{
+	return waking_non_zero_trylock(sem);
+}
diff --git a/arch/xtensa/kernel/setup.c b/arch/xtensa/kernel/setup.c
new file mode 100644
index 0000000..1f5bf5d
--- /dev/null
+++ b/arch/xtensa/kernel/setup.c
@@ -0,0 +1,520 @@
+/*
+ * arch/xtensa/setup.c
+ *
+ * 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) 1995  Linus Torvalds
+ * Copyright (C) 2001 - 2005  Tensilica Inc.
+ *
+ * Chris Zankel	<chris@zankel.net>
+ * Joe Taylor	<joe@tensilica.com, joetylr@yahoo.com>
+ * Kevin Chea
+ * Marc Gauthier<marc@tensilica.com> <marc@alumni.uwaterloo.ca>
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/tty.h>
+#include <linux/bootmem.h>
+#include <linux/kernel.h>
+
+#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
+# include <linux/console.h>
+#endif
+
+#ifdef CONFIG_RTC
+# include <linux/timex.h>
+#endif
+
+#ifdef CONFIG_PROC_FS
+# include <linux/seq_file.h>
+#endif
+
+#include <asm/system.h>
+#include <asm/bootparam.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/timex.h>
+#include <asm/platform.h>
+#include <asm/page.h>
+#include <asm/setup.h>
+
+#include <xtensa/config/system.h>
+
+#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
+struct screen_info screen_info = { 0, 24, 0, 0, 0, 80, 0, 0, 0, 24, 1, 16};
+#endif
+
+#ifdef CONFIG_BLK_DEV_FD
+extern struct fd_ops no_fd_ops;
+struct fd_ops *fd_ops;
+#endif
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+extern struct ide_ops no_ide_ops;
+struct ide_ops *ide_ops;
+#endif
+
+extern struct rtc_ops no_rtc_ops;
+struct rtc_ops *rtc_ops;
+
+#ifdef CONFIG_PC_KEYB
+extern struct kbd_ops no_kbd_ops;
+struct kbd_ops *kbd_ops;
+#endif
+
+#ifdef CONFIG_BLK_DEV_INITRD
+extern void *initrd_start;
+extern void *initrd_end;
+extern void *__initrd_start;
+extern void *__initrd_end;
+int initrd_is_mapped = 0;
+extern int initrd_below_start_ok;
+#endif
+
+unsigned char aux_device_present;
+extern unsigned long loops_per_jiffy;
+
+/* Command line specified as configuration option. */
+
+static char command_line[COMMAND_LINE_SIZE];
+
+#ifdef CONFIG_CMDLINE_BOOL
+static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
+#endif
+
+sysmem_info_t __initdata sysmem;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+int initrd_is_mapped;
+#endif
+
+extern void init_mmu(void);
+
+/*
+ * Boot parameter parsing.
+ *
+ * The Xtensa port uses a list of variable-sized tags to pass data to
+ * the kernel. The first tag must be a BP_TAG_FIRST tag for the list
+ * to be recognised. The list is terminated with a zero-sized
+ * BP_TAG_LAST tag.
+ */
+
+typedef struct tagtable {
+	u32 tag;
+	int (*parse)(const bp_tag_t*);
+} tagtable_t;
+
+#define __tagtable(tag, fn) static tagtable_t __tagtable_##fn 		\
+	__attribute__((unused, __section__(".taglist"))) = { tag, fn }
+
+/* parse current tag */
+
+static int __init parse_tag_mem(const bp_tag_t *tag)
+{
+	meminfo_t *mi = (meminfo_t*)(tag->data);
+
+	if (mi->type != MEMORY_TYPE_CONVENTIONAL)
+		return -1;
+
+	if (sysmem.nr_banks >= SYSMEM_BANKS_MAX) {
+		printk(KERN_WARNING
+		       "Ignoring memory bank 0x%08lx size %ldKB\n",
+		       (unsigned long)mi->start,
+		       (unsigned long)mi->end - (unsigned long)mi->start);
+		return -EINVAL;
+	}
+	sysmem.bank[sysmem.nr_banks].type  = mi->type;
+	sysmem.bank[sysmem.nr_banks].start = PAGE_ALIGN(mi->start);
+	sysmem.bank[sysmem.nr_banks].end   = mi->end & PAGE_SIZE;
+	sysmem.nr_banks++;
+
+	return 0;
+}
+
+__tagtable(BP_TAG_MEMORY, parse_tag_mem);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+
+static int __init parse_tag_initrd(const bp_tag_t* tag)
+{
+	meminfo_t* mi;
+	mi = (meminfo_t*)(tag->data);
+	initrd_start = (void*)(mi->start);
+	initrd_end = (void*)(mi->end);
+
+	return 0;
+}
+
+__tagtable(BP_TAG_INITRD, parse_tag_initrd);
+
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+static int __init parse_tag_cmdline(const bp_tag_t* tag)
+{
+	strncpy(command_line, (char*)(tag->data), COMMAND_LINE_SIZE);
+	command_line[COMMAND_LINE_SIZE - 1] = '\0';
+	return 0;
+}
+
+__tagtable(BP_TAG_COMMAND_LINE, parse_tag_cmdline);
+
+static int __init parse_bootparam(const bp_tag_t* tag)
+{
+	extern tagtable_t __tagtable_begin, __tagtable_end;
+	tagtable_t *t;
+
+	/* Boot parameters must start with a BP_TAG_FIRST tag. */
+
+	if (tag->id != BP_TAG_FIRST) {
+		printk(KERN_WARNING "Invalid boot parameters!\n");
+		return 0;
+	}
+
+	tag = (bp_tag_t*)((unsigned long)tag + sizeof(bp_tag_t) + tag->size);
+
+	/* Parse all tags. */
+
+	while (tag != NULL && tag->id != BP_TAG_LAST) {
+	 	for (t = &__tagtable_begin; t < &__tagtable_end; t++) {
+			if (tag->id == t->tag) {
+				t->parse(tag);
+				break;
+			}
+		}
+		if (t == &__tagtable_end)
+			printk(KERN_WARNING "Ignoring tag "
+			       "0x%08x\n", tag->id);
+		tag = (bp_tag_t*)((unsigned long)(tag + 1) + tag->size);
+	}
+
+	return 0;
+}
+
+/*
+ * Initialize architecture. (Early stage)
+ */
+
+void __init init_arch(bp_tag_t *bp_start)
+{
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	initrd_start = &__initrd_start;
+	initrd_end = &__initrd_end;
+#endif
+
+	sysmem.nr_banks = 0;
+
+#ifdef CONFIG_CMDLINE_BOOL
+	strcpy(command_line, default_command_line);
+#endif
+
+	/* Parse boot parameters */
+
+        if (bp_start)
+	  parse_bootparam(bp_start);
+
+	if (sysmem.nr_banks == 0) {
+		sysmem.nr_banks = 1;
+		sysmem.bank[0].start = PLATFORM_DEFAULT_MEM_START;
+		sysmem.bank[0].end = PLATFORM_DEFAULT_MEM_START
+				     + PLATFORM_DEFAULT_MEM_SIZE;
+	}
+
+	/* Early hook for platforms */
+
+	platform_init(bp_start);
+
+	/* Initialize MMU. */
+
+	init_mmu();
+}
+
+/*
+ * Initialize system. Setup memory and reserve regions.
+ */
+
+extern char _end;
+extern char _stext;
+extern char _WindowVectors_text_start;
+extern char _WindowVectors_text_end;
+extern char _DebugInterruptVector_literal_start;
+extern char _DebugInterruptVector_text_end;
+extern char _KernelExceptionVector_literal_start;
+extern char _KernelExceptionVector_text_end;
+extern char _UserExceptionVector_literal_start;
+extern char _UserExceptionVector_text_end;
+extern char _DoubleExceptionVector_literal_start;
+extern char _DoubleExceptionVector_text_end;
+
+void __init setup_arch(char **cmdline_p)
+{
+	extern int mem_reserve(unsigned long, unsigned long, int);
+	extern void bootmem_init(void);
+
+	memcpy(saved_command_line, command_line, COMMAND_LINE_SIZE);
+	saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
+	*cmdline_p = command_line;
+
+	/* Reserve some memory regions */
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (initrd_start < initrd_end) {
+		initrd_is_mapped = mem_reserve(__pa(initrd_start),
+					       __pa(initrd_end), 0);
+		initrd_below_start_ok = 1;
+ 	} else {
+		initrd_start = 0;
+	}
+#endif
+
+	mem_reserve(__pa(&_stext),__pa(&_end), 1);
+
+	mem_reserve(__pa(&_WindowVectors_text_start),
+		    __pa(&_WindowVectors_text_end), 0);
+
+	mem_reserve(__pa(&_DebugInterruptVector_literal_start),
+		    __pa(&_DebugInterruptVector_text_end), 0);
+
+	mem_reserve(__pa(&_KernelExceptionVector_literal_start),
+		    __pa(&_KernelExceptionVector_text_end), 0);
+
+	mem_reserve(__pa(&_UserExceptionVector_literal_start),
+		    __pa(&_UserExceptionVector_text_end), 0);
+
+	mem_reserve(__pa(&_DoubleExceptionVector_literal_start),
+		    __pa(&_DoubleExceptionVector_text_end), 0);
+
+	bootmem_init();
+
+	platform_setup(cmdline_p);
+
+
+	paging_init();
+
+#ifdef CONFIG_VT
+# if defined(CONFIG_VGA_CONSOLE)
+	conswitchp = &vga_con;
+# elif defined(CONFIG_DUMMY_CONSOLE)
+	conswitchp = &dummy_con;
+# endif
+#endif
+
+#if CONFIG_PCI
+	platform_pcibios_init();
+#endif
+}
+
+void machine_restart(char * cmd)
+{
+	platform_restart();
+}
+
+void machine_halt(void)
+{
+	platform_halt();
+	while (1);
+}
+
+void machine_power_off(void)
+{
+	platform_power_off();
+	while (1);
+}
+#ifdef CONFIG_PROC_FS
+
+/*
+ * Display some core information through /proc/cpuinfo.
+ */
+
+static int
+c_show(struct seq_file *f, void *slot)
+{
+	/* high-level stuff */
+	seq_printf(f,"processor\t: 0\n"
+		     "vendor_id\t: Tensilica\n"
+		     "model\t\t: Xtensa " XCHAL_HW_RELEASE_NAME "\n"
+		     "core ID\t\t: " XCHAL_CORE_ID "\n"
+		     "build ID\t: 0x%x\n"
+		     "byte order\t: %s\n"
+ 		     "cpu MHz\t\t: %lu.%02lu\n"
+		     "bogomips\t: %lu.%02lu\n",
+		     XCHAL_BUILD_UNIQUE_ID,
+		     XCHAL_HAVE_BE ?  "big" : "little",
+		     CCOUNT_PER_JIFFY/(1000000/HZ),
+		     (CCOUNT_PER_JIFFY/(10000/HZ)) % 100,
+		     loops_per_jiffy/(500000/HZ),
+		     (loops_per_jiffy/(5000/HZ)) % 100);
+
+	seq_printf(f,"flags\t\t: "
+#if XCHAL_HAVE_NMI
+		     "nmi "
+#endif
+#if XCHAL_HAVE_DEBUG
+		     "debug "
+# if XCHAL_HAVE_OCD
+		     "ocd "
+# endif
+#endif
+#if XCHAL_HAVE_DENSITY
+	    	     "density "
+#endif
+#if XCHAL_HAVE_BOOLEANS
+		     "boolean "
+#endif
+#if XCHAL_HAVE_LOOPS
+		     "loop "
+#endif
+#if XCHAL_HAVE_NSA
+		     "nsa "
+#endif
+#if XCHAL_HAVE_MINMAX
+		     "minmax "
+#endif
+#if XCHAL_HAVE_SEXT
+		     "sext "
+#endif
+#if XCHAL_HAVE_CLAMPS
+		     "clamps "
+#endif
+#if XCHAL_HAVE_MAC16
+		     "mac16 "
+#endif
+#if XCHAL_HAVE_MUL16
+		     "mul16 "
+#endif
+#if XCHAL_HAVE_MUL32
+		     "mul32 "
+#endif
+#if XCHAL_HAVE_MUL32_HIGH
+		     "mul32h "
+#endif
+#if XCHAL_HAVE_FP
+		     "fpu "
+#endif
+		     "\n");
+
+	/* Registers. */
+	seq_printf(f,"physical aregs\t: %d\n"
+		     "misc regs\t: %d\n"
+		     "ibreak\t\t: %d\n"
+		     "dbreak\t\t: %d\n",
+		     XCHAL_NUM_AREGS,
+		     XCHAL_NUM_MISC_REGS,
+		     XCHAL_NUM_IBREAK,
+		     XCHAL_NUM_DBREAK);
+
+
+	/* Interrupt. */
+	seq_printf(f,"num ints\t: %d\n"
+		     "ext ints\t: %d\n"
+		     "int levels\t: %d\n"
+		     "timers\t\t: %d\n"
+		     "debug level\t: %d\n",
+		     XCHAL_NUM_INTERRUPTS,
+		     XCHAL_NUM_EXTINTERRUPTS,
+		     XCHAL_NUM_INTLEVELS,
+		     XCHAL_NUM_TIMERS,
+		     XCHAL_DEBUGLEVEL);
+
+	/* Coprocessors */
+#if XCHAL_HAVE_CP
+	seq_printf(f, "coprocessors\t: %d\n", XCHAL_CP_NUM);
+#else
+	seq_printf(f, "coprocessors\t: none\n");
+#endif
+
+	/* {I,D}{RAM,ROM} and XLMI */
+	seq_printf(f,"inst ROMs\t: %d\n"
+		     "inst RAMs\t: %d\n"
+		     "data ROMs\t: %d\n"
+		     "data RAMs\t: %d\n"
+		     "XLMI ports\t: %d\n",
+		     XCHAL_NUM_IROM,
+		     XCHAL_NUM_IRAM,
+		     XCHAL_NUM_DROM,
+		     XCHAL_NUM_DRAM,
+		     XCHAL_NUM_XLMI);
+
+	/* Cache */
+	seq_printf(f,"icache line size: %d\n"
+		     "icache ways\t: %d\n"
+		     "icache size\t: %d\n"
+		     "icache flags\t: "
+#if XCHAL_ICACHE_LINE_LOCKABLE
+		     "lock"
+#endif
+		     "\n"
+		     "dcache line size: %d\n"
+		     "dcache ways\t: %d\n"
+		     "dcache size\t: %d\n"
+		     "dcache flags\t: "
+#if XCHAL_DCACHE_IS_WRITEBACK
+		     "writeback"
+#endif
+#if XCHAL_DCACHE_LINE_LOCKABLE
+		     "lock"
+#endif
+		     "\n",
+		     XCHAL_ICACHE_LINESIZE,
+		     XCHAL_ICACHE_WAYS,
+		     XCHAL_ICACHE_SIZE,
+		     XCHAL_DCACHE_LINESIZE,
+		     XCHAL_DCACHE_WAYS,
+		     XCHAL_DCACHE_SIZE);
+
+	/* MMU */
+	seq_printf(f,"ASID bits\t: %d\n"
+		     "ASID invalid\t: %d\n"
+		     "ASID kernel\t: %d\n"
+		     "rings\t\t: %d\n"
+		     "itlb ways\t: %d\n"
+		     "itlb AR ways\t: %d\n"
+		     "dtlb ways\t: %d\n"
+		     "dtlb AR ways\t: %d\n",
+		     XCHAL_MMU_ASID_BITS,
+		     XCHAL_MMU_ASID_INVALID,
+		     XCHAL_MMU_ASID_KERNEL,
+		     XCHAL_MMU_RINGS,
+		     XCHAL_ITLB_WAYS,
+		     XCHAL_ITLB_ARF_WAYS,
+		     XCHAL_DTLB_WAYS,
+		     XCHAL_DTLB_ARF_WAYS);
+
+	return 0;
+}
+
+/*
+ * We show only CPU #0 info.
+ */
+static void *
+c_start(struct seq_file *f, loff_t *pos)
+{
+	return (void *) ((*pos == 0) ? (void *)1 : NULL);
+}
+
+static void *
+c_next(struct seq_file *f, void *v, loff_t *pos)
+{
+	return NULL;
+}
+
+static void
+c_stop(struct seq_file *f, void *v)
+{
+}
+
+struct seq_operations cpuinfo_op =
+{
+	start:  c_start,
+	next:   c_next,
+	stop:   c_stop,
+	show:   c_show
+};
+
+#endif /* CONFIG_PROC_FS */
+
diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c
new file mode 100644
index 0000000..df6e1e1
--- /dev/null
+++ b/arch/xtensa/kernel/signal.c
@@ -0,0 +1,713 @@
+// TODO coprocessor stuff
+/*
+ *  linux/arch/xtensa/kernel/signal.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  1997-11-28  Modified for POSIX.1b signals by Richard Henderson
+ *
+ *  Joe Taylor <joe@tensilica.com>
+ *  Chris Zankel <chris@zankel.net>
+ *
+ *
+ *
+ */
+
+#include <xtensa/config/core.h>
+#include <xtensa/hal.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/unistd.h>
+#include <linux/stddef.h>
+#include <linux/personality.h>
+#include <asm/ucontext.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/cacheflush.h>
+
+#define DEBUG_SIG  0
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options,
+			  struct rusage * ru);
+asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset);
+
+extern struct task_struct *coproc_owners[];
+
+
+/*
+ * Atomically swap in the new signal mask, and wait for a signal.
+ */
+
+int sys_sigsuspend(struct pt_regs *regs)
+{
+	old_sigset_t mask = (old_sigset_t) regs->areg[3];
+	sigset_t saveset;
+
+	mask &= _BLOCKABLE;
+	spin_lock_irq(&current->sighand->siglock);
+	saveset = current->blocked;
+	siginitset(&current->blocked, mask);
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+
+	regs->areg[2] = -EINTR;
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		if (do_signal(regs, &saveset))
+			return -EINTR;
+	}
+}
+
+asmlinkage int
+sys_rt_sigsuspend(struct pt_regs *regs)
+{
+	sigset_t *unewset = (sigset_t *) regs->areg[4];
+	size_t sigsetsize = (size_t) regs->areg[3];
+	sigset_t saveset, newset;
+	/* XXX: Don't preclude handling different sized sigset_t's.  */
+	if (sigsetsize != sizeof(sigset_t))
+		return -EINVAL;
+
+	if (copy_from_user(&newset, unewset, sizeof(newset)))
+		return -EFAULT;
+	sigdelsetmask(&newset, ~_BLOCKABLE);
+	spin_lock_irq(&current->sighand->siglock);
+	saveset = current->blocked;
+	current->blocked = newset;
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+
+	regs->areg[2] = -EINTR;
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		if (do_signal(regs, &saveset))
+			return -EINTR;
+	}
+}
+
+asmlinkage int
+sys_sigaction(int sig, const struct old_sigaction *act,
+	      struct old_sigaction *oact)
+{
+	struct k_sigaction new_ka, old_ka;
+	int ret;
+
+	if (act) {
+		old_sigset_t mask;
+		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
+		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+			return -EFAULT;
+		__get_user(new_ka.sa.sa_flags, &act->sa_flags);
+		__get_user(mask, &act->sa_mask);
+		siginitset(&new_ka.sa.sa_mask, mask);
+	}
+
+	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+	if (!ret && oact) {
+		if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
+		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+			return -EFAULT;
+		__put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+		__put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
+	}
+
+	return ret;
+}
+
+asmlinkage int
+sys_sigaltstack(struct pt_regs *regs)
+{
+	const stack_t *uss = (stack_t *) regs->areg[4];
+	stack_t *uoss = (stack_t *) regs->areg[3];
+
+	if (regs->depc > 64)
+		panic ("Double exception sys_sigreturn\n");
+
+
+	return do_sigaltstack(uss, uoss, regs->areg[1]);
+}
+
+
+/*
+ * Do a signal return; undo the signal stack.
+ */
+
+struct sigframe
+{
+	struct sigcontext sc;
+	struct _cpstate cpstate;
+	unsigned long extramask[_NSIG_WORDS-1];
+	unsigned char retcode[6];
+	unsigned int reserved[4]; /* Reserved area for chaining */
+	unsigned int window[4]; /* Window of 4 registers for initial context */
+};
+
+struct rt_sigframe
+{
+	struct siginfo info;
+	struct ucontext uc;
+	struct _cpstate cpstate;
+	unsigned char retcode[6];
+	unsigned int reserved[4]; /* Reserved area for chaining */
+	unsigned int window[4]; /* Window of 4 registers for initial context */
+};
+
+extern void release_all_cp (struct task_struct *);
+
+
+// FIXME restore_cpextra
+static inline int
+restore_cpextra (struct _cpstate *buf)
+{
+#if 0
+	/* The signal handler may have used coprocessors in which
+	 * case they are still enabled.  We disable them to force a
+	 * reloading of the original task's CP state by the lazy
+	 * context-switching mechanisms of CP exception handling.
+	 * Also, we essentially discard any coprocessor state that the
+	 * signal handler created. */
+
+	struct task_struct *tsk = current;
+	release_all_cp(tsk);
+	return __copy_from_user(tsk->thread.cpextra, buf, TOTAL_CPEXTRA_SIZE);
+#endif
+	return 0;
+}
+
+/* Note: We don't copy double exception 'tregs', we have to finish double exc. first before we return to signal handler! This dbl.exc.handler might cause another double exception, but I think we are fine as the situation is the same as if we had returned to the signal handerl and got an interrupt immediately...
+ */
+
+
+static int
+restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
+{
+	struct thread_struct *thread;
+	unsigned int err = 0;
+	unsigned long ps;
+	struct _cpstate *buf;
+
+#define COPY(x)	err |= __get_user(regs->x, &sc->sc_##x)
+	COPY(pc);
+	COPY(depc);
+	COPY(wmask);
+	COPY(lbeg);
+	COPY(lend);
+	COPY(lcount);
+	COPY(sar);
+	COPY(windowbase);
+	COPY(windowstart);
+#undef COPY
+
+	/* For PS, restore only PS.CALLINC.
+	 * Assume that all other bits are either the same as for the signal
+	 * handler, or the user mode value doesn't matter (e.g. PS.OWB).
+	 */
+	err |= __get_user(ps, &sc->sc_ps);
+	regs->ps = (regs->ps & ~XCHAL_PS_CALLINC_MASK)
+		| (ps & XCHAL_PS_CALLINC_MASK);
+
+	/* Additional corruption checks */
+
+	if ((regs->windowbase >= (XCHAL_NUM_AREGS/4))
+	|| ((regs->windowstart & ~((1<<(XCHAL_NUM_AREGS/4)) - 1)) != 0) )
+		err = 1;
+	if ((regs->lcount > 0)
+	&& ((regs->lbeg > TASK_SIZE) || (regs->lend > TASK_SIZE)) )
+		err = 1;
+
+	/* Restore extended register state.
+	 * See struct thread_struct in processor.h.
+	 */
+	thread = &current->thread;
+
+	err |= __copy_from_user (regs->areg, sc->sc_areg, XCHAL_NUM_AREGS*4);
+	err |= __get_user(buf, &sc->sc_cpstate);
+	if (buf) {
+		if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
+			goto badframe;
+		err |= restore_cpextra(buf);
+	}
+
+	regs->syscall = -1;		/* disable syscall checks */
+	return err;
+
+badframe:
+	return 1;
+}
+
+static inline void
+flush_my_cpstate(struct task_struct *tsk)
+{
+	unsigned long flags;
+	local_irq_save(flags);
+
+#if 0	// FIXME
+	for (i = 0; i < XCHAL_CP_NUM; i++) {
+		if (tsk == coproc_owners[i]) {
+			xthal_validate_cp(i);
+			xthal_save_cpregs(tsk->thread.cpregs_ptr[i], i);
+
+			/* Invalidate and "disown" the cp to allow
+			 * callers the chance to reset cp state in the
+			 * task_struct. */
+
+			xthal_invalidate_cp(i);
+			coproc_owners[i] = 0;
+		}
+	}
+#endif
+	local_irq_restore(flags);
+}
+
+/* Return codes:
+	0:  nothing saved
+	1:  stuff to save, successful
+       -1:  stuff to save, error happened
+*/
+static int
+save_cpextra (struct _cpstate *buf)
+{
+#if (XCHAL_EXTRA_SA_SIZE == 0) && (XCHAL_CP_NUM == 0)
+	return 0;
+#else
+
+	/* FIXME: If a task has never used a coprocessor, there is
+	 * no need to save and restore anything.  Tracking this
+	 * information would allow us to optimize this section.
+	 * Perhaps we can use current->used_math or (current->flags &
+	 * PF_USEDFPU) or define a new field in the thread
+	 * structure. */
+
+	/* We flush any live, task-owned cp state to the task_struct,
+	 * then copy it all to the sigframe.  Then we clear all
+	 * cp/extra state in the task_struct, effectively
+	 * clearing/resetting all cp/extra state for the signal
+	 * handler (cp-exception handling will load these new values
+	 * into the cp/extra registers.)  This step is important for
+	 * things like a floating-point cp, where the OS must reset
+	 * the FCR to the default rounding mode. */
+
+	int err = 0;
+	struct task_struct *tsk = current;
+
+	flush_my_cpstate(tsk);
+	/* Note that we just copy everything: 'extra' and 'cp' state together.*/
+	err |= __copy_to_user(buf, tsk->thread.cp_save, XTENSA_CP_EXTRA_SIZE);
+	memset(tsk->thread.cp_save, 0, XTENSA_CP_EXTRA_SIZE);
+
+#if (XTENSA_CP_EXTRA_SIZE == 0)
+#error Sanity check on memset above, cpextra_size should not be zero.
+#endif
+
+	return err ? -1 : 1;
+#endif
+}
+
+static int
+setup_sigcontext(struct sigcontext *sc, struct _cpstate *cpstate,
+		 struct pt_regs *regs, unsigned long mask)
+{
+	struct thread_struct *thread;
+	int err = 0;
+
+//printk("setup_sigcontext\n");
+#define COPY(x)	err |= __put_user(regs->x, &sc->sc_##x)
+	COPY(pc);
+	COPY(ps);
+	COPY(depc);
+	COPY(wmask);
+	COPY(lbeg);
+	COPY(lend);
+	COPY(lcount);
+	COPY(sar);
+	COPY(windowbase);
+	COPY(windowstart);
+#undef COPY
+
+	/* Save extended register state.
+	 * See struct thread_struct in processor.h.
+	 */
+	thread = &current->thread;
+	err |= __copy_to_user (sc->sc_areg, regs->areg, XCHAL_NUM_AREGS * 4);
+	err |= save_cpextra(cpstate);
+	err |= __put_user(err ? NULL : cpstate, &sc->sc_cpstate);
+	/* non-iBCS2 extensions.. */
+	err |= __put_user(mask, &sc->oldmask);
+
+	return err;
+}
+
+asmlinkage int sys_sigreturn(struct pt_regs *regs)
+{
+	struct sigframe *frame = (struct sigframe *)regs->areg[1];
+	sigset_t set;
+	if (regs->depc > 64)
+		panic ("Double exception sys_sigreturn\n");
+
+	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+		goto badframe;
+
+	if (__get_user(set.sig[0], &frame->sc.oldmask)
+	    || (_NSIG_WORDS > 1
+		&& __copy_from_user(&set.sig[1], &frame->extramask,
+				    sizeof(frame->extramask))))
+		goto badframe;
+
+	sigdelsetmask(&set, ~_BLOCKABLE);
+
+	spin_lock_irq(&current->sighand->siglock);
+	current->blocked = set;
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+
+	if (restore_sigcontext(regs, &frame->sc))
+		goto badframe;
+	return regs->areg[2];
+
+badframe:
+	force_sig(SIGSEGV, current);
+	return 0;
+}
+
+asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
+{
+	struct rt_sigframe *frame = (struct rt_sigframe *)regs->areg[1];
+	sigset_t set;
+	stack_t st;
+	int ret;
+	if (regs->depc > 64)
+	{
+		printk("!!!!!!! DEPC !!!!!!!\n");
+		return 0;
+	}
+
+	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+		goto badframe;
+
+	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
+		goto badframe;
+
+	sigdelsetmask(&set, ~_BLOCKABLE);
+	spin_lock_irq(&current->sighand->siglock);
+	current->blocked = set;
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+
+	if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
+		goto badframe;
+	ret = regs->areg[2];
+
+	if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
+		goto badframe;
+	/* It is more difficult to avoid calling this function than to
+	   call it and ignore errors.  */
+	do_sigaltstack(&st, NULL, regs->areg[1]);
+
+	return ret;
+
+badframe:
+	force_sig(SIGSEGV, current);
+	return 0;
+}
+
+/*
+ * Set up a signal frame.
+ */
+
+/*
+ * Determine which stack to use..
+ */
+static inline void *
+get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
+{
+	if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! on_sig_stack(sp))
+		sp = current->sas_ss_sp + current->sas_ss_size;
+
+	return (void *)((sp - frame_size) & -16ul);
+}
+
+#define USE_SIGRETURN		0
+#define USE_RT_SIGRETURN	1
+
+static int
+gen_return_code(unsigned char *codemem, unsigned int use_rt_sigreturn)
+{
+	unsigned int retcall;
+	int err = 0;
+
+#if 0
+	/* Ignoring SA_RESTORER for now; it's supposed to be obsolete,
+	 * and the xtensa glibc doesn't use it.
+	 */
+	if (ka->sa.sa_flags & SA_RESTORER) {
+		regs->pr = (unsigned long) ka->sa.sa_restorer;
+	} else
+#endif /* 0 */
+	{
+
+#if (__NR_sigreturn > 255) || (__NR_rt_sigreturn > 255)
+
+/* The 12-bit immediate is really split up within the 24-bit MOVI
+ * instruction.  As long as the above system call numbers fit within
+ * 8-bits, the following code works fine. See the Xtensa ISA for
+ * details.
+ */
+
+#error Generating the MOVI instruction below breaks!
+#endif
+
+		retcall = use_rt_sigreturn ? __NR_rt_sigreturn : __NR_sigreturn;
+
+#ifdef __XTENSA_EB__   /* Big Endian version */
+		/* Generate instruction:  MOVI a2, retcall */
+		err |= __put_user(0x22, &codemem[0]);
+		err |= __put_user(0x0a, &codemem[1]);
+		err |= __put_user(retcall, &codemem[2]);
+		/* Generate instruction:  SYSCALL */
+		err |= __put_user(0x00, &codemem[3]);
+		err |= __put_user(0x05, &codemem[4]);
+		err |= __put_user(0x00, &codemem[5]);
+
+#elif defined __XTENSA_EL__   /* Little Endian version */
+		/* Generate instruction:  MOVI a2, retcall */
+		err |= __put_user(0x22, &codemem[0]);
+		err |= __put_user(0xa0, &codemem[1]);
+		err |= __put_user(retcall, &codemem[2]);
+		/* Generate instruction:  SYSCALL */
+		err |= __put_user(0x00, &codemem[3]);
+		err |= __put_user(0x50, &codemem[4]);
+		err |= __put_user(0x00, &codemem[5]);
+#else
+#error Must use compiler for Xtensa processors.
+#endif
+	}
+
+	/* Flush generated code out of the data cache */
+
+	if (err == 0)
+		__flush_invalidate_cache_range((unsigned long)codemem, 6UL);
+
+	return err;
+}
+
+static void
+set_thread_state(struct pt_regs *regs, void *stack, unsigned char *retaddr,
+	void *handler, unsigned long arg1, void *arg2, void *arg3)
+{
+	/* Set up registers for signal handler */
+	start_thread(regs, (unsigned long) handler, (unsigned long) stack);
+
+	/* Set up a stack frame for a call4
+	 * Note: PS.CALLINC is set to one by start_thread
+	 */
+	regs->areg[4] = (((unsigned long) retaddr) & 0x3fffffff) | 0x40000000;
+	regs->areg[6] = arg1;
+	regs->areg[7] = (unsigned long) arg2;
+	regs->areg[8] = (unsigned long) arg3;
+}
+
+static void setup_frame(int sig, struct k_sigaction *ka,
+			sigset_t *set, struct pt_regs *regs)
+{
+	struct sigframe *frame;
+	int err = 0;
+	int signal;
+
+	frame = get_sigframe(ka, regs->areg[1], sizeof(*frame));
+	if (regs->depc > 64)
+	{
+		printk("!!!!!!! DEPC !!!!!!!\n");
+		return;
+	}
+
+
+	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+		goto give_sigsegv;
+
+	signal = current_thread_info()->exec_domain
+		&& current_thread_info()->exec_domain->signal_invmap
+		&& sig < 32
+		? current_thread_info()->exec_domain->signal_invmap[sig]
+		: sig;
+
+	err |= setup_sigcontext(&frame->sc, &frame->cpstate, regs, set->sig[0]);
+
+	if (_NSIG_WORDS > 1) {
+		err |= __copy_to_user(frame->extramask, &set->sig[1],
+				      sizeof(frame->extramask));
+	}
+
+	/* Create sys_sigreturn syscall in stack frame */
+	err |= gen_return_code(frame->retcode, USE_SIGRETURN);
+
+	if (err)
+		goto give_sigsegv;
+
+	/* Create signal handler execution context.
+	 * Return context not modified until this point.
+	 */
+	set_thread_state(regs, frame, frame->retcode,
+		ka->sa.sa_handler, signal, &frame->sc, NULL);
+
+	/* Set access mode to USER_DS.  Nomenclature is outdated, but
+	 * functionality is used in uaccess.h
+	 */
+	set_fs(USER_DS);
+
+
+#if DEBUG_SIG
+	printk("SIG deliver (%s:%d): signal=%d sp=%p pc=%08x\n",
+		current->comm, current->pid, signal, frame, regs->pc);
+#endif
+
+	return;
+
+give_sigsegv:
+	if (sig == SIGSEGV)
+		ka->sa.sa_handler = SIG_DFL;
+	force_sig(SIGSEGV, current);
+}
+
+static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+			   sigset_t *set, struct pt_regs *regs)
+{
+	struct rt_sigframe *frame;
+	int err = 0;
+	int signal;
+
+	frame = get_sigframe(ka, regs->areg[1], sizeof(*frame));
+	if (regs->depc > 64)
+		panic ("Double exception sys_sigreturn\n");
+
+	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+		goto give_sigsegv;
+
+	signal = current_thread_info()->exec_domain
+		&& current_thread_info()->exec_domain->signal_invmap
+		&& sig < 32
+		? current_thread_info()->exec_domain->signal_invmap[sig]
+		: sig;
+
+	err |= copy_siginfo_to_user(&frame->info, info);
+
+	/* Create the ucontext.  */
+	err |= __put_user(0, &frame->uc.uc_flags);
+	err |= __put_user(0, &frame->uc.uc_link);
+	err |= __put_user((void *)current->sas_ss_sp,
+			  &frame->uc.uc_stack.ss_sp);
+	err |= __put_user(sas_ss_flags(regs->areg[1]),
+			  &frame->uc.uc_stack.ss_flags);
+	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+	err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->cpstate,
+			        regs, set->sig[0]);
+	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+
+	/* Create sys_rt_sigreturn syscall in stack frame */
+	err |= gen_return_code(frame->retcode, USE_RT_SIGRETURN);
+
+	if (err)
+		goto give_sigsegv;
+
+	/* Create signal handler execution context.
+	 * Return context not modified until this point.
+	 */
+	set_thread_state(regs, frame, frame->retcode,
+		ka->sa.sa_handler, signal, &frame->info, &frame->uc);
+
+	/* Set access mode to USER_DS.  Nomenclature is outdated, but
+	 * functionality is used in uaccess.h
+	 */
+	set_fs(USER_DS);
+
+#if DEBUG_SIG
+	printk("SIG rt deliver (%s:%d): signal=%d sp=%p pc=%08x\n",
+		current->comm, current->pid, signal, frame, regs->pc);
+#endif
+
+	return;
+
+give_sigsegv:
+	if (sig == SIGSEGV)
+		ka->sa.sa_handler = SIG_DFL;
+	force_sig(SIGSEGV, current);
+}
+
+
+
+/*
+ * Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ *
+ * Note that we go through the signals twice: once to check the signals that
+ * the kernel can handle, and then we build all the user-level signal handling
+ * stack-frames in one go after that.
+ */
+int do_signal(struct pt_regs *regs, sigset_t *oldset)
+{
+	siginfo_t info;
+	int signr;
+	struct k_sigaction ka;
+
+	if (!oldset)
+		oldset = &current->blocked;
+
+	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+
+	/* Are we from a system call? */
+	if (regs->syscall >= 0) {
+		/* If so, check system call restarting.. */
+		switch (regs->areg[2]) {
+			case ERESTARTNOHAND:
+			case ERESTART_RESTARTBLOCK:
+				regs->areg[2] = -EINTR;
+				break;
+
+			case ERESTARTSYS:
+				if (!(ka.sa.sa_flags & SA_RESTART)) {
+					regs->areg[2] = -EINTR;
+					break;
+				}
+			/* fallthrough */
+			case ERESTARTNOINTR:
+				regs->areg[2] = regs->syscall;
+				regs->pc -= 3;
+		}
+	}
+
+	if (signr == 0)
+		return 0;		/* no signals delivered */
+
+	/* Whee!  Actually deliver the signal.  */
+
+	/* Set up the stack frame */
+	if (ka.sa.sa_flags & SA_SIGINFO)
+		setup_rt_frame(signr, &ka, &info, oldset, regs);
+	else
+		setup_frame(signr, &ka, oldset, regs);
+
+	if (ka.sa.sa_flags & SA_ONESHOT)
+		ka.sa.sa_handler = SIG_DFL;
+
+	if (!(ka.sa.sa_flags & SA_NODEFER)) {
+		spin_lock_irq(&current->sighand->siglock);
+		sigorsets(&current->blocked, &current->blocked, &ka.sa.sa_mask);
+		sigaddset(&current->blocked, signr);
+		recalc_sigpending();
+		spin_unlock_irq(&current->sighand->siglock);
+	}
+	return 1;
+}
diff --git a/arch/xtensa/kernel/syscalls.c b/arch/xtensa/kernel/syscalls.c
new file mode 100644
index 0000000..abc8ed6
--- /dev/null
+++ b/arch/xtensa/kernel/syscalls.c
@@ -0,0 +1,418 @@
+/*
+ * arch/xtensa/kernel/syscall.c
+ *
+ * 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) 2001 - 2005 Tensilica Inc.
+ * Copyright (C) 2000 Silicon Graphics, Inc.
+ * Copyright (C) 1995 - 2000 by Ralf Baechle
+ *
+ * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
+ * Marc Gauthier <marc@tensilica.com, marc@alumni.uwaterloo.ca>
+ * Chris Zankel <chris@zankel.net>
+ * Kevin Chea
+ *
+ */
+
+#define DEBUG	0
+
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/mman.h>
+#include <linux/sched.h>
+#include <linux/file.h>
+#include <linux/slab.h>
+#include <linux/utsname.h>
+#include <linux/unistd.h>
+#include <linux/stringify.h>
+#include <linux/syscalls.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/errno.h>
+#include <asm/ptrace.h>
+#include <asm/signal.h>
+#include <asm/uaccess.h>
+#include <asm/hardirq.h>
+#include <asm/mman.h>
+#include <asm/shmparam.h>
+#include <asm/page.h>
+#include <asm/ipc.h>
+
+extern void do_syscall_trace(void);
+typedef int (*syscall_t)(void *a0,...);
+extern int (*do_syscalls)(struct pt_regs *regs, syscall_t fun,
+				     int narg);
+extern syscall_t sys_call_table[];
+extern unsigned char sys_narg_table[];
+
+/*
+ * sys_pipe() is the normal C calling standard for creating a pipe. It's not
+ * the way unix traditional does this, though.
+ */
+
+int sys_pipe(int __user *userfds)
+{
+	int fd[2];
+	int error;
+
+	error = do_pipe(fd);
+	if (!error) {
+		if (copy_to_user(userfds, fd, 2 * sizeof(int)))
+			error = -EFAULT;
+	}
+	return error;
+}
+
+/*
+ * Common code for old and new mmaps.
+ */
+
+static inline long do_mmap2(unsigned long addr, unsigned long len,
+    			    unsigned long prot, unsigned long flags,
+			    unsigned long fd, unsigned long pgoff)
+{
+	int error = -EBADF;
+	struct file * file = NULL;
+
+	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+	if (!(flags & MAP_ANONYMOUS)) {
+		file = fget(fd);
+		if (!file)
+			goto out;
+	}
+
+	down_write(&current->mm->mmap_sem);
+	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+	up_write(&current->mm->mmap_sem);
+
+	if (file)
+		fput(file);
+out:
+	return error;
+}
+
+unsigned long old_mmap(unsigned long addr, size_t len, int prot,
+		       int flags, int fd, off_t offset)
+{
+	return do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
+}
+
+long sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
+	       unsigned long flags, unsigned long fd, unsigned long pgoff)
+{
+	return do_mmap2(addr, len, prot, flags, fd, pgoff);
+}
+
+int sys_fork(struct pt_regs *regs)
+{
+	return do_fork(SIGCHLD, regs->areg[1], regs, 0, NULL, NULL);
+}
+
+int sys_vfork(struct pt_regs *regs)
+{
+	return do_fork(CLONE_VFORK|CLONE_VM|SIGCHLD, regs->areg[1],
+		       regs, 0, NULL, NULL);
+}
+
+int sys_clone(struct pt_regs *regs)
+{
+	unsigned long clone_flags;
+	unsigned long newsp;
+	int __user *parent_tidptr, *child_tidptr;
+	clone_flags = regs->areg[4];
+	newsp = regs->areg[3];
+	parent_tidptr = (int __user *)regs->areg[5];
+	child_tidptr = (int __user *)regs->areg[6];
+	if (!newsp)
+		newsp = regs->areg[1];
+	return do_fork(clone_flags,newsp,regs,0,parent_tidptr,child_tidptr);
+}
+
+/*
+ * sys_execve() executes a new program.
+ */
+
+int sys_execve(struct pt_regs *regs)
+{
+	int error;
+	char * filename;
+
+	filename = getname((char *) (long)regs->areg[5]);
+	error = PTR_ERR(filename);
+	if (IS_ERR(filename))
+		goto out;
+	error = do_execve(filename, (char **) (long)regs->areg[3],
+	                  (char **) (long)regs->areg[4], regs);
+	putname(filename);
+
+out:
+	return error;
+}
+
+int sys_uname(struct old_utsname * name)
+{
+	if (name && !copy_to_user(name, &system_utsname, sizeof (*name)))
+		return 0;
+	return -EFAULT;
+}
+
+int sys_olduname(struct oldold_utsname * name)
+{
+	int error;
+
+	if (!name)
+		return -EFAULT;
+	if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
+		return -EFAULT;
+
+	error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
+	error -= __put_user(0,name->sysname+__OLD_UTS_LEN);
+	error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
+	error -= __put_user(0,name->nodename+__OLD_UTS_LEN);
+	error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN);
+	error -= __put_user(0,name->release+__OLD_UTS_LEN);
+	error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN);
+	error -= __put_user(0,name->version+__OLD_UTS_LEN);
+	error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
+	error -= __put_user(0,name->machine+__OLD_UTS_LEN);
+
+	return error ? -EFAULT : 0;
+}
+
+
+/*
+ * Build the string table for the builtin "poor man's strace".
+ */
+
+#if DEBUG
+#define SYSCALL(fun, narg) #fun,
+static char *sfnames[] = {
+#include "syscalls.h"
+};
+#undef SYS
+#endif
+
+void system_call (struct pt_regs *regs)
+{
+	syscall_t syscall;
+	unsigned long parm0, parm1, parm2, parm3, parm4, parm5;
+	int nargs, res;
+	unsigned int syscallnr;
+	int ps;
+
+#if DEBUG
+	int i;
+	unsigned long parms[6];
+	char *sysname;
+#endif
+
+	regs->syscall = regs->areg[2];
+
+	do_syscall_trace();
+
+	/* Have to load after syscall_trace because strace
+	 * sometimes changes regs->syscall.
+	 */
+	syscallnr = regs->syscall;
+
+	parm0 = parm1 = parm2 = parm3 = parm4 = parm5 = 0;
+
+	/* Restore interrupt level to syscall invoker's.
+	 * If this were in assembly, we wouldn't disable
+	 * interrupts in the first place:
+	 */
+	local_save_flags (ps);
+	local_irq_restore((ps & ~XCHAL_PS_INTLEVEL_MASK) |
+			  (regs->ps & XCHAL_PS_INTLEVEL_MASK) );
+
+	if (syscallnr > __NR_Linux_syscalls) {
+		regs->areg[2] = -ENOSYS;
+		return;
+	}
+
+	syscall = sys_call_table[syscallnr];
+	nargs = sys_narg_table[syscallnr];
+
+	if (syscall == NULL) {
+		regs->areg[2] = -ENOSYS;
+		return;
+	}
+
+	/* There shouldn't be more than six arguments in the table! */
+
+	if (nargs > 6)
+		panic("Internal error - too many syscall arguments (%d)!\n",
+		      nargs);
+
+	/* Linux takes system-call arguments in registers.  The ABI
+         * and Xtensa software conventions require the system-call
+         * number in a2.  If an argument exists in a2, we move it to
+         * the next available register.  Note that for improved
+         * efficiency, we do NOT shift all parameters down one
+         * register to maintain the original order.
+	 *
+         * At best case (zero arguments), we just write the syscall
+         * number to a2.  At worst case (1 to 6 arguments), we move
+         * the argument in a2 to the next available register, then
+         * write the syscall number to a2.
+	 *
+         * For clarity, the following truth table enumerates all
+         * possibilities.
+	 *
+         * arguments	syscall number	arg0, arg1, arg2, arg3, arg4, arg5
+         * ---------	--------------	----------------------------------
+	 *	0	      a2
+	 *	1	      a2	a3
+	 *	2	      a2	a4,   a3
+	 *	3	      a2	a5,   a3,   a4
+	 *	4	      a2	a6,   a3,   a4,   a5
+	 *	5	      a2	a7,   a3,   a4,   a5,   a6
+	 *	6	      a2	a8,   a3,   a4,   a5,   a6,   a7
+	 */
+	if (nargs) {
+		parm0 = regs->areg[nargs+2];
+		parm1 = regs->areg[3];
+		parm2 = regs->areg[4];
+		parm3 = regs->areg[5];
+		parm4 = regs->areg[6];
+		parm5 = regs->areg[7];
+	} else /* nargs == 0 */
+		parm0 = (unsigned long) regs;
+
+#if DEBUG
+	parms[0] = parm0;
+	parms[1] = parm1;
+	parms[2] = parm2;
+	parms[3] = parm3;
+	parms[4] = parm4;
+	parms[5] = parm5;
+
+	sysname = sfnames[syscallnr];
+	if (strncmp(sysname, "sys_", 4) == 0)
+		sysname = sysname + 4;
+
+	printk("\017SYSCALL:I:%x:%d:%s  %s(", regs->pc, current->pid,
+	       current->comm, sysname);
+	for (i = 0; i < nargs; i++)
+		printk((i>0) ? ", %#lx" : "%#lx", parms[i]);
+	printk(")\n");
+#endif
+
+	res = syscall((void *)parm0, parm1, parm2, parm3, parm4, parm5);
+
+#if DEBUG
+	printk("\017SYSCALL:O:%d:%s  %s(",current->pid, current->comm, sysname);
+	for (i = 0; i < nargs; i++)
+		printk((i>0) ? ", %#lx" : "%#lx", parms[i]);
+	if (res < 4096)
+		printk(") = %d\n", res);
+	else
+		printk(") = %#x\n", res);
+#endif /* DEBUG */
+
+	regs->areg[2] = res;
+	do_syscall_trace();
+}
+
+/*
+ * sys_ipc() is the de-multiplexer for the SysV IPC calls..
+ *
+ * This is really horribly ugly.
+ */
+
+int sys_ipc (uint call, int first, int second,
+			int third, void __user *ptr, long fifth)
+{
+	int version, ret;
+
+	version = call >> 16; /* hack for backward compatibility */
+	call &= 0xffff;
+	ret = -ENOSYS;
+
+	switch (call) {
+	case SEMOP:
+		ret = sys_semtimedop (first, (struct sembuf __user *)ptr,
+				     second, NULL);
+		break;
+
+	case SEMTIMEDOP:
+		ret = sys_semtimedop (first, (struct sembuf __user *)ptr,
+				      second, (const struct timespec *) fifth);
+		break;
+
+	case SEMGET:
+		ret = sys_semget (first, second, third);
+		break;
+
+	case SEMCTL: {
+		union semun fourth;
+
+		if (ptr && !get_user(fourth.__pad, (void *__user *) ptr))
+			ret = sys_semctl (first, second, third, fourth);
+		break;
+		}
+
+	case MSGSND:
+		ret = sys_msgsnd (first, (struct msgbuf __user*) ptr,
+				  second, third);
+		break;
+
+	case MSGRCV:
+		switch (version) {
+		case 0: {
+			struct ipc_kludge tmp;
+
+			if (ptr && !copy_from_user(&tmp,
+					   (struct ipc_kludge *) ptr,
+					   sizeof (tmp)))
+				ret = sys_msgrcv (first, tmp.msgp, second,
+						  tmp.msgtyp, third);
+			break;
+			}
+
+		default:
+			ret = sys_msgrcv (first, (struct msgbuf __user *) ptr,
+					  second, 0, third);
+			break;
+		}
+		break;
+
+	case MSGGET:
+		ret = sys_msgget ((key_t) first, second);
+		break;
+
+	case MSGCTL:
+		ret = sys_msgctl (first, second, (struct msqid_ds __user*) ptr);
+		break;
+
+	case SHMAT: {
+		ulong raddr;
+		ret = do_shmat (first, (char __user *) ptr, second, &raddr);
+
+		if (!ret)
+			ret = put_user (raddr, (ulong __user *) third);
+
+		break;
+		}
+
+	case SHMDT:
+		ret = sys_shmdt ((char __user *)ptr);
+		break;
+
+	case SHMGET:
+		ret = sys_shmget (first, second, third);
+		break;
+
+	case SHMCTL:
+		ret = sys_shmctl (first, second, (struct shmid_ds __user*) ptr);
+		break;
+	}
+	return ret;
+}
+
diff --git a/arch/xtensa/kernel/syscalls.h b/arch/xtensa/kernel/syscalls.h
new file mode 100644
index 0000000..5b3f75f
--- /dev/null
+++ b/arch/xtensa/kernel/syscalls.h
@@ -0,0 +1,248 @@
+/*
+ * arch/xtensa/kernel/syscalls.h
+ *
+ * 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) 1995, 1996, 1997, 1998 by Ralf Baechle
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ *
+ * Changes by Joe Taylor <joe@tensilica.com>
+ */
+
+/*
+ * This file is being included twice - once to build a list of all
+ * syscalls and once to build a table of how many arguments each syscall
+ * accepts.  Syscalls that receive a pointer to the saved registers are
+ * marked as having zero arguments.
+ *
+ * The binary compatibility calls are in a separate list.
+ *
+ * Entry '0' used to be system_call.  It's removed to disable indirect
+ * system calls for now so user tasks can't recurse.  See mips'
+ * sys_syscall for a comparable example.
+ */
+
+SYSCALL(0, 0)		                /* 00 */
+
+SYSCALL(sys_exit, 1)
+SYSCALL(sys_fork, 0)
+SYSCALL(sys_read, 3)
+SYSCALL(sys_write, 3)
+SYSCALL(sys_open, 3)			/* 05 */
+SYSCALL(sys_close, 1)
+SYSCALL(sys_waitpid, 3)
+SYSCALL(sys_creat, 2)
+SYSCALL(sys_link, 2)
+SYSCALL(sys_unlink, 1)			/* 10 */
+SYSCALL(sys_execve, 0)
+SYSCALL(sys_chdir, 1)
+SYSCALL(sys_time, 1)
+SYSCALL(sys_mknod, 3)
+SYSCALL(sys_chmod, 2)			/* 15 */
+SYSCALL(sys_lchown, 3)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_stat, 2)
+SYSCALL(sys_lseek, 3)
+SYSCALL(sys_getpid, 0)			/* 20 */
+SYSCALL(sys_mount, 5)
+SYSCALL(sys_oldumount, 1)
+SYSCALL(sys_setuid, 1)
+SYSCALL(sys_getuid, 0)
+SYSCALL(sys_stime, 1)			/* 25 */
+SYSCALL(sys_ptrace, 4)
+SYSCALL(sys_alarm, 1)
+SYSCALL(sys_fstat, 2)
+SYSCALL(sys_pause, 0)
+SYSCALL(sys_utime, 2)			/* 30 */
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_access, 2)
+SYSCALL(sys_nice, 1)
+SYSCALL(sys_ni_syscall, 0)		/* 35 */
+SYSCALL(sys_sync, 0)
+SYSCALL(sys_kill, 2)
+SYSCALL(sys_rename, 2)
+SYSCALL(sys_mkdir, 2)
+SYSCALL(sys_rmdir, 1)			/* 40 */
+SYSCALL(sys_dup, 1)
+SYSCALL(sys_pipe, 1)
+SYSCALL(sys_times, 1)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_brk, 1)			/* 45 */
+SYSCALL(sys_setgid, 1)
+SYSCALL(sys_getgid, 0)
+SYSCALL(sys_ni_syscall, 0)		/* was signal(2) */
+SYSCALL(sys_geteuid, 0)
+SYSCALL(sys_getegid, 0)			/* 50 */
+SYSCALL(sys_acct, 1)
+SYSCALL(sys_umount, 2)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_ioctl, 3)
+SYSCALL(sys_fcntl, 3)			/* 55 */
+SYSCALL(sys_ni_syscall, 2)
+SYSCALL(sys_setpgid, 2)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_olduname, 1)
+SYSCALL(sys_umask, 1)			/* 60 */
+SYSCALL(sys_chroot, 1)
+SYSCALL(sys_ustat, 2)
+SYSCALL(sys_dup2, 2)
+SYSCALL(sys_getppid, 0)
+SYSCALL(sys_getpgrp, 0)			/* 65 */
+SYSCALL(sys_setsid, 0)
+SYSCALL(sys_sigaction, 3)
+SYSCALL(sys_sgetmask, 0)
+SYSCALL(sys_ssetmask, 1)
+SYSCALL(sys_setreuid, 2)		/* 70 */
+SYSCALL(sys_setregid, 2)
+SYSCALL(sys_sigsuspend, 0)
+SYSCALL(sys_sigpending, 1)
+SYSCALL(sys_sethostname, 2)
+SYSCALL(sys_setrlimit, 2)		/* 75 */
+SYSCALL(sys_getrlimit, 2)
+SYSCALL(sys_getrusage, 2)
+SYSCALL(sys_gettimeofday, 2)
+SYSCALL(sys_settimeofday, 2)
+SYSCALL(sys_getgroups, 2)		/* 80 */
+SYSCALL(sys_setgroups, 2)
+SYSCALL(sys_ni_syscall, 0)		 /* old_select */
+SYSCALL(sys_symlink, 2)
+SYSCALL(sys_lstat, 2)
+SYSCALL(sys_readlink, 3)		/* 85 */
+SYSCALL(sys_uselib, 1)
+SYSCALL(sys_swapon, 2)
+SYSCALL(sys_reboot, 3)
+SYSCALL(old_readdir, 3)
+SYSCALL(old_mmap, 6)			/* 90 */
+SYSCALL(sys_munmap, 2)
+SYSCALL(sys_truncate, 2)
+SYSCALL(sys_ftruncate, 2)
+SYSCALL(sys_fchmod, 2)
+SYSCALL(sys_fchown, 3)			/* 95 */
+SYSCALL(sys_getpriority, 2)
+SYSCALL(sys_setpriority, 3)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_statfs, 2)
+SYSCALL(sys_fstatfs, 2)			/* 100 */
+SYSCALL(sys_ni_syscall, 3)
+SYSCALL(sys_socketcall, 2)
+SYSCALL(sys_syslog, 3)
+SYSCALL(sys_setitimer, 3)
+SYSCALL(sys_getitimer, 2)		/* 105 */
+SYSCALL(sys_newstat, 2)
+SYSCALL(sys_newlstat, 2)
+SYSCALL(sys_newfstat, 2)
+SYSCALL(sys_uname, 1)
+SYSCALL(sys_ni_syscall, 0)		/* 110 */
+SYSCALL(sys_vhangup, 0)
+SYSCALL(sys_ni_syscall, 0)		/* was sys_idle() */
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_wait4, 4)
+SYSCALL(sys_swapoff, 1)			/* 115 */
+SYSCALL(sys_sysinfo, 1)
+SYSCALL(sys_ipc, 5)   			/* 6 really, but glibc uses only 5) */
+SYSCALL(sys_fsync, 1)
+SYSCALL(sys_sigreturn, 0)
+SYSCALL(sys_clone, 0)			/* 120 */
+SYSCALL(sys_setdomainname, 2)
+SYSCALL(sys_newuname, 1)
+SYSCALL(sys_ni_syscall, 0) 		/* sys_modify_ldt */
+SYSCALL(sys_adjtimex, 1)
+SYSCALL(sys_mprotect, 3)		/* 125 */
+SYSCALL(sys_sigprocmask, 3)
+SYSCALL(sys_ni_syscall, 2)		/* old sys_create_module */
+SYSCALL(sys_init_module, 2)
+SYSCALL(sys_delete_module, 1)
+SYSCALL(sys_ni_syscall, 1)		/* old sys_get_kernel_sysm */	/* 130 */
+SYSCALL(sys_quotactl, 0)
+SYSCALL(sys_getpgid, 1)
+SYSCALL(sys_fchdir, 1)
+SYSCALL(sys_bdflush, 2)
+SYSCALL(sys_sysfs, 3)			/* 135 */
+SYSCALL(sys_personality, 1)
+SYSCALL(sys_ni_syscall, 0)		/* for afs_syscall */
+SYSCALL(sys_setfsuid, 1)
+SYSCALL(sys_setfsgid, 1)
+SYSCALL(sys_llseek, 5)			/* 140 */
+SYSCALL(sys_getdents, 3)
+SYSCALL(sys_select, 5)
+SYSCALL(sys_flock, 2)
+SYSCALL(sys_msync, 3)
+SYSCALL(sys_readv, 3)			/* 145 */
+SYSCALL(sys_writev, 3)
+SYSCALL(sys_ni_syscall, 3)
+SYSCALL(sys_ni_syscall, 3)
+SYSCALL(sys_ni_syscall, 4)		/* handled in fast syscall handler. */
+SYSCALL(sys_ni_syscall, 0)		/* 150 */
+SYSCALL(sys_getsid, 1)
+SYSCALL(sys_fdatasync, 1)
+SYSCALL(sys_sysctl, 1)
+SYSCALL(sys_mlock, 2)
+SYSCALL(sys_munlock, 2)			/* 155 */
+SYSCALL(sys_mlockall, 1)
+SYSCALL(sys_munlockall, 0)
+SYSCALL(sys_sched_setparam,2)
+SYSCALL(sys_sched_getparam,2)
+SYSCALL(sys_sched_setscheduler,3)	/* 160 */
+SYSCALL(sys_sched_getscheduler,1)
+SYSCALL(sys_sched_yield,0)
+SYSCALL(sys_sched_get_priority_max,1)
+SYSCALL(sys_sched_get_priority_min,1)
+SYSCALL(sys_sched_rr_get_interval,2)	/* 165 */
+SYSCALL(sys_nanosleep,2)
+SYSCALL(sys_mremap,4)
+SYSCALL(sys_accept, 3)
+SYSCALL(sys_bind, 3)
+SYSCALL(sys_connect, 3)			/* 170 */
+SYSCALL(sys_getpeername, 3)
+SYSCALL(sys_getsockname, 3)
+SYSCALL(sys_getsockopt, 5)
+SYSCALL(sys_listen, 2)
+SYSCALL(sys_recv, 4)			/* 175 */
+SYSCALL(sys_recvfrom, 6)
+SYSCALL(sys_recvmsg, 3)
+SYSCALL(sys_send, 4)
+SYSCALL(sys_sendmsg, 3)
+SYSCALL(sys_sendto, 6)			/* 180 */
+SYSCALL(sys_setsockopt, 5)
+SYSCALL(sys_shutdown, 2)
+SYSCALL(sys_socket, 3)
+SYSCALL(sys_socketpair, 4)
+SYSCALL(sys_setresuid, 3)		/* 185 */
+SYSCALL(sys_getresuid, 3)
+SYSCALL(sys_ni_syscall, 5)		/* old sys_query_module */
+SYSCALL(sys_poll, 3)
+SYSCALL(sys_nfsservctl, 3)
+SYSCALL(sys_setresgid, 3)		/* 190 */
+SYSCALL(sys_getresgid, 3)
+SYSCALL(sys_prctl, 5)
+SYSCALL(sys_rt_sigreturn, 0)
+SYSCALL(sys_rt_sigaction, 4)
+SYSCALL(sys_rt_sigprocmask, 4)		/* 195 */
+SYSCALL(sys_rt_sigpending, 2)
+SYSCALL(sys_rt_sigtimedwait, 4)
+SYSCALL(sys_rt_sigqueueinfo, 3)
+SYSCALL(sys_rt_sigsuspend, 0)
+SYSCALL(sys_pread64, 5)			/* 200 */
+SYSCALL(sys_pwrite64, 5)
+SYSCALL(sys_chown, 3)
+SYSCALL(sys_getcwd, 2)
+SYSCALL(sys_capget, 2)
+SYSCALL(sys_capset, 2)			/* 205 */
+SYSCALL(sys_sigaltstack, 0)
+SYSCALL(sys_sendfile, 4)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_mmap2, 6)			/* 210 */
+SYSCALL(sys_truncate64, 2)
+SYSCALL(sys_ftruncate64, 2)
+SYSCALL(sys_stat64, 2)
+SYSCALL(sys_lstat64, 2)
+SYSCALL(sys_fstat64, 2)			/* 215 */
+SYSCALL(sys_pivot_root, 2)
+SYSCALL(sys_mincore, 3)
+SYSCALL(sys_madvise, 3)
+SYSCALL(sys_getdents64, 3)
+SYSCALL(sys_vfork, 0)			/* 220 */
diff --git a/arch/xtensa/kernel/time.c b/arch/xtensa/kernel/time.c
new file mode 100644
index 0000000..e07287d
--- /dev/null
+++ b/arch/xtensa/kernel/time.c
@@ -0,0 +1,227 @@
+/*
+ * arch/xtensa/kernel/time.c
+ *
+ * Timer and clock support.
+ *
+ * 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) 2005 Tensilica Inc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/time.h>
+#include <linux/timex.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/profile.h>
+#include <linux/delay.h>
+
+#include <asm/timex.h>
+#include <asm/platform.h>
+
+
+extern volatile unsigned long wall_jiffies;
+
+u64 jiffies_64 = INITIAL_JIFFIES;
+EXPORT_SYMBOL(jiffies_64);
+
+spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
+EXPORT_SYMBOL(rtc_lock);
+
+
+#ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
+unsigned long ccount_per_jiffy;		/* per 1/HZ */
+unsigned long ccount_nsec;		/* nsec per ccount increment */
+#endif
+
+unsigned int last_ccount_stamp;
+static long last_rtc_update = 0;
+
+/*
+ * Scheduler clock - returns current tim in nanosec units.
+ */
+
+unsigned long long sched_clock(void)
+{
+	return (unsigned long long)jiffies * (1000000000 / HZ);
+}
+
+static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static struct irqaction timer_irqaction = {
+	.handler =	timer_interrupt,
+	.flags =	SA_INTERRUPT,
+	.name =		"timer",
+};
+
+void __init time_init(void)
+{
+	time_t sec_o, sec_n = 0;
+
+	/* The platform must provide a function to calibrate the processor
+	 * speed for the CALIBRATE.
+	 */
+
+#if CONFIG_XTENSA_CALIBRATE_CCOUNT
+	printk("Calibrating CPU frequency ");
+	platform_calibrate_ccount();
+	printk("%d.%02d MHz\n", (int)ccount_per_jiffy/(1000000/HZ),
+			(int)(ccount_per_jiffy/(10000/HZ))%100);
+#endif
+
+	/* Set time from RTC (if provided) */
+
+	if (platform_get_rtc_time(&sec_o) == 0)
+		while (platform_get_rtc_time(&sec_n))
+			if (sec_o != sec_n)
+				break;
+
+	xtime.tv_nsec = 0;
+	last_rtc_update = xtime.tv_sec = sec_n;
+	last_ccount_stamp = get_ccount();
+
+	set_normalized_timespec(&wall_to_monotonic,
+		-xtime.tv_sec, -xtime.tv_nsec);
+
+	/* Initialize the linux timer interrupt. */
+
+	setup_irq(LINUX_TIMER_INT, &timer_irqaction);
+	set_linux_timer(get_ccount() + CCOUNT_PER_JIFFY);
+}
+
+
+int do_settimeofday(struct timespec *tv)
+{
+	time_t wtm_sec, sec = tv->tv_sec;
+	long wtm_nsec, nsec = tv->tv_nsec;
+	unsigned long ccount;
+
+	if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
+		return -EINVAL;
+
+	write_seqlock_irq(&xtime_lock);
+
+	/* This is revolting. We need to set "xtime" correctly. However, the
+	 * value in this location is the value at the most recent update of
+	 * wall time.  Discover what correction gettimeofday() would have
+	 * made, and then undo it!
+	 */
+	ccount = get_ccount();
+	nsec -= (ccount - last_ccount_stamp) * CCOUNT_NSEC;
+	nsec -= (jiffies - wall_jiffies) * CCOUNT_PER_JIFFY * CCOUNT_NSEC;
+
+	wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
+	wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
+
+	set_normalized_timespec(&xtime, sec, nsec);
+	set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
+
+	time_adjust = 0;                /* stop active adjtime() */
+	time_status |= STA_UNSYNC;
+	time_maxerror = NTP_PHASE_LIMIT;
+	time_esterror = NTP_PHASE_LIMIT;
+	write_sequnlock_irq(&xtime_lock);
+	return 0;
+}
+
+EXPORT_SYMBOL(do_settimeofday);
+
+
+void do_gettimeofday(struct timeval *tv)
+{
+	unsigned long flags;
+	unsigned long sec, usec, delta, lost, seq;
+
+	do {
+		seq = read_seqbegin_irqsave(&xtime_lock, flags);
+
+		delta = get_ccount() - last_ccount_stamp;
+		sec = xtime.tv_sec;
+		usec = (xtime.tv_nsec / NSEC_PER_USEC);
+
+		lost = jiffies - wall_jiffies;
+
+	} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
+
+	usec += lost * (1000000UL/HZ) + (delta * CCOUNT_NSEC) / NSEC_PER_USEC;
+	for (; usec >= 1000000; sec++, usec -= 1000000)
+		;
+
+	tv->tv_sec = sec;
+	tv->tv_usec = usec;
+}
+
+EXPORT_SYMBOL(do_gettimeofday);
+
+/*
+ * The timer interrupt is called HZ times per second.
+ */
+
+irqreturn_t timer_interrupt (int irq, void *dev_id, struct pt_regs *regs)
+{
+
+	unsigned long next;
+
+	next = get_linux_timer();
+
+again:
+	while ((signed long)(get_ccount() - next) > 0) {
+
+		profile_tick(CPU_PROFILING, regs);
+#ifndef CONFIG_SMP
+		update_process_times(user_mode(regs));
+#endif
+
+		write_seqlock(&xtime_lock);
+
+		last_ccount_stamp = next;
+		next += CCOUNT_PER_JIFFY;
+		do_timer (regs); /* Linux handler in kernel/timer.c */
+
+		if ((time_status & STA_UNSYNC) == 0 &&
+		    xtime.tv_sec - last_rtc_update >= 659 &&
+		    abs((xtime.tv_nsec/1000)-(1000000-1000000/HZ))<5000000/HZ &&
+		    jiffies - wall_jiffies == 1) {
+
+			if (platform_set_rtc_time(xtime.tv_sec+1) == 0)
+				last_rtc_update = xtime.tv_sec+1;
+			else
+				/* Do it again in 60 s */
+				last_rtc_update += 60;
+		}
+		write_sequnlock(&xtime_lock);
+	}
+
+	/* NOTE: writing CCOMPAREn clears the interrupt.  */
+
+	set_linux_timer (next);
+
+	/* Make sure we didn't miss any tick... */
+
+	if ((signed long)(get_ccount() - next) > 0)
+		goto again;
+
+	/* Allow platform to do something usefull (Wdog). */
+
+	platform_heartbeat();
+
+	return IRQ_HANDLED;
+}
+
+#ifndef CONFIG_GENERIC_CALIBRATE_DELAY
+void __devinit calibrate_delay(void)
+{
+	loops_per_jiffy = CCOUNT_PER_JIFFY;
+	printk("Calibrating delay loop (skipped)... "
+	       "%lu.%02lu BogoMIPS preset\n",
+	       loops_per_jiffy/(1000000/HZ),
+	       (loops_per_jiffy/(10000/HZ)) % 100);
+}
+#endif
+
diff --git a/arch/xtensa/kernel/traps.c b/arch/xtensa/kernel/traps.c
new file mode 100644
index 0000000..804246e
--- /dev/null
+++ b/arch/xtensa/kernel/traps.c
@@ -0,0 +1,498 @@
+/*
+ * arch/xtensa/kernel/traps.c
+ *
+ * Exception handling.
+ *
+ * Derived from code with the following copyrights:
+ * Copyright (C) 1994 - 1999 by Ralf Baechle
+ * Modified for R3000 by Paul M. Antoine, 1995, 1996
+ * Complete output from die() by Ulf Carlsson, 1998
+ * Copyright (C) 1999 Silicon Graphics, Inc.
+ *
+ * Essentially rewritten for the Xtensa architecture port.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ *
+ * Joe Taylor	<joe@tensilica.com, joetylr@yahoo.com>
+ * Chris Zankel	<chris@zankel.net>
+ * Marc Gauthier<marc@tensilica.com, marc@alumni.uwaterloo.ca>
+ * Kevin Chea
+ *
+ * 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/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/stringify.h>
+#include <linux/kallsyms.h>
+
+#include <asm/ptrace.h>
+#include <asm/timex.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+
+#ifdef CONFIG_KGDB
+extern int gdb_enter;
+extern int return_from_debug_flag;
+#endif
+
+/*
+ * Machine specific interrupt handlers
+ */
+
+extern void kernel_exception(void);
+extern void user_exception(void);
+
+extern void fast_syscall_kernel(void);
+extern void fast_syscall_user(void);
+extern void fast_alloca(void);
+extern void fast_unaligned(void);
+extern void fast_second_level_miss(void);
+extern void fast_store_prohibited(void);
+extern void fast_coprocessor(void);
+
+extern void do_illegal_instruction (struct pt_regs*);
+extern void do_interrupt (struct pt_regs*);
+extern void do_unaligned_user (struct pt_regs*);
+extern void do_multihit (struct pt_regs*, unsigned long);
+extern void do_page_fault (struct pt_regs*, unsigned long);
+extern void do_debug (struct pt_regs*);
+extern void system_call (struct pt_regs*);
+
+/*
+ * The vector table must be preceded by a save area (which
+ * implies it must be in RAM, unless one places RAM immediately
+ * before a ROM and puts the vector at the start of the ROM (!))
+ */
+
+#define KRNL		0x01
+#define USER		0x02
+
+#define COPROCESSOR(x)							\
+{ XCHAL_EXCCAUSE_COPROCESSOR ## x ## _DISABLED, USER, fast_coprocessor }
+
+typedef struct {
+	int cause;
+	int fast;
+	void* handler;
+} dispatch_init_table_t;
+
+dispatch_init_table_t __init dispatch_init_table[] = {
+
+{ XCHAL_EXCCAUSE_ILLEGAL_INSTRUCTION,	0,	   do_illegal_instruction},
+{ XCHAL_EXCCAUSE_SYSTEM_CALL,		KRNL,	   fast_syscall_kernel },
+{ XCHAL_EXCCAUSE_SYSTEM_CALL,		USER,	   fast_syscall_user },
+{ XCHAL_EXCCAUSE_SYSTEM_CALL,		0,	   system_call },
+/* XCHAL_EXCCAUSE_INSTRUCTION_FETCH unhandled */
+/* XCHAL_EXCCAUSE_LOAD_STORE_ERROR unhandled*/
+{ XCHAL_EXCCAUSE_LEVEL1_INTERRUPT,	0,	   do_interrupt },
+{ XCHAL_EXCCAUSE_ALLOCA,		USER|KRNL, fast_alloca },
+/* XCHAL_EXCCAUSE_INTEGER_DIVIDE_BY_ZERO unhandled */
+/* XCHAL_EXCCAUSE_PRIVILEGED unhandled */
+#if XCHAL_UNALIGNED_LOAD_EXCEPTION || XCHAL_UNALIGNED_STORE_EXCEPTION
+#ifdef CONFIG_UNALIGNED_USER
+{ XCHAL_EXCCAUSE_UNALIGNED,		USER,	   fast_unaligned },
+#else
+{ XCHAL_EXCCAUSE_UNALIGNED,		0,	   do_unaligned_user },
+#endif
+{ XCHAL_EXCCAUSE_UNALIGNED,		KRNL,	   fast_unaligned },
+#endif
+{ XCHAL_EXCCAUSE_ITLB_MISS,		0,	   do_page_fault },
+{ XCHAL_EXCCAUSE_ITLB_MISS,		USER|KRNL, fast_second_level_miss},
+{ XCHAL_EXCCAUSE_ITLB_MULTIHIT,		0,	   do_multihit },
+{ XCHAL_EXCCAUSE_ITLB_PRIVILEGE,	0,	   do_page_fault },
+/* XCHAL_EXCCAUSE_SIZE_RESTRICTION unhandled */
+{ XCHAL_EXCCAUSE_FETCH_CACHE_ATTRIBUTE,	0,	   do_page_fault },
+{ XCHAL_EXCCAUSE_DTLB_MISS,		USER|KRNL, fast_second_level_miss},
+{ XCHAL_EXCCAUSE_DTLB_MISS,		0,	   do_page_fault },
+{ XCHAL_EXCCAUSE_DTLB_MULTIHIT,		0,	   do_multihit },
+{ XCHAL_EXCCAUSE_DTLB_PRIVILEGE,	0,	   do_page_fault },
+/* XCHAL_EXCCAUSE_DTLB_SIZE_RESTRICTION unhandled */
+{ XCHAL_EXCCAUSE_STORE_CACHE_ATTRIBUTE,	USER|KRNL, fast_store_prohibited },
+{ XCHAL_EXCCAUSE_STORE_CACHE_ATTRIBUTE,	0,	   do_page_fault },
+{ XCHAL_EXCCAUSE_LOAD_CACHE_ATTRIBUTE,	0,	   do_page_fault },
+/* XCCHAL_EXCCAUSE_FLOATING_POINT unhandled */
+#if (XCHAL_CP_MASK & 1)
+COPROCESSOR(0),
+#endif
+#if (XCHAL_CP_MASK & 2)
+COPROCESSOR(1),
+#endif
+#if (XCHAL_CP_MASK & 4)
+COPROCESSOR(2),
+#endif
+#if (XCHAL_CP_MASK & 8)
+COPROCESSOR(3),
+#endif
+#if (XCHAL_CP_MASK & 16)
+COPROCESSOR(4),
+#endif
+#if (XCHAL_CP_MASK & 32)
+COPROCESSOR(5),
+#endif
+#if (XCHAL_CP_MASK & 64)
+COPROCESSOR(6),
+#endif
+#if (XCHAL_CP_MASK & 128)
+COPROCESSOR(7),
+#endif
+{ EXCCAUSE_MAPPED_DEBUG,		0,		do_debug },
+{ -1, -1, 0 }
+
+};
+
+/* The exception table <exc_table> serves two functions:
+ * 1. it contains three dispatch tables (fast_user, fast_kernel, default-c)
+ * 2. it is a temporary memory buffer for the exception handlers.
+ */
+
+unsigned long exc_table[EXC_TABLE_SIZE/4];
+
+void die(const char*, struct pt_regs*, long);
+
+static inline void
+__die_if_kernel(const char *str, struct pt_regs *regs, long err)
+{
+	if (!user_mode(regs))
+		die(str, regs, err);
+}
+
+/*
+ * Unhandled Exceptions. Kill user task or panic if in kernel space.
+ */
+
+void do_unhandled(struct pt_regs *regs, unsigned long exccause)
+{
+	__die_if_kernel("Caught unhandled exception - should not happen",
+	    		regs, SIGKILL);
+
+	/* If in user mode, send SIGILL signal to current process */
+	printk("Caught unhandled exception in '%s' "
+	       "(pid = %d, pc = %#010lx) - should not happen\n"
+	       "\tEXCCAUSE is %ld\n",
+	       current->comm, current->pid, regs->pc, exccause);
+	force_sig(SIGILL, current);
+}
+
+/*
+ * Multi-hit exception. This if fatal!
+ */
+
+void do_multihit(struct pt_regs *regs, unsigned long exccause)
+{
+	die("Caught multihit exception", regs, SIGKILL);
+}
+
+/*
+ * Level-1 interrupt.
+ * We currently have no priority encoding.
+ */
+
+unsigned long ignored_level1_interrupts;
+extern void do_IRQ(int, struct pt_regs *);
+
+void do_interrupt (struct pt_regs *regs)
+{
+	unsigned long intread = get_sr (INTREAD);
+	unsigned long intenable = get_sr (INTENABLE);
+	int i, mask;
+
+	/* Handle all interrupts (no priorities).
+	 * (Clear the interrupt before processing, in case it's
+	 *  edge-triggered or software-generated)
+	 */
+
+	for (i=0, mask = 1; i < XCHAL_NUM_INTERRUPTS; i++, mask <<= 1) {
+		if (mask & (intread & intenable)) {
+			set_sr (mask, INTCLEAR);
+			do_IRQ (i,regs);
+		}
+	}
+}
+
+/*
+ * Illegal instruction. Fatal if in kernel space.
+ */
+
+void
+do_illegal_instruction(struct pt_regs *regs)
+{
+	__die_if_kernel("Illegal instruction in kernel", regs, SIGKILL);
+
+	/* If in user mode, send SIGILL signal to current process. */
+
+	printk("Illegal Instruction in '%s' (pid = %d, pc = %#010lx)\n",
+	    current->comm, current->pid, regs->pc);
+	force_sig(SIGILL, current);
+}
+
+
+/*
+ * Handle unaligned memory accesses from user space. Kill task.
+ *
+ * If CONFIG_UNALIGNED_USER is not set, we don't allow unaligned memory
+ * accesses causes from user space.
+ */
+
+#if XCHAL_UNALIGNED_LOAD_EXCEPTION || XCHAL_UNALIGNED_STORE_EXCEPTION
+#ifndef CONFIG_UNALIGNED_USER
+void
+do_unaligned_user (struct pt_regs *regs)
+{
+	siginfo_t info;
+
+	__die_if_kernel("Unhandled unaligned exception in kernel",
+	    		regs, SIGKILL);
+
+	current->thread.bad_vaddr = regs->excvaddr;
+	current->thread.error_code = -3;
+	printk("Unaligned memory access to %08lx in '%s' "
+	       "(pid = %d, pc = %#010lx)\n",
+	       regs->excvaddr, current->comm, current->pid, regs->pc);
+	info.si_signo = SIGBUS;
+	info.si_errno = 0;
+	info.si_code = BUS_ADRALN;
+	info.si_addr = (void *) regs->excvaddr;
+	force_sig_info(SIGSEGV, &info, current);
+
+}
+#endif
+#endif
+
+void
+do_debug(struct pt_regs *regs)
+{
+#ifdef CONFIG_KGDB
+	/* If remote debugging is configured AND enabled, we give control to
+	 * kgdb.  Otherwise, we fall through, perhaps giving control to the
+	 * native debugger.
+	 */
+
+	if (gdb_enter) {
+		extern void gdb_handle_exception(struct pt_regs *);
+		gdb_handle_exception(regs);
+		return_from_debug_flag = 1;
+		return;
+	}
+#endif
+
+	__die_if_kernel("Breakpoint in kernel", regs, SIGKILL);
+
+	/* If in user mode, send SIGTRAP signal to current process */
+
+	force_sig(SIGTRAP, current);
+}
+
+
+/*
+ * Initialize dispatch tables.
+ *
+ * The exception vectors are stored compressed the __init section in the
+ * dispatch_init_table. This function initializes the following three tables
+ * from that compressed table:
+ * - fast user		first dispatch table for user exceptions
+ * - fast kernel	first dispatch table for kernel exceptions
+ * - default C-handler	C-handler called by the default fast handler.
+ *
+ * See vectors.S for more details.
+ */
+
+#define set_handler(idx,handler) (exc_table[idx] = (unsigned long) (handler))
+
+void trap_init(void)
+{
+	int i;
+
+	/* Setup default vectors. */
+
+	for(i = 0; i < 64; i++) {
+		set_handler(EXC_TABLE_FAST_USER/4   + i, user_exception);
+		set_handler(EXC_TABLE_FAST_KERNEL/4 + i, kernel_exception);
+		set_handler(EXC_TABLE_DEFAULT/4 + i, do_unhandled);
+	}
+
+	/* Setup specific handlers. */
+
+	for(i = 0; dispatch_init_table[i].cause >= 0; i++) {
+
+		int fast = dispatch_init_table[i].fast;
+		int cause = dispatch_init_table[i].cause;
+		void *handler = dispatch_init_table[i].handler;
+
+		if (fast == 0)
+			set_handler (EXC_TABLE_DEFAULT/4 + cause, handler);
+		if (fast && fast & USER)
+			set_handler (EXC_TABLE_FAST_USER/4 + cause, handler);
+		if (fast && fast & KRNL)
+			set_handler (EXC_TABLE_FAST_KERNEL/4 + cause, handler);
+	}
+
+	/* Initialize EXCSAVE_1 to hold the address of the exception table. */
+
+	i = (unsigned long)exc_table;
+	__asm__ __volatile__("wsr  %0, "__stringify(EXCSAVE_1)"\n" : : "a" (i));
+}
+
+/*
+ * This function dumps the current valid window frame and other base registers.
+ */
+
+void show_regs(struct pt_regs * regs)
+{
+	int i, wmask;
+
+	wmask = regs->wmask & ~1;
+
+	for (i = 0; i < 32; i++) {
+		if (wmask & (1 << (i / 4)))
+			break;
+		if ((i % 8) == 0)
+			printk ("\n" KERN_INFO "a%02d: ", i);
+		printk("%08lx ", regs->areg[i]);
+	}
+	printk("\n");
+
+	printk("pc: %08lx, ps: %08lx, depc: %08lx, excvaddr: %08lx\n",
+	       regs->pc, regs->ps, regs->depc, regs->excvaddr);
+	printk("lbeg: %08lx, lend: %08lx lcount: %08lx, sar: %08lx\n",
+	       regs->lbeg, regs->lend, regs->lcount, regs->sar);
+	if (user_mode(regs))
+		printk("wb: %08lx, ws: %08lx, wmask: %08lx, syscall: %ld\n",
+		       regs->windowbase, regs->windowstart, regs->wmask,
+		       regs->syscall);
+}
+
+void show_trace(struct task_struct *task, unsigned long *sp)
+{
+	unsigned long a0, a1, pc;
+	unsigned long sp_start, sp_end;
+
+	a1 = (unsigned long)sp;
+
+	if (a1 == 0)
+		__asm__ __volatile__ ("mov %0, a1\n" : "=a"(a1));
+
+
+	sp_start = a1 & ~(THREAD_SIZE-1);
+	sp_end = sp_start + THREAD_SIZE;
+
+	printk("Call Trace:");
+#ifdef CONFIG_KALLSYMS
+	printk("\n");
+#endif
+	spill_registers();
+
+	while (a1 > sp_start && a1 < sp_end) {
+		sp = (unsigned long*)a1;
+
+		a0 = *(sp - 4);
+		a1 = *(sp - 3);
+
+		if (a1 <= (unsigned long) sp)
+			break;
+
+		pc = MAKE_PC_FROM_RA(a0, a1);
+
+		if (kernel_text_address(pc)) {
+			printk(" [<%08lx>] ", pc);
+			print_symbol("%s\n", pc);
+		}
+	}
+	printk("\n");
+}
+
+/*
+ * This routine abuses get_user()/put_user() to reference pointers
+ * with at least a bit of error checking ...
+ */
+
+static int kstack_depth_to_print = 24;
+
+void show_stack(struct task_struct *task, unsigned long *sp)
+{
+	int i = 0;
+	unsigned long *stack;
+
+	if (sp == 0)
+		__asm__ __volatile__ ("mov %0, a1\n" : "=a"(sp));
+
+ 	stack = sp;
+
+	printk("\nStack: ");
+
+	for (i = 0; i < kstack_depth_to_print; i++) {
+		if (kstack_end(sp))
+			break;
+		if (i && ((i % 8) == 0))
+			printk("\n       ");
+		printk("%08lx ", *sp++);
+	}
+	printk("\n");
+	show_trace(task, stack);
+}
+
+void dump_stack(void)
+{
+	show_stack(current, NULL);
+}
+
+EXPORT_SYMBOL(dump_stack);
+
+
+void show_code(unsigned int *pc)
+{
+	long i;
+
+	printk("\nCode:");
+
+	for(i = -3 ; i < 6 ; i++) {
+		unsigned long insn;
+		if (__get_user(insn, pc + i)) {
+			printk(" (Bad address in pc)\n");
+			break;
+		}
+		printk("%c%08lx%c",(i?' ':'<'),insn,(i?' ':'>'));
+	}
+}
+
+spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
+
+void die(const char * str, struct pt_regs * regs, long err)
+{
+	static int die_counter;
+	int nl = 0;
+
+	console_verbose();
+	spin_lock_irq(&die_lock);
+
+	printk("%s: sig: %ld [#%d]\n", str, err, ++die_counter);
+#ifdef CONFIG_PREEMPT
+	printk("PREEMPT ");
+	nl = 1;
+#endif
+	if (nl)
+		printk("\n");
+	show_regs(regs);
+	if (!user_mode(regs))
+		show_stack(NULL, (unsigned long*)regs->areg[1]);
+
+	spin_unlock_irq(&die_lock);
+
+	if (in_interrupt())
+		panic("Fatal exception in interrupt");
+
+	if (panic_on_oops) {
+		printk(KERN_EMERG "Fatal exception: panic in 5 seconds\n");
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(5 * HZ);
+		panic("Fatal exception");
+	}
+	do_exit(err);
+}
+
+
diff --git a/arch/xtensa/kernel/vectors.S b/arch/xtensa/kernel/vectors.S
new file mode 100644
index 0000000..81808f0
--- /dev/null
+++ b/arch/xtensa/kernel/vectors.S
@@ -0,0 +1,464 @@
+/*
+ * arch/xtensa/kernel/vectors.S
+ *
+ * This file contains all exception vectors (user, kernel, and double),
+ * as well as the window vectors (overflow and underflow), and the debug
+ * vector. These are the primary vectors executed by the processor if an
+ * exception occurs.
+ *
+ * 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) 2005 Tensilica, Inc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ *
+ */
+
+/*
+ * We use a two-level table approach. The user and kernel exception vectors
+ * use a first-level dispatch table to dispatch the exception to a registered
+ * fast handler or the default handler, if no fast handler was registered.
+ * The default handler sets up a C-stack and dispatches the exception to a
+ * registerd C handler in the second-level dispatch table.
+ *
+ * Fast handler entry condition:
+ *
+ *   a0:	trashed, original value saved on stack (PT_AREG0)
+ *   a1:	a1
+ *   a2:	new stack pointer, original value in depc
+ *   a3:	dispatch table
+ *   depc:	a2, original value saved on stack (PT_DEPC)
+ *   excsave_1:	a3
+ *
+ * The value for PT_DEPC saved to stack also functions as a boolean to
+ * indicate that the exception is either a double or a regular exception:
+ *
+ *   PT_DEPC	>= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception
+ *		<  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
+ *
+ * Note:  Neither the kernel nor the user exception handler generate literals.
+ *
+ */
+
+#include <linux/linkage.h>
+#include <asm/ptrace.h>
+#include <asm/ptrace.h>
+#include <asm/current.h>
+#include <asm/offsets.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/thread_info.h>
+#include <asm/processor.h>
+
+
+/*
+ * User exception vector. (Exceptions with PS.UM == 1, PS.EXCM == 0)
+ *
+ * We get here when an exception occurred while we were in userland.
+ * We switch to the kernel stack and jump to the first level handler
+ * associated to the exception cause.
+ *
+ * Note: the saved kernel stack pointer (EXC_TABLE_KSTK) is already
+ *       decremented by PT_USER_SIZE.
+ */
+
+	.section .UserExceptionVector.text, "ax"
+
+ENTRY(_UserExceptionVector)
+
+	xsr	a3, EXCSAVE_1		# save a3 and get dispatch table
+	wsr	a2, DEPC		# save a2
+	l32i	a2, a3, EXC_TABLE_KSTK	# load kernel stack to a2
+	s32i	a0, a2, PT_AREG0	# save a0 to ESF
+	rsr	a0, EXCCAUSE		# retrieve exception cause
+	s32i	a0, a2, PT_DEPC		# mark it as a regular exception
+	addx4	a0, a0, a3		# find entry in table
+	l32i	a0, a0, EXC_TABLE_FAST_USER	# load handler
+	jx	a0
+
+/*
+ * Kernel exception vector. (Exceptions with PS.UM == 0, PS.EXCM == 0)
+ *
+ * We get this exception when we were already in kernel space.
+ * We decrement the current stack pointer (kernel) by PT_SIZE and
+ * jump to the first-level handler associated with the exception cause.
+ *
+ * Note: we need to preserve space for the spill region.
+ */
+
+	.section .KernelExceptionVector.text, "ax"
+
+ENTRY(_KernelExceptionVector)
+
+	xsr	a3, EXCSAVE_1		# save a3, and get dispatch table
+	wsr	a2, DEPC		# save a2
+	addi	a2, a1, -16-PT_SIZE	# adjust stack pointer
+	s32i	a0, a2, PT_AREG0	# save a0 to ESF
+	rsr	a0, EXCCAUSE		# retrieve exception cause
+	s32i	a0, a2, PT_DEPC		# mark it as a regular exception
+	addx4	a0, a0, a3		# find entry in table
+	l32i	a0, a0, EXC_TABLE_FAST_KERNEL	# load handler address
+	jx	a0
+
+
+/*
+ * Double exception vector (Exceptions with PS.EXCM == 1)
+ * We get this exception when another exception occurs while were are
+ * already in an exception, such as window overflow/underflow exception,
+ * or 'expected' exceptions, for example memory exception when we were trying
+ * to read data from an invalid address in user space.
+ *
+ * Note that this vector is never invoked for level-1 interrupts, because such
+ * interrupts are disabled (masked) when PS.EXCM is set.
+ *
+ * We decode the exception and take the appropriate action.  However, the
+ * double exception vector is much more careful, because a lot more error
+ * cases go through the double exception vector than through the user and
+ * kernel exception vectors.
+ *
+ * Occasionally, the kernel expects a double exception to occur.  This usually
+ * happens when accessing user-space memory with the user's permissions
+ * (l32e/s32e instructions).  The kernel state, though, is not always suitable
+ * for immediate transfer of control to handle_double, where "normal" exception
+ * processing occurs. Also in kernel mode, TLB misses can occur if accessing
+ * vmalloc memory, possibly requiring repair in a double exception handler.
+ *
+ * The variable at TABLE_FIXUP offset from the pointer in EXCSAVE_1 doubles as
+ * a boolean variable and a pointer to a fixup routine. If the variable
+ * EXC_TABLE_FIXUP is non-zero, this handler jumps to that address. A value of
+ * zero indicates to use the default kernel/user exception handler.
+ * There is only one exception, when the value is identical to the exc_table
+ * label, the kernel is in trouble. This mechanism is used to protect critical
+ * sections, mainly when the handler writes to the stack to assert the stack
+ * pointer is valid. Once the fixup/default handler leaves that area, the
+ * EXC_TABLE_FIXUP variable is reset to the fixup handler or zero.
+ *
+ * Procedures wishing to use this mechanism should set EXC_TABLE_FIXUP to the
+ * nonzero address of a fixup routine before it could cause a double exception
+ * and reset it before it returns.
+ *
+ * Some other things to take care of when a fast exception handler doesn't
+ * specify a particular fixup handler but wants to use the default handlers:
+ *
+ *  - The original stack pointer (in a1) must not be modified. The fast
+ *    exception handler should only use a2 as the stack pointer.
+ *
+ *  - If the fast handler manipulates the stack pointer (in a2), it has to
+ *    register a valid fixup handler and cannot use the default handlers.
+ *
+ *  - The handler can use any other generic register from a3 to a15, but it
+ *    must save the content of these registers to stack (PT_AREG3...PT_AREGx)
+ *
+ *  - These registers must be saved before a double exception can occur.
+ *
+ *  - If we ever implement handling signals while in double exceptions, the
+ *    number of registers a fast handler has saved (excluding a0 and a1) must
+ *    be written to  PT_AREG1. (1 if only a3 is used, 2 for a3 and a4, etc. )
+ *
+ * The fixup handlers are special handlers:
+ *
+ *  - Fixup entry conditions differ from regular exceptions:
+ *
+ *	a0:	   DEPC
+ *	a1: 	   a1
+ *	a2:	   trashed, original value in EXC_TABLE_DOUBLE_A2
+ *	a3:	   exctable
+ *	depc:	   a0
+ *	excsave_1: a3
+ *
+ *  - When the kernel enters the fixup handler, it still assumes it is in a
+ *    critical section, so EXC_TABLE_FIXUP variable is set to exc_table.
+ *    The fixup handler, therefore, has to re-register itself as the fixup
+ *    handler before it returns from the double exception.
+ *
+ *  - Fixup handler can share the same exception frame with the fast handler.
+ *    The kernel stack pointer is not changed when entering the fixup handler.
+ *
+ *  - Fixup handlers can jump to the default kernel and user exception
+ *    handlers. Before it jumps, though, it has to setup a exception frame
+ *    on stack. Because the default handler resets the register fixup handler
+ *    the fixup handler must make sure that the default handler returns to
+ *    it instead of the exception address, so it can re-register itself as
+ *    the fixup handler.
+ *
+ * In case of a critical condition where the kernel cannot recover, we jump
+ * to unrecoverable_exception with the following entry conditions.
+ * All registers a0...a15 are unchanged from the last exception, except:
+ *
+ *	a0:	   last address before we jumped to the unrecoverable_exception.
+ *	excsave_1: a0
+ *
+ *
+ * See the handle_alloca_user and spill_registers routines for example clients.
+ *
+ * FIXME: Note: we currently don't allow signal handling coming from a double
+ *        exception, so the item markt with (*) is not required.
+ */
+
+	.section .DoubleExceptionVector.text, "ax"
+	.begin literal_prefix .DoubleExceptionVector
+
+ENTRY(_DoubleExceptionVector)
+
+	/* Deliberately destroy excsave (don't assume it's value was valid). */
+
+	wsr	a3, EXCSAVE_1		# save a3
+
+	/* Check for kernel double exception (usually fatal). */
+
+	rsr	a3, PS
+	_bbci.l	a3, PS_UM_SHIFT, .Lksp
+
+	/* Check if we are currently handling a window exception. */
+	/* Note: We don't need to indicate that we enter a critical section. */
+
+	xsr	a0, DEPC		# get DEPC, save a0
+
+	movi	a3, XCHAL_WINDOW_VECTORS_VADDR
+	_bltu	a0, a3, .Lfixup
+	addi	a3, a3, XSHAL_WINDOW_VECTORS_SIZE
+	_bgeu	a0, a3, .Lfixup
+
+	/* Window overflow/underflow exception. Get stack pointer. */
+
+	mov	a3, a2
+	movi	a2, exc_table
+	l32i	a2, a2, EXC_TABLE_KSTK
+
+	/* Check for overflow/underflow exception, jump if overflow. */
+
+	_bbci.l	a0, 6, .Lovfl
+
+	/* a0: depc, a1: a1, a2: kstk, a3: a2, depc: a0, excsave: a3  */
+
+	/* Restart window underflow exception.
+	 * We return to the instruction in user space that caused the window
+	 * underflow exception. Therefore, we change window base to the value
+	 * before we entered the window underflow exception and prepare the
+	 * registers to return as if we were coming from a regular exception
+	 * by changing depc (in a0).
+	 * Note: We can trash the current window frame (a0...a3) and depc!
+	 */
+
+	wsr	a2, DEPC		# save stack pointer temporarily
+	rsr	a0, PS
+	extui	a0, a0, XCHAL_PS_OWB_SHIFT, XCHAL_PS_OWB_BITS
+	wsr	a0, WINDOWBASE
+	rsync
+
+	/* We are now in the previous window frame. Save registers again. */
+
+	xsr	a2, DEPC		# save a2 and get stack pointer
+	s32i	a0, a2, PT_AREG0
+
+	wsr	a3, EXCSAVE_1		# save a3
+	movi	a3, exc_table
+
+	rsr	a0, EXCCAUSE
+	s32i	a0, a2, PT_DEPC		# mark it as a regular exception
+	addx4	a0, a0, a3
+	l32i	a0, a0, EXC_TABLE_FAST_USER
+	jx	a0
+
+.Lfixup:/* Check for a fixup handler or if we were in a critical section. */
+
+	/* a0: depc, a1: a1, a2: a2, a3: trashed, depc: a0, excsave1: a3 */
+
+	movi	a3, exc_table
+	s32i	a2, a3, EXC_TABLE_DOUBLE_SAVE	# temporary variable
+
+	/* Enter critical section. */
+
+	l32i	a2, a3, EXC_TABLE_FIXUP
+	s32i	a3, a3, EXC_TABLE_FIXUP
+	beq	a2, a3, .Lunrecoverable_fixup	# critical!
+	beqz	a2, .Ldflt			# no handler was registered
+
+	/* a0: depc, a1: a1, a2: trash, a3: exctable, depc: a0, excsave: a3 */
+
+	jx	a2
+
+.Ldflt:	/* Get stack pointer. */
+
+	l32i	a3, a3, EXC_TABLE_DOUBLE_SAVE
+	addi	a2, a3, -PT_USER_SIZE
+
+.Lovfl:	/* Jump to default handlers. */
+
+	/* a0: depc, a1: a1, a2: kstk, a3: a2, depc: a0, excsave: a3 */
+
+	xsr	a3, DEPC
+	s32i	a0, a2, PT_DEPC
+	s32i	a3, a2, PT_AREG0
+
+	/* a0: avail, a1: a1, a2: kstk, a3: avail, depc: a2, excsave: a3 */
+
+	movi	a3, exc_table
+	rsr	a0, EXCCAUSE
+	addx4	a0, a0, a3
+	l32i	a0, a0, EXC_TABLE_FAST_USER
+	jx	a0
+
+	/*
+	 * We only allow the ITLB miss exception if we are in kernel space.
+	 * All other exceptions are unexpected and thus unrecoverable!
+	 */
+
+	.extern fast_second_level_miss_double_kernel
+
+.Lksp:	/* a0: a0, a1: a1, a2: a2, a3: trashed, depc: depc, excsave: a3 */
+
+	rsr	a3, EXCCAUSE
+	beqi	a3, XCHAL_EXCCAUSE_ITLB_MISS, 1f
+	addi	a3, a3, -XCHAL_EXCCAUSE_DTLB_MISS
+	bnez	a3, .Lunrecoverable
+1:	movi	a3, fast_second_level_miss_double_kernel
+	jx	a3
+
+	/* Critical! We can't handle this situation. PANIC! */
+
+	.extern unrecoverable_exception
+
+.Lunrecoverable_fixup:
+	l32i	a2, a3, EXC_TABLE_DOUBLE_SAVE
+	xsr	a0, DEPC
+
+.Lunrecoverable:
+	rsr	a3, EXCSAVE_1
+	wsr	a0, EXCSAVE_1
+	movi	a0, unrecoverable_exception
+	callx0	a0
+
+	.end literal_prefix
+
+
+/*
+ * Debug interrupt vector
+ *
+ * There is not much space here, so simply jump to another handler.
+ * EXCSAVE[DEBUGLEVEL] has been set to that handler.
+ */
+
+	.section .DebugInterruptVector.text, "ax"
+
+ENTRY(_DebugInterruptVector)
+	xsr	a0, EXCSAVE + XCHAL_DEBUGLEVEL
+	jx	a0
+
+
+
+/* Window overflow and underflow handlers.
+ * The handlers must be 64 bytes apart, first starting with the underflow
+ * handlers underflow-4 to underflow-12, then the overflow handlers
+ * overflow-4 to overflow-12.
+ *
+ * Note: We rerun the underflow handlers if we hit an exception, so
+ *	 we try to access any page that would cause a page fault early.
+ */
+
+	.section		.WindowVectors.text, "ax"
+
+
+/* 4-Register Window Overflow Vector (Handler) */
+
+	.align 64
+.global _WindowOverflow4
+_WindowOverflow4:
+	s32e	a0, a5, -16
+	s32e	a1, a5, -12
+	s32e	a2, a5,  -8
+	s32e	a3, a5,  -4
+	rfwo
+
+
+/* 4-Register Window Underflow Vector (Handler) */
+
+	.align 64
+.global _WindowUnderflow4
+_WindowUnderflow4:
+	l32e	a0, a5, -16
+	l32e	a1, a5, -12
+	l32e	a2, a5,  -8
+	l32e	a3, a5,  -4
+	rfwu
+
+
+/* 8-Register Window Overflow Vector (Handler) */
+
+	.align 64
+.global _WindowOverflow8
+_WindowOverflow8:
+	s32e	a0, a9, -16
+	l32e	a0, a1, -12
+	s32e	a2, a9,  -8
+	s32e	a1, a9, -12
+	s32e	a3, a9,  -4
+	s32e	a4, a0, -32
+	s32e	a5, a0, -28
+	s32e	a6, a0, -24
+	s32e	a7, a0, -20
+	rfwo
+
+/* 8-Register Window Underflow Vector (Handler) */
+
+	.align 64
+.global _WindowUnderflow8
+_WindowUnderflow8:
+	l32e	a1, a9, -12
+	l32e	a0, a9, -16
+	l32e	a7, a1, -12
+	l32e	a2, a9,  -8
+	l32e	a4, a7, -32
+	l32e	a3, a9,  -4
+	l32e	a5, a7, -28
+	l32e	a6, a7, -24
+	l32e	a7, a7, -20
+	rfwu
+
+
+/* 12-Register Window Overflow Vector (Handler) */
+
+	.align 64
+.global _WindowOverflow12
+_WindowOverflow12:
+	s32e	a0,  a13, -16
+	l32e	a0,  a1,  -12
+	s32e	a1,  a13, -12
+	s32e	a2,  a13,  -8
+	s32e	a3,  a13,  -4
+	s32e	a4,  a0,  -48
+	s32e	a5,  a0,  -44
+	s32e	a6,  a0,  -40
+	s32e	a7,  a0,  -36
+	s32e	a8,  a0,  -32
+	s32e	a9,  a0,  -28
+	s32e	a10, a0,  -24
+	s32e	a11, a0,  -20
+	rfwo
+
+/* 12-Register Window Underflow Vector (Handler) */
+
+	.align 64
+.global _WindowUnderflow12
+_WindowUnderflow12:
+	l32e	a1,  a13, -12
+	l32e	a0,  a13, -16
+	l32e	a11, a1,  -12
+	l32e	a2,  a13,  -8
+	l32e	a4,  a11, -48
+	l32e	a8,  a11, -32
+	l32e	a3,  a13,  -4
+	l32e	a5,  a11, -44
+	l32e	a6,  a11, -40
+	l32e	a7,  a11, -36
+	l32e	a9,  a11, -28
+	l32e	a10, a11, -24
+	l32e	a11, a11, -20
+	rfwu
+
+	.text
+
+
diff --git a/arch/xtensa/kernel/vmlinux.lds.S b/arch/xtensa/kernel/vmlinux.lds.S
new file mode 100644
index 0000000..476b2b5
--- /dev/null
+++ b/arch/xtensa/kernel/vmlinux.lds.S
@@ -0,0 +1,341 @@
+/*
+ * arch/xtensa/kernel/vmlinux.lds.S
+ *
+ * Xtensa linker script
+ *
+ * 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) 2001 - 2005 Tensilica Inc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ * Marc Gauthier <marc@tensilica.com, marc@alumni.uwaterloo.ca>
+ * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
+ */
+
+#include <asm-generic/vmlinux.lds.h>
+
+#include <linux/config.h>
+#define _NOCLANGUAGE
+#include <xtensa/config/core.h>
+#include <xtensa/config/system.h>
+OUTPUT_ARCH(xtensa)
+ENTRY(_start)
+
+#if XCHAL_MEMORY_ORDER == XTHAL_BIGENDIAN
+jiffies = jiffies_64 + 4;
+#else
+jiffies = jiffies_64;
+#endif
+
+#define KERNELOFFSET 0x1000
+
+/* Note: In the following macros, it would be nice to specify only the
+   vector name and section kind and construct "sym" and "section" using
+   CPP concatenation, but that does not work reliably.  Concatenating a
+   string with "." produces an invalid token.  CPP will not print a
+   warning because it thinks this is an assembly file, but it leaves
+   them as multiple tokens and there may or may not be whitespace
+   between them.  */
+
+/* Macro for a relocation entry */
+
+#define RELOCATE_ENTRY(sym, section)		\
+	LONG(sym ## _start);			\
+	LONG(sym ## _end);			\
+	LONG(LOADADDR(section))
+
+/* Macro to define a section for a vector.
+ *
+ * Use of the MIN function catches the types of errors illustrated in
+ * the following example:
+ *
+ * Assume the section .DoubleExceptionVector.literal is completely
+ * full.  Then a programmer adds code to .DoubleExceptionVector.text
+ * that produces another literal.  The final literal position will
+ * overlay onto the first word of the adjacent code section
+ * .DoubleExceptionVector.text.  (In practice, the literals will
+ * overwrite the code, and the first few instructions will be
+ * garbage.)
+ */
+
+#define SECTION_VECTOR(sym, section, addr, max_prevsec_size, prevsec)       \
+  section addr : AT((MIN(LOADADDR(prevsec) + max_prevsec_size,		    \
+		         LOADADDR(prevsec) + SIZEOF(prevsec)) + 3) & ~ 3)   \
+  {									    \
+    . = ALIGN(4);							    \
+    sym ## _start = ABSOLUTE(.);		 			    \
+    *(section)								    \
+    sym ## _end = ABSOLUTE(.);						    \
+  }
+
+/*
+ *  Mapping of input sections to output sections when linking.
+ */
+
+SECTIONS
+{
+  . = XCHAL_KSEG_CACHED_VADDR + KERNELOFFSET;
+  /* .text section */
+
+  _text = .;
+  _stext = .;
+  _ftext = .;
+
+  .text :
+  {
+    /* The .head.text section must be the first section! */
+    *(.head.text)
+    *(.literal .text)
+    *(.srom.text)
+    VMLINUX_SYMBOL(__sched_text_start) = .;
+    *(.sched.text.literal .sched.text)
+    VMLINUX_SYMBOL(__sched_text_end) = .;
+    VMLINUX_SYMBOL(__lock_text_start) = .;
+    *(.spinlock.text.literal .spinlock.text)
+    VMLINUX_SYMBOL(__lock_text_end) = .;
+
+  }
+  _etext = .;
+
+  . = ALIGN(16);
+
+  RODATA
+
+  /*  Relocation table */
+
+  . = ALIGN(16);
+  __boot_reloc_table_start = ABSOLUTE(.);
+
+  __relocate : {
+
+    RELOCATE_ENTRY(_WindowVectors_text,
+		   .WindowVectors.text);
+#if 0
+    RELOCATE_ENTRY(_KernelExceptionVector_literal,
+		   .KernelExceptionVector.literal);
+#endif
+    RELOCATE_ENTRY(_KernelExceptionVector_text,
+		   .KernelExceptionVector.text);
+#if 0
+    RELOCATE_ENTRY(_UserExceptionVector_literal,
+		   .UserExceptionVector.literal);
+#endif
+    RELOCATE_ENTRY(_UserExceptionVector_text,
+		   .UserExceptionVector.text);
+    RELOCATE_ENTRY(_DoubleExceptionVector_literal,
+		   .DoubleExceptionVector.literal);
+    RELOCATE_ENTRY(_DoubleExceptionVector_text,
+		   .DoubleExceptionVector.text);
+  }
+  __boot_reloc_table_end = ABSOLUTE(.) ;
+
+  .fixup   : { *(.fixup) }
+
+  . = ALIGN(16);
+
+  __ex_table : {
+    __start___ex_table = .;
+    *(__ex_table)
+    __stop___ex_table = .;
+  }
+
+  /* Data section */
+
+  . = ALIGN(XCHAL_ICACHE_LINESIZE);
+  _fdata = .;
+  .data :
+  {
+    *(.data) CONSTRUCTORS
+    . = ALIGN(XCHAL_ICACHE_LINESIZE);
+    *(.data.cacheline_aligned)
+  }
+
+  _edata = .;
+
+  /* The initial task */
+  . = ALIGN(8192);
+  .data.init_task : { *(.data.init_task) }
+
+  /* Initialization code and data: */
+
+  . = ALIGN(1<<XCHAL_MMU_MIN_PTE_PAGE_SIZE);
+  __init_begin = .;
+  .init.text : {
+  	_sinittext = .;
+	*(.init.text.literal) *(.init.text)
+	_einittext = .;
+  }
+
+  .init.data :
+  {
+    *(.init.data)
+    . = ALIGN(0x4);
+    __tagtable_begin = .;
+    *(.taglist)
+    __tagtable_end = .;
+  }
+
+  . = ALIGN(XCHAL_ICACHE_LINESIZE);
+
+  __setup_start = .;
+  .init.setup : { *(.init.setup) }
+  __setup_end = .;
+
+  __initcall_start = .;
+  .initcall.init : {
+  	*(.initcall1.init)
+  	*(.initcall2.init)
+  	*(.initcall3.init)
+  	*(.initcall4.init)
+  	*(.initcall5.init)
+  	*(.initcall6.init)
+  	*(.initcall7.init)
+  }
+  __initcall_end = .;
+
+  __con_initcall_start = .;
+  .con_initcall.init : { *(.con_initcall.init) }
+  __con_initcall_end = .;
+
+  SECURITY_INIT
+
+  . = ALIGN(4);
+
+  __start___ftr_fixup = .;
+  __ftr_fixup : { *(__ftr_fixup) }
+  __stop___ftr_fixup = .;
+
+  . = ALIGN(32);
+  __per_cpu_start = .;
+  .data.percpu  : { *(.data.percpu) }
+  __per_cpu_end = .;
+
+  . = ALIGN(4096);
+  __initramfs_start =.;
+  .init.ramfs : { *(.init.ramfs) }
+  __initramfs_end = .;
+
+  /* We need this dummy segment here */
+
+  . = ALIGN(4);
+  .dummy : { LONG(0) }
+
+  /* The vectors are relocated to the real position at startup time */
+
+  SECTION_VECTOR (_WindowVectors_text,
+		  .WindowVectors.text,
+		  XCHAL_WINDOW_VECTORS_VADDR, 4,
+		  .dummy)
+  SECTION_VECTOR (_DebugInterruptVector_literal,
+		  .DebugInterruptVector.literal,
+		  XCHAL_INTLEVEL_VECTOR_VADDR(XCHAL_DEBUGLEVEL) - 4,
+		  SIZEOF(.WindowVectors.text),
+		  .WindowVectors.text)
+  SECTION_VECTOR (_DebugInterruptVector_text,
+		  .DebugInterruptVector.text,
+		  XCHAL_INTLEVEL_VECTOR_VADDR(XCHAL_DEBUGLEVEL),
+		  4,
+		  .DebugInterruptVector.literal)
+  SECTION_VECTOR (_KernelExceptionVector_literal,
+		  .KernelExceptionVector.literal,
+		  XCHAL_KERNELEXC_VECTOR_VADDR - 4,
+		  SIZEOF(.DebugInterruptVector.text),
+		  .DebugInterruptVector.text)
+  SECTION_VECTOR (_KernelExceptionVector_text,
+		  .KernelExceptionVector.text,
+		  XCHAL_KERNELEXC_VECTOR_VADDR,
+		  4,
+		  .KernelExceptionVector.literal)
+  SECTION_VECTOR (_UserExceptionVector_literal,
+		  .UserExceptionVector.literal,
+		  XCHAL_USEREXC_VECTOR_VADDR - 4,
+		  SIZEOF(.KernelExceptionVector.text),
+		  .KernelExceptionVector.text)
+  SECTION_VECTOR (_UserExceptionVector_text,
+		  .UserExceptionVector.text,
+		  XCHAL_USEREXC_VECTOR_VADDR,
+		  4,
+		  .UserExceptionVector.literal)
+  SECTION_VECTOR (_DoubleExceptionVector_literal,
+		  .DoubleExceptionVector.literal,
+		  XCHAL_DOUBLEEXC_VECTOR_VADDR - 16,
+		  SIZEOF(.UserExceptionVector.text),
+		  .UserExceptionVector.text)
+  SECTION_VECTOR (_DoubleExceptionVector_text,
+		  .DoubleExceptionVector.text,
+		  XCHAL_DOUBLEEXC_VECTOR_VADDR,
+		  32,
+		  .DoubleExceptionVector.literal)
+
+  . = (LOADADDR( .DoubleExceptionVector.text ) + SIZEOF( .DoubleExceptionVector.text ) + 3) & ~ 3;
+  . = ALIGN(1<<XCHAL_MMU_MIN_PTE_PAGE_SIZE);
+
+  __init_end = .;
+
+  . = ALIGN(8192);
+
+  /* BSS section */
+  _bss_start = .;
+  .sbss : { *(.sbss) *(.scommon) }
+  .bss : { *(COMMON) *(.bss) }
+  _bss_end = .;
+  _end = .;
+
+  /* only used by the boot loader  */
+
+  . = ALIGN(0x10);
+  .bootstrap : { *(.bootstrap.literal .bootstrap.text .bootstrap.data) }
+
+  . = ALIGN(0x1000);
+  __initrd_start = .;
+  .initrd : { *(.initrd) }
+  __initrd_end = .;
+
+  .ResetVector.text XCHAL_RESET_VECTOR_VADDR :
+  {
+    *(.ResetVector.text)
+  }
+
+
+  /* Sections to be discarded */
+  /DISCARD/ :
+  {
+        *(.text.exit)
+	*(.text.exit.literal)
+        *(.data.exit)
+        *(.exitcall.exit)
+  }
+
+
+  .debug  0 :  { *(.debug) }
+  .line  0 :  { *(.line) }
+  .debug_srcinfo  0 :  { *(.debug_srcinfo) }
+  .debug_sfnames  0 :  { *(.debug_sfnames) }
+  .debug_aranges  0 :  { *(.debug_aranges) }
+  .debug_pubnames  0 :  { *(.debug_pubnames) }
+  .debug_info  0 :  { *(.debug_info) }
+  .debug_abbrev  0 :  { *(.debug_abbrev) }
+  .debug_line  0 :  { *(.debug_line) }
+  .debug_frame  0 :  { *(.debug_frame) }
+  .debug_str  0 :  { *(.debug_str) }
+  .debug_loc  0 :  { *(.debug_loc) }
+  .debug_macinfo  0 :  { *(.debug_macinfo) }
+  .debug_weaknames  0 :  { *(.debug_weaknames) }
+  .debug_funcnames  0 :  { *(.debug_funcnames) }
+  .debug_typenames  0 :  { *(.debug_typenames) }
+  .debug_varnames  0 :  { *(.debug_varnames) }
+
+  .xt.insn 0 :
+  {
+    *(.xt.insn)
+    *(.gnu.linkonce.x*)
+  }
+
+  .xt.lit 0 :
+  {
+    *(.xt.lit)
+    *(.gnu.linkonce.p*)
+  }
+}
diff --git a/arch/xtensa/kernel/xtensa_ksyms.c b/arch/xtensa/kernel/xtensa_ksyms.c
new file mode 100644
index 0000000..efae56a
--- /dev/null
+++ b/arch/xtensa/kernel/xtensa_ksyms.c
@@ -0,0 +1,123 @@
+/*
+ * arch/xtensa/kernel/xtensa_ksyms.c
+ *
+ * Export Xtensa-specific functions for loadable modules.
+ *
+ * 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) 2001 - 2005  Tensilica Inc.
+ *
+ * Joe Taylor <joe@tensilica.com>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <asm/irq.h>
+#include <linux/in6.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#include <asm/uaccess.h>
+#include <asm/checksum.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/pgalloc.h>
+#include <asm/semaphore.h>
+#ifdef CONFIG_BLK_DEV_FD
+#include <asm/floppy.h>
+#endif
+#ifdef CONFIG_NET
+#include <net/checksum.h>
+#endif /* CONFIG_NET */
+
+
+/*
+ * String functions
+ */
+EXPORT_SYMBOL(memcmp);
+EXPORT_SYMBOL(memset);
+EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(memmove);
+EXPORT_SYMBOL(memchr);
+EXPORT_SYMBOL(strcat);
+EXPORT_SYMBOL(strchr);
+EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(strpbrk);
+EXPORT_SYMBOL(strncat);
+EXPORT_SYMBOL(strnlen);
+EXPORT_SYMBOL(strrchr);
+EXPORT_SYMBOL(strstr);
+
+EXPORT_SYMBOL(enable_irq);
+EXPORT_SYMBOL(disable_irq);
+EXPORT_SYMBOL(kernel_thread);
+
+/*
+ * gcc internal math functions
+ */
+extern long long __ashrdi3(long long, int);
+extern long long __ashldi3(long long, int);
+extern long long __lshrdi3(long long, int);
+extern int __divsi3(int, int);
+extern int __modsi3(int, int);
+extern long long __muldi3(long long, long long);
+extern int __mulsi3(int, int);
+extern unsigned int __udivsi3(unsigned int, unsigned int);
+extern unsigned int __umodsi3(unsigned int, unsigned int);
+extern unsigned long long __umoddi3(unsigned long long, unsigned long long);
+extern unsigned long long __udivdi3(unsigned long long, unsigned long long);
+
+EXPORT_SYMBOL(__ashldi3);
+EXPORT_SYMBOL(__ashrdi3);
+EXPORT_SYMBOL(__lshrdi3);
+EXPORT_SYMBOL(__divsi3);
+EXPORT_SYMBOL(__modsi3);
+EXPORT_SYMBOL(__muldi3);
+EXPORT_SYMBOL(__mulsi3);
+EXPORT_SYMBOL(__udivsi3);
+EXPORT_SYMBOL(__umodsi3);
+EXPORT_SYMBOL(__udivdi3);
+EXPORT_SYMBOL(__umoddi3);
+
+/*
+ * Semaphore operations
+ */
+EXPORT_SYMBOL(__down);
+EXPORT_SYMBOL(__down_interruptible);
+EXPORT_SYMBOL(__down_trylock);
+EXPORT_SYMBOL(__up);
+
+#ifdef CONFIG_NET
+/*
+ * Networking support
+ */
+EXPORT_SYMBOL(csum_partial_copy_generic);
+#endif /* CONFIG_NET */
+
+/*
+ * Architecture-specific symbols
+ */
+EXPORT_SYMBOL(__xtensa_copy_user);
+
+/*
+ * Kernel hacking ...
+ */
+
+#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
+// FIXME EXPORT_SYMBOL(screen_info);
+#endif
+
+EXPORT_SYMBOL(get_wchan);
+
+EXPORT_SYMBOL(outsb);
+EXPORT_SYMBOL(outsw);
+EXPORT_SYMBOL(outsl);
+EXPORT_SYMBOL(insb);
+EXPORT_SYMBOL(insw);
+EXPORT_SYMBOL(insl);