Linux-2.6.12-rc2

Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.

Let it rip!
diff --git a/arch/arm26/kernel/Makefile b/arch/arm26/kernel/Makefile
new file mode 100644
index 0000000..ee9fb49
--- /dev/null
+++ b/arch/arm26/kernel/Makefile
@@ -0,0 +1,17 @@
+#
+# Makefile for the linux kernel.
+#
+
+# Object file lists.
+
+AFLAGS_head.o           := -DTEXTADDR=$(TEXTADDR)
+
+obj-y		:= compat.o dma.o entry.o irq.o process.o ptrace.o       \
+		   semaphore.o setup.o signal.o sys_arm.o time.o traps.o \
+		   ecard.o dma.o ecard.o fiq.o time.o
+
+extra-y		:= head.o init_task.o vmlinux.lds
+
+obj-$(CONFIG_FIQ)		+= fiq.o
+obj-$(CONFIG_MODULES)		+= armksyms.o
+
diff --git a/arch/arm26/kernel/armksyms.c b/arch/arm26/kernel/armksyms.c
new file mode 100644
index 0000000..35514b3
--- /dev/null
+++ b/arch/arm26/kernel/armksyms.c
@@ -0,0 +1,220 @@
+/*
+ *  linux/arch/arm26/kernel/armksyms.c
+ *
+ *  Copyright (C) 2003 Ian Molton
+ *
+ * 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.
+ */
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/user.h>
+#include <linux/string.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/delay.h>
+#include <linux/in6.h>
+#include <linux/interrupt.h>
+#include <linux/pm.h>
+#include <linux/tty.h>
+#include <linux/vt_kern.h>
+#include <linux/smp_lock.h>
+#include <linux/syscalls.h>
+
+#include <asm/byteorder.h>
+#include <asm/elf.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/processor.h>
+#include <asm/semaphore.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/checksum.h>
+#include <asm/mach-types.h>
+
+extern void dump_thread(struct pt_regs *, struct user *);
+extern int dump_fpu(struct pt_regs *, struct user_fp_struct *);
+extern void inswb(unsigned int port, void *to, int len);
+extern void outswb(unsigned int port, const void *to, int len);
+
+extern void __bad_xchg(volatile void *ptr, int size);
+
+/*
+ * libgcc functions - functions that are used internally by the
+ * compiler...  (prototypes are not correct though, but that
+ * doesn't really matter since they're not versioned).
+ */
+extern void __ashldi3(void);
+extern void __ashrdi3(void);
+extern void __divsi3(void);
+extern void __lshrdi3(void);
+extern void __modsi3(void);
+extern void __muldi3(void);
+extern void __ucmpdi2(void);
+extern void __udivdi3(void);
+extern void __umoddi3(void);
+extern void __udivmoddi4(void);
+extern void __udivsi3(void);
+extern void __umodsi3(void);
+extern void abort(void);
+
+extern void ret_from_exception(void);
+extern void fpundefinstr(void);
+extern void fp_enter(void);
+
+/*
+ * This has a special calling convention; it doesn't
+ * modify any of the usual registers, except for LR.
+ * FIXME - we used to use our own local version - looks to be in kernel/softirq now
+ */
+//extern void __do_softirq(void);
+
+#define EXPORT_SYMBOL_ALIAS(sym,orig)		\
+ const char __kstrtab_##sym[]			\
+  __attribute__((section(".kstrtab"))) =	\
+    __MODULE_STRING(sym);			\
+ const struct module_symbol __ksymtab_##sym	\
+  __attribute__((section("__ksymtab"))) =	\
+    { (unsigned long)&orig, __kstrtab_##sym };
+
+/*
+ * floating point math emulator support.
+ * These symbols will never change their calling convention...
+ */
+EXPORT_SYMBOL_ALIAS(kern_fp_enter,fp_enter);
+EXPORT_SYMBOL_ALIAS(fp_printk,printk);
+EXPORT_SYMBOL_ALIAS(fp_send_sig,send_sig);
+
+EXPORT_SYMBOL(fpundefinstr);
+EXPORT_SYMBOL(ret_from_exception);
+
+#ifdef CONFIG_VT
+EXPORT_SYMBOL(kd_mksound);
+#endif
+
+//EXPORT_SYMBOL(__do_softirq);
+
+	/* platform dependent support */
+EXPORT_SYMBOL(dump_thread);
+EXPORT_SYMBOL(dump_fpu);
+EXPORT_SYMBOL(udelay);
+EXPORT_SYMBOL(kernel_thread);
+EXPORT_SYMBOL(system_rev);
+EXPORT_SYMBOL(system_serial_low);
+EXPORT_SYMBOL(system_serial_high);
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+EXPORT_SYMBOL(__bug);
+#endif
+EXPORT_SYMBOL(__bad_xchg);
+EXPORT_SYMBOL(__readwrite_bug);
+EXPORT_SYMBOL(enable_irq);
+EXPORT_SYMBOL(disable_irq);
+EXPORT_SYMBOL(set_irq_type);
+EXPORT_SYMBOL(pm_idle);
+EXPORT_SYMBOL(pm_power_off);
+
+	/* processor dependencies */
+EXPORT_SYMBOL(__machine_arch_type);
+
+	/* networking */
+EXPORT_SYMBOL(csum_partial_copy_nocheck);
+EXPORT_SYMBOL(__csum_ipv6_magic);
+
+	/* io */
+#ifndef __raw_readsb
+EXPORT_SYMBOL(__raw_readsb);
+#endif
+#ifndef __raw_readsw
+EXPORT_SYMBOL(__raw_readsw);
+#endif
+#ifndef __raw_readsl
+EXPORT_SYMBOL(__raw_readsl);
+#endif
+#ifndef __raw_writesb
+EXPORT_SYMBOL(__raw_writesb);
+#endif
+#ifndef __raw_writesw
+EXPORT_SYMBOL(__raw_writesw);
+#endif
+#ifndef __raw_writesl
+EXPORT_SYMBOL(__raw_writesl);
+#endif
+
+	/* string / mem functions */
+EXPORT_SYMBOL(strcpy);
+EXPORT_SYMBOL(strncpy);
+EXPORT_SYMBOL(strcat);
+EXPORT_SYMBOL(strncat);
+EXPORT_SYMBOL(strcmp);
+EXPORT_SYMBOL(strncmp);
+EXPORT_SYMBOL(strchr);
+EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(strnlen);
+EXPORT_SYMBOL(strpbrk);
+EXPORT_SYMBOL(strrchr);
+EXPORT_SYMBOL(strstr);
+EXPORT_SYMBOL(memset);
+EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(memmove);
+EXPORT_SYMBOL(memcmp);
+EXPORT_SYMBOL(memscan);
+EXPORT_SYMBOL(__memzero);
+
+	/* user mem (segment) */
+EXPORT_SYMBOL(uaccess_kernel);
+EXPORT_SYMBOL(uaccess_user);
+
+EXPORT_SYMBOL(__get_user_1);
+EXPORT_SYMBOL(__get_user_2);
+EXPORT_SYMBOL(__get_user_4);
+EXPORT_SYMBOL(__get_user_8);
+
+EXPORT_SYMBOL(__put_user_1);
+EXPORT_SYMBOL(__put_user_2);
+EXPORT_SYMBOL(__put_user_4);
+EXPORT_SYMBOL(__put_user_8);
+
+	/* gcc lib functions */
+EXPORT_SYMBOL(__ashldi3);
+EXPORT_SYMBOL(__ashrdi3);
+EXPORT_SYMBOL(__divsi3);
+EXPORT_SYMBOL(__lshrdi3);
+EXPORT_SYMBOL(__modsi3);
+EXPORT_SYMBOL(__muldi3);
+EXPORT_SYMBOL(__ucmpdi2);
+EXPORT_SYMBOL(__udivdi3);
+EXPORT_SYMBOL(__umoddi3);
+EXPORT_SYMBOL(__udivmoddi4);
+EXPORT_SYMBOL(__udivsi3);
+EXPORT_SYMBOL(__umodsi3);
+
+	/* bitops */
+EXPORT_SYMBOL(_set_bit_le);
+EXPORT_SYMBOL(_test_and_set_bit_le);
+EXPORT_SYMBOL(_clear_bit_le);
+EXPORT_SYMBOL(_test_and_clear_bit_le);
+EXPORT_SYMBOL(_change_bit_le);
+EXPORT_SYMBOL(_test_and_change_bit_le);
+EXPORT_SYMBOL(_find_first_zero_bit_le);
+EXPORT_SYMBOL(_find_next_zero_bit_le);
+
+	/* elf */
+EXPORT_SYMBOL(elf_platform);
+EXPORT_SYMBOL(elf_hwcap);
+
+	/* syscalls */
+EXPORT_SYMBOL(sys_write);
+EXPORT_SYMBOL(sys_read);
+EXPORT_SYMBOL(sys_lseek);
+EXPORT_SYMBOL(sys_open);
+EXPORT_SYMBOL(sys_exit);
+EXPORT_SYMBOL(sys_wait4);
+
+EXPORT_SYMBOL(get_wchan);
+
+#ifdef CONFIG_PREEMPT
+EXPORT_SYMBOL(kernel_flag);
+#endif
diff --git a/arch/arm26/kernel/asm-offsets.c b/arch/arm26/kernel/asm-offsets.c
new file mode 100644
index 0000000..4ccacae
--- /dev/null
+++ b/arch/arm26/kernel/asm-offsets.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 1995-2001 Russell King
+ *               2001-2002 Keith Owens
+ *               2003      Ian Molton
+ *     
+ * Generate definitions needed by assembly language modules.
+ * This code generates raw asm output which is post-processed to extract
+ * and format the required data.
+ *
+ * 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.
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+
+/*
+ * Make sure that the compiler and target are compatible.
+ */
+#if defined(__APCS_32__) && defined(CONFIG_CPU_26)
+#error Sorry, your compiler targets APCS-32 but this kernel requires APCS-26
+#endif
+#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 95)
+#error Sorry, your compiler is known to miscompile kernels.  Only use gcc 2.95.3 and later.
+#endif
+#if __GNUC__ == 2 && __GNUC_MINOR__ == 95
+/* shame we can't detect the .1 or .2 releases */
+#warning GCC 2.95.2 and earlier miscompiles kernels.
+#endif
+
+/* Use marker if you need to separate the values later */
+
+#define DEFINE(sym, val) \
+        asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+
+#define BLANK() asm volatile("\n->" : : )
+
+int main(void)
+{
+  DEFINE(TSK_ACTIVE_MM,		offsetof(struct task_struct, active_mm));
+  BLANK();
+  DEFINE(VMA_VM_MM,		offsetof(struct vm_area_struct, vm_mm));
+  DEFINE(VMA_VM_FLAGS,		offsetof(struct vm_area_struct, vm_flags));
+  BLANK();
+  DEFINE(VM_EXEC,	       	VM_EXEC);
+  BLANK();
+  BLANK();
+  DEFINE(PAGE_PRESENT,		_PAGE_PRESENT);
+  DEFINE(PAGE_READONLY,		_PAGE_READONLY);
+  DEFINE(PAGE_NOT_USER,		_PAGE_NOT_USER);
+  DEFINE(PAGE_OLD,		_PAGE_OLD);
+  DEFINE(PAGE_CLEAN,		_PAGE_CLEAN);
+  BLANK();
+  DEFINE(PAGE_SZ,	       	PAGE_SIZE);
+  BLANK();
+  DEFINE(SYS_ERROR0,		0x9f0000);
+  return 0; 
+}
diff --git a/arch/arm26/kernel/calls.S b/arch/arm26/kernel/calls.S
new file mode 100644
index 0000000..e3d2768
--- /dev/null
+++ b/arch/arm26/kernel/calls.S
@@ -0,0 +1,265 @@
+/*
+ *  linux/arch/arm26/kernel/calls.S
+ *
+ *  Copyright (C) 2003 Ian Molton
+ *
+ * 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.
+ *
+ *  FIXME
+ *  This file is included twice in entry.S which may not be necessary
+ */
+
+//FIXME - clearly NR_syscalls is never defined here
+
+#ifndef NR_syscalls
+#define NR_syscalls 256
+#else
+
+__syscall_start:
+/* 0 */		.long	sys_ni_syscall
+		.long	sys_exit
+		.long	sys_fork_wrapper
+		.long	sys_read
+		.long	sys_write
+/* 5 */		.long	sys_open
+		.long	sys_close
+		.long	sys_ni_syscall		/* was sys_waitpid */
+		.long	sys_creat
+		.long	sys_link
+/* 10 */	.long	sys_unlink
+		.long	sys_execve_wrapper
+		.long	sys_chdir
+		.long	sys_time		/* used by libc4 */
+		.long	sys_mknod
+/* 15 */	.long	sys_chmod
+		.long	sys_lchown16
+		.long	sys_ni_syscall		/* was sys_break */
+		.long	sys_ni_syscall		/* was sys_stat */
+		.long	sys_lseek
+/* 20 */	.long	sys_getpid
+		.long	sys_mount
+		.long	sys_oldumount		/* used by libc4 */
+		.long	sys_setuid16
+		.long	sys_getuid16
+/* 25 */	.long	sys_stime
+		.long	sys_ptrace
+		.long	sys_alarm		/* used by libc4 */
+		.long	sys_ni_syscall		/* was sys_fstat */
+		.long	sys_pause
+/* 30 */	.long	sys_utime		/* used by libc4 */
+		.long	sys_ni_syscall		/* was sys_stty */
+		.long	sys_ni_syscall		/* was sys_getty */
+		.long	sys_access
+		.long	sys_nice
+/* 35 */	.long	sys_ni_syscall		/* was sys_ftime */
+		.long	sys_sync
+		.long	sys_kill
+		.long	sys_rename
+		.long	sys_mkdir
+/* 40 */	.long	sys_rmdir
+		.long	sys_dup
+		.long	sys_pipe
+		.long	sys_times
+		.long	sys_ni_syscall		/* was sys_prof */
+/* 45 */	.long	sys_brk
+		.long	sys_setgid16
+		.long	sys_getgid16
+		.long	sys_ni_syscall		/* was sys_signal */
+		.long	sys_geteuid16
+/* 50 */	.long	sys_getegid16
+		.long	sys_acct
+		.long	sys_umount
+		.long	sys_ni_syscall		/* was sys_lock */
+		.long	sys_ioctl
+/* 55 */	.long	sys_fcntl
+		.long	sys_ni_syscall		/* was sys_mpx */
+		.long	sys_setpgid
+		.long	sys_ni_syscall		/* was sys_ulimit */
+		.long	sys_ni_syscall		/* was sys_olduname */
+/* 60 */	.long	sys_umask
+		.long	sys_chroot
+		.long	sys_ustat
+		.long	sys_dup2
+		.long	sys_getppid
+/* 65 */	.long	sys_getpgrp
+		.long	sys_setsid
+		.long	sys_sigaction
+		.long	sys_ni_syscall		/* was sys_sgetmask */
+		.long	sys_ni_syscall		/* was sys_ssetmask */
+/* 70 */	.long	sys_setreuid16
+		.long	sys_setregid16
+		.long	sys_sigsuspend_wrapper
+		.long	sys_sigpending
+		.long	sys_sethostname
+/* 75 */	.long	sys_setrlimit
+		.long	sys_old_getrlimit	/* used by libc4 */
+		.long	sys_getrusage
+		.long	sys_gettimeofday
+		.long	sys_settimeofday
+/* 80 */	.long	sys_getgroups16
+		.long	sys_setgroups16
+		.long	old_select		/* used by libc4 */
+		.long	sys_symlink
+		.long	sys_ni_syscall		/* was sys_lstat */
+/* 85 */	.long	sys_readlink
+		.long	sys_uselib
+		.long	sys_swapon
+		.long	sys_reboot
+		.long	old_readdir		/* used by libc4 */
+/* 90 */	.long	old_mmap		/* used by libc4 */
+		.long	sys_munmap
+		.long	sys_truncate
+		.long	sys_ftruncate
+		.long	sys_fchmod
+/* 95 */	.long	sys_fchown16
+		.long	sys_getpriority
+		.long	sys_setpriority
+		.long	sys_ni_syscall		/* was sys_profil */
+		.long	sys_statfs
+/* 100 */	.long	sys_fstatfs
+		.long	sys_ni_syscall
+		.long	sys_socketcall
+		.long	sys_syslog
+		.long	sys_setitimer
+/* 105 */	.long	sys_getitimer
+		.long	sys_newstat
+		.long	sys_newlstat
+		.long	sys_newfstat
+		.long	sys_ni_syscall		/* was sys_uname */
+/* 110 */	.long	sys_ni_syscall		/* was sys_iopl */
+		.long	sys_vhangup
+		.long	sys_ni_syscall
+		.long	sys_syscall		/* call a syscall */
+		.long	sys_wait4
+/* 115 */	.long	sys_swapoff
+		.long	sys_sysinfo
+		.long	sys_ipc
+		.long	sys_fsync
+		.long	sys_sigreturn_wrapper
+/* 120 */	.long	sys_clone_wapper
+		.long	sys_setdomainname
+		.long	sys_newuname
+		.long	sys_ni_syscall
+		.long	sys_adjtimex
+/* 125 */	.long	sys_mprotect
+		.long	sys_sigprocmask
+		.long	sys_ni_syscall  /* WAS: sys_create_module */
+		.long	sys_init_module
+		.long	sys_delete_module
+/* 130 */	.long	sys_ni_syscall  /* WAS: sys_get_kernel_syms */
+		.long	sys_quotactl
+		.long	sys_getpgid
+		.long	sys_fchdir
+		.long	sys_bdflush
+/* 135 */	.long	sys_sysfs
+		.long	sys_personality
+		.long	sys_ni_syscall		/* .long	_sys_afs_syscall */
+		.long	sys_setfsuid16
+		.long	sys_setfsgid16
+/* 140 */	.long	sys_llseek
+		.long	sys_getdents
+		.long	sys_select
+		.long	sys_flock
+		.long	sys_msync
+/* 145 */	.long	sys_readv
+		.long	sys_writev
+		.long	sys_getsid
+		.long	sys_fdatasync
+		.long	sys_sysctl
+/* 150 */	.long	sys_mlock
+		.long	sys_munlock
+		.long	sys_mlockall
+		.long	sys_munlockall
+		.long	sys_sched_setparam
+/* 155 */	.long	sys_sched_getparam
+		.long	sys_sched_setscheduler
+		.long	sys_sched_getscheduler
+		.long	sys_sched_yield
+		.long	sys_sched_get_priority_max
+/* 160 */	.long	sys_sched_get_priority_min
+		.long	sys_sched_rr_get_interval
+		.long	sys_nanosleep
+		.long	sys_arm_mremap
+		.long	sys_setresuid16
+/* 165 */	.long	sys_getresuid16
+		.long	sys_ni_syscall
+		.long	sys_ni_syscall /* WAS: sys_query_module */
+		.long	sys_poll
+		.long	sys_nfsservctl
+/* 170 */	.long	sys_setresgid16
+		.long	sys_getresgid16
+		.long	sys_prctl
+		.long	sys_rt_sigreturn_wrapper
+		.long	sys_rt_sigaction
+/* 175 */	.long	sys_rt_sigprocmask
+		.long	sys_rt_sigpending
+		.long	sys_rt_sigtimedwait
+		.long	sys_rt_sigqueueinfo
+		.long	sys_rt_sigsuspend_wrapper
+/* 180 */	.long	sys_pread64
+		.long	sys_pwrite64
+		.long	sys_chown16
+		.long	sys_getcwd
+		.long	sys_capget
+/* 185 */	.long	sys_capset
+		.long	sys_sigaltstack_wrapper
+		.long	sys_sendfile
+		.long	sys_ni_syscall
+		.long	sys_ni_syscall
+/* 190 */	.long	sys_vfork_wrapper
+		.long	sys_getrlimit
+		.long	sys_mmap2
+		.long	sys_truncate64
+		.long	sys_ftruncate64
+/* 195 */	.long	sys_stat64
+		.long	sys_lstat64
+		.long	sys_fstat64
+		.long	sys_lchown
+		.long	sys_getuid
+/* 200 */	.long	sys_getgid
+		.long	sys_geteuid
+		.long	sys_getegid
+		.long	sys_setreuid
+		.long	sys_setregid
+/* 205 */	.long	sys_getgroups
+		.long	sys_setgroups
+		.long	sys_fchown
+		.long	sys_setresuid
+		.long	sys_getresuid
+/* 210 */	.long	sys_setresgid
+		.long	sys_getresgid
+		.long	sys_chown
+		.long	sys_setuid
+		.long	sys_setgid
+/* 215 */	.long	sys_setfsuid
+		.long	sys_setfsgid
+		.long	sys_getdents64
+		.long	sys_pivot_root
+		.long	sys_mincore
+/* 220 */	.long	sys_madvise
+		.long	sys_fcntl64
+		.long	sys_ni_syscall /* TUX */
+		.long	sys_ni_syscall /* WAS: sys_security */
+		.long	sys_gettid
+/* 225 */	.long	sys_readahead
+		.long	sys_setxattr
+		.long	sys_lsetxattr
+		.long	sys_fsetxattr
+		.long	sys_getxattr
+/* 230 */	.long	sys_lgetxattr
+		.long	sys_fgetxattr
+		.long	sys_listxattr
+		.long	sys_llistxattr
+		.long	sys_flistxattr
+/* 235 */	.long	sys_removexattr
+		.long	sys_lremovexattr
+		.long	sys_fremovexattr
+		.long	sys_tkill
+__syscall_end:
+
+		.rept	NR_syscalls - (__syscall_end - __syscall_start) / 4
+			.long	sys_ni_syscall
+		.endr
+#endif
diff --git a/arch/arm26/kernel/compat.c b/arch/arm26/kernel/compat.c
new file mode 100644
index 0000000..db0310d
--- /dev/null
+++ b/arch/arm26/kernel/compat.c
@@ -0,0 +1,174 @@
+/*
+ *  linux/arch/arm26/kernel/compat.c
+ *
+ *  Copyright (C) 2001 Russell King
+ *                2003 Ian Molton
+ *
+ * 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.
+ *
+ * We keep the old params compatibility cruft in one place (here)
+ * so we don't end up with lots of mess around other places.
+ *
+ * NOTE:
+ *  The old struct param_struct is deprecated, but it will be kept in
+ *  the kernel for 5 years from now (2001). This will allow boot loaders
+ *  to convert to the new struct tag way.
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/init.h>
+
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/page.h>
+
+//#include <asm/arch.h>
+//#include <asm/mach/irq.h>
+
+/*
+ * Usage:
+ *  - do not go blindly adding fields, add them at the end
+ *  - when adding fields, don't rely on the address until
+ *    a patch from me has been released
+ *  - unused fields should be zero (for future expansion)
+ *  - this structure is relatively short-lived - only
+ *    guaranteed to contain useful data in setup_arch()
+ *
+ * This is the old deprecated way to pass parameters to the kernel
+ */
+struct param_struct {
+    union {
+	struct {
+	    unsigned long page_size;		/*  0 */
+	    unsigned long nr_pages;		/*  4 */
+	    unsigned long ramdisk_size;		/*  8 */
+	    unsigned long flags;		/* 12 */
+#define FLAG_READONLY	1
+#define FLAG_RDLOAD	4
+#define FLAG_RDPROMPT	8
+	    unsigned long rootdev;		/* 16 */
+	    unsigned long video_num_cols;	/* 20 */
+	    unsigned long video_num_rows;	/* 24 */
+	    unsigned long video_x;		/* 28 */
+	    unsigned long video_y;		/* 32 */
+	    unsigned long memc_control_reg;	/* 36 */
+	    unsigned char sounddefault;		/* 40 */
+	    unsigned char adfsdrives;		/* 41 */
+	    unsigned char bytes_per_char_h;	/* 42 */
+	    unsigned char bytes_per_char_v;	/* 43 */
+	    unsigned long pages_in_bank[4];	/* 44 */
+	    unsigned long pages_in_vram;	/* 60 */
+	    unsigned long initrd_start;		/* 64 */
+	    unsigned long initrd_size;		/* 68 */
+	    unsigned long rd_start;		/* 72 */
+	    unsigned long system_rev;		/* 76 */
+	    unsigned long system_serial_low;	/* 80 */
+	    unsigned long system_serial_high;	/* 84 */
+	    unsigned long mem_fclk_21285;       /* 88 */
+	} s;
+	char unused[256];
+    } u1;
+    union {
+	char paths[8][128];
+	struct {
+	    unsigned long magic;
+	    char n[1024 - sizeof(unsigned long)];
+	} s;
+    } u2;
+    char commandline[COMMAND_LINE_SIZE];
+};
+
+static struct tag * __init memtag(struct tag *tag, unsigned long start, unsigned long size)
+{
+	tag = tag_next(tag);
+	tag->hdr.tag = ATAG_MEM;
+	tag->hdr.size = tag_size(tag_mem32);
+	tag->u.mem.size = size;
+	tag->u.mem.start = start;
+
+	return tag;
+}
+
+static void __init build_tag_list(struct param_struct *params, void *taglist)
+{
+	struct tag *tag = taglist;
+
+	if (params->u1.s.page_size != PAGE_SIZE) {
+		printk(KERN_WARNING "Warning: bad configuration page, "
+		       "trying to continue\n");
+		return;
+	}
+
+	printk(KERN_DEBUG "Converting old-style param struct to taglist\n");
+
+	tag->hdr.tag  = ATAG_CORE;
+	tag->hdr.size = tag_size(tag_core);
+	tag->u.core.flags = params->u1.s.flags & FLAG_READONLY;
+	tag->u.core.pagesize = params->u1.s.page_size;
+	tag->u.core.rootdev = params->u1.s.rootdev;
+
+	tag = tag_next(tag);
+	tag->hdr.tag = ATAG_RAMDISK;
+	tag->hdr.size = tag_size(tag_ramdisk);
+	tag->u.ramdisk.flags = (params->u1.s.flags & FLAG_RDLOAD ? 1 : 0) |
+			       (params->u1.s.flags & FLAG_RDPROMPT ? 2 : 0);
+	tag->u.ramdisk.size  = params->u1.s.ramdisk_size;
+	tag->u.ramdisk.start = params->u1.s.rd_start;
+
+	tag = tag_next(tag);
+	tag->hdr.tag = ATAG_INITRD;
+	tag->hdr.size = tag_size(tag_initrd);
+	tag->u.initrd.start = params->u1.s.initrd_start;
+	tag->u.initrd.size  = params->u1.s.initrd_size;
+
+	tag = tag_next(tag);
+	tag->hdr.tag = ATAG_SERIAL;
+	tag->hdr.size = tag_size(tag_serialnr);
+	tag->u.serialnr.low = params->u1.s.system_serial_low;
+	tag->u.serialnr.high = params->u1.s.system_serial_high;
+
+	tag = tag_next(tag);
+	tag->hdr.tag = ATAG_REVISION;
+	tag->hdr.size = tag_size(tag_revision);
+	tag->u.revision.rev = params->u1.s.system_rev;
+
+	tag = memtag(tag, PHYS_OFFSET, params->u1.s.nr_pages * PAGE_SIZE);
+
+	tag = tag_next(tag);
+	tag->hdr.tag = ATAG_ACORN;
+	tag->hdr.size = tag_size(tag_acorn);
+	tag->u.acorn.memc_control_reg = params->u1.s.memc_control_reg;
+	tag->u.acorn.vram_pages       = params->u1.s.pages_in_vram;
+	tag->u.acorn.sounddefault     = params->u1.s.sounddefault;
+	tag->u.acorn.adfsdrives       = params->u1.s.adfsdrives;
+
+	tag = tag_next(tag);
+	tag->hdr.tag = ATAG_CMDLINE;
+	tag->hdr.size = (strlen(params->commandline) + 3 +
+			 sizeof(struct tag_header)) >> 2;
+	strcpy(tag->u.cmdline.cmdline, params->commandline);
+
+	tag = tag_next(tag);
+	tag->hdr.tag = ATAG_NONE;
+	tag->hdr.size = 0;
+
+	memmove(params, taglist, ((int)tag) - ((int)taglist) +
+				 sizeof(struct tag_header));
+}
+
+void __init convert_to_tag_list(struct tag *tags)
+{
+	struct param_struct *params = (struct param_struct *)tags;
+	build_tag_list(params, &params->u2);
+}
+
+void __init squash_mem_tags(struct tag *tag)
+{
+	for (; tag->hdr.size; tag = tag_next(tag))
+		if (tag->hdr.tag == ATAG_MEM)
+			tag->hdr.tag = ATAG_NONE;
+}
diff --git a/arch/arm26/kernel/dma.c b/arch/arm26/kernel/dma.c
new file mode 100644
index 0000000..80b5a77
--- /dev/null
+++ b/arch/arm26/kernel/dma.c
@@ -0,0 +1,273 @@
+/*
+ *  linux/arch/arm26/kernel/dma.c
+ *
+ *  Copyright (C) 1995-2000 Russell King
+ *                2003      Ian Molton
+ *
+ * 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.
+ *
+ *  Front-end to the DMA handling.  This handles the allocation/freeing
+ *  of DMA channels, and provides a unified interface to the machines
+ *  DMA facilities.
+ */
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/mman.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+
+#include <asm/dma.h>
+
+DEFINE_SPINLOCK(dma_spin_lock);
+
+static dma_t dma_chan[MAX_DMA_CHANNELS];
+
+/*
+ * Get dma list for /proc/dma
+ */
+int get_dma_list(char *buf)
+{
+	dma_t *dma;
+	char *p = buf;
+	int i;
+
+	for (i = 0, dma = dma_chan; i < MAX_DMA_CHANNELS; i++, dma++)
+		if (dma->lock)
+			p += sprintf(p, "%2d: %14s %s\n", i,
+				     dma->d_ops->type, dma->device_id);
+
+	return p - buf;
+}
+
+/*
+ * Request DMA channel
+ *
+ * On certain platforms, we have to allocate an interrupt as well...
+ */
+int request_dma(dmach_t channel, const char *device_id)
+{
+	dma_t *dma = dma_chan + channel;
+	int ret;
+
+	if (channel >= MAX_DMA_CHANNELS || !dma->d_ops)
+		goto bad_dma;
+
+	if (xchg(&dma->lock, 1) != 0)
+		goto busy;
+
+	dma->device_id = device_id;
+	dma->active    = 0;
+	dma->invalid   = 1;
+
+	ret = 0;
+	if (dma->d_ops->request)
+		ret = dma->d_ops->request(channel, dma);
+
+	if (ret)
+		xchg(&dma->lock, 0);
+
+	return ret;
+
+bad_dma:
+	printk(KERN_ERR "dma: trying to allocate DMA%d\n", channel);
+	return -EINVAL;
+
+busy:
+	return -EBUSY;
+}
+
+/*
+ * Free DMA channel
+ *
+ * On certain platforms, we have to free interrupt as well...
+ */
+void free_dma(dmach_t channel)
+{
+	dma_t *dma = dma_chan + channel;
+
+	if (channel >= MAX_DMA_CHANNELS || !dma->d_ops)
+		goto bad_dma;
+
+	if (dma->active) {
+		printk(KERN_ERR "dma%d: freeing active DMA\n", channel);
+		dma->d_ops->disable(channel, dma);
+		dma->active = 0;
+	}
+
+	if (xchg(&dma->lock, 0) != 0) {
+		if (dma->d_ops->free)
+			dma->d_ops->free(channel, dma);
+		return;
+	}
+
+	printk(KERN_ERR "dma%d: trying to free free DMA\n", channel);
+	return;
+
+bad_dma:
+	printk(KERN_ERR "dma: trying to free DMA%d\n", channel);
+}
+
+/* Set DMA Scatter-Gather list
+ */
+void set_dma_sg (dmach_t channel, struct scatterlist *sg, int nr_sg)
+{
+	dma_t *dma = dma_chan + channel;
+
+	if (dma->active)
+		printk(KERN_ERR "dma%d: altering DMA SG while "
+		       "DMA active\n", channel);
+
+	dma->sg = sg;
+	dma->sgcount = nr_sg;
+	dma->using_sg = 1;
+	dma->invalid = 1;
+}
+
+/* Set DMA address
+ *
+ * Copy address to the structure, and set the invalid bit
+ */
+void set_dma_addr (dmach_t channel, unsigned long physaddr)
+{
+	dma_t *dma = dma_chan + channel;
+
+	if (dma->active)
+		printk(KERN_ERR "dma%d: altering DMA address while "
+		       "DMA active\n", channel);
+
+	dma->sg = &dma->buf;
+	dma->sgcount = 1;
+	dma->buf.__address = (char *)physaddr;//FIXME - not pretty
+	dma->using_sg = 0;
+	dma->invalid = 1;
+}
+
+/* Set DMA byte count
+ *
+ * Copy address to the structure, and set the invalid bit
+ */
+void set_dma_count (dmach_t channel, unsigned long count)
+{
+	dma_t *dma = dma_chan + channel;
+
+	if (dma->active)
+		printk(KERN_ERR "dma%d: altering DMA count while "
+		       "DMA active\n", channel);
+
+	dma->sg = &dma->buf;
+	dma->sgcount = 1;
+	dma->buf.length = count;
+	dma->using_sg = 0;
+	dma->invalid = 1;
+}
+
+/* Set DMA direction mode
+ */
+void set_dma_mode (dmach_t channel, dmamode_t mode)
+{
+	dma_t *dma = dma_chan + channel;
+
+	if (dma->active)
+		printk(KERN_ERR "dma%d: altering DMA mode while "
+		       "DMA active\n", channel);
+
+	dma->dma_mode = mode;
+	dma->invalid = 1;
+}
+
+/* Enable DMA channel
+ */
+void enable_dma (dmach_t channel)
+{
+	dma_t *dma = dma_chan + channel;
+
+	if (!dma->lock)
+		goto free_dma;
+
+	if (dma->active == 0) {
+		dma->active = 1;
+		dma->d_ops->enable(channel, dma);
+	}
+	return;
+
+free_dma:
+	printk(KERN_ERR "dma%d: trying to enable free DMA\n", channel);
+	BUG();
+}
+
+/* Disable DMA channel
+ */
+void disable_dma (dmach_t channel)
+{
+	dma_t *dma = dma_chan + channel;
+
+	if (!dma->lock)
+		goto free_dma;
+
+	if (dma->active == 1) {
+		dma->active = 0;
+		dma->d_ops->disable(channel, dma);
+	}
+	return;
+
+free_dma:
+	printk(KERN_ERR "dma%d: trying to disable free DMA\n", channel);
+	BUG();
+}
+
+/*
+ * Is the specified DMA channel active?
+ */
+int dma_channel_active(dmach_t channel)
+{
+	return dma_chan[channel].active;
+}
+
+void set_dma_page(dmach_t channel, char pagenr)
+{
+	printk(KERN_ERR "dma%d: trying to set_dma_page\n", channel);
+}
+
+void set_dma_speed(dmach_t channel, int cycle_ns)
+{
+	dma_t *dma = dma_chan + channel;
+	int ret = 0;
+
+	if (dma->d_ops->setspeed)
+		ret = dma->d_ops->setspeed(channel, dma, cycle_ns);
+	dma->speed = ret;
+}
+
+int get_dma_residue(dmach_t channel)
+{
+	dma_t *dma = dma_chan + channel;
+	int ret = 0;
+
+	if (dma->d_ops->residue)
+		ret = dma->d_ops->residue(channel, dma);
+
+	return ret;
+}
+
+void __init init_dma(void)
+{
+	arch_dma_init(dma_chan);
+}
+
+EXPORT_SYMBOL(request_dma);
+EXPORT_SYMBOL(free_dma);
+EXPORT_SYMBOL(enable_dma);
+EXPORT_SYMBOL(disable_dma);
+EXPORT_SYMBOL(set_dma_addr);
+EXPORT_SYMBOL(set_dma_count);
+EXPORT_SYMBOL(set_dma_mode);
+EXPORT_SYMBOL(set_dma_page);
+EXPORT_SYMBOL(get_dma_residue);
+EXPORT_SYMBOL(set_dma_sg);
+EXPORT_SYMBOL(set_dma_speed);
+
+EXPORT_SYMBOL(dma_spin_lock);
diff --git a/arch/arm26/kernel/ecard.c b/arch/arm26/kernel/ecard.c
new file mode 100644
index 0000000..824c6b5
--- /dev/null
+++ b/arch/arm26/kernel/ecard.c
@@ -0,0 +1,850 @@
+/*
+ *  linux/arch/arm26/kernel/ecard.c
+ *
+ *  Copyright 1995-2001 Russell King
+ *  Copyright 2003 Ian Molton
+ *
+ * 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.
+ *
+ *  Find all installed expansion cards, and handle interrupts from them.
+ *
+ *  Created from information from Acorns RiscOS3 PRMs
+ *  15-Jun-2003 IM      Modified from ARM32 (RiscPC capable) version
+ *  10-Jan-1999	RMK	Run loaders in a simulated RISC OS environment.
+ *  06-May-1997	RMK	Added blacklist for cards whose loader doesn't work.
+ *  12-Sep-1997	RMK	Created new handling of interrupt enables/disables
+ *			- cards can now register their own routine to control
+ *			interrupts (recommended).
+ *  29-Sep-1997	RMK	Expansion card interrupt hardware not being re-enabled
+ *			on reset from Linux. (Caused cards not to respond
+ *			under RiscOS without hard reset).
+ *
+ */
+#define ECARD_C
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/device.h>
+#include <linux/init.h>
+
+#include <asm/dma.h>
+#include <asm/ecard.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mmu_context.h>
+#include <asm/irqchip.h>
+#include <asm/tlbflush.h>
+
+enum req {
+	req_readbytes,
+	req_reset
+};
+
+struct ecard_request {
+	enum req	req;
+	ecard_t		*ec;
+	unsigned int	address;
+	unsigned int	length;
+	unsigned int	use_loader;
+	void		*buffer;
+};
+
+struct expcard_blacklist {
+	unsigned short	 manufacturer;
+	unsigned short	 product;
+	const char	*type;
+};
+
+static ecard_t *cards;
+static ecard_t *slot_to_expcard[MAX_ECARDS];
+static unsigned int ectcr;
+
+/* List of descriptions of cards which don't have an extended
+ * identification, or chunk directories containing a description.
+ */
+static struct expcard_blacklist __initdata blacklist[] = {
+	{ MANU_ACORN, PROD_ACORN_ETHER1, "Acorn Ether1" }
+};
+
+asmlinkage extern int
+ecard_loader_reset(volatile unsigned char *pa, loader_t loader);
+asmlinkage extern int
+ecard_loader_read(int off, volatile unsigned char *pa, loader_t loader);
+
+static const struct ecard_id *
+ecard_match_device(const struct ecard_id *ids, struct expansion_card *ec);
+
+static inline unsigned short
+ecard_getu16(unsigned char *v)
+{
+	return v[0] | v[1] << 8;
+}
+
+static inline signed long
+ecard_gets24(unsigned char *v)
+{
+	return v[0] | v[1] << 8 | v[2] << 16 | ((v[2] & 0x80) ? 0xff000000 : 0);
+}
+
+static inline ecard_t *
+slot_to_ecard(unsigned int slot)
+{
+	return slot < MAX_ECARDS ? slot_to_expcard[slot] : NULL;
+}
+
+/* ===================== Expansion card daemon ======================== */
+/*
+ * Since the loader programs on the expansion cards need to be run
+ * in a specific environment, create a separate task with this
+ * environment up, and pass requests to this task as and when we
+ * need to.
+ *
+ * This should allow 99% of loaders to be called from Linux.
+ *
+ * From a security standpoint, we trust the card vendors.  This
+ * may be a misplaced trust.
+ */
+#define BUS_ADDR(x) ((((unsigned long)(x)) << 2) + IO_BASE)
+#define POD_INT_ADDR(x)	((volatile unsigned char *)\
+			 ((BUS_ADDR((x)) - IO_BASE) + IO_START))
+
+static inline void ecard_task_reset(struct ecard_request *req)
+{
+	struct expansion_card *ec = req->ec;
+	if (ec->loader)
+		ecard_loader_reset(POD_INT_ADDR(ec->podaddr), ec->loader);
+}
+
+static void
+ecard_task_readbytes(struct ecard_request *req)
+{
+	unsigned char *buf = (unsigned char *)req->buffer;
+	volatile unsigned char *base_addr =
+		(volatile unsigned char *)POD_INT_ADDR(req->ec->podaddr);
+	unsigned int len = req->length;
+	unsigned int off = req->address;
+
+	if (!req->use_loader || !req->ec->loader) {
+		off *= 4;
+		while (len--) {
+			*buf++ = base_addr[off];
+			off += 4;
+		}
+	} else {
+		while(len--) {
+			/*
+			 * The following is required by some
+			 * expansion card loader programs.
+			 */
+			*(unsigned long *)0x108 = 0;
+			*buf++ = ecard_loader_read(off++, base_addr,
+						   req->ec->loader);
+		}
+	}
+}
+
+static void ecard_do_request(struct ecard_request *req)
+{
+	switch (req->req) {
+	case req_readbytes:
+		ecard_task_readbytes(req);
+		break;
+
+	case req_reset:
+		ecard_task_reset(req);
+		break;
+	}
+}
+
+/*
+ * On 26-bit processors, we don't need the kcardd thread to access the
+ * expansion card loaders.  We do it directly.
+ */
+#define ecard_call(req)	ecard_do_request(req)
+
+/* ======================= Mid-level card control ===================== */
+
+static void
+ecard_readbytes(void *addr, ecard_t *ec, int off, int len, int useld)
+{
+	struct ecard_request req;
+
+	req.req		= req_readbytes;
+	req.ec		= ec;
+	req.address	= off;
+	req.length	= len;
+	req.use_loader	= useld;
+	req.buffer	= addr;
+
+	ecard_call(&req);
+}
+
+int ecard_readchunk(struct in_chunk_dir *cd, ecard_t *ec, int id, int num)
+{
+	struct ex_chunk_dir excd;
+	int index = 16;
+	int useld = 0;
+
+	if (!ec->cid.cd)
+		return 0;
+
+	while(1) {
+		ecard_readbytes(&excd, ec, index, 8, useld);
+		index += 8;
+		if (c_id(&excd) == 0) {
+			if (!useld && ec->loader) {
+				useld = 1;
+				index = 0;
+				continue;
+			}
+			return 0;
+		}
+		if (c_id(&excd) == 0xf0) { /* link */
+			index = c_start(&excd);
+			continue;
+		}
+		if (c_id(&excd) == 0x80) { /* loader */
+			if (!ec->loader) {
+				ec->loader = (loader_t)kmalloc(c_len(&excd),
+							       GFP_KERNEL);
+				if (ec->loader)
+					ecard_readbytes(ec->loader, ec,
+							(int)c_start(&excd),
+							c_len(&excd), useld);
+				else
+					return 0;
+			}
+			continue;
+		}
+		if (c_id(&excd) == id && num-- == 0)
+			break;
+	}
+
+	if (c_id(&excd) & 0x80) {
+		switch (c_id(&excd) & 0x70) {
+		case 0x70:
+			ecard_readbytes((unsigned char *)excd.d.string, ec,
+					(int)c_start(&excd), c_len(&excd),
+					useld);
+			break;
+		case 0x00:
+			break;
+		}
+	}
+	cd->start_offset = c_start(&excd);
+	memcpy(cd->d.string, excd.d.string, 256);
+	return 1;
+}
+
+/* ======================= Interrupt control ============================ */
+
+static void ecard_def_irq_enable(ecard_t *ec, int irqnr)
+{
+}
+
+static void ecard_def_irq_disable(ecard_t *ec, int irqnr)
+{
+}
+
+static int ecard_def_irq_pending(ecard_t *ec)
+{
+	return !ec->irqmask || ec->irqaddr[0] & ec->irqmask;
+}
+
+static void ecard_def_fiq_enable(ecard_t *ec, int fiqnr)
+{
+	panic("ecard_def_fiq_enable called - impossible");
+}
+
+static void ecard_def_fiq_disable(ecard_t *ec, int fiqnr)
+{
+	panic("ecard_def_fiq_disable called - impossible");
+}
+
+static int ecard_def_fiq_pending(ecard_t *ec)
+{
+	return !ec->fiqmask || ec->fiqaddr[0] & ec->fiqmask;
+}
+
+static expansioncard_ops_t ecard_default_ops = {
+	ecard_def_irq_enable,
+	ecard_def_irq_disable,
+	ecard_def_irq_pending,
+	ecard_def_fiq_enable,
+	ecard_def_fiq_disable,
+	ecard_def_fiq_pending
+};
+
+/*
+ * Enable and disable interrupts from expansion cards.
+ * (interrupts are disabled for these functions).
+ *
+ * They are not meant to be called directly, but via enable/disable_irq.
+ */
+static void ecard_irq_unmask(unsigned int irqnr)
+{
+	ecard_t *ec = slot_to_ecard(irqnr - 32);
+
+	if (ec) {
+		if (!ec->ops)
+			ec->ops = &ecard_default_ops;
+
+		if (ec->claimed && ec->ops->irqenable)
+			ec->ops->irqenable(ec, irqnr);
+		else
+			printk(KERN_ERR "ecard: rejecting request to "
+				"enable IRQs for %d\n", irqnr);
+	}
+}
+
+static void ecard_irq_mask(unsigned int irqnr)
+{
+	ecard_t *ec = slot_to_ecard(irqnr - 32);
+
+	if (ec) {
+		if (!ec->ops)
+			ec->ops = &ecard_default_ops;
+
+		if (ec->ops && ec->ops->irqdisable)
+			ec->ops->irqdisable(ec, irqnr);
+	}
+}
+
+static struct irqchip ecard_chip = {
+	.ack	= ecard_irq_mask,
+	.mask	= ecard_irq_mask,
+	.unmask = ecard_irq_unmask,
+};
+
+void ecard_enablefiq(unsigned int fiqnr)
+{
+	ecard_t *ec = slot_to_ecard(fiqnr);
+
+	if (ec) {
+		if (!ec->ops)
+			ec->ops = &ecard_default_ops;
+
+		if (ec->claimed && ec->ops->fiqenable)
+			ec->ops->fiqenable(ec, fiqnr);
+		else
+			printk(KERN_ERR "ecard: rejecting request to "
+				"enable FIQs for %d\n", fiqnr);
+	}
+}
+
+void ecard_disablefiq(unsigned int fiqnr)
+{
+	ecard_t *ec = slot_to_ecard(fiqnr);
+
+	if (ec) {
+		if (!ec->ops)
+			ec->ops = &ecard_default_ops;
+
+		if (ec->ops->fiqdisable)
+			ec->ops->fiqdisable(ec, fiqnr);
+	}
+}
+
+static void
+ecard_dump_irq_state(ecard_t *ec)
+{
+	printk("  %d: %sclaimed, ",
+	       ec->slot_no,
+	       ec->claimed ? "" : "not ");
+
+	if (ec->ops && ec->ops->irqpending &&
+	    ec->ops != &ecard_default_ops)
+		printk("irq %spending\n",
+		       ec->ops->irqpending(ec) ? "" : "not ");
+	else
+		printk("irqaddr %p, mask = %02X, status = %02X\n",
+		       ec->irqaddr, ec->irqmask, *ec->irqaddr);
+}
+
+static void ecard_check_lockup(struct irqdesc *desc)
+{
+	static int last, lockup;
+	ecard_t *ec;
+
+	/*
+	 * If the timer interrupt has not run since the last million
+	 * unrecognised expansion card interrupts, then there is
+	 * something seriously wrong.  Disable the expansion card
+	 * interrupts so at least we can continue.
+	 *
+	 * Maybe we ought to start a timer to re-enable them some time
+	 * later?
+	 */
+	if (last == jiffies) {
+		lockup += 1;
+		if (lockup > 1000000) {
+			printk(KERN_ERR "\nInterrupt lockup detected - "
+			       "disabling all expansion card interrupts\n");
+
+			desc->chip->mask(IRQ_EXPANSIONCARD);
+
+			printk("Expansion card IRQ state:\n");
+
+			for (ec = cards; ec; ec = ec->next)
+				ecard_dump_irq_state(ec);
+		}
+	} else
+		lockup = 0;
+
+	/*
+	 * If we did not recognise the source of this interrupt,
+	 * warn the user, but don't flood the user with these messages.
+	 */
+	if (!last || time_after(jiffies, (unsigned long)(last + 5*HZ))) {
+		last = jiffies;
+		printk(KERN_WARNING "Unrecognised interrupt from backplane\n");
+	}
+}
+
+static void
+ecard_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
+{
+	ecard_t *ec;
+	int called = 0;
+
+	desc->chip->mask(irq);
+	for (ec = cards; ec; ec = ec->next) {
+		int pending;
+
+		if (!ec->claimed || ec->irq == NO_IRQ)
+			continue;
+
+		if (ec->ops && ec->ops->irqpending)
+			pending = ec->ops->irqpending(ec);
+		else
+			pending = ecard_default_ops.irqpending(ec);
+
+		if (pending) {
+			struct irqdesc *d = irq_desc + ec->irq;
+			d->handle(ec->irq, d, regs);
+			called ++;
+		}
+	}
+	desc->chip->unmask(irq);
+
+	if (called == 0)
+		ecard_check_lockup(desc);
+}
+
+#define ecard_irqexp_handler NULL
+#define ecard_probeirqhw() (0)
+
+unsigned int ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed)
+{
+	unsigned long address = 0;
+	int slot = ec->slot_no;
+
+	ectcr &= ~(1 << slot);
+
+	switch (type) {
+	case ECARD_MEMC:
+		address = IO_EC_MEMC_BASE + (slot << 12);
+		break;
+
+	case ECARD_IOC:
+		address = IO_EC_IOC_BASE + (slot << 12) + (speed << 17);
+		break;
+
+	default:
+		break;
+	}
+
+	return address;
+}
+
+static int ecard_prints(char *buffer, ecard_t *ec)
+{
+	char *start = buffer;
+
+	buffer += sprintf(buffer, "  %d: ", ec->slot_no);
+
+	if (ec->cid.id == 0) {
+		struct in_chunk_dir incd;
+
+		buffer += sprintf(buffer, "[%04X:%04X] ",
+			ec->cid.manufacturer, ec->cid.product);
+
+		if (!ec->card_desc && ec->cid.cd &&
+		    ecard_readchunk(&incd, ec, 0xf5, 0)) {
+			ec->card_desc = kmalloc(strlen(incd.d.string)+1, GFP_KERNEL);
+
+			if (ec->card_desc)
+				strcpy((char *)ec->card_desc, incd.d.string);
+		}
+
+		buffer += sprintf(buffer, "%s\n", ec->card_desc ? ec->card_desc : "*unknown*");
+	} else
+		buffer += sprintf(buffer, "Simple card %d\n", ec->cid.id);
+
+	return buffer - start;
+}
+
+static int get_ecard_dev_info(char *buf, char **start, off_t pos, int count)
+{
+	ecard_t *ec = cards;
+	off_t at = 0;
+	int len, cnt;
+
+	cnt = 0;
+	while (ec && count > cnt) {
+		len = ecard_prints(buf, ec);
+		at += len;
+		if (at >= pos) {
+			if (!*start) {
+				*start = buf + (pos - (at - len));
+				cnt = at - pos;
+			} else
+				cnt += len;
+			buf += len;
+		}
+		ec = ec->next;
+	}
+	return (count > cnt) ? cnt : count;
+}
+
+static struct proc_dir_entry *proc_bus_ecard_dir = NULL;
+
+static void ecard_proc_init(void)
+{
+	proc_bus_ecard_dir = proc_mkdir("ecard", proc_bus);
+	create_proc_info_entry("devices", 0, proc_bus_ecard_dir,
+		get_ecard_dev_info);
+}
+
+#define ec_set_resource(ec,nr,st,sz,flg)			\
+	do {							\
+		(ec)->resource[nr].name = ec->dev.bus_id;	\
+		(ec)->resource[nr].start = st;			\
+		(ec)->resource[nr].end = (st) + (sz) - 1;	\
+		(ec)->resource[nr].flags = flg;			\
+	} while (0)
+
+static void __init ecard_init_resources(struct expansion_card *ec)
+{
+	unsigned long base = PODSLOT_IOC0_BASE;
+	unsigned int slot = ec->slot_no;
+	int i;
+
+	ec_set_resource(ec, ECARD_RES_MEMC,
+			PODSLOT_MEMC_BASE + (slot << 14),
+			PODSLOT_MEMC_SIZE, IORESOURCE_MEM);
+
+	for (i = 0; i < ECARD_RES_IOCSYNC - ECARD_RES_IOCSLOW; i++) {
+		ec_set_resource(ec, i + ECARD_RES_IOCSLOW,
+				base + (slot << 14) + (i << 19),
+				PODSLOT_IOC_SIZE, IORESOURCE_MEM);
+	}
+
+	for (i = 0; i < ECARD_NUM_RESOURCES; i++) {
+		if (ec->resource[i].start &&
+		    request_resource(&iomem_resource, &ec->resource[i])) {
+			printk(KERN_ERR "%s: resource(s) not available\n",
+				ec->dev.bus_id);
+			ec->resource[i].end -= ec->resource[i].start;
+			ec->resource[i].start = 0;
+		}
+	}
+}
+
+static ssize_t ecard_show_irq(struct device *dev, char *buf)
+{
+	struct expansion_card *ec = ECARD_DEV(dev);
+	return sprintf(buf, "%u\n", ec->irq);
+}
+
+static ssize_t ecard_show_vendor(struct device *dev, char *buf)
+{
+	struct expansion_card *ec = ECARD_DEV(dev);
+	return sprintf(buf, "%u\n", ec->cid.manufacturer);
+}
+
+static ssize_t ecard_show_device(struct device *dev, char *buf)
+{
+	struct expansion_card *ec = ECARD_DEV(dev);
+	return sprintf(buf, "%u\n", ec->cid.product);
+}
+
+static ssize_t ecard_show_dma(struct device *dev, char *buf)
+{
+	struct expansion_card *ec = ECARD_DEV(dev);
+	return sprintf(buf, "%u\n", ec->dma);
+}
+
+static ssize_t ecard_show_resources(struct device *dev, char *buf)
+{
+	struct expansion_card *ec = ECARD_DEV(dev);
+	char *str = buf;
+	int i;
+
+	for (i = 0; i < ECARD_NUM_RESOURCES; i++)
+		str += sprintf(str, "%08lx %08lx %08lx\n",
+				ec->resource[i].start,
+				ec->resource[i].end,
+				ec->resource[i].flags);
+
+	return str - buf;
+}
+
+static DEVICE_ATTR(irq, S_IRUGO, ecard_show_irq, NULL);
+static DEVICE_ATTR(vendor, S_IRUGO, ecard_show_vendor, NULL);
+static DEVICE_ATTR(device, S_IRUGO, ecard_show_device, NULL);
+static DEVICE_ATTR(dma, S_IRUGO, ecard_show_dma, NULL);
+static DEVICE_ATTR(resource, S_IRUGO, ecard_show_resources, NULL);
+
+/*
+ * Probe for an expansion card.
+ *
+ * If bit 1 of the first byte of the card is set, then the
+ * card does not exist.
+ */
+static int __init
+ecard_probe(int slot, card_type_t type)
+{
+	ecard_t **ecp;
+	ecard_t *ec;
+	struct ex_ecid cid;
+	int i, rc = -ENOMEM;
+
+	ec = kmalloc(sizeof(ecard_t), GFP_KERNEL);
+	if (!ec)
+		goto nomem;
+
+	memset(ec, 0, sizeof(ecard_t));
+
+	ec->slot_no	= slot;
+	ec->type        = type;
+	ec->irq		= NO_IRQ;
+	ec->fiq		= NO_IRQ;
+	ec->dma		= NO_DMA;
+	ec->card_desc	= NULL;
+	ec->ops		= &ecard_default_ops;
+
+	rc = -ENODEV;
+	if ((ec->podaddr = ecard_address(ec, type, ECARD_SYNC)) == 0)
+		goto nodev;
+
+	cid.r_zero = 1;
+	ecard_readbytes(&cid, ec, 0, 16, 0);
+	if (cid.r_zero)
+		goto nodev;
+
+	ec->cid.id	= cid.r_id;
+	ec->cid.cd	= cid.r_cd;
+	ec->cid.is	= cid.r_is;
+	ec->cid.w	= cid.r_w;
+	ec->cid.manufacturer = ecard_getu16(cid.r_manu);
+	ec->cid.product = ecard_getu16(cid.r_prod);
+	ec->cid.country = cid.r_country;
+	ec->cid.irqmask = cid.r_irqmask;
+	ec->cid.irqoff  = ecard_gets24(cid.r_irqoff);
+	ec->cid.fiqmask = cid.r_fiqmask;
+	ec->cid.fiqoff  = ecard_gets24(cid.r_fiqoff);
+	ec->fiqaddr	=
+	ec->irqaddr	= (unsigned char *)ioaddr(ec->podaddr);
+
+	if (ec->cid.is) {
+		ec->irqmask = ec->cid.irqmask;
+		ec->irqaddr += ec->cid.irqoff;
+		ec->fiqmask = ec->cid.fiqmask;
+		ec->fiqaddr += ec->cid.fiqoff;
+	} else {
+		ec->irqmask = 1;
+		ec->fiqmask = 4;
+	}
+
+	for (i = 0; i < sizeof(blacklist) / sizeof(*blacklist); i++)
+		if (blacklist[i].manufacturer == ec->cid.manufacturer &&
+		    blacklist[i].product == ec->cid.product) {
+			ec->card_desc = blacklist[i].type;
+			break;
+		}
+
+	snprintf(ec->dev.bus_id, sizeof(ec->dev.bus_id), "ecard%d", slot);
+	ec->dev.parent = NULL;
+	ec->dev.bus    = &ecard_bus_type;
+	ec->dev.dma_mask = &ec->dma_mask;
+	ec->dma_mask = (u64)0xffffffff;
+
+	ecard_init_resources(ec);
+
+	/*
+	 * hook the interrupt handlers
+	 */
+	ec->irq = 32 + slot;
+	set_irq_chip(ec->irq, &ecard_chip);
+	set_irq_handler(ec->irq, do_level_IRQ);
+	set_irq_flags(ec->irq, IRQF_VALID);
+
+	for (ecp = &cards; *ecp; ecp = &(*ecp)->next);
+
+	*ecp = ec;
+	slot_to_expcard[slot] = ec;
+
+	device_register(&ec->dev);
+	device_create_file(&ec->dev, &dev_attr_dma);
+	device_create_file(&ec->dev, &dev_attr_irq);
+	device_create_file(&ec->dev, &dev_attr_resource);
+	device_create_file(&ec->dev, &dev_attr_vendor);
+	device_create_file(&ec->dev, &dev_attr_device); 
+
+	return 0;
+
+nodev:
+	kfree(ec);
+nomem:
+	return rc;
+}
+
+/*
+ * Initialise the expansion card system.
+ * Locate all hardware - interrupt management and
+ * actual cards.
+ */
+static int __init ecard_init(void)
+{
+	int slot, irqhw;
+
+	printk("Probing expansion cards\n");
+
+	for (slot = 0; slot < MAX_ECARDS; slot ++) {
+		ecard_probe(slot, ECARD_IOC);
+	}
+
+	irqhw = ecard_probeirqhw();
+
+	set_irq_chained_handler(IRQ_EXPANSIONCARD,
+				irqhw ? ecard_irqexp_handler : ecard_irq_handler);
+
+	ecard_proc_init();
+
+	return 0;
+}
+
+subsys_initcall(ecard_init);
+
+/*
+ *	ECARD "bus"
+ */
+static const struct ecard_id *
+ecard_match_device(const struct ecard_id *ids, struct expansion_card *ec)
+{
+	int i;
+
+	for (i = 0; ids[i].manufacturer != 65535; i++)
+		if (ec->cid.manufacturer == ids[i].manufacturer &&
+		    ec->cid.product == ids[i].product)
+			return ids + i;
+
+	return NULL;
+}
+
+static int ecard_drv_probe(struct device *dev)
+{
+	struct expansion_card *ec = ECARD_DEV(dev);
+	struct ecard_driver *drv = ECARD_DRV(dev->driver);
+	const struct ecard_id *id;
+	int ret;
+
+	id = ecard_match_device(drv->id_table, ec);
+
+	ecard_claim(ec);
+	ret = drv->probe(ec, id);
+	if (ret)
+		ecard_release(ec);
+	return ret;
+}
+
+static int ecard_drv_remove(struct device *dev)
+{
+	struct expansion_card *ec = ECARD_DEV(dev);
+	struct ecard_driver *drv = ECARD_DRV(dev->driver);
+
+	drv->remove(ec);
+	ecard_release(ec);
+
+	return 0;
+}
+
+/*
+ * Before rebooting, we must make sure that the expansion card is in a
+ * sensible state, so it can be re-detected.  This means that the first
+ * page of the ROM must be visible.  We call the expansion cards reset
+ * handler, if any.
+ */
+static void ecard_drv_shutdown(struct device *dev)
+{
+	struct expansion_card *ec = ECARD_DEV(dev);
+	struct ecard_driver *drv = ECARD_DRV(dev->driver);
+	struct ecard_request req;
+
+	if (drv->shutdown)
+		drv->shutdown(ec);
+	ecard_release(ec);
+	req.req = req_reset;
+	req.ec = ec;
+	ecard_call(&req);
+}
+
+int ecard_register_driver(struct ecard_driver *drv)
+{
+	drv->drv.bus = &ecard_bus_type;
+	drv->drv.probe = ecard_drv_probe;
+	drv->drv.remove = ecard_drv_remove;
+	drv->drv.shutdown = ecard_drv_shutdown;
+
+	return driver_register(&drv->drv);
+}
+
+void ecard_remove_driver(struct ecard_driver *drv)
+{
+	driver_unregister(&drv->drv);
+}
+
+static int ecard_match(struct device *_dev, struct device_driver *_drv)
+{
+	struct expansion_card *ec = ECARD_DEV(_dev);
+	struct ecard_driver *drv = ECARD_DRV(_drv);
+	int ret;
+
+	if (drv->id_table) {
+		ret = ecard_match_device(drv->id_table, ec) != NULL;
+	} else {
+		ret = ec->cid.id == drv->id;
+	}
+
+	return ret;
+}
+
+struct bus_type ecard_bus_type = {
+	.name	= "ecard",
+	.match	= ecard_match,
+};
+
+static int ecard_bus_init(void)
+{
+	return bus_register(&ecard_bus_type);
+}
+
+postcore_initcall(ecard_bus_init);
+
+EXPORT_SYMBOL(ecard_readchunk);
+EXPORT_SYMBOL(ecard_address);
+EXPORT_SYMBOL(ecard_register_driver);
+EXPORT_SYMBOL(ecard_remove_driver);
+EXPORT_SYMBOL(ecard_bus_type);
diff --git a/arch/arm26/kernel/entry.S b/arch/arm26/kernel/entry.S
new file mode 100644
index 0000000..a231dd8
--- /dev/null
+++ b/arch/arm26/kernel/entry.S
@@ -0,0 +1,961 @@
+/* arch/arm26/kernel/entry.S
+ * 
+ * Assembled from chunks of code in arch/arm
+ *
+ * Copyright (C) 2003 Ian Molton
+ * Based on the work of RMK.
+ *
+ */
+
+#include <linux/linkage.h>
+
+#include <asm/assembler.h>
+#include <asm/asm_offsets.h>
+#include <asm/errno.h>
+#include <asm/hardware.h>
+#include <asm/sysirq.h>
+#include <asm/thread_info.h>
+#include <asm/page.h>
+#include <asm/ptrace.h>
+
+	.macro	zero_fp
+#ifndef CONFIG_NO_FRAME_POINTER
+	mov	fp, #0
+#endif
+	.endm
+
+	.text
+
+@ Bad Abort numbers
+@ -----------------
+@
+#define BAD_PREFETCH	0
+#define BAD_DATA	1
+#define BAD_ADDREXCPTN	2
+#define BAD_IRQ		3
+#define BAD_UNDEFINSTR	4
+
+@ OS version number used in SWIs
+@  RISC OS is 0
+@  RISC iX is 8
+@
+#define OS_NUMBER	9
+#define ARMSWI_OFFSET	0x000f0000
+
+@
+@ Stack format (ensured by USER_* and SVC_*)
+@ PSR and PC are comined on arm26
+@
+
+#define S_OFF		8
+
+#define S_OLD_R0	64
+#define S_PC		60
+#define S_LR		56
+#define S_SP		52
+#define S_IP		48
+#define S_FP		44
+#define S_R10		40
+#define S_R9		36
+#define S_R8		32
+#define S_R7		28
+#define S_R6		24
+#define S_R5		20
+#define S_R4		16
+#define S_R3		12
+#define S_R2		8
+#define S_R1		4
+#define S_R0		0
+
+	.macro	save_user_regs
+	str	r0, [sp, #-4]!   @ Store SVC r0
+	str	lr, [sp, #-4]!   @ Store user mode PC
+	sub	sp, sp, #15*4
+	stmia	sp, {r0 - lr}^   @ Store the other user-mode regs
+	mov	r0, r0
+	.endm
+
+	.macro	slow_restore_user_regs
+	ldmia	sp, {r0 - lr}^   @ restore the user regs not including PC
+	mov	r0, r0
+	ldr	lr, [sp, #15*4]  @ get user PC
+	add	sp, sp, #15*4+8  @ free stack
+	movs	pc, lr           @ return
+	.endm
+
+	.macro	fast_restore_user_regs
+	add	sp, sp, #S_OFF
+	ldmib	sp, {r1 - lr}^
+	mov	r0, r0
+	ldr	lr, [sp, #15*4]
+	add	sp, sp, #15*4+8
+	movs	pc, lr
+	.endm
+
+	.macro	save_svc_regs
+	str     sp, [sp, #-16]!
+	str     lr, [sp, #8]
+	str     lr, [sp, #4]
+	stmfd   sp!, {r0 - r12}
+	mov     r0, #-1
+	str     r0, [sp, #S_OLD_R0]
+	zero_fp
+	.endm
+
+	.macro	save_svc_regs_irq
+	str     sp, [sp, #-16]!
+	str     lr, [sp, #4]
+	ldr     lr, .LCirq
+	ldr     lr, [lr]
+	str     lr, [sp, #8]
+	stmfd   sp!, {r0 - r12}
+	mov     r0, #-1
+	str     r0, [sp, #S_OLD_R0]
+	zero_fp
+	.endm
+
+	.macro	restore_svc_regs
+                ldmfd   sp, {r0 - pc}^
+	.endm
+
+	.macro	mask_pc, rd, rm
+	bic	\rd, \rm, #PCMASK
+	.endm
+
+	.macro  disable_irqs, temp
+	mov     \temp, pc
+	orr     \temp, \temp, #PSR_I_BIT
+	teqp    \temp, #0
+	.endm
+
+	.macro	enable_irqs, temp
+	mov     \temp, pc
+	and     \temp, \temp, #~PSR_I_BIT
+	teqp	\temp, #0
+	.endm
+
+	.macro	initialise_traps_extra
+	.endm
+
+	.macro	get_thread_info, rd
+	mov	\rd, sp, lsr #13
+	mov	\rd, \rd, lsl #13
+	.endm
+
+/*
+ * These are the registers used in the syscall handler, and allow us to
+ * have in theory up to 7 arguments to a function - r0 to r6.
+ *
+ * Note that tbl == why is intentional.
+ *
+ * We must set at least "tsk" and "why" when calling ret_with_reschedule.
+ */
+scno	.req	r7		@ syscall number
+tbl	.req	r8		@ syscall table pointer
+why	.req	r8		@ Linux syscall (!= 0)
+tsk	.req	r9		@ current thread_info
+
+/*
+ * Get the system call number.
+ */
+	.macro	get_scno
+	mask_pc	lr, lr
+	ldr	scno, [lr, #-4]		@ get SWI instruction
+	.endm
+/*
+ *  -----------------------------------------------------------------------
+ */
+
+/* 
+ * We rely on the fact that R0 is at the bottom of the stack (due to
+ * slow/fast restore user regs).
+ */
+#if S_R0 != 0
+#error "Please fix"
+#endif
+
+/*
+ * This is the fast syscall return path.  We do as little as
+ * possible here, and this includes saving r0 back into the SVC
+ * stack.
+ */
+ret_fast_syscall:
+	disable_irqs r1				@ disable interrupts
+	ldr	r1, [tsk, #TI_FLAGS]
+	tst	r1, #_TIF_WORK_MASK
+	bne	fast_work_pending
+	fast_restore_user_regs
+
+/*
+ * Ok, we need to do extra processing, enter the slow path.
+ */
+fast_work_pending:
+	str	r0, [sp, #S_R0+S_OFF]!		@ returned r0
+work_pending:
+	tst	r1, #_TIF_NEED_RESCHED
+	bne	work_resched
+	tst	r1, #_TIF_NOTIFY_RESUME | _TIF_SIGPENDING
+	beq	no_work_pending
+	mov	r0, sp				@ 'regs'
+	mov	r2, why				@ 'syscall'
+	bl	do_notify_resume
+	disable_irqs r1				@ disable interrupts
+	b	no_work_pending
+
+work_resched:
+	bl	schedule
+/*
+ * "slow" syscall return path.  "why" tells us if this was a real syscall.
+ */
+ENTRY(ret_to_user)
+ret_slow_syscall:
+	disable_irqs r1				@ disable interrupts
+	ldr	r1, [tsk, #TI_FLAGS]
+	tst	r1, #_TIF_WORK_MASK
+	bne	work_pending
+no_work_pending:
+	slow_restore_user_regs
+
+/*
+ * This is how we return from a fork.
+ */
+ENTRY(ret_from_fork)
+	bl	schedule_tail
+	get_thread_info tsk
+	ldr	r1, [tsk, #TI_FLAGS]		@ check for syscall tracing
+	mov	why, #1
+	tst	r1, #_TIF_SYSCALL_TRACE		@ are we tracing syscalls?
+	beq	ret_slow_syscall
+	mov	r1, sp
+	mov	r0, #1				@ trace exit [IP = 1]
+	bl	syscall_trace
+	b	ret_slow_syscall
+	
+// FIXME - is this strictly necessary?
+#include "calls.S"
+
+/*=============================================================================
+ * SWI handler
+ *-----------------------------------------------------------------------------
+ */
+
+	.align	5
+ENTRY(vector_swi)
+	save_user_regs
+	zero_fp
+	get_scno
+
+#ifdef CONFIG_ALIGNMENT_TRAP
+	ldr	ip, __cr_alignment
+	ldr	ip, [ip]
+	mcr	p15, 0, ip, c1, c0		@ update control register
+#endif
+	enable_irqs ip
+
+	str	r4, [sp, #-S_OFF]!		@ push fifth arg
+
+	get_thread_info tsk
+	ldr	ip, [tsk, #TI_FLAGS]		@ check for syscall tracing
+	bic	scno, scno, #0xff000000		@ mask off SWI op-code
+	eor	scno, scno, #OS_NUMBER << 20	@ check OS number
+	adr	tbl, sys_call_table		@ load syscall table pointer
+	tst	ip, #_TIF_SYSCALL_TRACE		@ are we tracing syscalls?
+	bne	__sys_trace
+
+	adral	lr, ret_fast_syscall            @ set return address
+        orral	lr, lr, #PSR_I_BIT | MODE_SVC26 @ Force SVC mode on return
+	cmp	scno, #NR_syscalls		@ check upper syscall limit
+	ldrcc	pc, [tbl, scno, lsl #2]		@ call sys_* routine
+
+	add	r1, sp, #S_OFF
+2:	mov	why, #0				@ no longer a real syscall
+	cmp	scno, #ARMSWI_OFFSET
+	eor	r0, scno, #OS_NUMBER << 20	@ put OS number back
+	bcs	arm_syscall	
+	b	sys_ni_syscall			@ not private func
+
+	/*
+	 * This is the really slow path.  We're going to be doing
+	 * context switches, and waiting for our parent to respond.
+	 */
+__sys_trace:
+	add	r1, sp, #S_OFF
+	mov	r0, #0				@ trace entry [IP = 0]
+	bl	syscall_trace
+
+	adral   lr, __sys_trace_return          @ set return address
+        orral   lr, lr, #PSR_I_BIT | MODE_SVC26 @ Force SVC mode on return
+	add	r1, sp, #S_R0 + S_OFF		@ pointer to regs
+	cmp	scno, #NR_syscalls		@ check upper syscall limit
+	ldmccia	r1, {r0 - r3}			@ have to reload r0 - r3
+	ldrcc	pc, [tbl, scno, lsl #2]		@ call sys_* routine
+	b	2b
+
+__sys_trace_return:
+	str	r0, [sp, #S_R0 + S_OFF]!	@ save returned r0
+	mov	r1, sp
+	mov	r0, #1				@ trace exit [IP = 1]
+	bl	syscall_trace
+	b	ret_slow_syscall
+
+	.align	5
+#ifdef CONFIG_ALIGNMENT_TRAP
+	.type	__cr_alignment, #object
+__cr_alignment:
+	.word	cr_alignment
+#endif
+
+	.type	sys_call_table, #object
+ENTRY(sys_call_table)
+#include "calls.S"
+
+/*============================================================================
+ * Special system call wrappers
+ */
+@ r0 = syscall number
+@ r5 = syscall table
+		.type	sys_syscall, #function
+sys_syscall:
+		eor	scno, r0, #OS_NUMBER << 20
+		cmp	scno, #NR_syscalls	@ check range
+		stmleia	sp, {r5, r6}		@ shuffle args
+		movle	r0, r1
+		movle	r1, r2
+		movle	r2, r3
+		movle	r3, r4
+		ldrle	pc, [tbl, scno, lsl #2]
+		b	sys_ni_syscall
+
+sys_fork_wrapper:
+		add	r0, sp, #S_OFF
+		b	sys_fork
+
+sys_vfork_wrapper:
+		add	r0, sp, #S_OFF
+		b	sys_vfork
+
+sys_execve_wrapper:
+		add	r3, sp, #S_OFF
+		b	sys_execve
+
+sys_clone_wapper:
+		add	r2, sp, #S_OFF
+		b	sys_clone
+
+sys_sigsuspend_wrapper:
+		add	r3, sp, #S_OFF
+		b	sys_sigsuspend
+
+sys_rt_sigsuspend_wrapper:
+		add	r2, sp, #S_OFF
+		b	sys_rt_sigsuspend
+
+sys_sigreturn_wrapper:
+		add	r0, sp, #S_OFF
+		b	sys_sigreturn
+
+sys_rt_sigreturn_wrapper:
+		add	r0, sp, #S_OFF
+		b	sys_rt_sigreturn
+
+sys_sigaltstack_wrapper:
+		ldr	r2, [sp, #S_OFF + S_SP]
+		b	do_sigaltstack
+
+/*
+ * Note: off_4k (r5) is always units of 4K.  If we can't do the requested
+ * offset, we return EINVAL.  FIXME - this lost some stuff from arm32 to
+ * ifdefs. check it out.
+ */
+sys_mmap2:
+		tst	r5, #((1 << (PAGE_SHIFT - 12)) - 1)
+		moveq	r5, r5, lsr #PAGE_SHIFT - 12
+		streq	r5, [sp, #4]
+		beq	do_mmap2
+		mov	r0, #-EINVAL
+		RETINSTR(mov,pc, lr)
+
+/*
+ *  Design issues:
+ *   - We have several modes that each vector can be called from,
+ *     each with its own set of registers.  On entry to any vector,
+ *     we *must* save the registers used in *that* mode.
+ *
+ *   - This code must be as fast as possible.
+ *
+ *  There are a few restrictions on the vectors:
+ *   - the SWI vector cannot be called from *any* non-user mode
+ *
+ *   - the FP emulator is *never* called from *any* non-user mode undefined
+ *     instruction.
+ *
+ */
+
+		.text
+
+		.macro handle_irq
+1:		mov     r4, #IOC_BASE
+		ldrb    r6, [r4, #0x24]            @ get high priority first
+		adr     r5, irq_prio_h
+		teq     r6, #0
+		ldreqb  r6, [r4, #0x14]            @ get low priority
+		adreq   r5, irq_prio_l
+
+                teq     r6, #0                     @ If an IRQ happened...
+                ldrneb  r0, [r5, r6]               @ get IRQ number
+                movne   r1, sp                     @ get struct pt_regs
+                adrne   lr, 1b                     @ Set return address to 1b
+                orrne   lr, lr, #PSR_I_BIT | MODE_SVC26  @ (and force SVC mode)
+                bne     asm_do_IRQ                 @ process IRQ (if asserted)
+		.endm
+
+
+/*
+ * Interrupt table (incorporates priority)
+ */
+		.macro	irq_prio_table
+irq_prio_l:	.byte	 0, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3
+		.byte	 4, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3
+		.byte	 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
+		.byte	 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
+		.byte	 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3
+		.byte	 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3
+		.byte	 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
+		.byte	 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
+		.byte	 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+		.byte	 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+		.byte	 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+		.byte	 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+		.byte	 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+		.byte	 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+		.byte	 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+		.byte	 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+irq_prio_h:	.byte	 0, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10
+		.byte	12, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10
+		.byte	13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
+		.byte	13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
+		.byte	14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10
+		.byte	14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10
+		.byte	13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
+		.byte	13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
+		.byte	15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
+		.byte	15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
+		.byte	13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
+		.byte	13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
+		.byte	15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
+		.byte	15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
+		.byte	13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
+		.byte	13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
+		.endm
+
+#if 1
+/*
+ * Uncomment these if you wish to get more debugging into about data aborts.
+ * FIXME - I bet we can find a way to encode these and keep performance.
+ */
+#define FAULT_CODE_LDRSTRPOST	0x80
+#define FAULT_CODE_LDRSTRPRE	0x40
+#define FAULT_CODE_LDRSTRREG	0x20
+#define FAULT_CODE_LDMSTM	0x10
+#define FAULT_CODE_LDCSTC	0x08
+#endif
+#define FAULT_CODE_PREFETCH	0x04
+#define FAULT_CODE_WRITE	0x02
+#define FAULT_CODE_FORCECOW	0x01
+
+/*=============================================================================
+ * Undefined FIQs
+ *-----------------------------------------------------------------------------
+ */
+_unexp_fiq:	ldr     sp, .LCfiq
+		mov	r12, #IOC_BASE
+		strb	r12, [r12, #0x38]	@ Disable FIQ register
+		teqp	pc, #PSR_I_BIT | PSR_F_BIT | MODE_SVC26
+		mov	r0, r0
+		stmfd	sp!, {r0 - r3, ip, lr}
+		adr	r0, Lfiqmsg
+		bl	printk
+		ldmfd	sp!, {r0 - r3, ip, lr}
+		teqp	pc, #PSR_I_BIT | PSR_F_BIT | MODE_FIQ26
+		mov	r0, r0
+		movs	pc, lr
+
+Lfiqmsg:	.ascii	"*** Unexpected FIQ\n\0"
+		.align
+
+.LCfiq:		.word	__temp_fiq
+.LCirq:		.word	__temp_irq
+
+/*=============================================================================
+ * Undefined instruction handler
+ *-----------------------------------------------------------------------------
+ * Handles floating point instructions
+ */
+vector_undefinstr:
+		tst	lr, #MODE_SVC26          @ did we come from a non-user mode?
+		bne	__und_svc                @ yes - deal with it.
+/* Otherwise, fall through for the user-space (common) case. */
+		save_user_regs
+		zero_fp                                 @ zero frame pointer
+		teqp	pc, #PSR_I_BIT | MODE_SVC26     @ disable IRQs
+.Lbug_undef:
+		ldr	r4, .LC2
+                ldr     pc, [r4]         @ Call FP module entry point
+/* FIXME - should we trap for a null pointer here? */
+
+/* The SVC mode case */
+__und_svc:	save_svc_regs                           @ Non-user mode
+                mask_pc r0, lr
+                and     r2, lr, #3
+                sub     r0, r0, #4
+                mov     r1, sp
+                bl      do_undefinstr
+                restore_svc_regs
+
+/* We get here if the FP emulator doesnt handle the undef instr.
+ * If the insn WAS handled, the emulator jumps to ret_from_exception by itself/
+ */
+		.globl	fpundefinstr 
+fpundefinstr:
+		mov	r0, lr
+		mov	r1, sp
+		teqp	pc, #MODE_SVC26
+		bl	do_undefinstr
+		b	ret_from_exception		@ Normal FP exit
+
+#if defined CONFIG_FPE_NWFPE || defined CONFIG_FPE_FASTFPE
+		/* The FPE is always present */
+		.equ	fpe_not_present, 0
+#else
+/* We get here if an undefined instruction happens and the floating
+ * point emulator is not present.  If the offending instruction was
+ * a WFS, we just perform a normal return as if we had emulated the
+ * operation.  This is a hack to allow some basic userland binaries
+ * to run so that the emulator module proper can be loaded. --philb
+ * FIXME - probably a broken useless hack...
+ */
+fpe_not_present:
+		adr	r10, wfs_mask_data
+		ldmia	r10, {r4, r5, r6, r7, r8}
+		ldr	r10, [sp, #S_PC]		@ Load PC
+		sub	r10, r10, #4
+		mask_pc	r10, r10
+		ldrt	r10, [r10]			@ get instruction
+		and	r5, r10, r5
+		teq	r5, r4				@ Is it WFS?
+		beq	ret_from_exception
+		and	r5, r10, r8
+		teq	r5, r6				@ Is it LDF/STF on sp or fp?
+		teqne	r5, r7
+		bne	fpundefinstr
+		tst	r10, #0x00200000		@ Does it have WB
+		beq	ret_from_exception
+		and	r4, r10, #255			@ get offset
+		and	r6, r10, #0x000f0000
+		tst	r10, #0x00800000		@ +/-
+		ldr	r5, [sp, r6, lsr #14]		@ Load reg
+		rsbeq	r4, r4, #0
+		add	r5, r5, r4, lsl #2
+		str	r5, [sp, r6, lsr #14]		@ Save reg
+		b	ret_from_exception
+
+wfs_mask_data:	.word	0x0e200110			@ WFS/RFS
+		.word	0x0fef0fff
+		.word	0x0d0d0100			@ LDF [sp]/STF [sp]
+		.word	0x0d0b0100			@ LDF [fp]/STF [fp]
+		.word	0x0f0f0f00
+#endif
+
+.LC2:		.word	fp_enter
+
+/*=============================================================================
+ * Prefetch abort handler
+ *-----------------------------------------------------------------------------
+ */
+#define DEBUG_UNDEF
+/* remember: lr = USR pc */
+vector_prefetch:
+		sub	lr, lr, #4
+		tst	lr, #MODE_SVC26
+		bne	__pabt_invalid
+		save_user_regs
+		teqp	pc, #MODE_SVC26         @ Enable IRQs...
+		mask_pc	r0, lr			@ Address of abort
+		mov	r1, sp			@ Tasks registers
+		bl	do_PrefetchAbort
+		teq	r0, #0			@ If non-zero, we believe this abort..
+		bne	ret_from_exception
+#ifdef DEBUG_UNDEF
+		adr	r0, t
+		bl	printk
+#endif
+		ldr	lr, [sp,#S_PC]		@ FIXME program to test this on.  I think its
+		b	.Lbug_undef		@ broken at the moment though!)
+
+__pabt_invalid:	save_svc_regs
+		mov	r0, sp			@ Prefetch aborts are definitely *not*
+		mov	r1, #BAD_PREFETCH	@ allowed in non-user modes.  We cant
+		and	r2, lr, #3		@ recover from this problem.
+		b	bad_mode
+
+#ifdef DEBUG_UNDEF
+t:		.ascii "*** undef ***\r\n\0"
+		.align
+#endif
+
+/*=============================================================================
+ * Address exception handler
+ *-----------------------------------------------------------------------------
+ * These aren't too critical.
+ * (they're not supposed to happen).
+ * In order to debug the reason for address exceptions in non-user modes,
+ * we have to obtain all the registers so that we can see what's going on.
+ */
+
+vector_addrexcptn:
+		sub	lr, lr, #8
+		tst	lr, #3
+		bne	Laddrexcptn_not_user
+		save_user_regs
+		teq	pc, #MODE_SVC26
+		mask_pc	r0, lr			@ Point to instruction
+		mov	r1, sp			@ Point to registers
+		mov	r2, #0x400
+		mov	lr, pc
+		bl	do_excpt
+		b	ret_from_exception
+
+Laddrexcptn_not_user:
+		save_svc_regs
+		and	r2, lr, #3
+		teq	r2, #3
+		bne	Laddrexcptn_illegal_mode
+		teqp	pc, #MODE_SVC26
+		mask_pc	r0, lr
+		mov	r1, sp
+		orr	r2, r2, #0x400
+		bl	do_excpt
+		ldmia	sp, {r0 - lr}		@ I cant remember the reason I changed this...
+		add	sp, sp, #15*4
+		movs	pc, lr
+
+Laddrexcptn_illegal_mode:
+		mov	r0, sp
+		str	lr, [sp, #-4]!
+		orr	r1, r2, #PSR_I_BIT | PSR_F_BIT
+		teqp	r1, #0			@ change into mode (wont be user mode)
+		mov	r0, r0
+		mov	r1, r8			@ Any register from r8 - r14 can be banked
+		mov	r2, r9
+		mov	r3, r10
+		mov	r4, r11
+		mov	r5, r12
+		mov	r6, r13
+		mov	r7, r14
+		teqp	pc, #PSR_F_BIT | MODE_SVC26 @ back to svc
+		mov	r0, r0
+		stmfd	sp!, {r1-r7}
+		ldmia	r0, {r0-r7}
+		stmfd	sp!, {r0-r7}
+		mov	r0, sp
+		mov	r1, #BAD_ADDREXCPTN
+		b	bad_mode
+
+/*=============================================================================
+ * Interrupt (IRQ) handler
+ *-----------------------------------------------------------------------------
+ * Note: if the IRQ was taken whilst in user mode, then *no* kernel routine
+ * is running, so do not have to save svc lr.
+ *
+ * Entered in IRQ mode.
+ */
+
+vector_IRQ:	ldr     sp, .LCirq         @ Setup some temporary stack
+                sub     lr, lr, #4
+                str     lr, [sp]           @ push return address
+
+		tst     lr, #3
+		bne	__irq_non_usr
+
+__irq_usr:	teqp	pc, #PSR_I_BIT | MODE_SVC26     @ Enter SVC mode
+		mov	r0, r0
+
+		ldr	lr, .LCirq
+		ldr	lr, [lr]           @ Restore lr for jump back to USR
+
+		save_user_regs
+
+		handle_irq
+
+		mov	why, #0
+		get_thread_info tsk
+		b	ret_to_user
+
+@ Place the IRQ priority table here so that the handle_irq macros above
+@ and below here can access it.
+
+		irq_prio_table
+
+__irq_non_usr:	teqp	pc, #PSR_I_BIT | MODE_SVC26     @ Enter SVC mode
+		mov	r0, r0
+
+		save_svc_regs_irq
+
+                and	r2, lr, #3
+		teq	r2, #3
+		bne	__irq_invalid                @ IRQ not from SVC mode
+
+		handle_irq
+
+		restore_svc_regs
+
+__irq_invalid:	mov	r0, sp
+		mov	r1, #BAD_IRQ
+		b	bad_mode
+
+/*=============================================================================
+ * Data abort handler code
+ *-----------------------------------------------------------------------------
+ *
+ * This handles both exceptions from user and SVC modes, computes the address
+ *  range of the problem, and does any correction that is required.  It then
+ *  calls the kernel data abort routine.
+ *
+ * This is where I wish that the ARM would tell you which address aborted.
+ */
+
+vector_data:	sub	lr, lr, #8		@ Correct lr
+		tst	lr, #3
+		bne	Ldata_not_user
+		save_user_regs
+		teqp	pc, #MODE_SVC26
+		mask_pc	r0, lr
+		bl	Ldata_do
+		b	ret_from_exception
+
+Ldata_not_user:
+		save_svc_regs
+		and	r2, lr, #3
+		teq	r2, #3
+		bne	Ldata_illegal_mode
+		tst	lr, #PSR_I_BIT
+		teqeqp	pc, #MODE_SVC26
+		mask_pc	r0, lr
+		bl	Ldata_do
+		restore_svc_regs
+
+Ldata_illegal_mode:
+		mov	r0, sp
+		mov	r1, #BAD_DATA
+		b	bad_mode
+
+Ldata_do:	mov	r3, sp
+		ldr	r4, [r0]		@ Get instruction
+		mov	r2, #0
+		tst	r4, #1 << 20		@ Check to see if it is a write instruction
+		orreq	r2, r2, #FAULT_CODE_WRITE @ Indicate write instruction
+		mov	r1, r4, lsr #22		@ Now branch to the relevent processing routine
+		and	r1, r1, #15 << 2
+		add	pc, pc, r1
+		movs	pc, lr
+		b	Ldata_unknown
+		b	Ldata_unknown
+		b	Ldata_unknown
+		b	Ldata_unknown
+		b	Ldata_ldrstr_post	@ ldr	rd, [rn], #m
+		b	Ldata_ldrstr_numindex	@ ldr	rd, [rn, #m]	@ RegVal
+		b	Ldata_ldrstr_post	@ ldr	rd, [rn], rm
+		b	Ldata_ldrstr_regindex	@ ldr	rd, [rn, rm]
+		b	Ldata_ldmstm		@ ldm*a	rn, <rlist>
+		b	Ldata_ldmstm		@ ldm*b	rn, <rlist>
+		b	Ldata_unknown
+		b	Ldata_unknown
+		b	Ldata_ldrstr_post	@ ldc	rd, [rn], #m	@ Same as ldr	rd, [rn], #m
+		b	Ldata_ldcstc_pre	@ ldc	rd, [rn, #m]
+		b	Ldata_unknown
+Ldata_unknown:	@ Part of jumptable
+		mov	r0, r1
+		mov	r1, r4
+		mov	r2, r3
+		b	baddataabort
+
+Ldata_ldrstr_post:
+		mov	r0, r4, lsr #14		@ Get Rn
+		and	r0, r0, #15 << 2	@ Mask out reg.
+		teq	r0, #15 << 2
+		ldr	r0, [r3, r0]		@ Get register
+		biceq	r0, r0, #PCMASK
+		mov	r1, r0
+#ifdef FAULT_CODE_LDRSTRPOST
+		orr	r2, r2, #FAULT_CODE_LDRSTRPOST
+#endif
+		b	do_DataAbort
+
+Ldata_ldrstr_numindex:
+		mov	r0, r4, lsr #14		@ Get Rn
+		and	r0, r0, #15 << 2	@ Mask out reg.
+		teq	r0, #15 << 2
+		ldr	r0, [r3, r0]		@ Get register
+		mov	r1, r4, lsl #20
+		biceq	r0, r0, #PCMASK
+		tst	r4, #1 << 23
+		addne	r0, r0, r1, lsr #20
+		subeq	r0, r0, r1, lsr #20
+		mov	r1, r0
+#ifdef FAULT_CODE_LDRSTRPRE
+		orr	r2, r2, #FAULT_CODE_LDRSTRPRE
+#endif
+		b	do_DataAbort
+
+Ldata_ldrstr_regindex:
+		mov	r0, r4, lsr #14		@ Get Rn
+		and	r0, r0, #15 << 2	@ Mask out reg.
+		teq	r0, #15 << 2
+		ldr	r0, [r3, r0]		@ Get register
+		and	r7, r4, #15
+		biceq	r0, r0, #PCMASK
+		teq	r7, #15			@ Check for PC
+		ldr	r7, [r3, r7, lsl #2]	@ Get Rm
+		and	r8, r4, #0x60		@ Get shift types
+		biceq	r7, r7, #PCMASK
+		mov	r9, r4, lsr #7		@ Get shift amount
+		and	r9, r9, #31
+		teq	r8, #0
+		moveq	r7, r7, lsl r9
+		teq	r8, #0x20		@ LSR shift
+		moveq	r7, r7, lsr r9
+		teq	r8, #0x40		@ ASR shift
+		moveq	r7, r7, asr r9
+		teq	r8, #0x60		@ ROR shift
+		moveq	r7, r7, ror r9
+		tst	r4, #1 << 23
+		addne	r0, r0, r7
+		subeq	r0, r0, r7		@ Apply correction
+		mov	r1, r0
+#ifdef FAULT_CODE_LDRSTRREG
+		orr	r2, r2, #FAULT_CODE_LDRSTRREG
+#endif
+		b	do_DataAbort
+
+Ldata_ldmstm:
+		mov	r7, #0x11
+		orr	r7, r7, r7, lsl #8
+		and	r0, r4, r7
+		and	r1, r4, r7, lsl #1
+		add	r0, r0, r1, lsr #1
+		and	r1, r4, r7, lsl #2
+		add	r0, r0, r1, lsr #2
+		and	r1, r4, r7, lsl #3
+		add	r0, r0, r1, lsr #3
+		add	r0, r0, r0, lsr #8
+		add	r0, r0, r0, lsr #4
+		and	r7, r0, #15		@ r7 = no. of registers to transfer.
+		mov	r5, r4, lsr #14		@ Get Rn
+		and	r5, r5, #15 << 2
+		ldr	r0, [r3, r5]		@ Get reg
+		eor	r6, r4, r4, lsl #2
+		tst	r6, #1 << 23		@ Check inc/dec ^ writeback
+		rsbeq	r7, r7, #0
+		add	r7, r0, r7, lsl #2	@ Do correction (signed)
+		subne	r1, r7, #1
+		subeq	r1, r0, #1
+		moveq	r0, r7
+		tst	r4, #1 << 21		@ Check writeback
+		strne	r7, [r3, r5]
+		eor	r6, r4, r4, lsl #1
+		tst	r6, #1 << 24		@ Check Pre/Post ^ inc/dec
+		addeq	r0, r0, #4
+		addeq	r1, r1, #4
+		teq	r5, #15*4		@ CHECK FOR PC
+		biceq	r1, r1, #PCMASK
+		biceq	r0, r0, #PCMASK
+#ifdef FAULT_CODE_LDMSTM
+		orr	r2, r2, #FAULT_CODE_LDMSTM
+#endif
+		b	do_DataAbort
+
+Ldata_ldcstc_pre:
+		mov	r0, r4, lsr #14		@ Get Rn
+		and	r0, r0, #15 << 2	@ Mask out reg.
+		teq	r0, #15 << 2
+		ldr	r0, [r3, r0]		@ Get register
+		mov	r1, r4, lsl #24		@ Get offset
+		biceq	r0, r0, #PCMASK
+		tst	r4, #1 << 23
+		addne	r0, r0, r1, lsr #24
+		subeq	r0, r0, r1, lsr #24
+		mov	r1, r0
+#ifdef FAULT_CODE_LDCSTC
+		orr	r2, r2, #FAULT_CODE_LDCSTC
+#endif
+		b	do_DataAbort
+
+
+/*
+ * This is the return code to user mode for abort handlers
+ */
+ENTRY(ret_from_exception)
+		get_thread_info tsk
+		mov	why, #0
+		b	ret_to_user
+
+		.data
+ENTRY(fp_enter)
+		.word	fpe_not_present
+		.text
+/*
+ * Register switch for older 26-bit only ARMs
+ */
+ENTRY(__switch_to)
+		add	r0, r0, #TI_CPU_SAVE
+		stmia	r0, {r4 - sl, fp, sp, lr}
+		add	r1, r1, #TI_CPU_SAVE
+		ldmia	r1, {r4 - sl, fp, sp, pc}^
+
+/*
+ *=============================================================================
+ *		Low-level interface code
+ *-----------------------------------------------------------------------------
+ *		Trap initialisation
+ *-----------------------------------------------------------------------------
+ *
+ * Note - FIQ code has changed.  The default is a couple of words in 0x1c, 0x20
+ * that call _unexp_fiq.  Nowever, we now copy the FIQ routine to 0x1c (removes
+ * some excess cycles).
+ *
+ * What we need to put into 0-0x1c are branches to branch to the kernel.
+ */
+
+		.section ".init.text",#alloc,#execinstr
+
+.Ljump_addresses:
+		swi	SYS_ERROR0
+		.word	vector_undefinstr	- 12
+		.word	vector_swi		- 16
+		.word	vector_prefetch		- 20
+		.word	vector_data		- 24
+		.word	vector_addrexcptn	- 28
+		.word	vector_IRQ		- 32
+		.word	_unexp_fiq		- 36
+		b	. + 8
+/*
+ * initialise the trap system
+ */
+ENTRY(__trap_init)
+		stmfd	sp!, {r4 - r7, lr}
+		adr	r1, .Ljump_addresses
+		ldmia	r1, {r1 - r7, ip, lr}
+		orr	r2, lr, r2, lsr #2
+		orr	r3, lr, r3, lsr #2
+		orr	r4, lr, r4, lsr #2
+		orr	r5, lr, r5, lsr #2
+		orr	r6, lr, r6, lsr #2
+		orr	r7, lr, r7, lsr #2
+		orr	ip, lr, ip, lsr #2
+		mov	r0, #0
+		stmia	r0, {r1 - r7, ip}
+		ldmfd	sp!, {r4 - r7, pc}^
+
+		.bss
+__temp_irq:	.space	4				@ saved lr_irq
+__temp_fiq:	.space	128
diff --git a/arch/arm26/kernel/fiq.c b/arch/arm26/kernel/fiq.c
new file mode 100644
index 0000000..08a97c9
--- /dev/null
+++ b/arch/arm26/kernel/fiq.c
@@ -0,0 +1,202 @@
+/*
+ *  linux/arch/arm26/kernel/fiq.c
+ *
+ *  Copyright (C) 1998 Russell King
+ *  Copyright (C) 1998, 1999 Phil Blundell
+ *  Copyright (C) 2003 Ian Molton
+ *
+ *  FIQ support written by Philip Blundell <philb@gnu.org>, 1998.
+ *
+ *  FIQ support re-written by Russell King to be more generic
+ *
+ * We now properly support a method by which the FIQ handlers can
+ * be stacked onto the vector.  We still do not support sharing
+ * the FIQ vector itself.
+ *
+ * Operation is as follows:
+ *  1. Owner A claims FIQ:
+ *     - default_fiq relinquishes control.
+ *  2. Owner A:
+ *     - inserts code.
+ *     - sets any registers,
+ *     - enables FIQ.
+ *  3. Owner B claims FIQ:
+ *     - if owner A has a relinquish function.
+ *       - disable FIQs.
+ *       - saves any registers.
+ *       - returns zero.
+ *  4. Owner B:
+ *     - inserts code.
+ *     - sets any registers,
+ *     - enables FIQ.
+ *  5. Owner B releases FIQ:
+ *     - Owner A is asked to reacquire FIQ:
+ *	 - inserts code.
+ *	 - restores saved registers.
+ *	 - enables FIQ.
+ *  6. Goto 3
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/init.h>
+#include <linux/seq_file.h>
+
+#include <asm/fiq.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pgalloc.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#define FIQ_VECTOR (vectors_base() + 0x1c)
+
+static unsigned long no_fiq_insn;
+
+#define unprotect_page_0()
+#define protect_page_0()
+
+/* Default reacquire function
+ * - we always relinquish FIQ control
+ * - we always reacquire FIQ control
+ */
+static int fiq_def_op(void *ref, int relinquish)
+{
+	if (!relinquish) {
+		unprotect_page_0();
+		*(unsigned long *)FIQ_VECTOR = no_fiq_insn;
+		protect_page_0();
+	}
+
+	return 0;
+}
+
+static struct fiq_handler default_owner = {
+	.name	= "default",
+	.fiq_op = fiq_def_op,
+};
+
+static struct fiq_handler *current_fiq = &default_owner;
+
+int show_fiq_list(struct seq_file *p, void *v)
+{
+	if (current_fiq != &default_owner)
+		seq_printf(p, "FIQ:              %s\n", current_fiq->name);
+
+	return 0;
+}
+
+void set_fiq_handler(void *start, unsigned int length)
+{
+	unprotect_page_0();
+
+	memcpy((void *)FIQ_VECTOR, start, length);
+
+	protect_page_0();
+}
+
+/*
+ * Taking an interrupt in FIQ mode is death, so both these functions
+ * disable irqs for the duration. 
+ */
+void set_fiq_regs(struct pt_regs *regs)
+{
+	register unsigned long tmp, tmp2;
+	__asm__ volatile (
+	"mov	%0, pc
+	bic	%1, %0, #0x3
+	orr	%1, %1, %3
+	teqp	%1, #0		@ select FIQ mode
+	mov	r0, r0
+	ldmia	%2, {r8 - r14}
+	teqp	%0, #0		@ return to SVC mode
+	mov	r0, r0"
+	: "=&r" (tmp), "=&r" (tmp2)
+	: "r" (&regs->ARM_r8), "I" (PSR_I_BIT | PSR_F_BIT | MODE_FIQ26)
+	/* These registers aren't modified by the above code in a way
+	   visible to the compiler, but we mark them as clobbers anyway
+	   so that GCC won't put any of the input or output operands in
+	   them.  */
+	: "r8", "r9", "r10", "r11", "r12", "r13", "r14");
+}
+
+void get_fiq_regs(struct pt_regs *regs)
+{
+	register unsigned long tmp, tmp2;
+	__asm__ volatile (
+	"mov	%0, pc
+	bic	%1, %0, #0x3
+	orr	%1, %1, %3
+	teqp	%1, #0		@ select FIQ mode
+	mov	r0, r0
+	stmia	%2, {r8 - r14}
+	teqp	%0, #0		@ return to SVC mode
+	mov	r0, r0"
+	: "=&r" (tmp), "=&r" (tmp2)
+	: "r" (&regs->ARM_r8), "I" (PSR_I_BIT | PSR_F_BIT | MODE_FIQ26)
+	/* These registers aren't modified by the above code in a way
+	   visible to the compiler, but we mark them as clobbers anyway
+	   so that GCC won't put any of the input or output operands in
+	   them.  */
+	: "r8", "r9", "r10", "r11", "r12", "r13", "r14");
+}
+
+int claim_fiq(struct fiq_handler *f)
+{
+	int ret = 0;
+
+	if (current_fiq) {
+		ret = -EBUSY;
+
+		if (current_fiq->fiq_op != NULL)
+			ret = current_fiq->fiq_op(current_fiq->dev_id, 1);
+	}
+
+	if (!ret) {
+		f->next = current_fiq;
+		current_fiq = f;
+	}
+
+	return ret;
+}
+
+void release_fiq(struct fiq_handler *f)
+{
+	if (current_fiq != f) {
+		printk(KERN_ERR "%s FIQ trying to release %s FIQ\n",
+		       f->name, current_fiq->name);
+#ifdef CONFIG_DEBUG_ERRORS
+		__backtrace();
+#endif
+		return;
+	}
+
+	do
+		current_fiq = current_fiq->next;
+	while (current_fiq->fiq_op(current_fiq->dev_id, 0));
+}
+
+void enable_fiq(int fiq)
+{
+	enable_irq(fiq + FIQ_START);
+}
+
+void disable_fiq(int fiq)
+{
+	disable_irq(fiq + FIQ_START);
+}
+
+EXPORT_SYMBOL(set_fiq_handler);
+EXPORT_SYMBOL(set_fiq_regs);
+EXPORT_SYMBOL(get_fiq_regs);
+EXPORT_SYMBOL(claim_fiq);
+EXPORT_SYMBOL(release_fiq);
+EXPORT_SYMBOL(enable_fiq);
+EXPORT_SYMBOL(disable_fiq);
+
+void __init init_FIQ(void)
+{
+	no_fiq_insn = *(unsigned long *)FIQ_VECTOR;
+	set_fs(get_fs());
+}
diff --git a/arch/arm26/kernel/head.S b/arch/arm26/kernel/head.S
new file mode 100644
index 0000000..8bfc625
--- /dev/null
+++ b/arch/arm26/kernel/head.S
@@ -0,0 +1,113 @@
+/*
+ *  linux/arch/arm26/kernel/head.S
+ *
+ *  Copyright (C) 1994-2000 Russell King
+ *  Copyright (C) 2003 Ian Molton
+ *
+ * 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.
+ *
+ *  26-bit kernel startup code
+ */
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <asm/mach-types.h>
+
+		.globl	swapper_pg_dir
+		.equ	swapper_pg_dir,	0x0207d000
+
+/*
+ * Entry point.
+ */
+		.section ".init.text",#alloc,#execinstr
+ENTRY(stext)
+
+__entry:
+		cmp	pc, #0x02000000
+		ldrlt	pc, LC0			@ if 0x01800000, call at 0x02080000
+		teq	r0, #0                  @ Check for old calling method
+		blne	oldparams		@ Move page if old
+
+		adr	r0, LC0
+		ldmib	r0, {r2-r5, sp}		@ Setup stack (and fetch other values)
+
+		mov	r0, #0			@ Clear BSS
+1:		cmp	r2, r3
+		strcc	r0, [r2], #4
+		bcc	1b
+
+		bl	detect_proc_type
+		str	r0, [r4]
+		bl	detect_arch_type
+		str	r0, [r5]
+
+#ifdef CONFIG_XIP_KERNEL
+               ldr     r3, ETEXT                       @ data section copy
+               ldr     r4, SDATA
+               ldr     r5, EDATA
+1:
+               ldr     r6, [r3], #4
+               str     r6, [r4], #4
+               cmp     r4, r5
+               blt     1b
+#endif
+		mov	fp, #0
+		b	start_kernel
+
+LC0:		.word	_stext
+		.word	__bss_start		@ r2
+		.word	_end			@ r3
+		.word	processor_id		@ r4
+		.word	__machine_arch_type	@ r5
+		.word	init_thread_union+8192	@ sp
+#ifdef CONFIG_XIP_KERNEL
+ETEXT:		.word   _endtext
+SDATA:		.word   _sdata
+EDATA:		.word   __bss_start
+#endif
+
+arm2_id:	.long	0x41560200  @ ARM2 and 250 dont have a CPUID
+arm250_id:	.long	0x41560250  @ So we create some after probing for them
+		.align
+
+oldparams:	mov     r4, #0x02000000
+		add	r3, r4, #0x00080000
+		add	r4, r4, #0x0007c000
+1:		ldmia	r0!, {r5 - r12}
+		stmia	r4!, {r5 - r12}
+		cmp	r4, r3
+		blt	1b
+		mov	pc, lr
+
+/*
+ * We need some way to automatically detect the difference between
+ * these two machines.  Unfortunately, it is not possible to detect
+ * the presence of the SuperIO chip, because that will hang the old
+ * Archimedes machines solid.
+ */
+/* DAG: Outdated, these have been combined !!!!!!! */
+detect_arch_type:
+#if defined(CONFIG_ARCH_ARC)
+		mov	r0, #MACH_TYPE_ARCHIMEDES
+#elif defined(CONFIG_ARCH_A5K)
+		mov	r0, #MACH_TYPE_A5K
+#endif
+		mov	pc, lr
+
+detect_proc_type:
+		mov	ip, lr
+		mov	r2, #0xea000000		@ Point undef instr to continuation
+		adr	r0, continue - 12
+		orr	r0, r2, r0, lsr #2
+		mov	r1, #0
+		str	r0, [r1, #4]
+		ldr	r0, arm2_id
+		swp	r2, r2, [r1]		@ check for swp (ARM2 cant)
+		ldr	r0, arm250_id
+		mrc	15, 0, r3, c0, c0	@ check for CP#15 (ARM250 cant)
+		mov	r0, r3
+continue:	mov	r2, #0xeb000000		@ Make undef vector loop
+		sub	r2, r2, #2
+		str	r2, [r1, #4]
+		mov	pc, ip
diff --git a/arch/arm26/kernel/init_task.c b/arch/arm26/kernel/init_task.c
new file mode 100644
index 0000000..4191565
--- /dev/null
+++ b/arch/arm26/kernel/init_task.c
@@ -0,0 +1,49 @@
+/*
+ *  linux/arch/arm26/kernel/init_task.c
+ *
+ * Copyright (C) 2003 Ian Molton
+ *
+ */
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/init_task.h>
+#include <linux/mqueue.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+
+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);
+
+/*
+ * Initial thread structure.
+ *
+ * We need to make sure that this is 8192-byte aligned due to the
+ * way process stacks are handled. This is done by making sure
+ * the linker maps this in the .text segment right after head.S,
+ * and making the linker scripts ensure the proper alignment.
+ *
+ * FIXME - should this be 32K alignment on arm26?
+ *
+ * The things we do for performance...
+ */
+union thread_union init_thread_union
+	__attribute__((__section__(".init.task"))) =
+		{ INIT_THREAD_INFO(init_task) };
+
+/*
+ * Initial task structure.
+ *
+ * All other task structs will be allocated on slabs in fork.c
+ */
+struct task_struct init_task = INIT_TASK(init_task);
+
+EXPORT_SYMBOL(init_task);
diff --git a/arch/arm26/kernel/irq.c b/arch/arm26/kernel/irq.c
new file mode 100644
index 0000000..f3cc103
--- /dev/null
+++ b/arch/arm26/kernel/irq.c
@@ -0,0 +1,716 @@
+/*
+ *  linux/arch/arm/kernel/irq.c
+ *
+ *  Copyright (C) 1992 Linus Torvalds
+ *  Modifications for ARM processor Copyright (C) 1995-2000 Russell King.
+ *  'Borrowed' for ARM26 and (C) 2003 Ian Molton.
+ *
+ * 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.
+ *
+ *  This file contains the code used by various IRQ handling routines:
+ *  asking for different IRQ's should be done through these routines
+ *  instead of just grabbing them. Thus setups with different IRQ numbers
+ *  shouldn't result in any weird surprises, and installing new handlers
+ *  should be easier.
+ *
+ *  IRQ's are in fact implemented a bit like signal handlers for the kernel.
+ *  Naturally it's not a 1:1 relation, but there are similarities.
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/ptrace.h>
+#include <linux/kernel_stat.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/smp.h>
+#include <linux/init.h>
+#include <linux/seq_file.h>
+#include <linux/errno.h>
+
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/irqchip.h>
+
+//FIXME - this ought to be in a header IMO
+void __init arc_init_irq(void);
+
+/*
+ * Maximum IRQ count.  Currently, this is arbitary.  However, it should
+ * not be set too low to prevent false triggering.  Conversely, if it
+ * is set too high, then you could miss a stuck IRQ.
+ *
+ * FIXME Maybe we ought to set a timer and re-enable the IRQ at a later time?
+ */
+#define MAX_IRQ_CNT	100000
+
+static volatile unsigned long irq_err_count;
+static DEFINE_SPINLOCK(irq_controller_lock);
+
+struct irqdesc irq_desc[NR_IRQS];
+
+/*
+ * Dummy mask/unmask handler
+ */
+void dummy_mask_unmask_irq(unsigned int irq)
+{
+}
+
+void do_bad_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
+{
+	irq_err_count += 1;
+	printk(KERN_ERR "IRQ: spurious interrupt %d\n", irq);
+}
+
+static struct irqchip bad_chip = {
+	.ack	= dummy_mask_unmask_irq,
+	.mask	= dummy_mask_unmask_irq,
+	.unmask = dummy_mask_unmask_irq,
+};
+
+static struct irqdesc bad_irq_desc = {
+	.chip	= &bad_chip,
+	.handle = do_bad_IRQ,
+	.depth	= 1,
+};
+
+/**
+ *	disable_irq - disable an irq and wait for completion
+ *	@irq: Interrupt to disable
+ *
+ *	Disable the selected interrupt line.  We do this lazily.
+ *
+ *	This function may be called from IRQ context.
+ */
+void disable_irq(unsigned int irq)
+{
+	struct irqdesc *desc = irq_desc + irq;
+	unsigned long flags;
+	spin_lock_irqsave(&irq_controller_lock, flags);
+	if (!desc->depth++)
+		desc->enabled = 0;
+	spin_unlock_irqrestore(&irq_controller_lock, flags);
+}
+
+/**
+ *	enable_irq - enable interrupt handling on an irq
+ *	@irq: Interrupt to enable
+ *
+ *	Re-enables the processing of interrupts on this IRQ line.
+ *	Note that this may call the interrupt handler, so you may
+ *	get unexpected results if you hold IRQs disabled.
+ *
+ *	This function may be called from IRQ context.
+ */
+void enable_irq(unsigned int irq)
+{
+	struct irqdesc *desc = irq_desc + irq;
+	unsigned long flags;
+	int pending = 0;
+
+	spin_lock_irqsave(&irq_controller_lock, flags);
+	if (unlikely(!desc->depth)) {
+		printk("enable_irq(%u) unbalanced from %p\n", irq,
+			__builtin_return_address(0)); //FIXME bum addresses reported - why?
+	} else if (!--desc->depth) {
+		desc->probing = 0;
+		desc->enabled = 1;
+		desc->chip->unmask(irq);
+		pending = desc->pending;
+		desc->pending = 0;
+		/*
+		 * If the interrupt was waiting to be processed,
+		 * retrigger it.
+		 */
+		if (pending)
+			desc->chip->rerun(irq);
+	}
+	spin_unlock_irqrestore(&irq_controller_lock, flags);
+}
+
+int show_interrupts(struct seq_file *p, void *v)
+{
+	int i = *(loff_t *) v;
+	struct irqaction * action;
+
+	if (i < NR_IRQS) {
+	    	action = irq_desc[i].action;
+		if (!action)
+			continue;
+		seq_printf(p, "%3d: %10u ", i, kstat_irqs(i));
+		seq_printf(p, "  %s", action->name);
+		for (action = action->next; action; action = action->next) {
+			seq_printf(p, ", %s", action->name);
+		}
+		seq_putc(p, '\n');
+	} else if (i == NR_IRQS) {
+		show_fiq_list(p, v);
+		seq_printf(p, "Err: %10lu\n", irq_err_count);
+	}
+	return 0;
+}
+
+/*
+ * IRQ lock detection.
+ *
+ * Hopefully, this should get us out of a few locked situations.
+ * However, it may take a while for this to happen, since we need
+ * a large number if IRQs to appear in the same jiffie with the
+ * same instruction pointer (or within 2 instructions).
+ */
+static int check_irq_lock(struct irqdesc *desc, int irq, struct pt_regs *regs)
+{
+	unsigned long instr_ptr = instruction_pointer(regs);
+
+	if (desc->lck_jif == jiffies &&
+	    desc->lck_pc >= instr_ptr && desc->lck_pc < instr_ptr + 8) {
+		desc->lck_cnt += 1;
+
+		if (desc->lck_cnt > MAX_IRQ_CNT) {
+			printk(KERN_ERR "IRQ LOCK: IRQ%d is locking the system, disabled\n", irq);
+			return 1;
+		}
+	} else {
+		desc->lck_cnt = 0;
+		desc->lck_pc  = instruction_pointer(regs);
+		desc->lck_jif = jiffies;
+	}
+	return 0;
+}
+
+static void
+__do_irq(unsigned int irq, struct irqaction *action, struct pt_regs *regs)
+{
+	unsigned int status;
+	int ret;
+
+	spin_unlock(&irq_controller_lock);
+	if (!(action->flags & SA_INTERRUPT))
+		local_irq_enable();
+
+	status = 0;
+	do {
+		ret = action->handler(irq, action->dev_id, regs);
+		if (ret == IRQ_HANDLED)
+			status |= action->flags;
+		action = action->next;
+	} while (action);
+
+	if (status & SA_SAMPLE_RANDOM)
+		add_interrupt_randomness(irq);
+
+	spin_lock_irq(&irq_controller_lock);
+}
+
+/*
+ * This is for software-decoded IRQs.  The caller is expected to
+ * handle the ack, clear, mask and unmask issues.
+ */
+void
+do_simple_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
+{
+	struct irqaction *action;
+	const int cpu = smp_processor_id();
+
+	desc->triggered = 1;
+
+	kstat_cpu(cpu).irqs[irq]++;
+
+	action = desc->action;
+	if (action)
+		__do_irq(irq, desc->action, regs);
+}
+
+/*
+ * Most edge-triggered IRQ implementations seem to take a broken
+ * approach to this.  Hence the complexity.
+ */
+void
+do_edge_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
+{
+	const int cpu = smp_processor_id();
+
+	desc->triggered = 1;
+
+	/*
+	 * If we're currently running this IRQ, or its disabled,
+	 * we shouldn't process the IRQ.  Instead, turn on the
+	 * hardware masks.
+	 */
+	if (unlikely(desc->running || !desc->enabled))
+		goto running;
+
+	/*
+	 * Acknowledge and clear the IRQ, but don't mask it.
+	 */
+	desc->chip->ack(irq);
+
+	/*
+	 * Mark the IRQ currently in progress.
+	 */
+	desc->running = 1;
+
+	kstat_cpu(cpu).irqs[irq]++;
+
+	do {
+		struct irqaction *action;
+
+		action = desc->action;
+		if (!action)
+			break;
+
+		if (desc->pending && desc->enabled) {
+			desc->pending = 0;
+			desc->chip->unmask(irq);
+		}
+
+		__do_irq(irq, action, regs);
+	} while (desc->pending);
+
+	desc->running = 0;
+
+	/*
+	 * If we were disabled or freed, shut down the handler.
+	 */
+	if (likely(desc->action && !check_irq_lock(desc, irq, regs)))
+		return;
+
+ running:
+	/*
+	 * We got another IRQ while this one was masked or
+	 * currently running.  Delay it.
+	 */
+	desc->pending = 1;
+	desc->chip->mask(irq);
+	desc->chip->ack(irq);
+}
+
+/*
+ * Level-based IRQ handler.  Nice and simple.
+ */
+void
+do_level_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
+{
+	struct irqaction *action;
+	const int cpu = smp_processor_id();
+
+	desc->triggered = 1;
+
+	/*
+	 * Acknowledge, clear _AND_ disable the interrupt.
+	 */
+	desc->chip->ack(irq);
+
+	if (likely(desc->enabled)) {
+		kstat_cpu(cpu).irqs[irq]++;
+
+		/*
+		 * Return with this interrupt masked if no action
+		 */
+		action = desc->action;
+		if (action) {
+			__do_irq(irq, desc->action, regs);
+
+			if (likely(desc->enabled &&
+				   !check_irq_lock(desc, irq, regs)))
+				desc->chip->unmask(irq);
+		}
+	}
+}
+
+/*
+ * do_IRQ handles all hardware IRQ's.  Decoded IRQs should not
+ * come via this function.  Instead, they should provide their
+ * own 'handler'
+ */
+asmlinkage void asm_do_IRQ(int irq, struct pt_regs *regs)
+{
+	struct irqdesc *desc = irq_desc + irq;
+
+	/*
+	 * Some hardware gives randomly wrong interrupts.  Rather
+	 * than crashing, do something sensible.
+	 */
+	if (irq >= NR_IRQS)
+		desc = &bad_irq_desc;
+
+	irq_enter();
+	spin_lock(&irq_controller_lock);
+	desc->handle(irq, desc, regs);
+	spin_unlock(&irq_controller_lock);
+	irq_exit();
+}
+
+void __set_irq_handler(unsigned int irq, irq_handler_t handle, int is_chained)
+{
+	struct irqdesc *desc;
+	unsigned long flags;
+
+	if (irq >= NR_IRQS) {
+		printk(KERN_ERR "Trying to install handler for IRQ%d\n", irq);
+		return;
+	}
+
+	if (handle == NULL)
+		handle = do_bad_IRQ;
+
+	desc = irq_desc + irq;
+
+	if (is_chained && desc->chip == &bad_chip)
+		printk(KERN_WARNING "Trying to install chained handler for IRQ%d\n", irq);
+
+	spin_lock_irqsave(&irq_controller_lock, flags);
+	if (handle == do_bad_IRQ) {
+		desc->chip->mask(irq);
+		desc->chip->ack(irq);
+		desc->depth = 1;
+		desc->enabled = 0;
+	}
+	desc->handle = handle;
+	if (handle != do_bad_IRQ && is_chained) {
+		desc->valid = 0;
+		desc->probe_ok = 0;
+		desc->depth = 0;
+		desc->chip->unmask(irq);
+	}
+	spin_unlock_irqrestore(&irq_controller_lock, flags);
+}
+
+void set_irq_chip(unsigned int irq, struct irqchip *chip)
+{
+	struct irqdesc *desc;
+	unsigned long flags;
+
+	if (irq >= NR_IRQS) {
+		printk(KERN_ERR "Trying to install chip for IRQ%d\n", irq);
+		return;
+	}
+
+	if (chip == NULL)
+		chip = &bad_chip;
+
+	desc = irq_desc + irq;
+	spin_lock_irqsave(&irq_controller_lock, flags);
+	desc->chip = chip;
+	spin_unlock_irqrestore(&irq_controller_lock, flags);
+}
+
+int set_irq_type(unsigned int irq, unsigned int type)
+{
+	struct irqdesc *desc;
+	unsigned long flags;
+	int ret = -ENXIO;
+
+	if (irq >= NR_IRQS) {
+		printk(KERN_ERR "Trying to set irq type for IRQ%d\n", irq);
+		return -ENODEV;
+	}
+
+	desc = irq_desc + irq;
+	if (desc->chip->type) {
+		spin_lock_irqsave(&irq_controller_lock, flags);
+		ret = desc->chip->type(irq, type);
+		spin_unlock_irqrestore(&irq_controller_lock, flags);
+	}
+
+	return ret;
+}
+
+void set_irq_flags(unsigned int irq, unsigned int iflags)
+{
+	struct irqdesc *desc;
+	unsigned long flags;
+
+	if (irq >= NR_IRQS) {
+		printk(KERN_ERR "Trying to set irq flags for IRQ%d\n", irq);
+		return;
+	}
+
+	desc = irq_desc + irq;
+	spin_lock_irqsave(&irq_controller_lock, flags);
+	desc->valid = (iflags & IRQF_VALID) != 0;
+	desc->probe_ok = (iflags & IRQF_PROBE) != 0;
+	desc->noautoenable = (iflags & IRQF_NOAUTOEN) != 0;
+	spin_unlock_irqrestore(&irq_controller_lock, flags);
+}
+
+int setup_irq(unsigned int irq, struct irqaction *new)
+{
+	int shared = 0;
+	struct irqaction *old, **p;
+	unsigned long flags;
+	struct irqdesc *desc;
+
+	/*
+	 * Some drivers like serial.c use request_irq() heavily,
+	 * so we have to be careful not to interfere with a
+	 * running system.
+	 */
+	if (new->flags & SA_SAMPLE_RANDOM) {
+		/*
+		 * This function might sleep, we want to call it first,
+		 * outside of the atomic block.
+		 * Yes, this might clear the entropy pool if the wrong
+		 * driver is attempted to be loaded, without actually
+		 * installing a new handler, but is this really a problem,
+		 * only the sysadmin is able to do this.
+		 */
+	        rand_initialize_irq(irq);
+	}
+
+	/*
+	 * The following block of code has to be executed atomically
+	 */
+	desc = irq_desc + irq;
+	spin_lock_irqsave(&irq_controller_lock, flags);
+	p = &desc->action;
+	if ((old = *p) != NULL) {
+		/* Can't share interrupts unless both agree to */
+		if (!(old->flags & new->flags & SA_SHIRQ)) {
+			spin_unlock_irqrestore(&irq_controller_lock, flags);
+			return -EBUSY;
+		}
+
+		/* add new interrupt at end of irq queue */
+		do {
+			p = &old->next;
+			old = *p;
+		} while (old);
+		shared = 1;
+	}
+
+	*p = new;
+
+	if (!shared) {
+ 		desc->probing = 0;
+		desc->running = 0;
+		desc->pending = 0;
+		desc->depth = 1;
+		if (!desc->noautoenable) {
+			desc->depth = 0;
+			desc->enabled = 1;
+			desc->chip->unmask(irq);
+		}
+	}
+
+	spin_unlock_irqrestore(&irq_controller_lock, flags);
+	return 0;
+}
+
+/**
+ *	request_irq - allocate an interrupt line
+ *	@irq: Interrupt line to allocate
+ *	@handler: Function to be called when the IRQ occurs
+ *	@irqflags: Interrupt type flags
+ *	@devname: An ascii name for the claiming device
+ *	@dev_id: A cookie passed back to the handler function
+ *
+ *	This call allocates interrupt resources and enables the
+ *	interrupt line and IRQ handling. From the point this
+ *	call is made your handler function may be invoked. Since
+ *	your handler function must clear any interrupt the board
+ *	raises, you must take care both to initialise your hardware
+ *	and to set up the interrupt handler in the right order.
+ *
+ *	Dev_id must be globally unique. Normally the address of the
+ *	device data structure is used as the cookie. Since the handler
+ *	receives this value it makes sense to use it.
+ *
+ *	If your interrupt is shared you must pass a non NULL dev_id
+ *	as this is required when freeing the interrupt.
+ *
+ *	Flags:
+ *
+ *	SA_SHIRQ		Interrupt is shared
+ *
+ *	SA_INTERRUPT		Disable local interrupts while processing
+ *
+ *	SA_SAMPLE_RANDOM	The interrupt can be used for entropy
+ *
+ */
+
+//FIXME - handler used to return void - whats the significance of the change?
+int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *),
+		 unsigned long irq_flags, const char * devname, void *dev_id)
+{
+	unsigned long retval;
+	struct irqaction *action;
+
+	if (irq >= NR_IRQS || !irq_desc[irq].valid || !handler ||
+	    (irq_flags & SA_SHIRQ && !dev_id))
+		return -EINVAL;
+
+	action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
+	if (!action)
+		return -ENOMEM;
+
+	action->handler = handler;
+	action->flags = irq_flags;
+	cpus_clear(action->mask);
+	action->name = devname;
+	action->next = NULL;
+	action->dev_id = dev_id;
+
+	retval = setup_irq(irq, action);
+
+	if (retval)
+		kfree(action);
+	return retval;
+}
+
+EXPORT_SYMBOL(request_irq);
+
+/**
+ *	free_irq - free an interrupt
+ *	@irq: Interrupt line to free
+ *	@dev_id: Device identity to free
+ *
+ *	Remove an interrupt handler. The handler is removed and if the
+ *	interrupt line is no longer in use by any driver it is disabled.
+ *	On a shared IRQ the caller must ensure the interrupt is disabled
+ *	on the card it drives before calling this function.
+ *
+ *	This function may be called from interrupt context.
+ */
+void free_irq(unsigned int irq, void *dev_id)
+{
+	struct irqaction * action, **p;
+	unsigned long flags;
+
+	if (irq >= NR_IRQS || !irq_desc[irq].valid) {
+		printk(KERN_ERR "Trying to free IRQ%d\n",irq);
+#ifdef CONFIG_DEBUG_ERRORS
+		__backtrace();
+#endif
+		return;
+	}
+
+	spin_lock_irqsave(&irq_controller_lock, flags);
+	for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next) {
+		if (action->dev_id != dev_id)
+			continue;
+
+	    	/* Found it - now free it */
+		*p = action->next;
+		kfree(action);
+		goto out;
+	}
+	printk(KERN_ERR "Trying to free free IRQ%d\n",irq);
+#ifdef CONFIG_DEBUG_ERRORS
+	__backtrace();
+#endif
+out:
+	spin_unlock_irqrestore(&irq_controller_lock, flags);
+}
+
+EXPORT_SYMBOL(free_irq);
+
+/* Start the interrupt probing.  Unlike other architectures,
+ * we don't return a mask of interrupts from probe_irq_on,
+ * but return the number of interrupts enabled for the probe.
+ * The interrupts which have been enabled for probing is
+ * instead recorded in the irq_desc structure.
+ */
+unsigned long probe_irq_on(void)
+{
+	unsigned int i, irqs = 0;
+	unsigned long delay;
+
+	/*
+	 * first snaffle up any unassigned but
+	 * probe-able interrupts
+	 */
+	spin_lock_irq(&irq_controller_lock);
+	for (i = 0; i < NR_IRQS; i++) {
+		if (!irq_desc[i].probe_ok || irq_desc[i].action)
+			continue;
+
+		irq_desc[i].probing = 1;
+		irq_desc[i].triggered = 0;
+		if (irq_desc[i].chip->type)
+			irq_desc[i].chip->type(i, IRQT_PROBE);
+		irq_desc[i].chip->unmask(i);
+		irqs += 1;
+	}
+	spin_unlock_irq(&irq_controller_lock);
+
+	/*
+	 * wait for spurious interrupts to mask themselves out again
+	 */
+	for (delay = jiffies + HZ/10; time_before(jiffies, delay); )
+		/* min 100ms delay */;
+
+	/*
+	 * now filter out any obviously spurious interrupts
+	 */
+	spin_lock_irq(&irq_controller_lock);
+	for (i = 0; i < NR_IRQS; i++) {
+		if (irq_desc[i].probing && irq_desc[i].triggered) {
+			irq_desc[i].probing = 0;
+			irqs -= 1;
+		}
+	}
+	spin_unlock_irq(&irq_controller_lock);
+
+	return irqs;
+}
+
+EXPORT_SYMBOL(probe_irq_on);
+
+/*
+ * Possible return values:
+ *  >= 0 - interrupt number
+ *    -1 - no interrupt/many interrupts
+ */
+int probe_irq_off(unsigned long irqs)
+{
+	unsigned int i;
+	int irq_found = NO_IRQ;
+
+	/*
+	 * look at the interrupts, and find exactly one
+	 * that we were probing has been triggered
+	 */
+	spin_lock_irq(&irq_controller_lock);
+	for (i = 0; i < NR_IRQS; i++) {
+		if (irq_desc[i].probing &&
+		    irq_desc[i].triggered) {
+			if (irq_found != NO_IRQ) {
+				irq_found = NO_IRQ;
+				goto out;
+			}
+			irq_found = i;
+		}
+	}
+
+	if (irq_found == -1)
+		irq_found = NO_IRQ;
+out:
+	spin_unlock_irq(&irq_controller_lock);
+
+	return irq_found;
+}
+
+EXPORT_SYMBOL(probe_irq_off);
+
+void __init init_irq_proc(void)
+{
+}
+
+void __init init_IRQ(void)
+{
+	struct irqdesc *desc;
+	extern void init_dma(void);
+	int irq;
+
+	for (irq = 0, desc = irq_desc; irq < NR_IRQS; irq++, desc++)
+		*desc = bad_irq_desc;
+
+	arc_init_irq();
+	init_dma();
+}
diff --git a/arch/arm26/kernel/process.c b/arch/arm26/kernel/process.c
new file mode 100644
index 0000000..46aea6a
--- /dev/null
+++ b/arch/arm26/kernel/process.c
@@ -0,0 +1,401 @@
+/*
+ *  linux/arch/arm26/kernel/process.c
+ *
+ *  Copyright (C) 2003 Ian Molton - adapted for ARM26
+ *  Copyright (C) 1996-2000 Russell King - Converted to ARM.
+ *  Origional Copyright (C) 1995  Linus Torvalds
+ *
+ * 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.
+ */
+#include <stdarg.h>
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/delay.h>
+#include <linux/reboot.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/leds.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+
+extern const char *processor_modes[];
+extern void setup_mm_for_reboot(char mode);
+
+static volatile int hlt_counter;
+
+void disable_hlt(void)
+{
+	hlt_counter++;
+}
+
+EXPORT_SYMBOL(disable_hlt);
+
+void enable_hlt(void)
+{
+	hlt_counter--;
+}
+
+EXPORT_SYMBOL(enable_hlt);
+
+static int __init nohlt_setup(char *__unused)
+{
+	hlt_counter = 1;
+	return 1;
+}
+
+static int __init hlt_setup(char *__unused)
+{
+	hlt_counter = 0;
+	return 1;
+}
+
+__setup("nohlt", nohlt_setup);
+__setup("hlt", hlt_setup);
+
+/*
+ * This is our default idle handler.  We need to disable
+ * interrupts here to ensure we don't miss a wakeup call.
+ */
+void cpu_idle(void)
+{
+	/* endless idle loop with no priority at all */
+	preempt_disable();
+	while (1) {
+		while (!need_resched()) {
+			local_irq_disable();
+			if (!need_resched() && !hlt_counter)
+				local_irq_enable();
+		}
+	}
+	schedule();
+}
+
+static char reboot_mode = 'h';
+
+int __init reboot_setup(char *str)
+{
+	reboot_mode = str[0];
+	return 1;
+}
+
+__setup("reboot=", reboot_setup);
+
+/* ARM26 cant do these but we still need to define them. */
+void machine_halt(void)
+{
+}
+void machine_power_off(void)
+{
+}
+
+EXPORT_SYMBOL(machine_halt);
+EXPORT_SYMBOL(machine_power_off);
+
+void machine_restart(char * __unused)
+{
+	/*
+	 * Clean and disable cache, and turn off interrupts
+	 */
+	cpu_proc_fin();
+
+	/*
+	 * Tell the mm system that we are going to reboot -
+	 * we may need it to insert some 1:1 mappings so that
+	 * soft boot works.
+	 */
+	setup_mm_for_reboot(reboot_mode);
+
+	/*
+         * copy branch instruction to reset location and call it
+         */
+
+        *(unsigned long *)0 = *(unsigned long *)0x03800000;
+        ((void(*)(void))0)();
+
+	/*
+	 * Whoops - the architecture was unable to reboot.
+	 * Tell the user! Should never happen...
+	 */
+	mdelay(1000);
+	printk("Reboot failed -- System halted\n");
+	while (1);
+}
+
+EXPORT_SYMBOL(machine_restart);
+
+void show_regs(struct pt_regs * regs)
+{
+	unsigned long flags;
+
+	flags = condition_codes(regs);
+
+	printk("pc : [<%08lx>]    lr : [<%08lx>]    %s\n"
+	       "sp : %08lx  ip : %08lx  fp : %08lx\n",
+		instruction_pointer(regs),
+		regs->ARM_lr, print_tainted(), regs->ARM_sp,
+		regs->ARM_ip, regs->ARM_fp);
+	printk("r10: %08lx  r9 : %08lx  r8 : %08lx\n",
+		regs->ARM_r10, regs->ARM_r9,
+		regs->ARM_r8);
+	printk("r7 : %08lx  r6 : %08lx  r5 : %08lx  r4 : %08lx\n",
+		regs->ARM_r7, regs->ARM_r6,
+		regs->ARM_r5, regs->ARM_r4);
+	printk("r3 : %08lx  r2 : %08lx  r1 : %08lx  r0 : %08lx\n",
+		regs->ARM_r3, regs->ARM_r2,
+		regs->ARM_r1, regs->ARM_r0);
+	printk("Flags: %c%c%c%c",
+		flags & PSR_N_BIT ? 'N' : 'n',
+		flags & PSR_Z_BIT ? 'Z' : 'z',
+		flags & PSR_C_BIT ? 'C' : 'c',
+		flags & PSR_V_BIT ? 'V' : 'v');
+	printk("  IRQs o%s  FIQs o%s  Mode %s  Segment %s\n",
+		interrupts_enabled(regs) ? "n" : "ff",
+		fast_interrupts_enabled(regs) ? "n" : "ff",
+		processor_modes[processor_mode(regs)],
+		get_fs() == get_ds() ? "kernel" : "user");
+}
+
+void show_fpregs(struct user_fp *regs)
+{
+	int i;
+
+	for (i = 0; i < 8; i++) {
+		unsigned long *p;
+		char type;
+
+		p = (unsigned long *)(regs->fpregs + i);
+
+		switch (regs->ftype[i]) {
+			case 1: type = 'f'; break;
+			case 2: type = 'd'; break;
+			case 3: type = 'e'; break;
+			default: type = '?'; break;
+		}
+		if (regs->init_flag)
+			type = '?';
+
+		printk("  f%d(%c): %08lx %08lx %08lx%c",
+			i, type, p[0], p[1], p[2], i & 1 ? '\n' : ' ');
+	}
+			
+
+	printk("FPSR: %08lx FPCR: %08lx\n",
+		(unsigned long)regs->fpsr,
+		(unsigned long)regs->fpcr);
+}
+
+/*
+ * Task structure and kernel stack allocation.
+ */
+static unsigned long *thread_info_head;
+static unsigned int nr_thread_info;
+
+extern unsigned long get_page_8k(int priority);
+extern void free_page_8k(unsigned long page);
+
+// FIXME - is this valid?
+#define EXTRA_TASK_STRUCT	0
+#define ll_alloc_task_struct()	((struct thread_info *)get_page_8k(GFP_KERNEL))
+#define ll_free_task_struct(p)  free_page_8k((unsigned long)(p))
+
+//FIXME - do we use *task param below looks like we dont, which is ok?
+//FIXME - if EXTRA_TASK_STRUCT is zero we can optimise the below away permanently. *IF* its supposed to be zero.
+struct thread_info *alloc_thread_info(struct task_struct *task)
+{
+	struct thread_info *thread = NULL;
+
+	if (EXTRA_TASK_STRUCT) {
+		unsigned long *p = thread_info_head;
+
+		if (p) {
+			thread_info_head = (unsigned long *)p[0];
+			nr_thread_info -= 1;
+		}
+		thread = (struct thread_info *)p;
+	}
+
+	if (!thread)
+		thread = ll_alloc_task_struct();
+
+#ifdef CONFIG_MAGIC_SYSRQ
+	/*
+	 * The stack must be cleared if you want SYSRQ-T to
+	 * give sensible stack usage information
+	 */
+	if (thread) {
+		char *p = (char *)thread;
+		memzero(p+KERNEL_STACK_SIZE, KERNEL_STACK_SIZE);
+	}
+#endif
+	return thread;
+}
+
+void free_thread_info(struct thread_info *thread)
+{
+	if (EXTRA_TASK_STRUCT && nr_thread_info < EXTRA_TASK_STRUCT) {
+		unsigned long *p = (unsigned long *)thread;
+		p[0] = (unsigned long)thread_info_head;
+		thread_info_head = p;
+		nr_thread_info += 1;
+	} else
+		ll_free_task_struct(thread);
+}
+
+/*
+ * Free current thread data structures etc..
+ */
+void exit_thread(void)
+{
+}
+
+void flush_thread(void)
+{
+	struct thread_info *thread = current_thread_info();
+	struct task_struct *tsk = current;
+
+	memset(&tsk->thread.debug, 0, sizeof(struct debug_info));
+	memset(&thread->fpstate, 0, sizeof(union fp_state));
+
+	clear_used_math();
+}
+
+void release_thread(struct task_struct *dead_task)
+{
+}
+
+asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
+
+int
+copy_thread(int nr, unsigned long clone_flags, unsigned long stack_start,
+	    unsigned long unused, struct task_struct *p, struct pt_regs *regs)
+{
+	struct thread_info *thread = p->thread_info;
+	struct pt_regs *childregs;
+
+	childregs = __get_user_regs(thread);
+	*childregs = *regs;
+	childregs->ARM_r0 = 0;
+	childregs->ARM_sp = stack_start;
+
+	memset(&thread->cpu_context, 0, sizeof(struct cpu_context_save));
+	thread->cpu_context.sp = (unsigned long)childregs;
+	thread->cpu_context.pc = (unsigned long)ret_from_fork | MODE_SVC26 | PSR_I_BIT;
+
+	return 0;
+}
+
+/*
+ * fill in the fpe structure for a core dump...
+ */
+int dump_fpu (struct pt_regs *regs, struct user_fp *fp)
+{
+	struct thread_info *thread = current_thread_info();
+	int used_math = !!used_math();
+
+	if (used_math)
+		memcpy(fp, &thread->fpstate.soft, sizeof (*fp));
+
+	return used_math;
+}
+
+/*
+ * fill in the user structure for a core dump..
+ */
+void dump_thread(struct pt_regs * regs, struct user * dump)
+{
+	struct task_struct *tsk = current;
+
+	dump->magic = CMAGIC;
+	dump->start_code = tsk->mm->start_code;
+	dump->start_stack = regs->ARM_sp & ~(PAGE_SIZE - 1);
+
+	dump->u_tsize = (tsk->mm->end_code - tsk->mm->start_code) >> PAGE_SHIFT;
+	dump->u_dsize = (tsk->mm->brk - tsk->mm->start_data + PAGE_SIZE - 1) >> PAGE_SHIFT;
+	dump->u_ssize = 0;
+
+	dump->u_debugreg[0] = tsk->thread.debug.bp[0].address;
+	dump->u_debugreg[1] = tsk->thread.debug.bp[1].address;
+	dump->u_debugreg[2] = tsk->thread.debug.bp[0].insn;
+	dump->u_debugreg[3] = tsk->thread.debug.bp[1].insn;
+	dump->u_debugreg[4] = tsk->thread.debug.nsaved;
+
+	if (dump->start_stack < 0x04000000)
+		dump->u_ssize = (0x04000000 - dump->start_stack) >> PAGE_SHIFT;
+
+	dump->regs = *regs;
+	dump->u_fpvalid = dump_fpu (regs, &dump->u_fp);
+}
+
+/*
+ * Shuffle the argument into the correct register before calling the
+ * thread function.  r1 is the thread argument, r2 is the pointer to
+ * the thread function, and r3 points to the exit function.
+ * FIXME - make sure this is right - the older code used to zero fp
+ * and cause the parent to call sys_exit (do_exit in this version)
+ */
+extern void kernel_thread_helper(void);
+
+asm(    ".section .text\n"
+"       .align\n"
+"       .type   kernel_thread_helper, #function\n"
+"kernel_thread_helper:\n"
+"       mov     r0, r1\n"
+"       mov     lr, r3\n"
+"       mov     pc, r2\n"
+"       .size   kernel_thread_helper, . - kernel_thread_helper\n"
+"       .previous");
+
+/*
+ * Create a kernel thread.
+ */
+pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
+{
+        struct pt_regs regs;
+
+        memset(&regs, 0, sizeof(regs));
+
+        regs.ARM_r1 = (unsigned long)arg;
+        regs.ARM_r2 = (unsigned long)fn;
+        regs.ARM_r3 = (unsigned long)do_exit;
+        regs.ARM_pc = (unsigned long)kernel_thread_helper | MODE_SVC26;
+
+        return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
+}
+EXPORT_SYMBOL(kernel_thread);
+
+
+unsigned long get_wchan(struct task_struct *p)
+{
+	unsigned long fp, lr;
+	unsigned long stack_page;
+	int count = 0;
+	if (!p || p == current || p->state == TASK_RUNNING)
+		return 0;
+
+	stack_page = 4096 + (unsigned long)p;
+	fp = thread_saved_fp(p);
+	do {
+		if (fp < stack_page || fp > 4092+stack_page)
+			return 0;
+		lr = pc_pointer (((unsigned long *)fp)[-1]);
+		if (!in_sched_functions(lr))
+			return lr;
+		fp = *(unsigned long *) (fp - 12);
+	} while (count ++ < 16);
+	return 0;
+}
diff --git a/arch/arm26/kernel/ptrace.c b/arch/arm26/kernel/ptrace.c
new file mode 100644
index 0000000..2a13714
--- /dev/null
+++ b/arch/arm26/kernel/ptrace.c
@@ -0,0 +1,744 @@
+/*
+ *  linux/arch/arm26/kernel/ptrace.c
+ *
+ *  By Ross Biro 1/23/92
+ * edited by Linus Torvalds
+ * ARM modifications Copyright (C) 2000 Russell King
+ *
+ * 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.
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+#include <linux/security.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+//#include <asm/processor.h>
+
+#include "ptrace.h"
+
+#define REG_PC	15
+#define REG_PSR 15
+/*
+ * does not yet catch signals sent when the child dies.
+ * in exit.c or in signal.c.
+ */
+
+/*
+ * Breakpoint SWI instruction: SWI &9F0001
+ */
+#define BREAKINST_ARM	0xef9f0001
+
+/*
+ * Get the address of the live pt_regs for the specified task.
+ * These are saved onto the top kernel stack when the process
+ * is not running.
+ *
+ * Note: if a user thread is execve'd from kernel space, the
+ * kernel stack will not be empty on entry to the kernel, so
+ * ptracing these tasks will fail.
+ */
+static inline struct pt_regs *
+get_user_regs(struct task_struct *task)
+{
+	return __get_user_regs(task->thread_info);
+}
+
+/*
+ * this routine will get a word off of the processes privileged stack.
+ * the offset is how far from the base addr as stored in the THREAD.
+ * this routine assumes that all the privileged stacks are in our
+ * data space.
+ */
+static inline long get_user_reg(struct task_struct *task, int offset)
+{
+	return get_user_regs(task)->uregs[offset];
+}
+
+/*
+ * this routine will put a word on the processes privileged stack.
+ * the offset is how far from the base addr as stored in the THREAD.
+ * this routine assumes that all the privileged stacks are in our
+ * data space.
+ */
+static inline int
+put_user_reg(struct task_struct *task, int offset, long data)
+{
+	struct pt_regs newregs, *regs = get_user_regs(task);
+	int ret = -EINVAL;
+
+	newregs = *regs;
+	newregs.uregs[offset] = data;
+
+	if (valid_user_regs(&newregs)) {
+		regs->uregs[offset] = data;
+		ret = 0;
+	}
+
+	return ret;
+}
+
+static inline int
+read_u32(struct task_struct *task, unsigned long addr, u32 *res)
+{
+	int ret;
+
+	ret = access_process_vm(task, addr, res, sizeof(*res), 0);
+
+	return ret == sizeof(*res) ? 0 : -EIO;
+}
+
+static inline int
+read_instr(struct task_struct *task, unsigned long addr, u32 *res)
+{
+	int ret;
+	u32 val;
+	ret = access_process_vm(task, addr & ~3, &val, sizeof(val), 0);
+	ret = ret == sizeof(val) ? 0 : -EIO;
+	*res = val;
+	return ret;
+}
+
+/*
+ * Get value of register `rn' (in the instruction)
+ */
+static unsigned long
+ptrace_getrn(struct task_struct *child, unsigned long insn)
+{
+	unsigned int reg = (insn >> 16) & 15;
+	unsigned long val;
+
+	val = get_user_reg(child, reg);
+	if (reg == 15)
+		val = pc_pointer(val + 8); //FIXME - correct for arm26?
+
+	return val;
+}
+
+/*
+ * Get value of operand 2 (in an ALU instruction)
+ */
+static unsigned long
+ptrace_getaluop2(struct task_struct *child, unsigned long insn)
+{
+	unsigned long val;
+	int shift;
+	int type;
+
+	if (insn & 1 << 25) {
+		val = insn & 255;
+		shift = (insn >> 8) & 15;
+		type = 3;
+	} else {
+		val = get_user_reg (child, insn & 15);
+
+		if (insn & (1 << 4))
+			shift = (int)get_user_reg (child, (insn >> 8) & 15);
+		else
+			shift = (insn >> 7) & 31;
+
+		type = (insn >> 5) & 3;
+	}
+
+	switch (type) {
+	case 0:	val <<= shift;	break;
+	case 1:	val >>= shift;	break;
+	case 2:
+		val = (((signed long)val) >> shift);
+		break;
+	case 3:
+ 		val = (val >> shift) | (val << (32 - shift));
+		break;
+	}
+	return val;
+}
+
+/*
+ * Get value of operand 2 (in a LDR instruction)
+ */
+static unsigned long
+ptrace_getldrop2(struct task_struct *child, unsigned long insn)
+{
+	unsigned long val;
+	int shift;
+	int type;
+
+	val = get_user_reg(child, insn & 15);
+	shift = (insn >> 7) & 31;
+	type = (insn >> 5) & 3;
+
+	switch (type) {
+	case 0:	val <<= shift;	break;
+	case 1:	val >>= shift;	break;
+	case 2:
+		val = (((signed long)val) >> shift);
+		break;
+	case 3:
+ 		val = (val >> shift) | (val << (32 - shift));
+		break;
+	}
+	return val;
+}
+
+#define OP_MASK	0x01e00000
+#define OP_AND	0x00000000
+#define OP_EOR	0x00200000
+#define OP_SUB	0x00400000
+#define OP_RSB	0x00600000
+#define OP_ADD	0x00800000
+#define OP_ADC	0x00a00000
+#define OP_SBC	0x00c00000
+#define OP_RSC	0x00e00000
+#define OP_ORR	0x01800000
+#define OP_MOV	0x01a00000
+#define OP_BIC	0x01c00000
+#define OP_MVN	0x01e00000
+
+static unsigned long
+get_branch_address(struct task_struct *child, unsigned long pc, unsigned long insn)
+{
+	u32 alt = 0;
+
+	switch (insn & 0x0e000000) {
+	case 0x00000000:
+	case 0x02000000: {
+		/*
+		 * data processing
+		 */
+		long aluop1, aluop2, ccbit;
+
+		if ((insn & 0xf000) != 0xf000)
+			break;
+
+		aluop1 = ptrace_getrn(child, insn);
+		aluop2 = ptrace_getaluop2(child, insn);
+		ccbit  = get_user_reg(child, REG_PSR) & PSR_C_BIT ? 1 : 0;
+
+		switch (insn & OP_MASK) {
+		case OP_AND: alt = aluop1 & aluop2;		break;
+		case OP_EOR: alt = aluop1 ^ aluop2;		break;
+		case OP_SUB: alt = aluop1 - aluop2;		break;
+		case OP_RSB: alt = aluop2 - aluop1;		break;
+		case OP_ADD: alt = aluop1 + aluop2;		break;
+		case OP_ADC: alt = aluop1 + aluop2 + ccbit;	break;
+		case OP_SBC: alt = aluop1 - aluop2 + ccbit;	break;
+		case OP_RSC: alt = aluop2 - aluop1 + ccbit;	break;
+		case OP_ORR: alt = aluop1 | aluop2;		break;
+		case OP_MOV: alt = aluop2;			break;
+		case OP_BIC: alt = aluop1 & ~aluop2;		break;
+		case OP_MVN: alt = ~aluop2;			break;
+		}
+		break;
+	}
+
+	case 0x04000000:
+	case 0x06000000:
+		/*
+		 * ldr
+		 */
+		if ((insn & 0x0010f000) == 0x0010f000) {
+			unsigned long base;
+
+			base = ptrace_getrn(child, insn);
+			if (insn & 1 << 24) {
+				long aluop2;
+
+				if (insn & 0x02000000)
+					aluop2 = ptrace_getldrop2(child, insn);
+				else
+					aluop2 = insn & 0xfff;
+
+				if (insn & 1 << 23)
+					base += aluop2;
+				else
+					base -= aluop2;
+			}
+			if (read_u32(child, base, &alt) == 0)
+				alt = pc_pointer(alt);
+		}
+		break;
+
+	case 0x08000000:
+		/*
+		 * ldm
+		 */
+		if ((insn & 0x00108000) == 0x00108000) {
+			unsigned long base;
+			unsigned int nr_regs;
+
+			if (insn & (1 << 23)) {
+				nr_regs = hweight16(insn & 65535) << 2;
+
+				if (!(insn & (1 << 24)))
+					nr_regs -= 4;
+			} else {
+				if (insn & (1 << 24))
+					nr_regs = -4;
+				else
+					nr_regs = 0;
+			}
+
+			base = ptrace_getrn(child, insn);
+
+			if (read_u32(child, base + nr_regs, &alt) == 0)
+				alt = pc_pointer(alt);
+			break;
+		}
+		break;
+
+	case 0x0a000000: {
+		/*
+		 * bl or b
+		 */
+		signed long displ;
+		/* It's a branch/branch link: instead of trying to
+		 * figure out whether the branch will be taken or not,
+		 * we'll put a breakpoint at both locations.  This is
+		 * simpler, more reliable, and probably not a whole lot
+		 * slower than the alternative approach of emulating the
+		 * branch.
+		 */
+		displ = (insn & 0x00ffffff) << 8;
+		displ = (displ >> 6) + 8;
+		if (displ != 0 && displ != 4)
+			alt = pc + displ;
+	    }
+	    break;
+	}
+
+	return alt;
+}
+
+static int
+swap_insn(struct task_struct *task, unsigned long addr,
+	  void *old_insn, void *new_insn, int size)
+{
+	int ret;
+
+	ret = access_process_vm(task, addr, old_insn, size, 0);
+	if (ret == size)
+		ret = access_process_vm(task, addr, new_insn, size, 1);
+	return ret;
+}
+
+static void
+add_breakpoint(struct task_struct *task, struct debug_info *dbg, unsigned long addr)
+{
+	int nr = dbg->nsaved;
+
+	if (nr < 2) {
+		u32 new_insn = BREAKINST_ARM;
+		int res;
+
+		res = swap_insn(task, addr, &dbg->bp[nr].insn, &new_insn, 4);
+
+		if (res == 4) {
+			dbg->bp[nr].address = addr;
+			dbg->nsaved += 1;
+		}
+	} else
+		printk(KERN_ERR "ptrace: too many breakpoints\n");
+}
+
+/*
+ * Clear one breakpoint in the user program.  We copy what the hardware
+ * does and use bit 0 of the address to indicate whether this is a Thumb
+ * breakpoint or an ARM breakpoint.
+ */
+static void clear_breakpoint(struct task_struct *task, struct debug_entry *bp)
+{
+	unsigned long addr = bp->address;
+	u32 old_insn;
+	int ret;
+
+	ret = swap_insn(task, addr & ~3, &old_insn,
+			&bp->insn, 4);
+
+	if (ret != 4 || old_insn != BREAKINST_ARM)
+		printk(KERN_ERR "%s:%d: corrupted ARM breakpoint at "
+			"0x%08lx (0x%08x)\n", task->comm, task->pid,
+			addr, old_insn);
+}
+
+void ptrace_set_bpt(struct task_struct *child)
+{
+	struct pt_regs *regs;
+	unsigned long pc;
+	u32 insn;
+	int res;
+
+	regs = get_user_regs(child);
+	pc = instruction_pointer(regs);
+
+	res = read_instr(child, pc, &insn);
+	if (!res) {
+		struct debug_info *dbg = &child->thread.debug;
+		unsigned long alt;
+
+		dbg->nsaved = 0;
+
+		alt = get_branch_address(child, pc, insn);
+		if (alt)
+			add_breakpoint(child, dbg, alt);
+
+		/*
+		 * Note that we ignore the result of setting the above
+		 * breakpoint since it may fail.  When it does, this is
+		 * not so much an error, but a forewarning that we may
+		 * be receiving a prefetch abort shortly.
+		 *
+		 * If we don't set this breakpoint here, then we can
+		 * lose control of the thread during single stepping.
+		 */
+		if (!alt || predicate(insn) != PREDICATE_ALWAYS)
+			add_breakpoint(child, dbg, pc + 4);
+	}
+}
+
+/*
+ * Ensure no single-step breakpoint is pending.  Returns non-zero
+ * value if child was being single-stepped.
+ */
+void ptrace_cancel_bpt(struct task_struct *child)
+{
+	int i, nsaved = child->thread.debug.nsaved;
+
+	child->thread.debug.nsaved = 0;
+
+	if (nsaved > 2) {
+		printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved);
+		nsaved = 2;
+	}
+
+	for (i = 0; i < nsaved; i++)
+		clear_breakpoint(child, &child->thread.debug.bp[i]);
+}
+
+/*
+ * Called by kernel/ptrace.c when detaching..
+ *
+ * Make sure the single step bit is not set.
+ */
+void ptrace_disable(struct task_struct *child)
+{
+	child->ptrace &= ~PT_SINGLESTEP;
+	ptrace_cancel_bpt(child);
+}
+
+/*
+ * Handle hitting a breakpoint.
+ */
+void ptrace_break(struct task_struct *tsk, struct pt_regs *regs)
+{
+	siginfo_t info;
+
+	/*
+	 * The PC is always left pointing at the next instruction.  Fix this.
+	 */
+	regs->ARM_pc -= 4;
+
+	if (tsk->thread.debug.nsaved == 0)
+		printk(KERN_ERR "ptrace: bogus breakpoint trap\n");
+
+	ptrace_cancel_bpt(tsk);
+
+	info.si_signo = SIGTRAP;
+	info.si_errno = 0;
+	info.si_code  = TRAP_BRKPT;
+	info.si_addr  = (void *)instruction_pointer(regs) - 4;
+
+	force_sig_info(SIGTRAP, &info, tsk);
+}
+
+/*
+ * Read the word at offset "off" into the "struct user".  We
+ * actually access the pt_regs stored on the kernel stack.
+ */
+static int ptrace_read_user(struct task_struct *tsk, unsigned long off,
+			    unsigned long *ret)
+{
+	unsigned long tmp;
+
+	if (off & 3 || off >= sizeof(struct user))
+		return -EIO;
+
+	tmp = 0;
+	if (off < sizeof(struct pt_regs))
+		tmp = get_user_reg(tsk, off >> 2);
+
+	return put_user(tmp, ret);
+}
+
+/*
+ * Write the word at offset "off" into "struct user".  We
+ * actually access the pt_regs stored on the kernel stack.
+ */
+static int ptrace_write_user(struct task_struct *tsk, unsigned long off,
+			     unsigned long val)
+{
+	if (off & 3 || off >= sizeof(struct user))
+		return -EIO;
+
+	if (off >= sizeof(struct pt_regs))
+		return 0;
+
+	return put_user_reg(tsk, off >> 2, val);
+}
+
+/*
+ * Get all user integer registers.
+ */
+static int ptrace_getregs(struct task_struct *tsk, void *uregs)
+{
+	struct pt_regs *regs = get_user_regs(tsk);
+
+	return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0;
+}
+
+/*
+ * Set all user integer registers.
+ */
+static int ptrace_setregs(struct task_struct *tsk, void *uregs)
+{
+	struct pt_regs newregs;
+	int ret;
+
+	ret = -EFAULT;
+	if (copy_from_user(&newregs, uregs, sizeof(struct pt_regs)) == 0) {
+		struct pt_regs *regs = get_user_regs(tsk);
+
+		ret = -EINVAL;
+		if (valid_user_regs(&newregs)) {
+			*regs = newregs;
+			ret = 0;
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * Get the child FPU state.
+ */
+static int ptrace_getfpregs(struct task_struct *tsk, void *ufp)
+{
+	return copy_to_user(ufp, &tsk->thread_info->fpstate,
+			    sizeof(struct user_fp)) ? -EFAULT : 0;
+}
+
+/*
+ * Set the child FPU state.
+ */
+static int ptrace_setfpregs(struct task_struct *tsk, void *ufp)
+{
+	set_stopped_child_used_math(tsk);
+	return copy_from_user(&tsk->thread_info->fpstate, ufp,
+			      sizeof(struct user_fp)) ? -EFAULT : 0;
+}
+
+static int do_ptrace(int request, struct task_struct *child, long addr, long data)
+{
+	unsigned long tmp;
+	int ret;
+
+	switch (request) {
+		/*
+		 * read word at location "addr" in the child process.
+		 */
+		case PTRACE_PEEKTEXT:
+		case PTRACE_PEEKDATA:
+			ret = access_process_vm(child, addr, &tmp,
+						sizeof(unsigned long), 0);
+			if (ret == sizeof(unsigned long))
+				ret = put_user(tmp, (unsigned long *) data);
+			else
+				ret = -EIO;
+			break;
+
+		case PTRACE_PEEKUSR:
+			ret = ptrace_read_user(child, addr, (unsigned long *)data);
+			break;
+
+		/*
+		 * write the word at location addr.
+		 */
+		case PTRACE_POKETEXT:
+		case PTRACE_POKEDATA:
+			ret = access_process_vm(child, addr, &data,
+						sizeof(unsigned long), 1);
+			if (ret == sizeof(unsigned long))
+				ret = 0;
+			else
+				ret = -EIO;
+			break;
+
+		case PTRACE_POKEUSR:
+			ret = ptrace_write_user(child, addr, data);
+			break;
+
+		/*
+		 * continue/restart and stop at next (return from) syscall
+		 */
+		case PTRACE_SYSCALL:
+		case PTRACE_CONT:
+			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 single-step breakpoint is gone. */
+			child->ptrace &= ~PT_SINGLESTEP;
+			ptrace_cancel_bpt(child);
+			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:
+			/* make sure single-step breakpoint is gone. */
+			child->ptrace &= ~PT_SINGLESTEP;
+			ptrace_cancel_bpt(child);
+			if (child->exit_state != EXIT_ZOMBIE) {
+				child->exit_code = SIGKILL;
+				wake_up_process(child);
+			}
+			ret = 0;
+			break;
+
+		/*
+		 * execute single instruction.
+		 */
+		case PTRACE_SINGLESTEP:
+			ret = -EIO;
+			if ((unsigned long) data > _NSIG)
+				break;
+			child->ptrace |= PT_SINGLESTEP;
+			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+			child->exit_code = data;
+			/* give it a chance to run. */
+			wake_up_process(child);
+			ret = 0;
+			break;
+
+		case PTRACE_DETACH:
+			ret = ptrace_detach(child, data);
+			break;
+
+		case PTRACE_GETREGS:
+			ret = ptrace_getregs(child, (void *)data);
+			break;
+
+		case PTRACE_SETREGS:
+			ret = ptrace_setregs(child, (void *)data);
+			break;
+
+		case PTRACE_GETFPREGS:
+			ret = ptrace_getfpregs(child, (void *)data);
+			break;
+		
+		case PTRACE_SETFPREGS:
+			ret = ptrace_setfpregs(child, (void *)data);
+			break;
+
+		default:
+			ret = ptrace_request(child, request, addr, data);
+			break;
+	}
+
+	return ret;
+}
+
+asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
+{
+	struct task_struct *child;
+	int ret;
+
+	lock_kernel();
+	ret = -EPERM;
+	if (request == PTRACE_TRACEME) {
+		/* are we already being traced? */
+		if (current->ptrace & PT_PTRACED)
+			goto out;
+		ret = security_ptrace(current->parent, current);
+		if (ret)
+			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_tsk;
+
+	if (request == PTRACE_ATTACH) {
+		ret = ptrace_attach(child);
+		goto out_tsk;
+	}
+	ret = ptrace_check_attach(child, request == PTRACE_KILL);
+	if (ret == 0)
+		ret = do_ptrace(request, child, addr, data);
+
+out_tsk:
+	put_task_struct(child);
+out:
+	unlock_kernel();
+	return ret;
+}
+
+asmlinkage void syscall_trace(int why, struct pt_regs *regs)
+{
+	unsigned long ip;
+
+	if (!test_thread_flag(TIF_SYSCALL_TRACE))
+		return;
+	if (!(current->ptrace & PT_PTRACED))
+		return;
+
+	/*
+	 * Save IP.  IP is used to denote syscall entry/exit:
+	 *  IP = 0 -> entry, = 1 -> exit
+	 */
+	ip = regs->ARM_ip;
+	regs->ARM_ip = why;
+
+	/* 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;
+	}
+	regs->ARM_ip = ip;
+}
diff --git a/arch/arm26/kernel/ptrace.h b/arch/arm26/kernel/ptrace.h
new file mode 100644
index 0000000..846c9d8
--- /dev/null
+++ b/arch/arm26/kernel/ptrace.h
@@ -0,0 +1,13 @@
+/*
+ *  linux/arch/arm26/kernel/ptrace.h
+ *
+ *  Copyright (C) 2000-2003 Russell King
+ *  Copyright (C) 2003 Ian Molton
+ *
+ * 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.
+ */
+extern void ptrace_cancel_bpt(struct task_struct *);
+extern void ptrace_set_bpt(struct task_struct *);
+extern void ptrace_break(struct task_struct *, struct pt_regs *);
diff --git a/arch/arm26/kernel/semaphore.c b/arch/arm26/kernel/semaphore.c
new file mode 100644
index 0000000..3023a53
--- /dev/null
+++ b/arch/arm26/kernel/semaphore.c
@@ -0,0 +1,223 @@
+/*
+ *  ARM semaphore implementation, taken from
+ *
+ *  i386 semaphore implementation.
+ *
+ *  (C) Copyright 1999 Linus Torvalds
+ *  (C) Copyright 2003 Ian Molton (ARM26 mods)
+ *
+ *  Modified for ARM by Russell King
+ *
+ * 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.
+ */
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+
+#include <asm/semaphore.h>
+
+/*
+ * Semaphores are implemented using a two-way counter:
+ * The "count" variable is decremented for each process
+ * that tries to acquire the semaphore, while the "sleeping"
+ * variable is a count of such acquires.
+ *
+ * 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.
+ *
+ * "sleeping" and the contention routine ordering is
+ * protected by the semaphore spinlock.
+ *
+ * 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.
+ */
+
+/*
+ * Logic:
+ *  - only on a boundary condition do we need to care. When we go
+ *    from a negative count to a non-negative, we wake people up.
+ *  - when we go from a non-negative count to a negative do we
+ *    (a) synchronize with the "sleeper" count and (b) make sure
+ *    that we're on the wakeup list before we synchronize so that
+ *    we cannot lose wakeup events.
+ */
+
+void __up(struct semaphore *sem)
+{
+	wake_up(&sem->wait);
+}
+
+static DEFINE_SPINLOCK(semaphore_lock);
+
+void __sched __down(struct semaphore * sem)
+{
+	struct task_struct *tsk = current;
+	DECLARE_WAITQUEUE(wait, tsk);
+	tsk->state = TASK_UNINTERRUPTIBLE;
+	add_wait_queue_exclusive(&sem->wait, &wait);
+
+	spin_lock_irq(&semaphore_lock);
+	sem->sleepers++;
+	for (;;) {
+		int sleepers = sem->sleepers;
+
+		/*
+		 * Add "everybody else" into it. They aren't
+		 * playing, because we own the spinlock.
+		 */
+		if (!atomic_add_negative(sleepers - 1, &sem->count)) {
+			sem->sleepers = 0;
+			break;
+		}
+		sem->sleepers = 1;	/* us - see -1 above */
+		spin_unlock_irq(&semaphore_lock);
+
+		schedule();
+		tsk->state = TASK_UNINTERRUPTIBLE;
+		spin_lock_irq(&semaphore_lock);
+	}
+	spin_unlock_irq(&semaphore_lock);
+	remove_wait_queue(&sem->wait, &wait);
+	tsk->state = TASK_RUNNING;
+	wake_up(&sem->wait);
+}
+
+int __sched __down_interruptible(struct semaphore * sem)
+{
+	int retval = 0;
+	struct task_struct *tsk = current;
+	DECLARE_WAITQUEUE(wait, tsk);
+	tsk->state = TASK_INTERRUPTIBLE;
+	add_wait_queue_exclusive(&sem->wait, &wait);
+
+	spin_lock_irq(&semaphore_lock);
+	sem->sleepers ++;
+	for (;;) {
+		int sleepers = sem->sleepers;
+
+		/*
+		 * With signals pending, this turns into
+		 * the trylock failure case - we won't be
+		 * sleeping, and we* can't get the lock as
+		 * it has contention. Just correct the count
+		 * and exit.
+		 */
+		if (signal_pending(current)) {
+			retval = -EINTR;
+			sem->sleepers = 0;
+			atomic_add(sleepers, &sem->count);
+			break;
+		}
+
+		/*
+		 * Add "everybody else" into it. They aren't
+		 * playing, because we own the spinlock. The
+		 * "-1" is because we're still hoping to get
+		 * the lock.
+		 */
+		if (!atomic_add_negative(sleepers - 1, &sem->count)) {
+			sem->sleepers = 0;
+			break;
+		}
+		sem->sleepers = 1;	/* us - see -1 above */
+		spin_unlock_irq(&semaphore_lock);
+
+		schedule();
+		tsk->state = TASK_INTERRUPTIBLE;
+		spin_lock_irq(&semaphore_lock);
+	}
+	spin_unlock_irq(&semaphore_lock);
+	tsk->state = TASK_RUNNING;
+	remove_wait_queue(&sem->wait, &wait);
+	wake_up(&sem->wait);
+	return retval;
+}
+
+/*
+ * Trylock failed - make sure we correct for
+ * having decremented the count.
+ *
+ * We could have done the trylock with a
+ * single "cmpxchg" without failure cases,
+ * but then it wouldn't work on a 386.
+ */
+int __down_trylock(struct semaphore * sem)
+{
+	int sleepers;
+	unsigned long flags;
+
+	spin_lock_irqsave(&semaphore_lock, flags);
+	sleepers = sem->sleepers + 1;
+	sem->sleepers = 0;
+
+	/*
+	 * Add "everybody else" and us into it. They aren't
+	 * playing, because we own the spinlock.
+	 */
+	if (!atomic_add_negative(sleepers, &sem->count))
+		wake_up(&sem->wait);
+
+	spin_unlock_irqrestore(&semaphore_lock, flags);
+	return 1;
+}
+
+/*
+ * The semaphore operations have a special calling sequence that
+ * allow us to do a simpler in-line version of them. These routines
+ * need to convert that sequence back into the C sequence when
+ * there is contention on the semaphore.
+ *
+ * ip contains the semaphore pointer on entry. Save the C-clobbered
+ * registers (r0 to r3 and lr), but not ip, as we use it as a return
+ * value in some cases..
+ */
+asm("	.section .sched.text , #alloc, #execinstr	\n\
+	.align	5				\n\
+	.globl	__down_failed			\n\
+__down_failed:					\n\
+	stmfd	sp!, {r0 - r3, lr}		\n\
+	mov	r0, ip				\n\
+	bl	__down				\n\
+	ldmfd	sp!, {r0 - r3, pc}^		\n\
+						\n\
+	.align	5				\n\
+	.globl	__down_interruptible_failed	\n\
+__down_interruptible_failed:			\n\
+	stmfd	sp!, {r0 - r3, lr}		\n\
+	mov	r0, ip				\n\
+	bl	__down_interruptible		\n\
+	mov	ip, r0				\n\
+	ldmfd	sp!, {r0 - r3, pc}^		\n\
+						\n\
+	.align	5				\n\
+	.globl	__down_trylock_failed		\n\
+__down_trylock_failed:				\n\
+	stmfd	sp!, {r0 - r3, lr}		\n\
+	mov	r0, ip				\n\
+	bl	__down_trylock			\n\
+	mov	ip, r0				\n\
+	ldmfd	sp!, {r0 - r3, pc}^		\n\
+						\n\
+	.align	5				\n\
+	.globl	__up_wakeup			\n\
+__up_wakeup:					\n\
+	stmfd	sp!, {r0 - r3, lr}		\n\
+	mov	r0, ip				\n\
+	bl	__up				\n\
+	ldmfd	sp!, {r0 - r3, pc}^		\n\
+	");
+
+EXPORT_SYMBOL(__down_failed);
+EXPORT_SYMBOL(__down_interruptible_failed);
+EXPORT_SYMBOL(__down_trylock_failed);
+EXPORT_SYMBOL(__up_wakeup);
+
diff --git a/arch/arm26/kernel/setup.c b/arch/arm26/kernel/setup.c
new file mode 100644
index 0000000..4eb329e
--- /dev/null
+++ b/arch/arm26/kernel/setup.c
@@ -0,0 +1,573 @@
+/*
+ *  linux/arch/arm26/kernel/setup.c
+ *
+ *  Copyright (C) 1995-2001 Russell King
+ *  Copyright (C) 2003 Ian Molton
+ *
+ * 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.
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/utsname.h>
+#include <linux/blkdev.h>
+#include <linux/console.h>
+#include <linux/bootmem.h>
+#include <linux/seq_file.h>
+#include <linux/tty.h>
+#include <linux/init.h>
+#include <linux/root_dev.h>
+
+#include <asm/elf.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/procinfo.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/tlbflush.h>
+
+#include <asm/irqchip.h>
+
+#ifndef MEM_SIZE
+#define MEM_SIZE	(16*1024*1024)
+#endif
+
+#ifdef CONFIG_PREEMPT
+DEFINE_SPINLOCK(kernel_flag);
+#endif
+
+#if defined(CONFIG_FPE_NWFPE)
+char fpe_type[8];
+
+static int __init fpe_setup(char *line)
+{
+	memcpy(fpe_type, line, 8);
+	return 1;
+}
+
+__setup("fpe=", fpe_setup);
+#endif
+
+extern void paging_init(struct meminfo *);
+extern void convert_to_tag_list(struct tag *tags);
+extern void squash_mem_tags(struct tag *tag);
+extern void bootmem_init(struct meminfo *);
+extern int root_mountflags;
+extern int _stext, _text, _etext, _edata, _end;
+#ifdef CONFIG_XIP_KERNEL
+extern int _endtext, _sdata;
+#endif
+
+
+unsigned int processor_id;
+unsigned int __machine_arch_type;
+unsigned int system_rev;
+unsigned int system_serial_low;
+unsigned int system_serial_high;
+unsigned int elf_hwcap;
+unsigned int memc_ctrl_reg;
+unsigned int number_mfm_drives;
+
+struct processor processor;
+
+char elf_platform[ELF_PLATFORM_SIZE];
+
+unsigned long phys_initrd_start __initdata = 0;
+unsigned long phys_initrd_size __initdata = 0;
+static struct meminfo meminfo __initdata = { 0, };
+static struct proc_info_item proc_info;
+static const char *machine_name;
+static char command_line[COMMAND_LINE_SIZE];
+
+static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
+
+/*
+ * Standard memory resources
+ */
+static struct resource mem_res[] = {
+	{ "Video RAM",   0,     0,     IORESOURCE_MEM			},
+	{ "Kernel code", 0,     0,     IORESOURCE_MEM			},
+	{ "Kernel data", 0,     0,     IORESOURCE_MEM			}
+};
+
+#define video_ram   mem_res[0]
+#define kernel_code mem_res[1]
+#define kernel_data mem_res[2]
+
+static struct resource io_res[] = {
+	{ "reserved",    0x3bc, 0x3be, IORESOURCE_IO | IORESOURCE_BUSY },
+	{ "reserved",    0x378, 0x37f, IORESOURCE_IO | IORESOURCE_BUSY },
+	{ "reserved",    0x278, 0x27f, IORESOURCE_IO | IORESOURCE_BUSY }
+};
+
+#define lp0 io_res[0]
+#define lp1 io_res[1]
+#define lp2 io_res[2]
+
+#define dump_cpu_info() do { } while (0)
+
+static void __init setup_processor(void)
+{
+	extern struct proc_info_list __proc_info_begin, __proc_info_end;
+	struct proc_info_list *list;
+
+	/*
+	 * locate processor in the list of supported processor
+	 * types.  The linker builds this table for us from the
+	 * entries in arch/arm26/mm/proc-*.S
+	 */
+	for (list = &__proc_info_begin; list < &__proc_info_end ; list++)
+		if ((processor_id & list->cpu_mask) == list->cpu_val)
+			break;
+
+	/*
+	 * If processor type is unrecognised, then we
+	 * can do nothing...
+	 */
+	if (list >= &__proc_info_end) {
+		printk("CPU configuration botched (ID %08x), unable "
+		       "to continue.\n", processor_id);
+		while (1);
+	}
+
+	proc_info = *list->info;
+	processor = *list->proc;
+
+
+	printk("CPU: %s %s revision %d\n",
+	       proc_info.manufacturer, proc_info.cpu_name,
+	       (int)processor_id & 15);
+
+	dump_cpu_info();
+
+	sprintf(system_utsname.machine, "%s", list->arch_name);
+	sprintf(elf_platform, "%s", list->elf_name);
+	elf_hwcap = list->elf_hwcap;
+
+	cpu_proc_init();
+}
+
+/*
+ * Initial parsing of the command line.  We need to pick out the
+ * memory size.  We look for mem=size@start, where start and size
+ * are "size[KkMm]"
+ */
+static void __init
+parse_cmdline(struct meminfo *mi, char **cmdline_p, char *from)
+{
+	char c = ' ', *to = command_line;
+	int usermem = 0, len = 0;
+
+	for (;;) {
+		if (c == ' ' && !memcmp(from, "mem=", 4)) {
+			unsigned long size, start;
+
+			if (to != command_line)
+				to -= 1;
+
+			/*
+			 * If the user specifies memory size, we
+			 * blow away any automatically generated
+			 * size.
+			 */
+			if (usermem == 0) {
+				usermem = 1;
+				mi->nr_banks = 0;
+			}
+
+			start = PHYS_OFFSET;
+			size  = memparse(from + 4, &from);
+			if (*from == '@')
+				start = memparse(from + 1, &from);
+
+			mi->bank[mi->nr_banks].start = start;
+			mi->bank[mi->nr_banks].size  = size;
+			mi->bank[mi->nr_banks].node  = PHYS_TO_NID(start);
+			mi->nr_banks += 1;
+		}
+		c = *from++;
+		if (!c)
+			break;
+		if (COMMAND_LINE_SIZE <= ++len)
+			break;
+		*to++ = c;
+	}
+	*to = '\0';
+	*cmdline_p = command_line;
+}
+
+static void __init
+setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz)
+{
+#ifdef CONFIG_BLK_DEV_RAM
+	extern int rd_size, rd_image_start, rd_prompt, rd_doload;
+
+	rd_image_start = image_start;
+	rd_prompt = prompt;
+	rd_doload = doload;
+
+	if (rd_sz)
+		rd_size = rd_sz;
+#endif
+}
+
+static void __init
+request_standard_resources(struct meminfo *mi)
+{
+	struct resource *res;
+	int i;
+
+	kernel_code.start  = init_mm.start_code;
+	kernel_code.end    = init_mm.end_code - 1;
+#ifdef CONFIG_XIP_KERNEL
+	kernel_data.start  = init_mm.start_data;
+#else
+	kernel_data.start  = init_mm.end_code;
+#endif
+	kernel_data.end    = init_mm.brk - 1;
+
+	for (i = 0; i < mi->nr_banks; i++) {
+		unsigned long virt_start, virt_end;
+
+		if (mi->bank[i].size == 0)
+			continue;
+
+		virt_start = mi->bank[i].start;
+		virt_end   = virt_start + mi->bank[i].size - 1;
+
+		res = alloc_bootmem_low(sizeof(*res));
+		res->name  = "System RAM";
+		res->start = virt_start;
+		res->end   = virt_end;
+		res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+
+		request_resource(&iomem_resource, res);
+
+		if (kernel_code.start >= res->start &&
+		    kernel_code.end <= res->end)
+			request_resource(res, &kernel_code);
+		if (kernel_data.start >= res->start &&
+		    kernel_data.end <= res->end)
+			request_resource(res, &kernel_data);
+	}
+
+/*	FIXME - needed? if (mdesc->video_start) {
+		video_ram.start = mdesc->video_start;
+		video_ram.end   = mdesc->video_end;
+		request_resource(&iomem_resource, &video_ram);
+	}*/
+
+	/*
+	 * Some machines don't have the possibility of ever
+	 * possessing lp1 or lp2
+	 */
+	if (0)  /* FIXME - need to do this for A5k at least */
+		request_resource(&ioport_resource, &lp0);
+}
+
+/*
+ *  Tag parsing.
+ *
+ * This is the new way of passing data to the kernel at boot time.  Rather
+ * than passing a fixed inflexible structure to the kernel, we pass a list
+ * of variable-sized tags to the kernel.  The first tag must be a ATAG_CORE
+ * tag for the list to be recognised (to distinguish the tagged list from
+ * a param_struct).  The list is terminated with a zero-length tag (this tag
+ * is not parsed in any way).
+ */
+static int __init parse_tag_core(const struct tag *tag)
+{
+	if (tag->hdr.size > 2) {
+		if ((tag->u.core.flags & 1) == 0)
+			root_mountflags &= ~MS_RDONLY;
+		ROOT_DEV = old_decode_dev(tag->u.core.rootdev);
+	}
+	return 0;
+}
+
+__tagtable(ATAG_CORE, parse_tag_core);
+
+static int __init parse_tag_mem32(const struct tag *tag)
+{
+	if (meminfo.nr_banks >= NR_BANKS) {
+		printk(KERN_WARNING
+		       "Ignoring memory bank 0x%08x size %dKB\n",
+			tag->u.mem.start, tag->u.mem.size / 1024);
+		return -EINVAL;
+	}
+	meminfo.bank[meminfo.nr_banks].start = tag->u.mem.start;
+	meminfo.bank[meminfo.nr_banks].size  = tag->u.mem.size;
+	meminfo.bank[meminfo.nr_banks].node  = PHYS_TO_NID(tag->u.mem.start);
+	meminfo.nr_banks += 1;
+
+	return 0;
+}
+
+__tagtable(ATAG_MEM, parse_tag_mem32);
+
+#if defined(CONFIG_DUMMY_CONSOLE)
+struct screen_info screen_info = {
+ .orig_video_lines	= 30,
+ .orig_video_cols	= 80,
+ .orig_video_mode	= 0,
+ .orig_video_ega_bx	= 0,
+ .orig_video_isVGA	= 1,
+ .orig_video_points	= 8
+};
+
+static int __init parse_tag_videotext(const struct tag *tag)
+{
+	screen_info.orig_x            = tag->u.videotext.x;
+	screen_info.orig_y            = tag->u.videotext.y;
+	screen_info.orig_video_page   = tag->u.videotext.video_page;
+	screen_info.orig_video_mode   = tag->u.videotext.video_mode;
+	screen_info.orig_video_cols   = tag->u.videotext.video_cols;
+	screen_info.orig_video_ega_bx = tag->u.videotext.video_ega_bx;
+	screen_info.orig_video_lines  = tag->u.videotext.video_lines;
+	screen_info.orig_video_isVGA  = tag->u.videotext.video_isvga;
+	screen_info.orig_video_points = tag->u.videotext.video_points;
+	return 0;
+}
+
+__tagtable(ATAG_VIDEOTEXT, parse_tag_videotext);
+#endif
+
+static int __init parse_tag_acorn(const struct tag *tag)
+{
+        memc_ctrl_reg = tag->u.acorn.memc_control_reg;
+        number_mfm_drives = tag->u.acorn.adfsdrives;
+        return 0;
+}
+
+__tagtable(ATAG_ACORN, parse_tag_acorn);
+
+static int __init parse_tag_ramdisk(const struct tag *tag)
+{
+	setup_ramdisk((tag->u.ramdisk.flags & 1) == 0,
+		      (tag->u.ramdisk.flags & 2) == 0,
+		      tag->u.ramdisk.start, tag->u.ramdisk.size);
+	return 0;
+}
+
+__tagtable(ATAG_RAMDISK, parse_tag_ramdisk);
+
+static int __init parse_tag_initrd(const struct tag *tag)
+{
+	printk(KERN_WARNING "ATAG_INITRD is deprecated; please update your bootloader. \n");
+        phys_initrd_start = (unsigned long)tag->u.initrd.start;
+        phys_initrd_size = (unsigned long)tag->u.initrd.size;
+	return 0;
+}
+
+__tagtable(ATAG_INITRD, parse_tag_initrd);
+
+static int __init parse_tag_initrd2(const struct tag *tag)
+{
+	printk(KERN_WARNING "ATAG_INITRD is deprecated; please update your bootloader. \n");
+	phys_initrd_start = (unsigned long)tag->u.initrd.start;
+	phys_initrd_size = (unsigned long)tag->u.initrd.size;
+	return 0;
+}
+
+__tagtable(ATAG_INITRD2, parse_tag_initrd2);
+
+static int __init parse_tag_serialnr(const struct tag *tag)
+{
+	system_serial_low = tag->u.serialnr.low;
+	system_serial_high = tag->u.serialnr.high;
+	return 0;
+}
+
+__tagtable(ATAG_SERIAL, parse_tag_serialnr);
+
+static int __init parse_tag_revision(const struct tag *tag)
+{
+	system_rev = tag->u.revision.rev;
+	return 0;
+}
+
+__tagtable(ATAG_REVISION, parse_tag_revision);
+
+static int __init parse_tag_cmdline(const struct tag *tag)
+{
+	strncpy(default_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE);
+	default_command_line[COMMAND_LINE_SIZE - 1] = '\0';
+	return 0;
+}
+
+__tagtable(ATAG_CMDLINE, parse_tag_cmdline);
+
+/*
+ * Scan the tag table for this tag, and call its parse function.
+ * The tag table is built by the linker from all the __tagtable
+ * declarations.
+ */
+static int __init parse_tag(const struct tag *tag)
+{
+	extern struct tagtable __tagtable_begin, __tagtable_end;
+	struct tagtable *t;
+
+	for (t = &__tagtable_begin; t < &__tagtable_end; t++)
+		if (tag->hdr.tag == t->tag) {
+			t->parse(tag);
+			break;
+		}
+
+	return t < &__tagtable_end;
+}
+
+/*
+ * Parse all tags in the list, checking both the global and architecture
+ * specific tag tables.
+ */
+static void __init parse_tags(const struct tag *t)
+{
+	for (; t->hdr.size; t = tag_next(t))
+		if (!parse_tag(t))
+			printk(KERN_WARNING
+				"Ignoring unrecognised tag 0x%08x\n",
+				t->hdr.tag);
+}
+
+/*
+ * This holds our defaults.
+ */
+static struct init_tags {
+	struct tag_header hdr1;
+	struct tag_core   core;
+	struct tag_header hdr2;
+	struct tag_mem32  mem;
+	struct tag_header hdr3;
+} init_tags __initdata = {
+	{ tag_size(tag_core), ATAG_CORE },
+	{ 1, PAGE_SIZE, 0xff },
+	{ tag_size(tag_mem32), ATAG_MEM },
+	{ MEM_SIZE, PHYS_OFFSET },
+	{ 0, ATAG_NONE }
+};
+
+void __init setup_arch(char **cmdline_p)
+{
+	struct tag *tags = (struct tag *)&init_tags;
+	char *from = default_command_line;
+
+	setup_processor();
+	if(machine_arch_type == MACH_TYPE_A5K)
+		machine_name = "A5000";
+	else if(machine_arch_type == MACH_TYPE_ARCHIMEDES)
+		machine_name = "Archimedes";
+	else
+		machine_name = "UNKNOWN";
+
+	//FIXME - the tag struct is always copied here but this is a block
+	// of RAM that is accidentally reserved along with video RAM. perhaps
+	// it would be a good idea to explicitly reserve this?
+
+	tags = (struct tag *)0x0207c000;
+
+	/*
+	 * If we have the old style parameters, convert them to
+	 * a tag list.
+	 */
+	if (tags->hdr.tag != ATAG_CORE)
+		convert_to_tag_list(tags);
+	if (tags->hdr.tag != ATAG_CORE)
+		tags = (struct tag *)&init_tags;
+	if (tags->hdr.tag == ATAG_CORE) {
+		if (meminfo.nr_banks != 0)
+			squash_mem_tags(tags);
+		parse_tags(tags);
+	}
+
+	init_mm.start_code = (unsigned long) &_text;
+#ifndef CONFIG_XIP_KERNEL
+	init_mm.end_code   = (unsigned long) &_etext;
+#else
+	init_mm.end_code   = (unsigned long) &_endtext;
+	init_mm.start_data   = (unsigned long) &_sdata;
+#endif
+	init_mm.end_data   = (unsigned long) &_edata;
+	init_mm.brk	   = (unsigned long) &_end;
+
+	memcpy(saved_command_line, from, COMMAND_LINE_SIZE);
+	saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
+	parse_cmdline(&meminfo, cmdline_p, from);
+	bootmem_init(&meminfo);
+	paging_init(&meminfo);
+	request_standard_resources(&meminfo);
+
+#ifdef CONFIG_VT
+#if defined(CONFIG_DUMMY_CONSOLE)
+	conswitchp = &dummy_con;
+#endif
+#endif
+}
+
+static const char *hwcap_str[] = {
+	"swp",
+	"half",
+	"thumb",
+	"26bit",
+	"fastmult",
+	"fpa",
+	"vfp",
+	"edsp",
+	NULL
+};
+
+static int c_show(struct seq_file *m, void *v)
+{
+	int i;
+
+	seq_printf(m, "Processor\t: %s %s rev %d (%s)\n",
+		   proc_info.manufacturer, proc_info.cpu_name,
+		   (int)processor_id & 15, elf_platform);
+
+	seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
+		   loops_per_jiffy / (500000/HZ),
+		   (loops_per_jiffy / (5000/HZ)) % 100);
+
+	/* dump out the processor features */
+	seq_puts(m, "Features\t: ");
+
+	for (i = 0; hwcap_str[i]; i++)
+		if (elf_hwcap & (1 << i))
+			seq_printf(m, "%s ", hwcap_str[i]);
+
+	seq_puts(m, "\n");
+
+	seq_printf(m, "CPU part\t\t: %07x\n", processor_id >> 4);
+	seq_printf(m, "CPU revision\t: %d\n\n", processor_id & 15);
+	seq_printf(m, "Hardware\t: %s\n", machine_name);
+	seq_printf(m, "Revision\t: %04x\n", system_rev);
+	seq_printf(m, "Serial\t\t: %08x%08x\n",
+		   system_serial_high, system_serial_low);
+
+	return 0;
+}
+
+static void *c_start(struct seq_file *m, loff_t *pos)
+{
+	return *pos < 1 ? (void *)1 : NULL;
+}
+
+static void *c_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	++*pos;
+	return NULL;
+}
+
+static void c_stop(struct seq_file *m, void *v)
+{
+}
+
+struct seq_operations cpuinfo_op = {
+	.start	= c_start,
+	.next	= c_next,
+	.stop	= c_stop,
+	.show	= c_show
+};
diff --git a/arch/arm26/kernel/signal.c b/arch/arm26/kernel/signal.c
new file mode 100644
index 0000000..356d980
--- /dev/null
+++ b/arch/arm26/kernel/signal.c
@@ -0,0 +1,540 @@
+/*
+ *  linux/arch/arm26/kernel/signal.c
+ *
+ *  Copyright (C) 1995-2002 Russell King
+ *  Copyright (C) 2003 Ian Molton (ARM26)
+ *
+ * FIXME!!! This is probably very broken (13/05/2003)
+ *
+ * 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.
+ */
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/personality.h>
+#include <linux/tty.h>
+#include <linux/binfmts.h>
+#include <linux/elf.h>
+
+#include <asm/pgalloc.h>
+#include <asm/ucontext.h>
+#include <asm/uaccess.h>
+#include <asm/unistd.h>
+
+#include "ptrace.h"
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+/*
+ * For ARM syscalls, we encode the syscall number into the instruction.
+ */
+#define SWI_SYS_SIGRETURN	(0xef000000|(__NR_sigreturn))
+#define SWI_SYS_RT_SIGRETURN	(0xef000000|(__NR_rt_sigreturn))
+
+static int do_signal(sigset_t *oldset, struct pt_regs * regs, int syscall);
+
+/*
+ * atomically swap in the new signal mask, and wait for a signal.
+ */
+asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask, struct pt_regs *regs)
+{
+	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->ARM_r0 = -EINTR;
+
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		if (do_signal(&saveset, regs, 0))
+			return regs->ARM_r0;
+	}
+}
+
+asmlinkage int
+sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, struct pt_regs *regs)
+{
+	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->ARM_r0 = -EINTR;
+
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		if (do_signal(&saveset, regs, 0))
+			return regs->ARM_r0;
+	}
+}
+
+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 (!access_ok(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 (!access_ok(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;
+}
+
+/*
+ * Do a signal return; undo the signal stack.
+ */
+struct sigframe
+{
+	struct sigcontext sc;
+	unsigned long extramask[_NSIG_WORDS-1];
+	unsigned long retcode;
+};
+
+struct rt_sigframe
+{
+	struct siginfo *pinfo;
+	void *puc;
+	struct siginfo info;
+	struct ucontext uc;
+	unsigned long retcode;
+};
+
+static int
+restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
+{
+	int err = 0;
+
+	__get_user_error(regs->ARM_r0, &sc->arm_r0, err);
+	__get_user_error(regs->ARM_r1, &sc->arm_r1, err);
+	__get_user_error(regs->ARM_r2, &sc->arm_r2, err);
+	__get_user_error(regs->ARM_r3, &sc->arm_r3, err);
+	__get_user_error(regs->ARM_r4, &sc->arm_r4, err);
+	__get_user_error(regs->ARM_r5, &sc->arm_r5, err);
+	__get_user_error(regs->ARM_r6, &sc->arm_r6, err);
+	__get_user_error(regs->ARM_r7, &sc->arm_r7, err);
+	__get_user_error(regs->ARM_r8, &sc->arm_r8, err);
+	__get_user_error(regs->ARM_r9, &sc->arm_r9, err);
+	__get_user_error(regs->ARM_r10, &sc->arm_r10, err);
+	__get_user_error(regs->ARM_fp, &sc->arm_fp, err);
+	__get_user_error(regs->ARM_ip, &sc->arm_ip, err);
+	__get_user_error(regs->ARM_sp, &sc->arm_sp, err);
+	__get_user_error(regs->ARM_lr, &sc->arm_lr, err);
+	__get_user_error(regs->ARM_pc, &sc->arm_pc, err);
+
+	err |= !valid_user_regs(regs);
+
+	return err;
+}
+
+asmlinkage int sys_sigreturn(struct pt_regs *regs)
+{
+	struct sigframe *frame;
+	sigset_t set;
+
+	/*
+	 * Since we stacked the signal on a 64-bit boundary,
+	 * then 'sp' should be word aligned here.  If it's
+	 * not, then the user is trying to mess with us.
+	 */
+	if (regs->ARM_sp & 7)
+		goto badframe;
+
+	frame = (struct sigframe *)regs->ARM_sp;
+
+	if (!access_ok(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;
+
+	/* Send SIGTRAP if we're single-stepping */
+	if (current->ptrace & PT_SINGLESTEP) {
+                ptrace_cancel_bpt(current);
+                send_sig(SIGTRAP, current, 1);
+        }
+
+	return regs->ARM_r0;
+
+badframe:
+	force_sig(SIGSEGV, current);
+	return 0;
+}
+
+asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
+{
+	struct rt_sigframe *frame;
+	sigset_t set;
+
+	/*
+	 * Since we stacked the signal on a 64-bit boundary,
+	 * then 'sp' should be word aligned here.  If it's
+	 * not, then the user is trying to mess with us.
+	 */
+	if (regs->ARM_sp & 7)
+		goto badframe;
+
+	frame = (struct rt_sigframe *)regs->ARM_sp;
+
+	if (!access_ok(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;
+
+	/* Send SIGTRAP if we're single-stepping */
+	if (current->ptrace & PT_SINGLESTEP) {
+                ptrace_cancel_bpt(current);
+                send_sig(SIGTRAP, current, 1);
+        }
+
+	return regs->ARM_r0;
+
+badframe:
+	force_sig(SIGSEGV, current);
+	return 0;
+}
+
+static int
+setup_sigcontext(struct sigcontext *sc, /*struct _fpstate *fpstate,*/
+		 struct pt_regs *regs, unsigned long mask)
+{
+	int err = 0;
+
+	__put_user_error(regs->ARM_r0, &sc->arm_r0, err);
+	__put_user_error(regs->ARM_r1, &sc->arm_r1, err);
+	__put_user_error(regs->ARM_r2, &sc->arm_r2, err);
+	__put_user_error(regs->ARM_r3, &sc->arm_r3, err);
+	__put_user_error(regs->ARM_r4, &sc->arm_r4, err);
+	__put_user_error(regs->ARM_r5, &sc->arm_r5, err);
+	__put_user_error(regs->ARM_r6, &sc->arm_r6, err);
+	__put_user_error(regs->ARM_r7, &sc->arm_r7, err);
+	__put_user_error(regs->ARM_r8, &sc->arm_r8, err);
+	__put_user_error(regs->ARM_r9, &sc->arm_r9, err);
+	__put_user_error(regs->ARM_r10, &sc->arm_r10, err);
+	__put_user_error(regs->ARM_fp, &sc->arm_fp, err);
+	__put_user_error(regs->ARM_ip, &sc->arm_ip, err);
+	__put_user_error(regs->ARM_sp, &sc->arm_sp, err);
+	__put_user_error(regs->ARM_lr, &sc->arm_lr, err);
+	__put_user_error(regs->ARM_pc, &sc->arm_pc, err);
+
+	__put_user_error(current->thread.trap_no, &sc->trap_no, err);
+	__put_user_error(current->thread.error_code, &sc->error_code, err);
+	__put_user_error(current->thread.address, &sc->fault_address, err);
+	__put_user_error(mask, &sc->oldmask, err);
+
+	return err;
+}
+
+static inline void *
+get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, int framesize)
+{
+	unsigned long sp = regs->ARM_sp;
+
+	/*
+	 * This is the X/Open sanctioned signal stack switching.
+	 */
+	if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp))
+		sp = current->sas_ss_sp + current->sas_ss_size;
+
+	/*
+	 * ATPCS B01 mandates 8-byte alignment
+	 */
+	return (void *)((sp - framesize) & ~7);
+}
+
+static int
+setup_return(struct pt_regs *regs, struct k_sigaction *ka,
+	     unsigned long *rc, void *frame, int usig)
+{
+	unsigned long handler = (unsigned long)ka->sa.sa_handler;
+	unsigned long retcode;
+
+	if (ka->sa.sa_flags & SA_RESTORER) {
+		retcode = (unsigned long)ka->sa.sa_restorer;
+	} else {
+
+		if (__put_user((ka->sa.sa_flags & SA_SIGINFO)?SWI_SYS_RT_SIGRETURN:SWI_SYS_SIGRETURN, rc))
+			return 1;
+
+		retcode = ((unsigned long)rc);
+	}
+
+	regs->ARM_r0 = usig;
+	regs->ARM_sp = (unsigned long)frame;
+	regs->ARM_lr = retcode;
+	regs->ARM_pc = handler & ~3;
+
+	return 0;
+}
+
+static int
+setup_frame(int usig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *regs)
+{
+	struct sigframe *frame = get_sigframe(ka, regs, sizeof(*frame));
+	int err = 0;
+
+	if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
+		return 1;
+
+	err |= setup_sigcontext(&frame->sc, /*&frame->fpstate,*/ regs, set->sig[0]);
+
+	if (_NSIG_WORDS > 1) {
+		err |= __copy_to_user(frame->extramask, &set->sig[1],
+				      sizeof(frame->extramask));
+	}
+
+	if (err == 0)
+		err = setup_return(regs, ka, &frame->retcode, frame, usig);
+
+	return err;
+}
+
+static int
+setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
+	       sigset_t *set, struct pt_regs *regs)
+{
+	struct rt_sigframe *frame = get_sigframe(ka, regs, sizeof(*frame));
+	int err = 0;
+
+	if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
+		return 1;
+
+	__put_user_error(&frame->info, &frame->pinfo, err);
+	__put_user_error(&frame->uc, &frame->puc, err);
+	err |= copy_siginfo_to_user(&frame->info, info);
+
+	/* Clear all the bits of the ucontext we don't use.  */
+	err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));
+
+	err |= setup_sigcontext(&frame->uc.uc_mcontext, /*&frame->fpstate,*/
+				regs, set->sig[0]);
+	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+
+	if (err == 0)
+		err = setup_return(regs, ka, &frame->retcode, frame, usig);
+
+	if (err == 0) {
+		/*
+		 * For realtime signals we must also set the second and third
+		 * arguments for the signal handler.
+		 *   -- Peter Maydell <pmaydell@chiark.greenend.org.uk> 2000-12-06
+		 */
+		regs->ARM_r1 = (unsigned long)frame->pinfo;
+		regs->ARM_r2 = (unsigned long)frame->puc;
+	}
+
+	return err;
+}
+
+static inline void restart_syscall(struct pt_regs *regs)
+{
+        regs->ARM_r0 = regs->ARM_ORIG_r0;
+        regs->ARM_pc -= 4;
+}
+
+/*
+ * OK, we're invoking a handler
+ */	
+static void
+handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
+	      struct pt_regs * regs, int syscall)
+{
+	struct thread_info *thread = current_thread_info();
+	struct task_struct *tsk = current;
+	struct k_sigaction *ka = &tsk->sighand->action[sig-1];
+	int usig = sig;
+	int ret;
+
+        /*
+         * If we were from a system call, check for system call restarting...
+         */
+        if (syscall) {
+                switch (regs->ARM_r0) {
+                case -ERESTART_RESTARTBLOCK:
+                        current_thread_info()->restart_block.fn =
+                                do_no_restart_syscall;
+                case -ERESTARTNOHAND:
+                        regs->ARM_r0 = -EINTR;
+                        break;
+                case -ERESTARTSYS:
+                        if (!(ka->sa.sa_flags & SA_RESTART)) {
+                                regs->ARM_r0 = -EINTR;
+                                break;
+                        }
+                        /* fallthrough */
+                case -ERESTARTNOINTR:
+                        restart_syscall(regs);
+                }
+        }
+
+	/*
+	 * translate the signal
+	 */
+	if (usig < 32 && thread->exec_domain && thread->exec_domain->signal_invmap)
+		usig = thread->exec_domain->signal_invmap[usig];
+
+	/*
+	 * Set up the stack frame
+	 */
+	if (ka->sa.sa_flags & SA_SIGINFO)
+		ret = setup_rt_frame(usig, ka, info, oldset, regs);
+	else
+		ret = setup_frame(usig, ka, oldset, regs);
+
+	/*
+	 * Check that the resulting registers are actually sane.
+	 */
+	ret |= !valid_user_regs(regs);
+
+	if (ret == 0) {
+		if (ka->sa.sa_flags & SA_ONESHOT)
+			ka->sa.sa_handler = SIG_DFL;
+
+		if (!(ka->sa.sa_flags & SA_NODEFER)) {
+			spin_lock_irq(&tsk->sighand->siglock);
+			sigorsets(&tsk->blocked, &tsk->blocked,
+				  &ka->sa.sa_mask);
+			sigaddset(&tsk->blocked, sig);
+			recalc_sigpending();
+			spin_unlock_irq(&tsk->sighand->siglock);
+		}
+		return;
+	}
+
+	force_sigsegv(sig, tsk);
+}
+
+/*
+ * 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.
+ */
+static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
+{
+	siginfo_t info;
+	int signr;
+
+	/*
+	 * We want the common case to go fast, which
+	 * is why we may in certain cases get here from
+	 * kernel mode. Just return without doing anything
+	 * if so.
+	 */
+	if (!user_mode(regs))
+		return 0;
+
+        if (current->ptrace & PT_SINGLESTEP)
+                ptrace_cancel_bpt(current);
+	
+        signr = get_signal_to_deliver(&info, regs, NULL);
+        if (signr > 0) {
+                handle_signal(signr, &info, oldset, regs, syscall);
+                if (current->ptrace & PT_SINGLESTEP)
+                        ptrace_set_bpt(current);
+                return 1;
+        }
+
+        /*
+         * No signal to deliver to the process - restart the syscall.
+         */
+        if (syscall) {
+                if (regs->ARM_r0 == -ERESTART_RESTARTBLOCK) {
+                        u32 *usp;
+
+                        regs->ARM_sp -= 12;
+                        usp = (u32 *)regs->ARM_sp;
+
+                        put_user(regs->ARM_pc, &usp[0]);
+                        /* swi __NR_restart_syscall */
+                        put_user(0xef000000 | __NR_restart_syscall, &usp[1]);
+                        /* ldr  pc, [sp], #12 */
+// FIXME!!! is #12 correct there?
+                        put_user(0xe49df00c, &usp[2]);
+
+                        regs->ARM_pc = regs->ARM_sp + 4;
+                }
+                if (regs->ARM_r0 == -ERESTARTNOHAND ||
+                    regs->ARM_r0 == -ERESTARTSYS ||
+                    regs->ARM_r0 == -ERESTARTNOINTR) {
+                        restart_syscall(regs);
+                }
+        }
+        if (current->ptrace & PT_SINGLESTEP)
+                ptrace_set_bpt(current);
+        return 0;
+}
+
+asmlinkage void
+do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall)
+{
+	if (thread_flags & _TIF_SIGPENDING)
+		do_signal(&current->blocked, regs, syscall);
+}
diff --git a/arch/arm26/kernel/sys_arm.c b/arch/arm26/kernel/sys_arm.c
new file mode 100644
index 0000000..e7edd20
--- /dev/null
+++ b/arch/arm26/kernel/sys_arm.c
@@ -0,0 +1,324 @@
+/*
+ *  linux/arch/arm26/kernel/sys_arm.c
+ *
+ *  Copyright (C) People who wrote linux/arch/i386/kernel/sys_i386.c
+ *  Copyright (C) 1995, 1996 Russell King.
+ *  Copyright (C) 2003 Ian Molton.
+ *
+ * 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.
+ *
+ *  This file contains various random system calls that
+ *  have a non-standard calling sequence on the Linux/arm
+ *  platform.
+ */
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/stat.h>
+#include <linux/syscalls.h>
+#include <linux/mman.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/utsname.h>
+
+#include <asm/uaccess.h>
+#include <asm/ipc.h>
+
+extern unsigned long do_mremap(unsigned long addr, unsigned long old_len,
+			       unsigned long new_len, unsigned long flags,
+			       unsigned long new_addr);
+
+/*
+ * sys_pipe() is the normal C calling standard for creating
+ * a pipe. It's not the way unix traditionally does this, though.
+ */
+asmlinkage int sys_pipe(unsigned long * fildes)
+{
+	int fd[2];
+	int error;
+
+	error = do_pipe(fd);
+	if (!error) {
+		if (copy_to_user(fildes, fd, 2*sizeof(int)))
+			error = -EFAULT;
+	}
+	return error;
+}
+
+/* common code for old and new mmaps */
+inline long do_mmap2(
+	unsigned long addr, unsigned long len,
+	unsigned long prot, unsigned long flags,
+	unsigned long fd, unsigned long pgoff)
+{
+	int error = -EINVAL;
+	struct file * file = NULL;
+
+	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+
+	/*
+	 * If we are doing a fixed mapping, and address < PAGE_SIZE,
+	 * then deny it.
+	 */
+	if (flags & MAP_FIXED && addr < PAGE_SIZE && vectors_base() == 0)
+		goto out;
+
+	error = -EBADF;
+	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;
+}
+
+struct mmap_arg_struct {
+	unsigned long addr;
+	unsigned long len;
+	unsigned long prot;
+	unsigned long flags;
+	unsigned long fd;
+	unsigned long offset;
+};
+
+asmlinkage int old_mmap(struct mmap_arg_struct *arg)
+{
+	int error = -EFAULT;
+	struct mmap_arg_struct a;
+
+	if (copy_from_user(&a, arg, sizeof(a)))
+		goto out;
+
+	error = -EINVAL;
+	if (a.offset & ~PAGE_MASK)
+		goto out;
+
+	error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
+out:
+	return error;
+}
+
+asmlinkage unsigned long
+sys_arm_mremap(unsigned long addr, unsigned long old_len,
+	       unsigned long new_len, unsigned long flags,
+	       unsigned long new_addr)
+{
+	unsigned long ret = -EINVAL;
+
+	/*
+	 * If we are doing a fixed mapping, and address < PAGE_SIZE,
+	 * then deny it.
+	 */
+	if (flags & MREMAP_FIXED && new_addr < PAGE_SIZE &&
+	    vectors_base() == 0)
+		goto out;
+
+	down_write(&current->mm->mmap_sem);
+	ret = do_mremap(addr, old_len, new_len, flags, new_addr);
+	up_write(&current->mm->mmap_sem);
+
+out:
+	return ret;
+}
+
+/*
+ * Perform the select(nd, in, out, ex, tv) and mmap() system
+ * calls.
+ */
+
+struct sel_arg_struct {
+	unsigned long n;
+	fd_set *inp, *outp, *exp;
+	struct timeval *tvp;
+};
+
+asmlinkage int old_select(struct sel_arg_struct *arg)
+{
+	struct sel_arg_struct a;
+
+	if (copy_from_user(&a, arg, sizeof(a)))
+		return -EFAULT;
+	/* sys_select() does the appropriate kernel locking */
+	return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
+}
+
+/*
+ * sys_ipc() is the de-multiplexer for the SysV IPC calls..
+ *
+ * This is really horribly ugly.
+ */
+asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth)
+{
+	int version, ret;
+
+	version = call >> 16; /* hack for backward compatibility */
+	call &= 0xffff;
+
+	switch (call) {
+	case SEMOP:
+		return sys_semop (first, (struct sembuf *)ptr, second);
+	case SEMGET:
+		return sys_semget (first, second, third);
+	case SEMCTL: {
+		union semun fourth;
+		if (!ptr)
+			return -EINVAL;
+		if (get_user(fourth.__pad, (void **) ptr))
+			return -EFAULT;
+		return sys_semctl (first, second, third, fourth);
+	}
+
+	case MSGSND:
+		return sys_msgsnd (first, (struct msgbuf *) ptr, 
+				   second, third);
+	case MSGRCV:
+		switch (version) {
+		case 0: {
+			struct ipc_kludge tmp;
+			if (!ptr)
+				return -EINVAL;
+			if (copy_from_user(&tmp,(struct ipc_kludge *) ptr,
+					   sizeof (tmp)))
+				return -EFAULT;
+			return sys_msgrcv (first, tmp.msgp, second,
+					   tmp.msgtyp, third);
+		}
+		default:
+			return sys_msgrcv (first,
+					   (struct msgbuf *) ptr,
+					   second, fifth, third);
+		}
+	case MSGGET:
+		return sys_msgget ((key_t) first, second);
+	case MSGCTL:
+		return sys_msgctl (first, second, (struct msqid_ds *) ptr);
+
+	case SHMAT:
+		switch (version) {
+		default: {
+			ulong raddr;
+			ret = do_shmat (first, (char *) ptr, second, &raddr);
+			if (ret)
+				return ret;
+			return put_user (raddr, (ulong *) third);
+		}
+		case 1:	/* iBCS2 emulator entry point */
+			if (!segment_eq(get_fs(), get_ds()))
+				return -EINVAL;
+			return do_shmat (first, (char *) ptr,
+					  second, (ulong *) third);
+		}
+	case SHMDT: 
+		return sys_shmdt ((char *)ptr);
+	case SHMGET:
+		return sys_shmget (first, second, third);
+	case SHMCTL:
+		return sys_shmctl (first, second,
+				   (struct shmid_ds *) ptr);
+	default:
+		return -EINVAL;
+	}
+}
+
+/* Fork a new task - this creates a new program thread.
+ * This is called indirectly via a small wrapper
+ */
+asmlinkage int sys_fork(struct pt_regs *regs)
+{
+	return do_fork(SIGCHLD, regs->ARM_sp, regs, 0, NULL, NULL);
+}
+
+/* Clone a task - this clones the calling program thread.
+ * This is called indirectly via a small wrapper
+ */
+asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, struct pt_regs *regs)
+{
+	/*
+         * We don't support SETTID / CLEARTID  (FIXME!!! (nicked from arm32))
+         */
+        if (clone_flags & (CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID))
+                return -EINVAL;
+	
+	if (!newsp)
+		newsp = regs->ARM_sp;
+
+	return do_fork(clone_flags, newsp, regs, 0, NULL, NULL);
+}
+
+asmlinkage int sys_vfork(struct pt_regs *regs)
+{
+	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->ARM_sp, regs, 0, NULL, NULL);
+}
+
+/* sys_execve() executes a new program.
+ * This is called indirectly via a small wrapper
+ */
+asmlinkage int sys_execve(char *filenamei, char **argv, char **envp, struct pt_regs *regs)
+{
+	int error;
+	char * filename;
+
+	filename = getname(filenamei);
+	error = PTR_ERR(filename);
+	if (IS_ERR(filename))
+		goto out;
+	error = do_execve(filename, argv, envp, regs);
+	putname(filename);
+out:
+	return error;
+}
+
+/* FIXME - see if this is correct for arm26 */
+long execve(const char *filename, char **argv, char **envp)
+{
+	struct pt_regs regs;
+        int ret;
+         memset(&regs, 0, sizeof(struct pt_regs));
+        ret = do_execve((char *)filename, (char __user * __user *)argv,                         (char __user * __user *)envp, &regs);
+        if (ret < 0)
+                goto out;
+
+        /*
+         * Save argc to the register structure for userspace.
+         */
+        regs.ARM_r0 = ret;
+
+        /*
+         * We were successful.  We won't be returning to our caller, but
+         * instead to user space by manipulating the kernel stack.
+         */
+        asm(    "add    r0, %0, %1\n\t"
+                "mov    r1, %2\n\t"
+                "mov    r2, %3\n\t"
+                "bl     memmove\n\t"    /* copy regs to top of stack */
+                "mov    r8, #0\n\t"     /* not a syscall */
+                "mov    r9, %0\n\t"     /* thread structure */
+                "mov    sp, r0\n\t"     /* reposition stack pointer */
+                "b      ret_to_user"
+                :
+                : "r" (current_thread_info()),
+                  "Ir" (THREAD_SIZE - 8 - sizeof(regs)),
+                  "r" (&regs),
+                  "Ir" (sizeof(regs))
+                : "r0", "r1", "r2", "r3", "ip", "memory");
+
+ out:
+        return ret;
+}
+
+EXPORT_SYMBOL(execve);
diff --git a/arch/arm26/kernel/time.c b/arch/arm26/kernel/time.c
new file mode 100644
index 0000000..549a6b2
--- /dev/null
+++ b/arch/arm26/kernel/time.c
@@ -0,0 +1,234 @@
+/*
+ *  linux/arch/arm26/kernel/time.c
+ *
+ *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
+ *  Modifications for ARM (C) 1994-2001 Russell King
+ *  Mods for ARM26 (C) 2003 Ian Molton
+ *
+ * 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.
+ *
+ *  This file contains the ARM-specific time handling details:
+ *  reading the RTC at bootup, etc...
+ *
+ *  1994-07-02  Alan Modra
+ *              fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
+ *  1998-12-20  Updated NTP code according to technical memorandum Jan '96
+ *              "A Kernel Model for Precision Timekeeping" by Dave Mills
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/timex.h>
+#include <linux/errno.h>
+#include <linux/profile.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/ioc.h>
+
+u64 jiffies_64 = INITIAL_JIFFIES;
+
+EXPORT_SYMBOL(jiffies_64);
+
+extern unsigned long wall_jiffies;
+
+/* this needs a better home */
+DEFINE_SPINLOCK(rtc_lock);
+
+/* change this if you have some constant time drift */
+#define USECS_PER_JIFFY	(1000000/HZ)
+
+static int dummy_set_rtc(void)
+{
+	return 0;
+}
+
+/*
+ * hook for setting the RTC's idea of the current time.
+ */
+int (*set_rtc)(void) = dummy_set_rtc;
+
+/*
+ * Get time offset based on IOCs timer.
+ * FIXME - if this is called with interrutps off, why the shennanigans
+ * below ?
+ */
+static unsigned long gettimeoffset(void)
+{
+        unsigned int count1, count2, status;
+        long offset;
+
+        ioc_writeb (0, IOC_T0LATCH);
+        barrier ();
+        count1 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8);
+        barrier ();
+        status = ioc_readb(IOC_IRQREQA);
+        barrier ();
+        ioc_writeb (0, IOC_T0LATCH);
+        barrier ();
+        count2 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8);
+
+        offset = count2;
+        if (count2 < count1) {
+                /*
+                 * We have not had an interrupt between reading count1
+                 * and count2.
+                 */
+                if (status & (1 << 5))
+                        offset -= LATCH;
+        } else if (count2 > count1) {
+                /*
+                 * We have just had another interrupt between reading
+                 * count1 and count2.
+                 */
+                offset -= LATCH;
+        }
+
+        offset = (LATCH - offset) * (tick_nsec / 1000);
+        return (offset + LATCH/2) / LATCH;
+}
+
+/*
+ * Scheduler clock - returns current time in nanosec units.
+ */
+unsigned long long sched_clock(void)
+{
+	return (unsigned long long)jiffies * (1000000000 / HZ);
+}
+
+static unsigned long next_rtc_update;
+
+/*
+ * If we have an externally synchronized linux clock, then update
+ * CMOS clock accordingly every ~11 minutes.  set_rtc() has to be
+ * called as close as possible to 500 ms before the new second
+ * starts.
+ */
+static inline void do_set_rtc(void)
+{
+	if (time_status & STA_UNSYNC || set_rtc == NULL)
+		return;
+
+//FIXME - timespec.tv_sec is a time_t not unsigned long
+	if (next_rtc_update &&
+	    time_before((unsigned long)xtime.tv_sec, next_rtc_update))
+		return;
+
+	if (xtime.tv_nsec < 500000000 - ((unsigned) tick_nsec >> 1) &&
+	    xtime.tv_nsec >= 500000000 + ((unsigned) tick_nsec >> 1))
+		return;
+
+	if (set_rtc())
+		/*
+		 * rtc update failed.  Try again in 60s
+		 */
+		next_rtc_update = xtime.tv_sec + 60;
+	else
+		next_rtc_update = xtime.tv_sec + 660;
+}
+
+#define do_leds()
+
+void do_gettimeofday(struct timeval *tv)
+{
+	unsigned long flags;
+	unsigned long seq;
+	unsigned long usec, sec, lost;
+
+	do {
+		seq = read_seqbegin_irqsave(&xtime_lock, flags);
+		usec = gettimeoffset();
+
+		lost = jiffies - wall_jiffies;
+		if (lost)
+			usec += lost * USECS_PER_JIFFY;
+
+		sec = xtime.tv_sec;
+		usec += xtime.tv_nsec / 1000;
+	} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
+
+	/* usec may have gone up a lot: be safe */
+	while (usec >= 1000000) {
+		usec -= 1000000;
+		sec++;
+	}
+
+	tv->tv_sec = sec;
+	tv->tv_usec = usec;
+}
+
+EXPORT_SYMBOL(do_gettimeofday);
+
+int do_settimeofday(struct timespec *tv)
+{
+	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
+	 * done, and then undo it!
+	 */
+	tv->tv_nsec -= 1000 * (gettimeoffset() +
+			(jiffies - wall_jiffies) * USECS_PER_JIFFY);
+
+	while (tv->tv_nsec < 0) {
+		tv->tv_nsec += NSEC_PER_SEC;
+		tv->tv_sec--;
+	}
+
+	xtime.tv_sec = tv->tv_sec;
+	xtime.tv_nsec = tv->tv_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);
+	clock_was_set();
+	return 0;
+}
+
+EXPORT_SYMBOL(do_settimeofday);
+
+static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+        do_timer(regs);
+#ifndef CONFIG_SMP
+	update_process_times(user_mode(regs));
+#endif
+        do_set_rtc(); //FIME - EVERY timer IRQ?
+        profile_tick(CPU_PROFILING, regs);
+	return IRQ_HANDLED; //FIXME - is this right?
+}
+
+static struct irqaction timer_irq = {
+	.name	= "timer",
+	.flags	= SA_INTERRUPT,
+	.handler = timer_interrupt,
+};
+
+extern void ioctime_init(void);
+
+/*
+ * Set up timer interrupt.
+ */
+void __init time_init(void)
+{
+	ioc_writeb(LATCH & 255, IOC_T0LTCHL);
+        ioc_writeb(LATCH >> 8, IOC_T0LTCHH);
+        ioc_writeb(0, IOC_T0GO);
+
+
+        setup_irq(IRQ_TIMER, &timer_irq);
+}
+
diff --git a/arch/arm26/kernel/traps.c b/arch/arm26/kernel/traps.c
new file mode 100644
index 0000000..f64f590
--- /dev/null
+++ b/arch/arm26/kernel/traps.c
@@ -0,0 +1,548 @@
+/*
+ *  linux/arch/arm26/kernel/traps.c
+ *
+ *  Copyright (C) 1995-2002 Russell King
+ *  Fragments that appear the same as linux/arch/i386/kernel/traps.c (C) Linus Torvalds
+ *  Copyright (C) 2003 Ian Molton (ARM26)
+ *
+ * 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.
+ *
+ *  'traps.c' handles hardware exceptions after we have saved some state in
+ *  'linux/arch/arm26/lib/traps.S'.  Mostly a debugging aid, but will probably
+ *  kill the offending process.
+ */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/spinlock.h>
+#include <linux/personality.h>
+#include <linux/ptrace.h>
+#include <linux/elf.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+
+#include <asm/atomic.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/unistd.h>
+#include <asm/semaphore.h>
+
+#include "ptrace.h"
+
+extern void c_backtrace (unsigned long fp, int pmode);
+extern void show_pte(struct mm_struct *mm, unsigned long addr);
+
+const char *processor_modes[] = { "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" };
+
+static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" "*bad reason*"};
+
+/*
+ * Stack pointers should always be within the kernels view of
+ * physical memory.  If it is not there, then we can't dump
+ * out any information relating to the stack.
+ */
+static int verify_stack(unsigned long sp)
+{
+	if (sp < PAGE_OFFSET || (sp > (unsigned long)high_memory && high_memory != 0))
+		return -EFAULT;
+
+	return 0;
+}
+
+/*
+ * Dump out the contents of some memory nicely...
+ */
+static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
+{
+	unsigned long p = bottom & ~31;
+	mm_segment_t fs;
+	int i;
+
+	/*
+	 * We need to switch to kernel mode so that we can use __get_user
+	 * to safely read from kernel space.  Note that we now dump the
+	 * code first, just in case the backtrace kills us.
+	 */
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+
+	printk("%s", str);
+	printk("(0x%08lx to 0x%08lx)\n", bottom, top);
+
+	for (p = bottom & ~31; p < top;) {
+		printk("%04lx: ", p & 0xffff);
+
+		for (i = 0; i < 8; i++, p += 4) {
+			unsigned int val;
+
+			if (p < bottom || p >= top)
+				printk("         ");
+			else {
+				__get_user(val, (unsigned long *)p);
+				printk("%08x ", val);
+			}
+		}
+		printk ("\n");
+	}
+
+	set_fs(fs);
+}
+
+static void dump_instr(struct pt_regs *regs)
+{
+	unsigned long addr = instruction_pointer(regs);
+	const int width = 8;
+	mm_segment_t fs;
+	int i;
+
+	/*
+	 * We need to switch to kernel mode so that we can use __get_user
+	 * to safely read from kernel space.  Note that we now dump the
+	 * code first, just in case the backtrace kills us.
+	 */
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+
+	printk("Code: ");
+	for (i = -4; i < 1; i++) {
+		unsigned int val, bad;
+
+		bad = __get_user(val, &((u32 *)addr)[i]);
+
+		if (!bad)
+			printk(i == 0 ? "(%0*x) " : "%0*x ", width, val);
+		else {
+			printk("bad PC value.");
+			break;
+		}
+	}
+	printk("\n");
+
+	set_fs(fs);
+}
+
+/*static*/ void __dump_stack(struct task_struct *tsk, unsigned long sp)
+{
+	dump_mem("Stack: ", sp, 8192+(unsigned long)tsk->thread_info);
+}
+
+void dump_stack(void)
+{
+#ifdef CONFIG_DEBUG_ERRORS
+        __backtrace();
+#endif
+}
+
+EXPORT_SYMBOL(dump_stack);
+
+//FIXME - was a static fn
+void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
+{
+	unsigned int fp;
+	int ok = 1;
+
+	printk("Backtrace: ");
+	fp = regs->ARM_fp;
+	if (!fp) {
+		printk("no frame pointer");
+		ok = 0;
+	} else if (verify_stack(fp)) {
+		printk("invalid frame pointer 0x%08x", fp);
+		ok = 0;
+	} else if (fp < (unsigned long)(tsk->thread_info + 1))
+		printk("frame pointer underflow");
+	printk("\n");
+
+	if (ok)
+		c_backtrace(fp, processor_mode(regs));
+}
+
+/* FIXME - this is probably wrong.. */
+void show_stack(struct task_struct *task, unsigned long *sp) {
+	dump_mem("Stack: ", (unsigned long)sp, 8192+(unsigned long)task->thread_info);
+}
+
+DEFINE_SPINLOCK(die_lock);
+
+/*
+ * This function is protected against re-entrancy.
+ */
+NORET_TYPE void die(const char *str, struct pt_regs *regs, int err)
+{
+	struct task_struct *tsk = current;
+
+	console_verbose();
+	spin_lock_irq(&die_lock);
+
+	printk("Internal error: %s: %x\n", str, err);
+	printk("CPU: %d\n", smp_processor_id());
+	show_regs(regs);
+	printk("Process %s (pid: %d, stack limit = 0x%p)\n",
+		current->comm, current->pid, tsk->thread_info + 1);
+
+	if (!user_mode(regs) || in_interrupt()) {
+		__dump_stack(tsk, (unsigned long)(regs + 1));
+		dump_backtrace(regs, tsk);
+		dump_instr(regs);
+	}
+while(1);
+	spin_unlock_irq(&die_lock);
+	do_exit(SIGSEGV);
+}
+
+void die_if_kernel(const char *str, struct pt_regs *regs, int err)
+{
+	if (user_mode(regs))
+    		return;
+
+    	die(str, regs, err);
+}
+
+static DECLARE_MUTEX(undef_sem);
+static int (*undef_hook)(struct pt_regs *);
+
+int request_undef_hook(int (*fn)(struct pt_regs *))
+{
+	int ret = -EBUSY;
+
+	down(&undef_sem);
+	if (undef_hook == NULL) {
+		undef_hook = fn;
+		ret = 0;
+	}
+	up(&undef_sem);
+
+	return ret;
+}
+
+int release_undef_hook(int (*fn)(struct pt_regs *))
+{
+	int ret = -EINVAL;
+
+	down(&undef_sem);
+	if (undef_hook == fn) {
+		undef_hook = NULL;
+		ret = 0;
+	}
+	up(&undef_sem);
+
+	return ret;
+}
+
+static int undefined_extension(struct pt_regs *regs, unsigned int op)
+{
+	switch (op) {
+	case 1:	/* 0xde01 / 0x?7f001f0 */
+		ptrace_break(current, regs);
+		return 0;
+	}
+	return 1;
+}
+
+asmlinkage void do_undefinstr(struct pt_regs *regs)
+{
+	siginfo_t info;
+	void *pc;
+
+	regs->ARM_pc -= 4;
+
+	pc = (unsigned long *)instruction_pointer(regs); /* strip PSR */
+
+	if (user_mode(regs)) {
+		u32 instr;
+
+		get_user(instr, (u32 *)pc);
+
+		if ((instr & 0x0fff00ff) == 0x07f000f0 &&
+		    undefined_extension(regs, (instr >> 8) & 255) == 0) {
+			regs->ARM_pc += 4;
+			return;
+		}
+	} else {
+		if (undef_hook && undef_hook(regs) == 0) {
+			regs->ARM_pc += 4;
+			return;
+		}
+	}
+
+#ifdef CONFIG_DEBUG_USER
+	printk(KERN_INFO "%s (%d): undefined instruction: pc=%p\n",
+		current->comm, current->pid, pc);
+	dump_instr(regs);
+#endif
+
+	current->thread.error_code = 0;
+	current->thread.trap_no = 6;
+
+	info.si_signo = SIGILL;
+	info.si_errno = 0;
+	info.si_code  = ILL_ILLOPC;
+	info.si_addr  = pc;
+
+	force_sig_info(SIGILL, &info, current);
+
+	die_if_kernel("Oops - undefined instruction", regs, 0);
+}
+
+asmlinkage void do_excpt(unsigned long address, struct pt_regs *regs, int mode)
+{
+	siginfo_t info;
+
+#ifdef CONFIG_DEBUG_USER
+	printk(KERN_INFO "%s (%d): address exception: pc=%08lx\n",
+		current->comm, current->pid, instruction_pointer(regs));
+	dump_instr(regs);
+#endif
+
+	current->thread.error_code = 0;
+	current->thread.trap_no = 11;
+
+	info.si_signo = SIGBUS;
+	info.si_errno = 0;
+	info.si_code  = BUS_ADRERR;
+	info.si_addr  = (void *)address;
+
+	force_sig_info(SIGBUS, &info, current);
+
+	die_if_kernel("Oops - address exception", regs, mode);
+}
+
+asmlinkage void do_unexp_fiq (struct pt_regs *regs)
+{
+#ifndef CONFIG_IGNORE_FIQ
+	printk("Hmm.  Unexpected FIQ received, but trying to continue\n");
+	printk("You may have a hardware problem...\n");
+#endif
+}
+
+/*
+ * bad_mode handles the impossible case in the vectors.  If you see one of
+ * these, then it's extremely serious, and could mean you have buggy hardware.
+ * It never returns, and never tries to sync.  We hope that we can at least
+ * dump out some state information...
+ */
+asmlinkage void bad_mode(struct pt_regs *regs, int reason, int proc_mode)
+{
+	unsigned int vectors = vectors_base();
+
+	console_verbose();
+
+	printk(KERN_CRIT "Bad mode in %s handler detected: mode %s\n",
+		handler[reason<5?reason:4], processor_modes[proc_mode]);
+
+	/*
+	 * Dump out the vectors and stub routines.  Maybe a better solution
+	 * would be to dump them out only if we detect that they are corrupted.
+	 */
+	dump_mem(KERN_CRIT "Vectors: ", vectors, vectors + 0x40);
+	dump_mem(KERN_CRIT "Stubs: ", vectors + 0x200, vectors + 0x4b8);
+
+	die("Oops", regs, 0);
+	local_irq_disable();
+	panic("bad mode");
+}
+
+static int bad_syscall(int n, struct pt_regs *regs)
+{
+	struct thread_info *thread = current_thread_info();
+	siginfo_t info;
+
+	if (current->personality != PER_LINUX && thread->exec_domain->handler) {
+		thread->exec_domain->handler(n, regs);
+		return regs->ARM_r0;
+	}
+
+#ifdef CONFIG_DEBUG_USER
+	printk(KERN_ERR "[%d] %s: obsolete system call %08x.\n",
+		current->pid, current->comm, n);
+	dump_instr(regs);
+#endif
+
+	info.si_signo = SIGILL;
+	info.si_errno = 0;
+	info.si_code  = ILL_ILLTRP;
+	info.si_addr  = (void *)instruction_pointer(regs) - 4;
+
+	force_sig_info(SIGILL, &info, current);
+	die_if_kernel("Oops", regs, n);
+	return regs->ARM_r0;
+}
+
+static inline void
+do_cache_op(unsigned long start, unsigned long end, int flags)
+{
+	struct vm_area_struct *vma;
+
+	if (end < start)
+		return;
+
+	vma = find_vma(current->active_mm, start);
+	if (vma && vma->vm_start < end) {
+		if (start < vma->vm_start)
+			start = vma->vm_start;
+		if (end > vma->vm_end)
+			end = vma->vm_end;
+	}
+}
+
+/*
+ * Handle all unrecognised system calls.
+ *  0x9f0000 - 0x9fffff are some more esoteric system calls
+ */
+#define NR(x) ((__ARM_NR_##x) - __ARM_NR_BASE)
+asmlinkage int arm_syscall(int no, struct pt_regs *regs)
+{
+	siginfo_t info;
+
+	if ((no >> 16) != 0x9f)
+		return bad_syscall(no, regs);
+
+	switch (no & 0xffff) {
+	case 0: /* branch through 0 */
+		info.si_signo = SIGSEGV;
+		info.si_errno = 0;
+		info.si_code  = SEGV_MAPERR;
+		info.si_addr  = NULL;
+
+		force_sig_info(SIGSEGV, &info, current);
+
+		die_if_kernel("branch through zero", regs, 0);
+		return 0;
+
+	case NR(breakpoint): /* SWI BREAK_POINT */
+		ptrace_break(current, regs);
+		return regs->ARM_r0;
+
+	case NR(cacheflush):
+		return 0;
+
+	case NR(usr26):
+		break;
+
+	default:
+		/* Calls 9f00xx..9f07ff are defined to return -ENOSYS
+		   if not implemented, rather than raising SIGILL.  This
+		   way the calling program can gracefully determine whether
+		   a feature is supported.  */
+		if (no <= 0x7ff)
+			return -ENOSYS;
+		break;
+	}
+#ifdef CONFIG_DEBUG_USER
+	/*
+	 * experience shows that these seem to indicate that
+	 * something catastrophic has happened
+	 */
+	printk("[%d] %s: arm syscall %d\n", current->pid, current->comm, no);
+	dump_instr(regs);
+	if (user_mode(regs)) {
+		show_regs(regs);
+		c_backtrace(regs->ARM_fp, processor_mode(regs));
+	}
+#endif
+	info.si_signo = SIGILL;
+	info.si_errno = 0;
+	info.si_code  = ILL_ILLTRP;
+	info.si_addr  = (void *)instruction_pointer(regs) - 4;
+
+	force_sig_info(SIGILL, &info, current);
+	die_if_kernel("Oops", regs, no);
+	return 0;
+}
+
+void __bad_xchg(volatile void *ptr, int size)
+{
+	printk("xchg: bad data size: pc 0x%p, ptr 0x%p, size %d\n",
+		__builtin_return_address(0), ptr, size);
+	BUG();
+}
+
+/*
+ * A data abort trap was taken, but we did not handle the instruction.
+ * Try to abort the user program, or panic if it was the kernel.
+ */
+asmlinkage void
+baddataabort(int code, unsigned long instr, struct pt_regs *regs)
+{
+	unsigned long addr = instruction_pointer(regs);
+	siginfo_t info;
+
+#ifdef CONFIG_DEBUG_USER
+	printk(KERN_ERR "[%d] %s: bad data abort: code %d instr 0x%08lx\n",
+		current->pid, current->comm, code, instr);
+	dump_instr(regs);
+	show_pte(current->mm, addr);
+#endif
+
+	info.si_signo = SIGILL;
+	info.si_errno = 0;
+	info.si_code  = ILL_ILLOPC;
+	info.si_addr  = (void *)addr;
+
+	force_sig_info(SIGILL, &info, current);
+	die_if_kernel("unknown data abort code", regs, instr);
+}
+
+volatile void __bug(const char *file, int line, void *data)
+{
+	printk(KERN_CRIT"kernel BUG at %s:%d!", file, line);
+	if (data)
+		printk(KERN_CRIT" - extra data = %p", data);
+	printk("\n");
+	*(int *)0 = 0;
+}
+
+void __readwrite_bug(const char *fn)
+{
+	printk("%s called, but not implemented", fn);
+	BUG();
+}
+
+void __pte_error(const char *file, int line, unsigned long val)
+{
+	printk("%s:%d: bad pte %08lx.\n", file, line, val);
+}
+
+void __pmd_error(const char *file, int line, unsigned long val)
+{
+	printk("%s:%d: bad pmd %08lx.\n", file, line, val);
+}
+
+void __pgd_error(const char *file, int line, unsigned long val)
+{
+	printk("%s:%d: bad pgd %08lx.\n", file, line, val);
+}
+
+asmlinkage void __div0(void)
+{
+	printk("Division by zero in kernel.\n");
+	dump_stack();
+}
+
+void abort(void)
+{
+	BUG();
+
+	/* if that doesn't kill us, halt */
+	panic("Oops failed to kill thread");
+}
+
+void __init trap_init(void)
+{
+	extern void __trap_init(unsigned long);
+	unsigned long base = vectors_base();
+
+	__trap_init(base);
+	if (base != 0)
+		printk(KERN_DEBUG "Relocating machine vectors to 0x%08lx\n",
+			base);
+}
diff --git a/arch/arm26/kernel/vmlinux-arm26-xip.lds.in b/arch/arm26/kernel/vmlinux-arm26-xip.lds.in
new file mode 100644
index 0000000..ca61ec8
--- /dev/null
+++ b/arch/arm26/kernel/vmlinux-arm26-xip.lds.in
@@ -0,0 +1,134 @@
+/* ld script to make ARM Linux kernel
+ * taken from the i386 version by Russell King
+ * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ * borrowed from Russels ARM port by Ian Molton
+ */
+
+#include <asm-generic/vmlinux.lds.h>
+
+OUTPUT_ARCH(arm)
+ENTRY(stext)
+jiffies = jiffies_64;
+SECTIONS
+{
+	. = TEXTADDR;
+	.init : {			/* Init code and data		*/
+		_stext = .;
+		__init_begin = .;
+			_sinittext = .;
+			*(.init.text)
+			_einittext = .;
+		__proc_info_begin = .;
+			*(.proc.info)
+		__proc_info_end = .;
+		__arch_info_begin = .;
+			*(.arch.info)
+		__arch_info_end = .;
+		__tagtable_begin = .;
+			*(.taglist)
+		__tagtable_end = .;
+		. = ALIGN(16);
+		__setup_start = .;
+			*(.init.setup)
+		__setup_end = .;
+		__early_begin = .;
+			*(__early_param)
+		__early_end = .;
+		__initcall_start = .;
+			*(.initcall1.init)
+			*(.initcall2.init)
+			*(.initcall3.init)
+			*(.initcall4.init)
+			*(.initcall5.init)
+			*(.initcall6.init)
+			*(.initcall7.init)
+		__initcall_end = .;
+		__con_initcall_start = .;
+			*(.con_initcall.init)
+		__con_initcall_end = .;
+		. = ALIGN(32);
+		__initramfs_start = .;
+			usr/built-in.o(.init.ramfs)
+		__initramfs_end = .;
+		. = ALIGN(32768);
+		__init_end = .;
+	}
+
+	/DISCARD/ : {			/* Exit code and data		*/
+		*(.exit.text)
+		*(.exit.data)
+		*(.exitcall.exit)
+	}
+
+	.text : {			/* Real text segment		*/
+		_text = .;		/* Text and read-only data	*/
+			*(.text)
+			SCHED_TEXT
+			LOCK_TEXT       /* FIXME - borrowed from arm32 - check*/
+			*(.fixup)
+			*(.gnu.warning)
+			*(.rodata)
+			*(.rodata.*)
+			*(.glue_7)
+			*(.glue_7t)
+		*(.got)			/* Global offset table		*/
+
+		_etext = .;		/* End of text section		*/
+	}
+
+	. = ALIGN(16);
+	__ex_table : {			/* Exception table		*/
+		__start___ex_table = .;
+			*(__ex_table)
+		__stop___ex_table = .;
+	}
+
+	RODATA
+
+	_endtext = .;
+
+	. = DATAADDR;
+
+	_sdata = .;
+
+	.data : {
+		. = ALIGN(8192);
+		/*
+		 * first, the init thread union, aligned
+		 * to an 8192 byte boundary. (see arm26/kernel/init_task.c)
+		 * FIXME - sould this be 32K aligned on arm26?
+		 */
+		*(.init.task)
+
+		/*
+		 * The cacheline aligned data
+		 */
+		. = ALIGN(32);
+		*(.data.cacheline_aligned)
+
+		/*
+		 * and the usual data section
+		 */
+		*(.data)
+		CONSTRUCTORS
+
+		*(.init.data)
+
+		_edata = .;
+	}
+
+	.bss : {
+		__bss_start = .;	/* BSS				*/
+		*(.bss)
+		*(COMMON)
+		_end = . ;
+	}
+					/* Stabs debugging sections.	*/
+	.stab 0 : { *(.stab) }
+	.stabstr 0 : { *(.stabstr) }
+	.stab.excl 0 : { *(.stab.excl) }
+	.stab.exclstr 0 : { *(.stab.exclstr) }
+	.stab.index 0 : { *(.stab.index) }
+	.stab.indexstr 0 : { *(.stab.indexstr) }
+	.comment 0 : { *(.comment) }
+}
diff --git a/arch/arm26/kernel/vmlinux-arm26.lds.in b/arch/arm26/kernel/vmlinux-arm26.lds.in
new file mode 100644
index 0000000..d1d3418
--- /dev/null
+++ b/arch/arm26/kernel/vmlinux-arm26.lds.in
@@ -0,0 +1,127 @@
+/* ld script to make ARM Linux kernel
+ * taken from the i386 version by Russell King
+ * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ * borrowed from Russels ARM port by Ian Molton and subsequently modified.
+ */
+
+#include <asm-generic/vmlinux.lds.h>
+
+OUTPUT_ARCH(arm)
+ENTRY(stext)
+jiffies = jiffies_64;
+SECTIONS
+{
+	. = TEXTADDR;
+	.init : {			/* Init code and data		*/
+		_stext = .;
+		__init_begin = .;
+			_sinittext = .;
+			*(.init.text)
+			_einittext = .;
+		__proc_info_begin = .;
+			*(.proc.info)
+		__proc_info_end = .;
+		__arch_info_begin = .;
+			*(.arch.info)
+		__arch_info_end = .;
+		__tagtable_begin = .;
+			*(.taglist)
+		__tagtable_end = .;
+			*(.init.data)
+		. = ALIGN(16);
+		__setup_start = .;
+			*(.init.setup)
+		__setup_end = .;
+		__early_begin = .;
+			*(__early_param)
+		__early_end = .;
+		__initcall_start = .;
+			*(.initcall1.init)
+			*(.initcall2.init)
+			*(.initcall3.init)
+			*(.initcall4.init)
+			*(.initcall5.init)
+			*(.initcall6.init)
+			*(.initcall7.init)
+		__initcall_end = .;
+		__con_initcall_start = .;
+			*(.con_initcall.init)
+		__con_initcall_end = .;
+		. = ALIGN(32);
+		__initramfs_start = .;
+			usr/built-in.o(.init.ramfs)
+		__initramfs_end = .;
+		. = ALIGN(32768);
+		__init_end = .;
+	}
+
+	/DISCARD/ : {			/* Exit code and data		*/
+		*(.exit.text)
+		*(.exit.data)
+		*(.exitcall.exit)
+	}
+
+	.text : {			/* Real text segment		*/
+		_text = .;		/* Text and read-only data	*/
+			*(.text)
+			SCHED_TEXT
+			LOCK_TEXT
+			*(.fixup)
+			*(.gnu.warning)
+			*(.rodata)
+			*(.rodata.*)
+			*(.glue_7)
+			*(.glue_7t)
+		*(.got)			/* Global offset table		*/
+
+		_etext = .;		/* End of text section		*/
+	}
+
+	. = ALIGN(16);
+	__ex_table : {			/* Exception table		*/
+		__start___ex_table = .;
+			*(__ex_table)
+		__stop___ex_table = .;
+	}
+
+	RODATA
+
+	. = ALIGN(8192);
+
+	.data : {
+		/*
+		 * first, the init task union, aligned
+		 * to an 8192 byte boundary. (see arm26/kernel/init_task.c)
+		 */
+		*(.init.task)
+
+		/*
+		 * The cacheline aligned data
+		 */
+		. = ALIGN(32);
+		*(.data.cacheline_aligned)
+
+		/*
+		 * and the usual data section
+		 */
+		*(.data)
+		CONSTRUCTORS
+
+		_edata = .;
+	}
+
+	.bss : {
+		__bss_start = .;	/* BSS				*/
+		*(.bss)
+		*(COMMON)
+		_end = . ;
+	}
+					/* Stabs debugging sections.	*/
+	.stab 0 : { *(.stab) }
+	.stabstr 0 : { *(.stabstr) }
+	.stab.excl 0 : { *(.stab.excl) }
+	.stab.exclstr 0 : { *(.stab.exclstr) }
+	.stab.index 0 : { *(.stab.index) }
+	.stab.indexstr 0 : { *(.stab.indexstr) }
+	.comment 0 : { *(.comment) }
+}
diff --git a/arch/arm26/kernel/vmlinux.lds.S b/arch/arm26/kernel/vmlinux.lds.S
new file mode 100644
index 0000000..811a690
--- /dev/null
+++ b/arch/arm26/kernel/vmlinux.lds.S
@@ -0,0 +1,12 @@
+#include <linux/config.h>
+
+#ifdef CONFIG_XIP_KERNEL
+
+#include "vmlinux-arm26-xip.lds.in"
+
+#else
+
+#include "vmlinux-arm26.lds.in"
+
+#endif
+