[PATCH] avr32 architecture

This adds support for the Atmel AVR32 architecture as well as the AT32AP7000
CPU and the AT32STK1000 development board.

AVR32 is a new high-performance 32-bit RISC microprocessor core, designed for
cost-sensitive embedded applications, with particular emphasis on low power
consumption and high code density.  The AVR32 architecture is not binary
compatible with earlier 8-bit AVR architectures.

The AVR32 architecture, including the instruction set, is described by the
AVR32 Architecture Manual, available from

http://www.atmel.com/dyn/resources/prod_documents/doc32000.pdf

The Atmel AT32AP7000 is the first CPU implementing the AVR32 architecture.  It
features a 7-stage pipeline, 16KB instruction and data caches and a full
Memory Management Unit.  It also comes with a large set of integrated
peripherals, many of which are shared with the AT91 ARM-based controllers from
Atmel.

Full data sheet is available from

http://www.atmel.com/dyn/resources/prod_documents/doc32003.pdf

while the CPU core implementation including caches and MMU is documented by
the AVR32 AP Technical Reference, available from

http://www.atmel.com/dyn/resources/prod_documents/doc32001.pdf

Information about the AT32STK1000 development board can be found at

http://www.atmel.com/dyn/products/tools_card.asp?tool_id=3918

including a BSP CD image with an earlier version of this patch, development
tools (binaries and source/patches) and a root filesystem image suitable for
booting from SD card.

Alternatively, there's a preliminary "getting started" guide available at
http://avr32linux.org/twiki/bin/view/Main/GettingStarted which provides links
to the sources and patches you will need in order to set up a cross-compiling
environment for avr32-linux.

This patch, as well as the other patches included with the BSP and the
toolchain patches, is actively supported by Atmel Corporation.

[dmccr@us.ibm.com: Fix more pxx_page macro locations]
[bunk@stusta.de: fix `make defconfig']
Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>
Signed-off-by: Adrian Bunk <bunk@stusta.de>
Signed-off-by: Dave McCracken <dmccr@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
diff --git a/arch/avr32/kernel/ptrace.c b/arch/avr32/kernel/ptrace.c
new file mode 100644
index 0000000..3c89e59
--- /dev/null
+++ b/arch/avr32/kernel/ptrace.c
@@ -0,0 +1,371 @@
+/*
+ * Copyright (C) 2004-2006 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#undef DEBUG
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp_lock.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/user.h>
+#include <linux/security.h>
+#include <linux/unistd.h>
+#include <linux/notifier.h>
+
+#include <asm/traps.h>
+#include <asm/uaccess.h>
+#include <asm/ocd.h>
+#include <asm/mmu_context.h>
+#include <asm/kdebug.h>
+
+static struct pt_regs *get_user_regs(struct task_struct *tsk)
+{
+	return (struct pt_regs *)((unsigned long) tsk->thread_info +
+				  THREAD_SIZE - sizeof(struct pt_regs));
+}
+
+static void ptrace_single_step(struct task_struct *tsk)
+{
+	pr_debug("ptrace_single_step: pid=%u, SR=0x%08lx\n",
+		 tsk->pid, tsk->thread.cpu_context.sr);
+	if (!(tsk->thread.cpu_context.sr & SR_D)) {
+		/*
+		 * Set a breakpoint at the current pc to force the
+		 * process into debug mode.  The syscall/exception
+		 * exit code will set a breakpoint at the return
+		 * address when this flag is set.
+		 */
+		pr_debug("ptrace_single_step: Setting TIF_BREAKPOINT\n");
+		set_tsk_thread_flag(tsk, TIF_BREAKPOINT);
+	}
+
+	/* The monitor code will do the actual step for us */
+	set_tsk_thread_flag(tsk, TIF_SINGLE_STEP);
+}
+
+/*
+ * Called by kernel/ptrace.c when detaching
+ *
+ * Make sure any single step bits, etc. are not set
+ */
+void ptrace_disable(struct task_struct *child)
+{
+	clear_tsk_thread_flag(child, TIF_SINGLE_STEP);
+}
+
+/*
+ * Handle hitting a breakpoint
+ */
+static void ptrace_break(struct task_struct *tsk, struct pt_regs *regs)
+{
+	siginfo_t info;
+
+	info.si_signo = SIGTRAP;
+	info.si_errno = 0;
+	info.si_code  = TRAP_BRKPT;
+	info.si_addr  = (void __user *)instruction_pointer(regs);
+
+	pr_debug("ptrace_break: Sending SIGTRAP to PID %u (pc = 0x%p)\n",
+		 tsk->pid, info.si_addr);
+	force_sig_info(SIGTRAP, &info, tsk);
+}
+
+/*
+ * Read the word at offset "offset" into the task's "struct user". We
+ * actually access the pt_regs struct stored on the kernel stack.
+ */
+static int ptrace_read_user(struct task_struct *tsk, unsigned long offset,
+			    unsigned long __user *data)
+{
+	unsigned long *regs;
+	unsigned long value;
+
+	pr_debug("ptrace_read_user(%p, %#lx, %p)\n",
+		 tsk, offset, data);
+
+	if (offset & 3 || offset >= sizeof(struct user)) {
+		printk("ptrace_read_user: invalid offset 0x%08lx\n", offset);
+		return -EIO;
+	}
+
+	regs = (unsigned long *)get_user_regs(tsk);
+
+	value = 0;
+	if (offset < sizeof(struct pt_regs))
+		value = regs[offset / sizeof(regs[0])];
+
+	return put_user(value, data);
+}
+
+/*
+ * Write the word "value" to offset "offset" into the task's "struct
+ * user". We actually access the pt_regs struct stored on the kernel
+ * stack.
+ */
+static int ptrace_write_user(struct task_struct *tsk, unsigned long offset,
+			     unsigned long value)
+{
+	unsigned long *regs;
+
+	if (offset & 3 || offset >= sizeof(struct user)) {
+		printk("ptrace_write_user: invalid offset 0x%08lx\n", offset);
+		return -EIO;
+	}
+
+	if (offset >= sizeof(struct pt_regs))
+		return 0;
+
+	regs = (unsigned long *)get_user_regs(tsk);
+	regs[offset / sizeof(regs[0])] = value;
+
+	return 0;
+}
+
+static int ptrace_getregs(struct task_struct *tsk, void __user *uregs)
+{
+	struct pt_regs *regs = get_user_regs(tsk);
+
+	return copy_to_user(uregs, regs, sizeof(*regs)) ? -EFAULT : 0;
+}
+
+static int ptrace_setregs(struct task_struct *tsk, const void __user *uregs)
+{
+	struct pt_regs newregs;
+	int ret;
+
+	ret = -EFAULT;
+	if (copy_from_user(&newregs, uregs, sizeof(newregs)) == 0) {
+		struct pt_regs *regs = get_user_regs(tsk);
+
+		ret = -EINVAL;
+		if (valid_user_regs(&newregs)) {
+			*regs = newregs;
+			ret = 0;
+		}
+	}
+
+	return ret;
+}
+
+long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+{
+	unsigned long tmp;
+	int ret;
+
+	pr_debug("arch_ptrace(%ld, %ld, %#lx, %#lx)\n",
+		 request, child->pid, addr, data);
+
+	pr_debug("ptrace: Enabling monitor mode...\n");
+	__mtdr(DBGREG_DC, __mfdr(DBGREG_DC) | DC_MM | DC_DBE);
+
+	switch (request) {
+	/* Read the word at location addr in the child process */
+	case PTRACE_PEEKTEXT:
+	case PTRACE_PEEKDATA:
+		ret = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+		if (ret == sizeof(tmp))
+			ret = put_user(tmp, (unsigned long __user *)data);
+		else
+			ret = -EIO;
+		break;
+
+	case PTRACE_PEEKUSR:
+		ret = ptrace_read_user(child, addr,
+				       (unsigned long __user *)data);
+		break;
+
+	/* Write the word in data at location addr */
+	case PTRACE_POKETEXT:
+	case PTRACE_POKEDATA:
+		ret = access_process_vm(child, addr, &data, sizeof(data), 1);
+		if (ret == sizeof(data))
+			ret = 0;
+		else
+			ret = -EIO;
+		break;
+
+	case PTRACE_POKEUSR:
+		ret = ptrace_write_user(child, addr, data);
+		break;
+
+	/* continue and stop at next (return from) syscall */
+	case PTRACE_SYSCALL:
+	/* restart after signal */
+	case PTRACE_CONT:
+		ret = -EIO;
+		if (!valid_signal(data))
+			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;
+		/* XXX: Are we sure no breakpoints are active here? */
+		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->exit_state == EXIT_ZOMBIE)
+			break;
+		child->exit_code = SIGKILL;
+		wake_up_process(child);
+		break;
+
+	/*
+	 * execute single instruction.
+	 */
+	case PTRACE_SINGLESTEP:
+		ret = -EIO;
+		if (!valid_signal(data))
+			break;
+		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+		ptrace_single_step(child);
+		child->exit_code = data;
+		wake_up_process(child);
+		ret = 0;
+		break;
+
+	/* Detach a process that was attached */
+	case PTRACE_DETACH:
+		ret = ptrace_detach(child, data);
+		break;
+
+	case PTRACE_GETREGS:
+		ret = ptrace_getregs(child, (void __user *)data);
+		break;
+
+	case PTRACE_SETREGS:
+		ret = ptrace_setregs(child, (const void __user *)data);
+		break;
+
+	default:
+		ret = ptrace_request(child, request, addr, data);
+		break;
+	}
+
+	pr_debug("sys_ptrace returning %d (DC = 0x%08lx)\n", ret, __mfdr(DBGREG_DC));
+	return ret;
+}
+
+asmlinkage void syscall_trace(void)
+{
+	pr_debug("syscall_trace called\n");
+	if (!test_thread_flag(TIF_SYSCALL_TRACE))
+		return;
+	if (!(current->ptrace & PT_PTRACED))
+		return;
+
+	pr_debug("syscall_trace: notifying parent\n");
+	/* 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) {
+		pr_debug("syscall_trace: sending signal %d to PID %u\n",
+			 current->exit_code, current->pid);
+		send_sig(current->exit_code, current, 1);
+		current->exit_code = 0;
+	}
+}
+
+asmlinkage void do_debug_priv(struct pt_regs *regs)
+{
+	unsigned long dc, ds;
+	unsigned long die_val;
+
+	ds = __mfdr(DBGREG_DS);
+
+	pr_debug("do_debug_priv: pc = %08lx, ds = %08lx\n", regs->pc, ds);
+
+	if (ds & DS_SSS)
+		die_val = DIE_SSTEP;
+	else
+		die_val = DIE_BREAKPOINT;
+
+	if (notify_die(die_val, regs, 0, SIGTRAP) == NOTIFY_STOP)
+		return;
+
+	if (likely(ds & DS_SSS)) {
+		extern void itlb_miss(void);
+		extern void tlb_miss_common(void);
+		struct thread_info *ti;
+
+		dc = __mfdr(DBGREG_DC);
+		dc &= ~DC_SS;
+		__mtdr(DBGREG_DC, dc);
+
+		ti = current_thread_info();
+		ti->flags |= _TIF_BREAKPOINT;
+
+		/* The TLB miss handlers don't check thread flags */
+		if ((regs->pc >= (unsigned long)&itlb_miss)
+		    && (regs->pc <= (unsigned long)&tlb_miss_common)) {
+			__mtdr(DBGREG_BWA2A, sysreg_read(RAR_EX));
+			__mtdr(DBGREG_BWC2A, 0x40000001 | (get_asid() << 1));
+		}
+
+		/*
+		 * If we're running in supervisor mode, the breakpoint
+		 * will take us where we want directly, no need to
+		 * single step.
+		 */
+		if ((regs->sr & MODE_MASK) != MODE_SUPERVISOR)
+			ti->flags |= TIF_SINGLE_STEP;
+	} else {
+		panic("Unable to handle debug trap at pc = %08lx\n",
+		      regs->pc);
+	}
+}
+
+/*
+ * Handle breakpoints, single steps and other debuggy things. To keep
+ * things simple initially, we run with interrupts and exceptions
+ * disabled all the time.
+ */
+asmlinkage void do_debug(struct pt_regs *regs)
+{
+	unsigned long dc, ds;
+
+	ds = __mfdr(DBGREG_DS);
+	pr_debug("do_debug: pc = %08lx, ds = %08lx\n", regs->pc, ds);
+
+	if (test_thread_flag(TIF_BREAKPOINT)) {
+		pr_debug("TIF_BREAKPOINT set\n");
+		/* We're taking care of it */
+		clear_thread_flag(TIF_BREAKPOINT);
+		__mtdr(DBGREG_BWC2A, 0);
+	}
+
+	if (test_thread_flag(TIF_SINGLE_STEP)) {
+		pr_debug("TIF_SINGLE_STEP set, ds = 0x%08lx\n", ds);
+		if (ds & DS_SSS) {
+			dc = __mfdr(DBGREG_DC);
+			dc &= ~DC_SS;
+			__mtdr(DBGREG_DC, dc);
+
+			clear_thread_flag(TIF_SINGLE_STEP);
+			ptrace_break(current, regs);
+		}
+	} else {
+		/* regular breakpoint */
+		ptrace_break(current, regs);
+	}
+}