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/sh/kernel/Makefile b/arch/sh/kernel/Makefile
new file mode 100644
index 0000000..8b81969
--- /dev/null
+++ b/arch/sh/kernel/Makefile
@@ -0,0 +1,22 @@
+#
+# Makefile for the Linux/SuperH kernel.
+#
+
+extra-y	:= head.o init_task.o vmlinux.lds
+
+obj-y	:= process.o signal.o entry.o traps.o irq.o \
+	ptrace.o setup.o time.o sys_sh.o semaphore.o \
+	io.o io_generic.o sh_ksyms.o
+
+obj-y				+= cpu/
+
+obj-$(CONFIG_SMP)		+= smp.o
+obj-$(CONFIG_CF_ENABLER)	+= cf-enabler.o
+obj-$(CONFIG_SH_STANDARD_BIOS)	+= sh_bios.o
+obj-$(CONFIG_SH_KGDB)		+= kgdb_stub.o kgdb_jmp.o
+obj-$(CONFIG_SH_CPU_FREQ)	+= cpufreq.o
+obj-$(CONFIG_MODULES)		+= module.o
+obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
+
+USE_STANDARD_AS_RULE := true
+
diff --git a/arch/sh/kernel/asm-offsets.c b/arch/sh/kernel/asm-offsets.c
new file mode 100644
index 0000000..dc6725c
--- /dev/null
+++ b/arch/sh/kernel/asm-offsets.c
@@ -0,0 +1,32 @@
+/*
+ * This program is used to generate definitions needed by
+ * assembly language modules.
+ *
+ * We use the technique used in the OSF Mach kernel code:
+ * generate asm statements containing #defines,
+ * compile this file to assembler, and then extract the
+ * #defines from the assembly-language output.
+ */
+
+#include <linux/stddef.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <asm/thread_info.h>
+
+#define DEFINE(sym, val) \
+        asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+
+#define BLANK() asm volatile("\n->" : : )
+
+int main(void)
+{
+	/* offsets into the thread_info struct */
+	DEFINE(TI_TASK,		offsetof(struct thread_info, task));
+	DEFINE(TI_EXEC_DOMAIN,	offsetof(struct thread_info, exec_domain));
+	DEFINE(TI_FLAGS,	offsetof(struct thread_info, flags));
+	DEFINE(TI_CPU,		offsetof(struct thread_info, cpu));
+	DEFINE(TI_PRE_COUNT,	offsetof(struct thread_info, preempt_count));
+	DEFINE(TI_RESTART_BLOCK,offsetof(struct thread_info, restart_block));
+
+	return 0;
+}
diff --git a/arch/sh/kernel/cf-enabler.c b/arch/sh/kernel/cf-enabler.c
new file mode 100644
index 0000000..7a3b18f
--- /dev/null
+++ b/arch/sh/kernel/cf-enabler.c
@@ -0,0 +1,158 @@
+/* $Id: cf-enabler.c,v 1.4 2004/02/22 22:44:36 kkojima Exp $
+ *
+ *  linux/drivers/block/cf-enabler.c
+ *
+ *  Copyright (C) 1999  Niibe Yutaka
+ *  Copyright (C) 2000  Toshiharu Nozawa
+ *  Copyright (C) 2001  A&D Co., Ltd.
+ *
+ *  Enable the CF configuration.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+/*
+ * You can connect Compact Flash directly to the bus of SuperH.
+ * This is the enabler for that.
+ *
+ * SIM: How generic is this really? It looks pretty board, or at
+ * least SH sub-type, specific to me.
+ * I know it doesn't work on the Overdrive!
+ */
+
+/*
+ * 0xB8000000 : Attribute
+ * 0xB8001000 : Common Memory
+ * 0xBA000000 : I/O
+ */
+#if defined(CONFIG_IDE) && defined(CONFIG_CPU_SH4)
+/* SH4 can't access PCMCIA interface through P2 area.
+ * we must remap it with appropreate attribute bit of the page set.
+ * this part is based on Greg Banks' hd64465_ss.c implementation - Masahiro Abe */
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+
+#if defined(CONFIG_CF_AREA6)
+#define slot_no 0
+#else
+#define slot_no 1
+#endif
+
+/* defined in mm/ioremap.c */
+extern void * p3_ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags);
+
+/* use this pointer to access to directly connected compact flash io area*/
+void *cf_io_base;
+
+static int __init allocate_cf_area(void)
+{
+	pgprot_t prot;
+	unsigned long paddrbase, psize;
+
+	/* open I/O area window */
+	paddrbase = virt_to_phys((void*)CONFIG_CF_BASE_ADDR);
+	psize = PAGE_SIZE;
+	prot = PAGE_KERNEL_PCC(slot_no, _PAGE_PCC_IO16);
+	cf_io_base = p3_ioremap(paddrbase, psize, prot.pgprot);
+	if (!cf_io_base) {
+		printk("allocate_cf_area : can't open CF I/O window!\n");
+		return -ENOMEM;
+	}
+/*	printk("p3_ioremap(paddr=0x%08lx, psize=0x%08lx, prot=0x%08lx)=0x%08lx\n",
+	    	paddrbase, psize, prot.pgprot, cf_io_base);*/
+
+	/* XXX : do we need attribute and common-memory area also? */
+
+	return 0;
+}
+#endif
+
+static int __init cf_init_default(void)
+{
+/* You must have enabled the card, and set the level interrupt
+ * before reaching this point. Possibly in boot ROM or boot loader.
+ */
+#if defined(CONFIG_IDE) && defined(CONFIG_CPU_SH4)
+	allocate_cf_area();
+#endif
+#if defined(CONFIG_SH_UNKNOWN)
+	/* This should be done in each board's init_xxx_irq. */
+	make_imask_irq(14);
+	disable_irq(14);
+#endif
+	return 0;
+}
+
+#if defined(CONFIG_SH_SOLUTION_ENGINE)
+#include <asm/se/se.h>
+
+/*
+ * SolutionEngine
+ *
+ * 0xB8400000 : Common Memory
+ * 0xB8500000 : Attribute
+ * 0xB8600000 : I/O
+ */
+
+static int __init cf_init_se(void)
+{
+	if ((ctrl_inw(MRSHPC_CSR) & 0x000c) != 0)
+		return 0;	/* Not detected */
+
+	if ((ctrl_inw(MRSHPC_CSR) & 0x0080) == 0) {
+		ctrl_outw(0x0674, MRSHPC_CPWCR); /* Card Vcc is 3.3v? */
+	} else {
+		ctrl_outw(0x0678, MRSHPC_CPWCR); /* Card Vcc is 5V */
+	}
+
+	/*
+	 *  PC-Card window open 
+	 *  flag == COMMON/ATTRIBUTE/IO
+	 */
+	/* common window open */
+	ctrl_outw(0x8a84, MRSHPC_MW0CR1);/* window 0xb8400000 */
+	if((ctrl_inw(MRSHPC_CSR) & 0x4000) != 0)
+		/* common mode & bus width 16bit SWAP = 1*/
+		ctrl_outw(0x0b00, MRSHPC_MW0CR2);
+	else
+		/* common mode & bus width 16bit SWAP = 0*/
+		ctrl_outw(0x0300, MRSHPC_MW0CR2); 
+
+	/* attribute window open */
+	ctrl_outw(0x8a85, MRSHPC_MW1CR1);/* window 0xb8500000 */
+	if ((ctrl_inw(MRSHPC_CSR) & 0x4000) != 0)
+		/* attribute mode & bus width 16bit SWAP = 1*/
+		ctrl_outw(0x0a00, MRSHPC_MW1CR2);
+	else
+		/* attribute mode & bus width 16bit SWAP = 0*/
+		ctrl_outw(0x0200, MRSHPC_MW1CR2);
+
+	/* I/O window open */
+	ctrl_outw(0x8a86, MRSHPC_IOWCR1);/* I/O window 0xb8600000 */
+	ctrl_outw(0x0008, MRSHPC_CDCR);	 /* I/O card mode */
+	if ((ctrl_inw(MRSHPC_CSR) & 0x4000) != 0)
+		ctrl_outw(0x0a00, MRSHPC_IOWCR2); /* bus width 16bit SWAP = 1*/
+	else
+		ctrl_outw(0x0200, MRSHPC_IOWCR2); /* bus width 16bit SWAP = 0*/
+
+	ctrl_outw(0x2000, MRSHPC_ICR);
+	ctrl_outb(0x00, PA_MRSHPC_MW2 + 0x206);
+	ctrl_outb(0x42, PA_MRSHPC_MW2 + 0x200);
+	return 0;
+}
+#endif
+
+int __init cf_init(void)
+{
+#if defined(CONFIG_SH_SOLUTION_ENGINE)
+	if (MACH_SE)
+		return cf_init_se();
+#endif
+	return cf_init_default();
+}
+
+__initcall (cf_init);
diff --git a/arch/sh/kernel/cpu/Makefile b/arch/sh/kernel/cpu/Makefile
new file mode 100644
index 0000000..cd43714
--- /dev/null
+++ b/arch/sh/kernel/cpu/Makefile
@@ -0,0 +1,16 @@
+#
+# Makefile for the Linux/SuperH CPU-specifc backends.
+#
+
+obj-y	:= irq_ipr.o irq_imask.o init.o bus.o
+
+obj-$(CONFIG_CPU_SH2)		+= sh2/
+obj-$(CONFIG_CPU_SH3)		+= sh3/
+obj-$(CONFIG_CPU_SH4)		+= sh4/
+
+obj-$(CONFIG_SH_RTC)            += rtc.o
+obj-$(CONFIG_UBC_WAKEUP)	+= ubc.o
+obj-$(CONFIG_SH_ADC)            += adc.o
+
+USE_STANDARD_AS_RULE := true
+
diff --git a/arch/sh/kernel/cpu/adc.c b/arch/sh/kernel/cpu/adc.c
new file mode 100644
index 0000000..da3d687
--- /dev/null
+++ b/arch/sh/kernel/cpu/adc.c
@@ -0,0 +1,36 @@
+/*
+ * linux/arch/sh/kernel/adc.c -- SH3 on-chip ADC support
+ *
+ *  Copyright (C) 2004  Andriy Skulysh <askulysh@image.kiev.ua>
+ */
+
+#include <linux/module.h>
+#include <asm/adc.h>
+#include <asm/io.h>
+
+
+int adc_single(unsigned int channel)
+{
+	int off;
+	unsigned char csr;
+
+	if (channel >= 8) return -1;
+
+	off = (channel & 0x03) << 2;
+
+	csr = ctrl_inb(ADCSR);
+	csr = channel | ADCSR_ADST | ADCSR_CKS;
+	ctrl_outb(csr, ADCSR);
+
+	do {
+		csr = ctrl_inb(ADCSR);
+	} while ((csr & ADCSR_ADF) == 0);
+
+	csr &= ~(ADCSR_ADF | ADCSR_ADST);
+	ctrl_outb(csr, ADCSR);
+
+	return (((ctrl_inb(ADDRAH + off) << 8) |
+		ctrl_inb(ADDRAL + off)) >> 6);
+}
+
+EXPORT_SYMBOL(adc_single);
diff --git a/arch/sh/kernel/cpu/bus.c b/arch/sh/kernel/cpu/bus.c
new file mode 100644
index 0000000..ace82f4
--- /dev/null
+++ b/arch/sh/kernel/cpu/bus.c
@@ -0,0 +1,195 @@
+/*
+ * arch/sh/kernel/cpu/bus.c
+ *
+ * Virtual bus for SuperH.
+ *
+ * Copyright (C) 2004 Paul Mundt
+ *
+ * Shamelessly cloned from arch/arm/mach-omap/bus.c, which was written
+ * by:
+ *
+ *  	Copyright (C) 2003 - 2004 Nokia Corporation
+ *  	Written by Tony Lindgren <tony@atomide.com>
+ *  	Portions of code based on sa1111.c.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <asm/bus-sh.h>
+
+static int sh_bus_match(struct device *dev, struct device_driver *drv)
+{
+	struct sh_driver *shdrv = to_sh_driver(drv);
+	struct sh_dev *shdev = to_sh_dev(dev);
+
+	return shdev->dev_id == shdrv->dev_id;
+}
+
+static int sh_bus_suspend(struct device *dev, u32 state)
+{
+	struct sh_dev *shdev = to_sh_dev(dev);
+	struct sh_driver *shdrv = to_sh_driver(dev->driver);
+
+	if (shdrv && shdrv->suspend)
+		return shdrv->suspend(shdev, state);
+
+	return 0;
+}
+
+static int sh_bus_resume(struct device *dev)
+{
+	struct sh_dev *shdev = to_sh_dev(dev);
+	struct sh_driver *shdrv = to_sh_driver(dev->driver);
+
+	if (shdrv && shdrv->resume)
+		return shdrv->resume(shdev);
+
+	return 0;
+}
+
+static struct device sh_bus_devices[SH_NR_BUSES] = {
+	{
+		.bus_id		= SH_BUS_NAME_VIRT,
+	},
+};
+
+struct bus_type sh_bus_types[SH_NR_BUSES] = {
+	{
+		.name		= SH_BUS_NAME_VIRT,
+		.match		= sh_bus_match,
+		.suspend	= sh_bus_suspend,
+		.resume		= sh_bus_resume,
+	},
+};
+
+static int sh_device_probe(struct device *dev)
+{
+	struct sh_dev *shdev = to_sh_dev(dev);
+	struct sh_driver *shdrv = to_sh_driver(dev->driver);
+
+	if (shdrv && shdrv->probe)
+		return shdrv->probe(shdev);
+
+	return -ENODEV;
+}
+
+static int sh_device_remove(struct device *dev)
+{
+	struct sh_dev *shdev = to_sh_dev(dev);
+	struct sh_driver *shdrv = to_sh_driver(dev->driver);
+
+	if (shdrv && shdrv->remove)
+		return shdrv->remove(shdev);
+
+	return 0;
+}
+
+int sh_device_register(struct sh_dev *dev)
+{
+	if (!dev)
+		return -EINVAL;
+
+	if (dev->bus_id < 0 || dev->bus_id >= SH_NR_BUSES) {
+		printk(KERN_ERR "%s: bus_id invalid: %s bus: %d\n",
+		       __FUNCTION__, dev->name, dev->bus_id);
+		return -EINVAL;
+	}
+
+	dev->dev.parent = &sh_bus_devices[dev->bus_id];
+	dev->dev.bus    = &sh_bus_types[dev->bus_id];
+
+	/* This is needed for USB OHCI to work */
+	if (dev->dma_mask)
+		dev->dev.dma_mask = dev->dma_mask;
+
+	snprintf(dev->dev.bus_id, BUS_ID_SIZE, "%s%u",
+		 dev->name, dev->dev_id);
+
+	printk(KERN_INFO "Registering SH device '%s'. Parent at %s\n",
+	       dev->dev.bus_id, dev->dev.parent->bus_id);
+
+	return device_register(&dev->dev);
+}
+
+void sh_device_unregister(struct sh_dev *dev)
+{
+	device_unregister(&dev->dev);
+}
+
+int sh_driver_register(struct sh_driver *drv)
+{
+	if (!drv)
+		return -EINVAL;
+
+	if (drv->bus_id < 0 || drv->bus_id >= SH_NR_BUSES) {
+		printk(KERN_ERR "%s: bus_id invalid: bus: %d device %d\n",
+		       __FUNCTION__, drv->bus_id, drv->dev_id);
+		return -EINVAL;
+	}
+
+	drv->drv.probe  = sh_device_probe;
+	drv->drv.remove = sh_device_remove;
+	drv->drv.bus    = &sh_bus_types[drv->bus_id];
+
+	return driver_register(&drv->drv);
+}
+
+void sh_driver_unregister(struct sh_driver *drv)
+{
+	driver_unregister(&drv->drv);
+}
+
+static int __init sh_bus_init(void)
+{
+	int i, ret = 0;
+
+	for (i = 0; i < SH_NR_BUSES; i++) {
+		ret = device_register(&sh_bus_devices[i]);
+		if (ret != 0) {
+			printk(KERN_ERR "Unable to register bus device %s\n",
+			       sh_bus_devices[i].bus_id);
+			continue;
+		}
+
+		ret = bus_register(&sh_bus_types[i]);
+		if (ret != 0) {
+			printk(KERN_ERR "Unable to register bus %s\n",
+			       sh_bus_types[i].name);
+			device_unregister(&sh_bus_devices[i]);
+		}
+	}
+
+	printk(KERN_INFO "SH Virtual Bus initialized\n");
+
+	return ret;
+}
+
+static void __exit sh_bus_exit(void)
+{
+	int i;
+
+	for (i = 0; i < SH_NR_BUSES; i++) {
+		bus_unregister(&sh_bus_types[i]);
+		device_unregister(&sh_bus_devices[i]);
+	}
+}
+
+module_init(sh_bus_init);
+module_exit(sh_bus_exit);
+
+MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
+MODULE_DESCRIPTION("SH Virtual Bus");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(sh_bus_types);
+EXPORT_SYMBOL(sh_device_register);
+EXPORT_SYMBOL(sh_device_unregister);
+EXPORT_SYMBOL(sh_driver_register);
+EXPORT_SYMBOL(sh_driver_unregister);
+
diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c
new file mode 100644
index 0000000..cf94e8e
--- /dev/null
+++ b/arch/sh/kernel/cpu/init.c
@@ -0,0 +1,222 @@
+/*
+ * arch/sh/kernel/cpu/init.c
+ *
+ * CPU init code
+ *
+ * Copyright (C) 2002, 2003  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/cacheflush.h>
+#include <asm/cache.h>
+#include <asm/io.h>
+
+extern void detect_cpu_and_cache_system(void);
+
+/*
+ * Generic wrapper for command line arguments to disable on-chip
+ * peripherals (nofpu, nodsp, and so forth).
+ */
+#define onchip_setup(x)				\
+static int x##_disabled __initdata = 0;		\
+						\
+static int __init x##_setup(char *opts)		\
+{						\
+	x##_disabled = 1;			\
+	return 0;				\
+}						\
+__setup("no" __stringify(x), x##_setup);
+
+onchip_setup(fpu);
+onchip_setup(dsp);
+
+/*
+ * Generic first-level cache init
+ */
+static void __init cache_init(void)
+{
+	unsigned long ccr, flags;
+
+	if (cpu_data->type == CPU_SH_NONE)
+		panic("Unknown CPU");
+
+	jump_to_P2();
+	ccr = ctrl_inl(CCR);
+
+	/*
+	 * If the cache is already enabled .. flush it.
+	 */
+	if (ccr & CCR_CACHE_ENABLE) {
+		unsigned long ways, waysize, addrstart;
+
+		waysize = cpu_data->dcache.sets;
+
+		/*
+		 * If the OC is already in RAM mode, we only have
+		 * half of the entries to flush..
+		 */
+		if (ccr & CCR_CACHE_ORA)
+			waysize >>= 1;
+
+		waysize <<= cpu_data->dcache.entry_shift;
+
+#ifdef CCR_CACHE_EMODE
+		/* If EMODE is not set, we only have 1 way to flush. */
+		if (!(ccr & CCR_CACHE_EMODE))
+			ways = 1;
+		else
+#endif
+			ways = cpu_data->dcache.ways;
+
+		addrstart = CACHE_OC_ADDRESS_ARRAY;
+		do {
+			unsigned long addr;
+
+			for (addr = addrstart;
+			     addr < addrstart + waysize;
+			     addr += cpu_data->dcache.linesz)
+				ctrl_outl(0, addr);
+
+			addrstart += cpu_data->dcache.way_incr;
+		} while (--ways);
+	}
+
+	/*
+	 * Default CCR values .. enable the caches
+	 * and invalidate them immediately..
+	 */
+	flags = CCR_CACHE_ENABLE | CCR_CACHE_INVALIDATE;
+
+#ifdef CCR_CACHE_EMODE
+	/* Force EMODE if possible */
+	if (cpu_data->dcache.ways > 1)
+		flags |= CCR_CACHE_EMODE;
+#endif
+
+#ifdef CONFIG_SH_WRITETHROUGH
+	/* Turn on Write-through caching */
+	flags |= CCR_CACHE_WT;
+#else
+	/* .. or default to Write-back */
+	flags |= CCR_CACHE_CB;
+#endif
+
+#ifdef CONFIG_SH_OCRAM
+	/* Turn on OCRAM -- halve the OC */
+	flags |= CCR_CACHE_ORA;
+	cpu_data->dcache.sets >>= 1;
+#endif
+
+	ctrl_outl(flags, CCR);
+	back_to_P1();
+}
+
+#ifdef CONFIG_SH_DSP
+static void __init release_dsp(void)
+{
+	unsigned long sr;
+
+	/* Clear SR.DSP bit */
+	__asm__ __volatile__ (
+		"stc\tsr, %0\n\t"
+		"and\t%1, %0\n\t"
+		"ldc\t%0, sr\n\t"
+		: "=&r" (sr)
+		: "r" (~SR_DSP)
+	);
+}
+
+static void __init dsp_init(void)
+{
+	unsigned long sr;
+
+	/*
+	 * Set the SR.DSP bit, wait for one instruction, and then read
+	 * back the SR value.
+	 */
+	__asm__ __volatile__ (
+		"stc\tsr, %0\n\t"
+		"or\t%1, %0\n\t"
+		"ldc\t%0, sr\n\t"
+		"nop\n\t"
+		"stc\tsr, %0\n\t"
+		: "=&r" (sr)
+		: "r" (SR_DSP)
+	);
+
+	/* If the DSP bit is still set, this CPU has a DSP */
+	if (sr & SR_DSP)
+		cpu_data->flags |= CPU_HAS_DSP;
+
+	/* Now that we've determined the DSP status, clear the DSP bit. */
+	release_dsp();
+}
+#endif /* CONFIG_SH_DSP */
+
+/**
+ * sh_cpu_init
+ *
+ * This is our initial entry point for each CPU, and is invoked on the boot
+ * CPU prior to calling start_kernel(). For SMP, a combination of this and
+ * start_secondary() will bring up each processor to a ready state prior
+ * to hand forking the idle loop.
+ *
+ * We do all of the basic processor init here, including setting up the
+ * caches, FPU, DSP, kicking the UBC, etc. By the time start_kernel() is
+ * hit (and subsequently platform_setup()) things like determining the
+ * CPU subtype and initial configuration will all be done.
+ *
+ * Each processor family is still responsible for doing its own probing
+ * and cache configuration in detect_cpu_and_cache_system().
+ */
+asmlinkage void __init sh_cpu_init(void)
+{
+	/* First, probe the CPU */
+	detect_cpu_and_cache_system();
+
+	/* Init the cache */
+	cache_init();
+
+	/* Disable the FPU */
+	if (fpu_disabled) {
+		printk("FPU Disabled\n");
+		cpu_data->flags &= ~CPU_HAS_FPU;
+		disable_fpu();
+	}
+
+	/* FPU initialization */
+	if ((cpu_data->flags & CPU_HAS_FPU)) {
+		clear_thread_flag(TIF_USEDFPU);
+		clear_used_math();
+	}
+
+#ifdef CONFIG_SH_DSP
+	/* Probe for DSP */
+	dsp_init();
+
+	/* Disable the DSP */
+	if (dsp_disabled) {
+		printk("DSP Disabled\n");
+		cpu_data->flags &= ~CPU_HAS_DSP;
+		release_dsp();
+	}
+#endif
+
+#ifdef CONFIG_UBC_WAKEUP
+	/*
+	 * Some brain-damaged loaders decided it would be a good idea to put
+	 * the UBC to sleep. This causes some issues when it comes to things
+	 * like PTRACE_SINGLESTEP or doing hardware watchpoints in GDB.  So ..
+	 * we wake it up and hope that all is well.
+	 */
+	ubc_wakeup();
+#endif
+}
+
diff --git a/arch/sh/kernel/cpu/irq_imask.c b/arch/sh/kernel/cpu/irq_imask.c
new file mode 100644
index 0000000..f76901e
--- /dev/null
+++ b/arch/sh/kernel/cpu/irq_imask.c
@@ -0,0 +1,116 @@
+/* $Id: irq_imask.c,v 1.1.2.1 2002/11/17 10:53:43 mrbrown Exp $
+ *
+ * linux/arch/sh/kernel/irq_imask.c
+ *
+ * Copyright (C) 1999, 2000  Niibe Yutaka
+ *
+ * Simple interrupt handling using IMASK of SR register.
+ *
+ */
+
+/* NOTE: Will not work on level 15 */
+
+
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/kernel_stat.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+
+#include <linux/spinlock.h>
+#include <linux/cache.h>
+#include <linux/irq.h>
+
+/* Bitmap of IRQ masked */
+static unsigned long imask_mask = 0x7fff;
+static int interrupt_priority = 0;
+
+static void enable_imask_irq(unsigned int irq);
+static void disable_imask_irq(unsigned int irq);
+static void shutdown_imask_irq(unsigned int irq);
+static void mask_and_ack_imask(unsigned int);
+static void end_imask_irq(unsigned int irq);
+
+#define IMASK_PRIORITY	15
+
+static unsigned int startup_imask_irq(unsigned int irq)
+{ 
+	/* Nothing to do */
+	return 0; /* never anything pending */
+}
+
+static struct hw_interrupt_type imask_irq_type = {
+	"SR.IMASK",
+	startup_imask_irq,
+	shutdown_imask_irq,
+	enable_imask_irq,
+	disable_imask_irq,
+	mask_and_ack_imask,
+	end_imask_irq
+};
+
+void static inline set_interrupt_registers(int ip)
+{
+	unsigned long __dummy;
+
+	asm volatile("ldc	%2, r6_bank\n\t"
+		     "stc	sr, %0\n\t"
+		     "and	#0xf0, %0\n\t"
+		     "shlr2	%0\n\t"
+		     "cmp/eq	#0x3c, %0\n\t"
+		     "bt/s	1f	! CLI-ed\n\t"
+		     " stc	sr, %0\n\t"
+		     "and	%1, %0\n\t"
+		     "or	%2, %0\n\t"
+		     "ldc	%0, sr\n"
+		     "1:"
+		     : "=&z" (__dummy)
+		     : "r" (~0xf0), "r" (ip << 4)
+		     : "t");
+}
+
+static void disable_imask_irq(unsigned int irq)
+{
+	clear_bit(irq, &imask_mask);
+	if (interrupt_priority < IMASK_PRIORITY - irq)
+		interrupt_priority = IMASK_PRIORITY - irq;
+
+	set_interrupt_registers(interrupt_priority);
+}
+
+static void enable_imask_irq(unsigned int irq)
+{
+	set_bit(irq, &imask_mask);
+	interrupt_priority = IMASK_PRIORITY - ffz(imask_mask);
+
+	set_interrupt_registers(interrupt_priority);
+}
+
+static void mask_and_ack_imask(unsigned int irq)
+{
+	disable_imask_irq(irq);
+}
+
+static void end_imask_irq(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+		enable_imask_irq(irq);
+}
+
+static void shutdown_imask_irq(unsigned int irq)
+{
+	/* Nothing to do */
+}
+
+void make_imask_irq(unsigned int irq)
+{
+	disable_irq_nosync(irq);
+	irq_desc[irq].handler = &imask_irq_type;
+	enable_irq(irq);
+}
diff --git a/arch/sh/kernel/cpu/irq_ipr.c b/arch/sh/kernel/cpu/irq_ipr.c
new file mode 100644
index 0000000..7ea3d2d
--- /dev/null
+++ b/arch/sh/kernel/cpu/irq_ipr.c
@@ -0,0 +1,339 @@
+/* $Id: irq_ipr.c,v 1.1.2.1 2002/11/17 10:53:43 mrbrown Exp $
+ *
+ * linux/arch/sh/kernel/irq_ipr.c
+ *
+ * Copyright (C) 1999  Niibe Yutaka & Takeshi Yaegashi
+ * Copyright (C) 2000  Kazumoto Kojima
+ * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp>
+ *
+ * Interrupt handling for IPR-based IRQ.
+ *
+ * Supported system:
+ *	On-chip supporting modules (TMU, RTC, etc.).
+ *	On-chip supporting modules for SH7709/SH7709A/SH7729/SH7300.
+ *	Hitachi SolutionEngine external I/O:
+ *		MS7709SE01, MS7709ASE01, and MS7750SE01
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/machvec.h>
+
+struct ipr_data {
+	unsigned int addr;	/* Address of Interrupt Priority Register */
+	int shift;		/* Shifts of the 16-bit data */
+	int priority;		/* The priority */
+};
+static struct ipr_data ipr_data[NR_IRQS];
+
+static void enable_ipr_irq(unsigned int irq);
+static void disable_ipr_irq(unsigned int irq);
+
+/* shutdown is same as "disable" */
+#define shutdown_ipr_irq disable_ipr_irq
+
+static void mask_and_ack_ipr(unsigned int);
+static void end_ipr_irq(unsigned int irq);
+
+static unsigned int startup_ipr_irq(unsigned int irq)
+{
+	enable_ipr_irq(irq);
+	return 0; /* never anything pending */
+}
+
+static struct hw_interrupt_type ipr_irq_type = {
+	"IPR-IRQ",
+	startup_ipr_irq,
+	shutdown_ipr_irq,
+	enable_ipr_irq,
+	disable_ipr_irq,
+	mask_and_ack_ipr,
+	end_ipr_irq
+};
+
+static void disable_ipr_irq(unsigned int irq)
+{
+	unsigned long val, flags;
+	unsigned int addr = ipr_data[irq].addr;
+	unsigned short mask = 0xffff ^ (0x0f << ipr_data[irq].shift);
+
+	/* Set the priority in IPR to 0 */
+	local_irq_save(flags);
+	val = ctrl_inw(addr);
+	val &= mask;
+	ctrl_outw(val, addr);
+	local_irq_restore(flags);
+}
+
+static void enable_ipr_irq(unsigned int irq)
+{
+	unsigned long val, flags;
+	unsigned int addr = ipr_data[irq].addr;
+	int priority = ipr_data[irq].priority;
+	unsigned short value = (priority << ipr_data[irq].shift);
+
+	/* Set priority in IPR back to original value */
+	local_irq_save(flags);
+	val = ctrl_inw(addr);
+	val |= value;
+	ctrl_outw(val, addr);
+	local_irq_restore(flags);
+}
+
+static void mask_and_ack_ipr(unsigned int irq)
+{
+	disable_ipr_irq(irq);
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
+	/* This is needed when we use edge triggered setting */
+	/* XXX: Is it really needed? */
+	if (IRQ0_IRQ <= irq && irq <= IRQ5_IRQ) {
+		/* Clear external interrupt request */
+		int a = ctrl_inb(INTC_IRR0);
+		a &= ~(1 << (irq - IRQ0_IRQ));
+		ctrl_outb(a, INTC_IRR0);
+	}
+#endif
+}
+
+static void end_ipr_irq(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+		enable_ipr_irq(irq);
+}
+
+void make_ipr_irq(unsigned int irq, unsigned int addr, int pos, int priority)
+{
+	disable_irq_nosync(irq);
+	ipr_data[irq].addr = addr;
+	ipr_data[irq].shift = pos*4; /* POSition (0-3) x 4 means shift */
+	ipr_data[irq].priority = priority;
+
+	irq_desc[irq].handler = &ipr_irq_type;
+	disable_ipr_irq(irq);
+}
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7709)
+static unsigned char pint_map[256];
+static unsigned long portcr_mask = 0;
+
+static void enable_pint_irq(unsigned int irq);
+static void disable_pint_irq(unsigned int irq);
+
+/* shutdown is same as "disable" */
+#define shutdown_pint_irq disable_pint_irq
+
+static void mask_and_ack_pint(unsigned int);
+static void end_pint_irq(unsigned int irq);
+
+static unsigned int startup_pint_irq(unsigned int irq)
+{
+	enable_pint_irq(irq);
+	return 0; /* never anything pending */
+}
+
+static struct hw_interrupt_type pint_irq_type = {
+	"PINT-IRQ",
+	startup_pint_irq,
+	shutdown_pint_irq,
+	enable_pint_irq,
+	disable_pint_irq,
+	mask_and_ack_pint,
+	end_pint_irq
+};
+
+static void disable_pint_irq(unsigned int irq)
+{
+	unsigned long val, flags;
+
+	local_irq_save(flags);
+	val = ctrl_inw(INTC_INTER);
+	val &= ~(1 << (irq - PINT_IRQ_BASE));
+	ctrl_outw(val, INTC_INTER);	/* disable PINTn */
+	portcr_mask &= ~(3 << (irq - PINT_IRQ_BASE)*2);
+	local_irq_restore(flags);
+}
+
+static void enable_pint_irq(unsigned int irq)
+{
+	unsigned long val, flags;
+
+	local_irq_save(flags);
+	val = ctrl_inw(INTC_INTER);
+	val |= 1 << (irq - PINT_IRQ_BASE);
+	ctrl_outw(val, INTC_INTER);	/* enable PINTn */
+	portcr_mask |= 3 << (irq - PINT_IRQ_BASE)*2;
+	local_irq_restore(flags);
+}
+
+static void mask_and_ack_pint(unsigned int irq)
+{
+	disable_pint_irq(irq);
+}
+
+static void end_pint_irq(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+		enable_pint_irq(irq);
+}
+
+void make_pint_irq(unsigned int irq)
+{
+	disable_irq_nosync(irq);
+	irq_desc[irq].handler = &pint_irq_type;
+	disable_pint_irq(irq);
+}
+#endif
+
+void __init init_IRQ(void)
+{
+#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7709)
+	int i;
+#endif
+
+	make_ipr_irq(TIMER_IRQ, TIMER_IPR_ADDR, TIMER_IPR_POS, TIMER_PRIORITY);
+	make_ipr_irq(TIMER1_IRQ, TIMER1_IPR_ADDR, TIMER1_IPR_POS, TIMER1_PRIORITY);
+#if defined(CONFIG_SH_RTC)
+	make_ipr_irq(RTC_IRQ, RTC_IPR_ADDR, RTC_IPR_POS, RTC_PRIORITY);
+#endif
+
+#ifdef SCI_ERI_IRQ
+	make_ipr_irq(SCI_ERI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY);
+	make_ipr_irq(SCI_RXI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY);
+	make_ipr_irq(SCI_TXI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY);
+#endif
+
+#ifdef SCIF1_ERI_IRQ
+	make_ipr_irq(SCIF1_ERI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY);
+	make_ipr_irq(SCIF1_RXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY);
+	make_ipr_irq(SCIF1_BRI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY);
+	make_ipr_irq(SCIF1_TXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY);
+#endif
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7300)
+	make_ipr_irq(SCIF0_IRQ, SCIF0_IPR_ADDR, SCIF0_IPR_POS, SCIF0_PRIORITY);
+	make_ipr_irq(DMTE2_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY);
+	make_ipr_irq(DMTE3_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY);
+	make_ipr_irq(VIO_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY);
+#endif
+
+#ifdef SCIF_ERI_IRQ
+	make_ipr_irq(SCIF_ERI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY);
+	make_ipr_irq(SCIF_RXI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY);
+	make_ipr_irq(SCIF_BRI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY);
+	make_ipr_irq(SCIF_TXI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY);
+#endif
+
+#ifdef IRDA_ERI_IRQ
+	make_ipr_irq(IRDA_ERI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY);
+	make_ipr_irq(IRDA_RXI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY);
+	make_ipr_irq(IRDA_BRI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY);
+	make_ipr_irq(IRDA_TXI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY);
+#endif
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
+	/*
+	 * Initialize the Interrupt Controller (INTC)
+	 * registers to their power on values
+	 */
+
+	/*
+	 * Enable external irq (INTC IRQ mode).
+	 * You should set corresponding bits of PFC to "00"
+	 * to enable these interrupts.
+	 */
+	make_ipr_irq(IRQ0_IRQ, IRQ0_IPR_ADDR, IRQ0_IPR_POS, IRQ0_PRIORITY);
+	make_ipr_irq(IRQ1_IRQ, IRQ1_IPR_ADDR, IRQ1_IPR_POS, IRQ1_PRIORITY);
+	make_ipr_irq(IRQ2_IRQ, IRQ2_IPR_ADDR, IRQ2_IPR_POS, IRQ2_PRIORITY);
+	make_ipr_irq(IRQ3_IRQ, IRQ3_IPR_ADDR, IRQ3_IPR_POS, IRQ3_PRIORITY);
+	make_ipr_irq(IRQ4_IRQ, IRQ4_IPR_ADDR, IRQ4_IPR_POS, IRQ4_PRIORITY);
+	make_ipr_irq(IRQ5_IRQ, IRQ5_IPR_ADDR, IRQ5_IPR_POS, IRQ5_PRIORITY);
+#if !defined(CONFIG_CPU_SUBTYPE_SH7300)
+	make_ipr_irq(PINT0_IRQ, PINT0_IPR_ADDR, PINT0_IPR_POS, PINT0_PRIORITY);
+	make_ipr_irq(PINT8_IRQ, PINT8_IPR_ADDR, PINT8_IPR_POS, PINT8_PRIORITY);
+	enable_ipr_irq(PINT0_IRQ);
+	enable_ipr_irq(PINT8_IRQ);
+
+	for(i = 0; i < 16; i++)
+		make_pint_irq(PINT_IRQ_BASE + i);
+	for(i = 0; i < 256; i++)
+	{
+		if(i & 1) pint_map[i] = 0;
+		else if(i & 2) pint_map[i] = 1;
+		else if(i & 4) pint_map[i] = 2;
+		else if(i & 8) pint_map[i] = 3;
+		else if(i & 0x10) pint_map[i] = 4;
+		else if(i & 0x20) pint_map[i] = 5;
+		else if(i & 0x40) pint_map[i] = 6;
+		else if(i & 0x80) pint_map[i] = 7;
+	}
+#endif /* !CONFIG_CPU_SUBTYPE_SH7300 */
+#endif /* CONFIG_CPU_SUBTYPE_SH7707 || CONFIG_CPU_SUBTYPE_SH7709  || CONFIG_CPU_SUBTYPE_SH7300*/
+
+#ifdef CONFIG_CPU_SUBTYPE_ST40
+	init_IRQ_intc2();
+#endif
+
+	/* Perform the machine specific initialisation */
+	if (sh_mv.mv_init_irq != NULL) {
+		sh_mv.mv_init_irq();
+	}
+}
+#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
+int ipr_irq_demux(int irq)
+{
+#if !defined(CONFIG_CPU_SUBTYPE_SH7300)
+	unsigned long creg, dreg, d, sav;
+
+	if(irq == PINT0_IRQ)
+	{
+#if defined(CONFIG_CPU_SUBTYPE_SH7707)
+		creg = PORT_PACR;
+		dreg = PORT_PADR;
+#else
+		creg = PORT_PCCR;
+		dreg = PORT_PCDR;
+#endif
+		sav = ctrl_inw(creg);
+		ctrl_outw(sav | portcr_mask, creg);
+		d = (~ctrl_inb(dreg) ^ ctrl_inw(INTC_ICR2)) & ctrl_inw(INTC_INTER) & 0xff;
+		ctrl_outw(sav, creg);
+		if(d == 0) return irq;
+		return PINT_IRQ_BASE + pint_map[d];
+	}
+	else if(irq == PINT8_IRQ)
+	{
+#if defined(CONFIG_CPU_SUBTYPE_SH7707)
+		creg = PORT_PBCR;
+		dreg = PORT_PBDR;
+#else
+		creg = PORT_PFCR;
+		dreg = PORT_PFDR;
+#endif
+		sav = ctrl_inw(creg);
+		ctrl_outw(sav | (portcr_mask >> 16), creg);
+		d = (~ctrl_inb(dreg) ^ (ctrl_inw(INTC_ICR2) >> 8)) & (ctrl_inw(INTC_INTER) >> 8) & 0xff;
+		ctrl_outw(sav, creg);
+		if(d == 0) return irq;
+		return PINT_IRQ_BASE + 8 + pint_map[d];
+	}
+#endif
+	return irq;
+}
+#endif
+
+EXPORT_SYMBOL(make_ipr_irq);
+
diff --git a/arch/sh/kernel/cpu/rtc.c b/arch/sh/kernel/cpu/rtc.c
new file mode 100644
index 0000000..f8361f5
--- /dev/null
+++ b/arch/sh/kernel/cpu/rtc.c
@@ -0,0 +1,136 @@
+/*
+ * linux/arch/sh/kernel/rtc.c -- SH3 / SH4 on-chip RTC support
+ *
+ *  Copyright (C) 2000  Philipp Rumpf <prumpf@tux.org>
+ *  Copyright (C) 1999  Tetsuya Okada & Niibe Yutaka
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+
+#include <asm/io.h>
+#include <asm/rtc.h>
+
+#ifndef BCD_TO_BIN
+#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
+#endif
+
+#ifndef BIN_TO_BCD
+#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
+#endif
+
+void sh_rtc_gettimeofday(struct timespec *ts)
+{
+	unsigned int sec128, sec, sec2, min, hr, wk, day, mon, yr, yr100, cf_bit;
+	unsigned long flags;
+
+ again:
+	do {
+		local_irq_save(flags);
+		ctrl_outb(0, RCR1);  /* Clear CF-bit */
+		sec128 = ctrl_inb(R64CNT);
+		sec = ctrl_inb(RSECCNT);
+		min = ctrl_inb(RMINCNT);
+		hr  = ctrl_inb(RHRCNT);
+		wk  = ctrl_inb(RWKCNT);
+		day = ctrl_inb(RDAYCNT);
+		mon = ctrl_inb(RMONCNT);
+#if defined(CONFIG_CPU_SH4)
+		yr  = ctrl_inw(RYRCNT);
+		yr100 = (yr >> 8);
+		yr &= 0xff;
+#else
+		yr  = ctrl_inb(RYRCNT);
+		yr100 = (yr == 0x99) ? 0x19 : 0x20;
+#endif
+		sec2 = ctrl_inb(R64CNT);
+		cf_bit = ctrl_inb(RCR1) & RCR1_CF;
+		local_irq_restore(flags);
+	} while (cf_bit != 0 || ((sec128 ^ sec2) & RTC_BIT_INVERTED) != 0);
+
+	BCD_TO_BIN(yr100);
+	BCD_TO_BIN(yr);
+	BCD_TO_BIN(mon);
+	BCD_TO_BIN(day);
+	BCD_TO_BIN(hr);
+	BCD_TO_BIN(min);
+	BCD_TO_BIN(sec);
+
+	if (yr > 99 || mon < 1 || mon > 12 || day > 31 || day < 1 ||
+	    hr > 23 || min > 59 || sec > 59) {
+		printk(KERN_ERR
+		       "SH RTC: invalid value, resetting to 1 Jan 2000\n");
+		local_irq_save(flags);
+		ctrl_outb(RCR2_RESET, RCR2);  /* Reset & Stop */
+		ctrl_outb(0, RSECCNT);
+		ctrl_outb(0, RMINCNT);
+		ctrl_outb(0, RHRCNT);
+		ctrl_outb(6, RWKCNT);
+		ctrl_outb(1, RDAYCNT);
+		ctrl_outb(1, RMONCNT);
+#if defined(CONFIG_CPU_SH4)
+		ctrl_outw(0x2000, RYRCNT);
+#else
+		ctrl_outb(0, RYRCNT);
+#endif
+		ctrl_outb(RCR2_RTCEN|RCR2_START, RCR2);  /* Start */
+		goto again;
+	}
+
+#if RTC_BIT_INVERTED != 0
+	if ((sec128 & RTC_BIT_INVERTED))
+		sec--;
+#endif
+
+	ts->tv_sec = mktime(yr100 * 100 + yr, mon, day, hr, min, sec);
+	ts->tv_nsec = ((sec128 * 1000000) / 128) * 1000;
+}
+
+/*
+ * Changed to only care about tv_sec, and not the full timespec struct
+ * (i.e. tv_nsec).  It can easily be switched to timespec for future cpus
+ * that support setting usec or nsec RTC values.
+ */
+int sh_rtc_settimeofday(const time_t secs)
+{
+	int retval = 0;
+	int real_seconds, real_minutes, cmos_minutes;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	ctrl_outb(RCR2_RESET, RCR2);  /* Reset pre-scaler & stop RTC */
+
+	cmos_minutes = ctrl_inb(RMINCNT);
+	BCD_TO_BIN(cmos_minutes);
+
+	/*
+	 * since we're only adjusting minutes and seconds,
+	 * don't interfere with hour overflow. This avoids
+	 * messing with unknown time zones but requires your
+	 * RTC not to be off by more than 15 minutes
+	 */
+	real_seconds = secs % 60;
+	real_minutes = secs / 60;
+	if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
+		real_minutes += 30;	/* correct for half hour time zone */
+	real_minutes %= 60;
+
+	if (abs(real_minutes - cmos_minutes) < 30) {
+		BIN_TO_BCD(real_seconds);
+		BIN_TO_BCD(real_minutes);
+		ctrl_outb(real_seconds, RSECCNT);
+		ctrl_outb(real_minutes, RMINCNT);
+	} else {
+		printk(KERN_WARNING
+		       "set_rtc_time: can't update from %d to %d\n",
+		       cmos_minutes, real_minutes);
+		retval = -1;
+	}
+
+	ctrl_outb(RCR2_RTCEN|RCR2_START, RCR2);  /* Start RTC */
+	local_irq_restore(flags);
+
+	return retval;
+}
diff --git a/arch/sh/kernel/cpu/sh2/Makefile b/arch/sh/kernel/cpu/sh2/Makefile
new file mode 100644
index 0000000..389353f
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh2/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the Linux/SuperH SH-2 backends.
+#
+
+obj-y	:= probe.o
+
diff --git a/arch/sh/kernel/cpu/sh2/probe.c b/arch/sh/kernel/cpu/sh2/probe.c
new file mode 100644
index 0000000..f17a2a0
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh2/probe.c
@@ -0,0 +1,39 @@
+/*
+ * arch/sh/kernel/cpu/sh2/probe.c
+ *
+ * CPU Subtype Probing for SH-2.
+ *
+ * Copyright (C) 2002 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+
+#include <linux/init.h>
+#include <asm/processor.h>
+#include <asm/cache.h>
+
+int __init detect_cpu_and_cache_system(void)
+{
+	/*
+	 * For now, assume SH7604 .. fix this later.
+	 */
+	cpu_data->type			= CPU_SH7604;
+	cpu_data->dcache.ways		= 4;
+	cpu_data->dcache.way_shift	= 6;
+	cpu_data->dcache.sets		= 64;
+	cpu_data->dcache.entry_shift	= 4;
+	cpu_data->dcache.linesz		= L1_CACHE_BYTES;
+	cpu_data->dcache.flags		= 0;
+
+	/*
+	 * SH-2 doesn't have separate caches
+	 */
+	cpu_data->dcache.flags |= SH_CACHE_COMBINED;
+	cpu_data->icache = cpu_data->dcache;
+
+	return 0;
+}
+
diff --git a/arch/sh/kernel/cpu/sh3/Makefile b/arch/sh/kernel/cpu/sh3/Makefile
new file mode 100644
index 0000000..a64532e
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh3/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the Linux/SuperH SH-3 backends.
+#
+
+obj-y	:= ex.o probe.o
+
diff --git a/arch/sh/kernel/cpu/sh3/ex.S b/arch/sh/kernel/cpu/sh3/ex.S
new file mode 100644
index 0000000..966c085
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh3/ex.S
@@ -0,0 +1,199 @@
+/*
+ *  arch/sh/kernel/cpu/sh3/ex.S
+ *
+ *  The SH-3 exception vector table.
+
+ *  Copyright (C) 1999, 2000, 2002  Niibe Yutaka
+ *  Copyright (C) 2003  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ */
+#include <linux/linkage.h>
+#include <linux/config.h>
+
+	.align 2
+	.data
+
+ENTRY(exception_handling_table)
+	.long	exception_error		/* 000 */
+	.long	exception_error
+#if defined(CONFIG_MMU)
+	.long	tlb_miss_load		/* 040 */
+	.long	tlb_miss_store
+	.long	initial_page_write
+	.long	tlb_protection_violation_load
+	.long	tlb_protection_violation_store
+	.long	address_error_load
+	.long	address_error_store	/* 100 */
+#else
+	.long	exception_error	! tlb miss load		/* 040 */
+	.long	exception_error	! tlb miss store
+	.long	exception_error	! initial page write
+	.long	exception_error	! tlb prot violation load
+	.long	exception_error	! tlb prot violation store
+	.long	exception_error	! address error load
+	.long	exception_error	! address error store	/* 100 */
+#endif
+	.long	exception_error	! fpu_exception	/* 120 */
+	.long	exception_error			/* 140 */
+	.long	system_call	! Unconditional Trap	 /* 160 */
+	.long	exception_error	! reserved_instruction (filled by trap_init) /* 180 */
+	.long	exception_error	! illegal_slot_instruction (filled by trap_init) /*1A0*/
+ENTRY(nmi_slot)
+#if defined (CONFIG_KGDB_NMI)
+	.long	debug_enter	/* 1C0 */	! Allow trap to debugger
+#else
+	.long	exception_none	/* 1C0 */	! Not implemented yet
+#endif
+ENTRY(user_break_point_trap)
+	.long	break_point_trap	/* 1E0 */
+ENTRY(interrupt_table)
+	! external hardware
+	.long	do_IRQ	! 0000		/* 200 */
+	.long	do_IRQ	! 0001
+	.long	do_IRQ	! 0010
+	.long	do_IRQ	! 0011
+	.long	do_IRQ	! 0100
+	.long	do_IRQ	! 0101
+	.long	do_IRQ	! 0110
+	.long	do_IRQ	! 0111
+	.long	do_IRQ	! 1000		/* 300 */
+	.long	do_IRQ	! 1001
+	.long	do_IRQ	! 1010
+	.long	do_IRQ	! 1011
+	.long	do_IRQ	! 1100
+	.long	do_IRQ	! 1101
+	.long	do_IRQ	! 1110
+	.long	exception_error		
+	! Internal hardware
+	.long	do_IRQ	! TMU0 tuni0	/* 400 */
+	.long	do_IRQ	! TMU1 tuni1
+	.long	do_IRQ	! TMU2 tuni2
+	.long	do_IRQ	!      ticpi2
+	.long	do_IRQ	! RTC  ati
+	.long	do_IRQ	!      pri
+	.long	do_IRQ	!      cui
+	.long	do_IRQ	! SCI  eri
+	.long	do_IRQ	!      rxi	/* 500 */
+	.long	do_IRQ	!      txi
+	.long	do_IRQ	!      tei
+	.long	do_IRQ	! WDT  iti	/* 560 */
+	.long	do_IRQ	! REF  rcmi
+	.long	do_IRQ	!      rovi
+	.long	do_IRQ			
+	.long	do_IRQ			/* 5E0 */
+#if  defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \
+     defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
+	.long	do_IRQ	! 32 IRQ  irq0	/* 600 */
+	.long	do_IRQ	! 33      irq1
+	.long	do_IRQ	! 34      irq2
+	.long	do_IRQ	! 35      irq3
+	.long	do_IRQ	! 36      irq4
+	.long	do_IRQ	! 37      irq5
+	.long	do_IRQ	! 38
+	.long	do_IRQ	! 39
+	.long	do_IRQ	! 40 PINT pint0-7	/* 700 */
+	.long	do_IRQ	! 41      pint8-15
+	.long	do_IRQ	! 42
+	.long	do_IRQ	! 43
+	.long	do_IRQ	! 44
+	.long	do_IRQ	! 45	
+	.long	do_IRQ	! 46
+	.long	do_IRQ	! 47
+	.long	do_IRQ	! 48 DMAC dei0	/* 800 */
+	.long	do_IRQ	! 49      dei1
+	.long	do_IRQ	! 50      dei2
+	.long	do_IRQ	! 51      dei3
+	.long	do_IRQ	! 52 IrDA eri1
+	.long	do_IRQ	! 53      rxi1
+	.long	do_IRQ	! 54      bri1
+	.long	do_IRQ	! 55      txi1
+	.long	do_IRQ	! 56 SCIF eri2
+	.long	do_IRQ	! 57      rxi2
+	.long	do_IRQ	! 58      bri2
+	.long	do_IRQ	! 59      txi2
+	.long	do_IRQ	! 60 ADC  adi	/* 980 */
+#if defined(CONFIG_CPU_SUBTYPE_SH7705)
+	.long	exception_none	! 61	/* 9A0 */
+	.long	exception_none	! 62
+	.long	exception_none	! 63
+	.long	exception_none	! 64	/* A00 */
+	.long	do_IRQ	! 65 USB  usi0
+	.long	do_IRQ	! 66      usi1
+	.long	exception_none	! 67
+	.long	exception_none	! 68
+	.long	exception_none	! 69
+	.long	exception_none	! 70
+	.long	exception_none	! 71
+	.long	exception_none	! 72	/* B00 */
+	.long	exception_none	! 73
+	.long	exception_none	! 74
+	.long	exception_none	! 75
+	.long	exception_none	! 76
+	.long	exception_none	! 77
+	.long	exception_none	! 78
+	.long	exception_none	! 79
+	.long	do_IRQ	! 80 TPU0 tpi0	/* C00 */
+	.long	do_IRQ	! 81 TPU1 tpi1
+	.long	exception_none	! 82
+	.long	exception_none	! 83
+	.long	do_IRQ	! 84 TPU2 tpi2
+	.long	do_IRQ	! 85 TPU3 tpi3	/* CA0 */
+#endif
+#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7300)
+	.long   do_IRQ	! 61 LCDC lcdi	/* 9A0 */
+	.long   do_IRQ	! 62 PCC  pcc0i
+	.long   do_IRQ	! 63      pcc1i	/* 9E0 */
+#endif
+#if defined(CONFIG_CPU_SUBTYPE_SH7300)
+	.long   do_IRQ	! 64
+	.long   do_IRQ	! 65
+	.long   do_IRQ	! 66
+	.long   do_IRQ	! 67
+	.long   do_IRQ	! 68
+	.long   do_IRQ	! 69
+	.long   do_IRQ	! 70
+	.long   do_IRQ	! 71
+	.long   do_IRQ	! 72
+	.long   do_IRQ	! 73
+	.long   do_IRQ	! 74
+	.long   do_IRQ	! 75
+	.long   do_IRQ	! 76
+	.long   do_IRQ	! 77
+	.long   do_IRQ	! 78
+	.long   do_IRQ	! 79
+	.long   do_IRQ	! 80 SCIF0(SH7300)
+	.long   do_IRQ	! 81
+	.long   do_IRQ	! 82
+	.long   do_IRQ	! 83
+	.long   do_IRQ	! 84
+	.long   do_IRQ	! 85
+	.long   do_IRQ	! 86
+	.long   do_IRQ	! 87
+	.long   do_IRQ	! 88
+	.long   do_IRQ	! 89
+	.long   do_IRQ	! 90
+	.long   do_IRQ	! 91
+	.long   do_IRQ	! 92
+	.long   do_IRQ	! 93
+	.long   do_IRQ	! 94
+	.long   do_IRQ	! 95
+	.long   do_IRQ	! 96
+	.long   do_IRQ	! 97
+	.long   do_IRQ	! 98
+	.long   do_IRQ	! 99
+	.long   do_IRQ	! 100
+	.long   do_IRQ	! 101
+	.long   do_IRQ	! 102
+	.long   do_IRQ	! 103
+	.long   do_IRQ	! 104
+	.long   do_IRQ	! 105
+	.long   do_IRQ	! 106
+	.long   do_IRQ	! 107
+	.long   do_IRQ	! 108
+#endif
+#endif
+
diff --git a/arch/sh/kernel/cpu/sh3/probe.c b/arch/sh/kernel/cpu/sh3/probe.c
new file mode 100644
index 0000000..5cdc886
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh3/probe.c
@@ -0,0 +1,97 @@
+/*
+ * arch/sh/kernel/cpu/sh3/probe.c
+ *
+ * CPU Subtype Probing for SH-3.
+ *
+ * Copyright (C) 1999, 2000  Niibe Yutaka
+ * Copyright (C) 2002  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/init.h>
+#include <asm/processor.h>
+#include <asm/cache.h>
+#include <asm/io.h>
+
+int __init detect_cpu_and_cache_system(void)
+{
+	unsigned long addr0, addr1, data0, data1, data2, data3;
+
+	jump_to_P2();
+	/*
+	 * Check if the entry shadows or not.
+	 * When shadowed, it's 128-entry system.
+	 * Otherwise, it's 256-entry system.
+	 */
+	addr0 = CACHE_OC_ADDRESS_ARRAY + (3 << 12);
+	addr1 = CACHE_OC_ADDRESS_ARRAY + (1 << 12);
+
+	/* First, write back & invalidate */
+	data0  = ctrl_inl(addr0);
+	ctrl_outl(data0&~(SH_CACHE_VALID|SH_CACHE_UPDATED), addr0);
+	data1  = ctrl_inl(addr1);
+	ctrl_outl(data1&~(SH_CACHE_VALID|SH_CACHE_UPDATED), addr1);
+
+	/* Next, check if there's shadow or not */
+	data0 = ctrl_inl(addr0);
+	data0 ^= SH_CACHE_VALID;
+	ctrl_outl(data0, addr0);
+	data1 = ctrl_inl(addr1);
+	data2 = data1 ^ SH_CACHE_VALID;
+	ctrl_outl(data2, addr1);
+	data3 = ctrl_inl(addr0);
+
+	/* Lastly, invaliate them. */
+	ctrl_outl(data0&~SH_CACHE_VALID, addr0);
+	ctrl_outl(data2&~SH_CACHE_VALID, addr1);
+
+	back_to_P1();
+
+	cpu_data->dcache.ways		= 4;
+	cpu_data->dcache.entry_shift	= 4;
+	cpu_data->dcache.linesz		= L1_CACHE_BYTES;
+	cpu_data->dcache.flags		= 0;
+
+	/*
+	 * 7709A/7729 has 16K cache (256-entry), while 7702 has only
+	 * 2K(direct) 7702 is not supported (yet)
+	 */
+	if (data0 == data1 && data2 == data3) {	/* Shadow */
+		cpu_data->dcache.way_incr	= (1 << 11);
+		cpu_data->dcache.entry_mask	= 0x7f0;
+		cpu_data->dcache.sets		= 128;
+		cpu_data->type = CPU_SH7708;
+
+		cpu_data->flags |= CPU_HAS_MMU_PAGE_ASSOC;
+	} else {				/* 7709A or 7729  */
+		cpu_data->dcache.way_incr	= (1 << 12);
+		cpu_data->dcache.entry_mask	= 0xff0;
+		cpu_data->dcache.sets		= 256;
+		cpu_data->type = CPU_SH7729;
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7705)
+		cpu_data->type = CPU_SH7705;
+
+#if defined(CONFIG_SH7705_CACHE_32KB)
+		cpu_data->dcache.way_incr	= (1 << 13);
+		cpu_data->dcache.entry_mask	= 0x1ff0;
+		cpu_data->dcache.sets		= 512;
+		ctrl_outl(CCR_CACHE_32KB, CCR3);
+#else
+		ctrl_outl(CCR_CACHE_16KB, CCR3);
+#endif
+#endif
+	}
+
+	/*
+	 * SH-3 doesn't have separate caches
+	 */
+	cpu_data->dcache.flags |= SH_CACHE_COMBINED;
+	cpu_data->icache = cpu_data->dcache;
+
+	return 0;
+}
+
diff --git a/arch/sh/kernel/cpu/sh4/Makefile b/arch/sh/kernel/cpu/sh4/Makefile
new file mode 100644
index 0000000..ead1071
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for the Linux/SuperH SH-4 backends.
+#
+
+obj-y	:= ex.o probe.o
+
+obj-$(CONFIG_SH_FPU)                    += fpu.o
+obj-$(CONFIG_CPU_SUBTYPE_ST40STB1)	+= irq_intc2.o
+obj-$(CONFIG_SH_STORE_QUEUES)		+= sq.o
+
diff --git a/arch/sh/kernel/cpu/sh4/ex.S b/arch/sh/kernel/cpu/sh4/ex.S
new file mode 100644
index 0000000..8221e9d
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/ex.S
@@ -0,0 +1,384 @@
+/*
+ *  arch/sh/kernel/cpu/sh4/ex.S
+ *
+ *  The SH-4 exception vector table.
+
+ *  Copyright (C) 1999, 2000, 2002  Niibe Yutaka
+ *  Copyright (C) 2003  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ */
+#include <linux/linkage.h>
+#include <linux/config.h>
+
+	.align 2
+	.data
+
+ENTRY(exception_handling_table)
+	.long	exception_error		/* 000 */
+	.long	exception_error
+#if defined(CONFIG_MMU)
+	.long	tlb_miss_load		/* 040 */
+	.long	tlb_miss_store
+	.long	initial_page_write
+	.long	tlb_protection_violation_load
+	.long	tlb_protection_violation_store
+	.long	address_error_load
+	.long	address_error_store	/* 100 */
+#else
+	.long	exception_error	! tlb miss load		/* 040 */
+	.long	exception_error	! tlb miss store
+	.long	exception_error	! initial page write
+	.long	exception_error	! tlb prot violation load
+	.long	exception_error	! tlb prot violation store
+	.long	exception_error	! address error load
+	.long	exception_error	! address error store	/* 100 */
+#endif
+#if defined(CONFIG_SH_FPU)
+	.long	do_fpu_error		/* 120 */
+#else
+	.long	exception_error		/* 120 */
+#endif
+	.long	exception_error		/* 140 */
+	.long	system_call	! Unconditional Trap	 /* 160 */
+	.long	exception_error	! reserved_instruction (filled by trap_init) /* 180 */
+	.long	exception_error	! illegal_slot_instruction (filled by trap_init) /*1A0*/
+ENTRY(nmi_slot)
+#if defined (CONFIG_KGDB_NMI)
+	.long	debug_enter	/* 1C0 */	! Allow trap to debugger
+#else
+	.long	exception_none	/* 1C0 */	! Not implemented yet
+#endif
+ENTRY(user_break_point_trap)
+	.long	break_point_trap	/* 1E0 */
+ENTRY(interrupt_table)
+	! external hardware
+	.long	do_IRQ	! 0000		/* 200 */
+	.long	do_IRQ	! 0001
+	.long	do_IRQ	! 0010
+	.long	do_IRQ	! 0011
+	.long	do_IRQ	! 0100
+	.long	do_IRQ	! 0101
+	.long	do_IRQ	! 0110
+	.long	do_IRQ	! 0111
+	.long	do_IRQ	! 1000		/* 300 */
+	.long	do_IRQ	! 1001
+	.long	do_IRQ	! 1010
+	.long	do_IRQ	! 1011
+	.long	do_IRQ	! 1100
+	.long	do_IRQ	! 1101
+	.long	do_IRQ	! 1110
+	.long	exception_error		
+	! Internal hardware
+	.long	do_IRQ	! TMU0 tuni0	/* 400 */
+	.long	do_IRQ	! TMU1 tuni1
+	.long	do_IRQ	! TMU2 tuni2
+	.long	do_IRQ	!      ticpi2
+#if  defined(CONFIG_CPU_SUBTYPE_SH7760)
+	.long	exception_error
+	.long	exception_error
+	.long	exception_error
+	.long	exception_error
+	.long	exception_error			/* 500 */
+	.long	exception_error
+	.long	exception_error
+#else
+	.long	do_IRQ	! RTC  ati
+	.long	do_IRQ	!      pri
+	.long	do_IRQ	!      cui
+	.long	do_IRQ	! SCI  eri
+	.long	do_IRQ	!      rxi	/* 500 */
+	.long	do_IRQ	!      txi
+	.long	do_IRQ	!      tei
+#endif
+	.long	do_IRQ	! WDT  iti	/* 560 */
+	.long	do_IRQ	! REF  rcmi
+	.long	do_IRQ	!      rovi
+	.long	do_IRQ			
+	.long	do_IRQ			/* 5E0 */
+	.long	do_IRQ	! 32 Hitachi UDI	/* 600 */
+	.long	do_IRQ	! 33 GPIO
+	.long	do_IRQ	! 34 DMAC dmte0
+	.long	do_IRQ	! 35      dmte1
+	.long	do_IRQ	! 36      dmte2
+	.long	do_IRQ	! 37      dmte3
+	.long	do_IRQ	! 38      dmae
+	.long	exception_error			! 39	/* 6E0 */
+#if defined(CONFIG_CPU_SUBTYPE_SH7760)
+	.long	exception_error				/* 700 */
+	.long	exception_error
+	.long	exception_error
+	.long	exception_error				/* 760 */
+#else
+	.long	do_IRQ	! 40 SCIF eri		/* 700 */
+	.long	do_IRQ	! 41      rxi
+	.long	do_IRQ	! 42      bri
+	.long	do_IRQ	! 43      txi
+#endif
+#if CONFIG_NR_ONCHIP_DMA_CHANNELS == 8
+	.long	do_IRQ	! 44 DMAC dmte4		/* 780 */
+	.long	do_IRQ	! 45      dmte5
+	.long	do_IRQ	! 46      dmte6
+	.long	do_IRQ	! 47      dmte7		/* 7E0 */
+#else
+	.long	exception_error			! 44	/* 780 */
+	.long	exception_error			! 45
+	.long	exception_error			! 46
+	.long	exception_error			! 47
+#endif
+#if defined(CONFIG_SH_FPU)
+	.long	do_fpu_state_restore	! 48	/* 800 */
+	.long	do_fpu_state_restore	! 49	/* 820 */
+#else
+	.long	exception_error
+	.long	exception_error
+#endif
+#if defined(CONFIG_CPU_SUBTYPE_SH7751)
+	.long	exception_error			/* 840 */
+	.long	exception_error
+	.long	exception_error
+	.long	exception_error
+	.long	exception_error
+	.long	exception_error
+	.long	exception_error			/* 900 */
+	.long	exception_error
+	.long	exception_error
+	.long	exception_error
+	.long	exception_error
+	.long	exception_error
+	.long	exception_error
+	.long	exception_error
+	.long	do_IRQ	! PCI serr	/* A00 */
+	.long	do_IRQ	!     dma3
+	.long	do_IRQ	!     dma2
+	.long	do_IRQ	!     dma1
+	.long	do_IRQ	!     dma0
+	.long	do_IRQ	!     pwon
+	.long	do_IRQ	!     pwdwn
+	.long	do_IRQ	!     err
+	.long	do_IRQ	! TMU3 tuni3	/* B00 */
+	.long	exception_error
+	.long	exception_error
+	.long	exception_error
+	.long	do_IRQ	! TMU4 tuni4	/* B80 */
+#elif defined(CONFIG_CPU_SUBTYPE_SH7760)
+	.long	do_IRQ	! IRQ	irq6	/* 840 */
+	.long	do_IRQ	!	irq7
+	.long	do_IRQ	! SCIF	eri0
+	.long	do_IRQ	!	rxi0
+	.long	do_IRQ	!	bri0
+	.long	do_IRQ	!	txi0
+	.long	do_IRQ	! HCAN2	cani0	/* 900 */
+	.long	do_IRQ	!	cani1
+	.long	do_IRQ	! SSI	ssii0
+	.long	do_IRQ	!	ssii1
+	.long	do_IRQ	! HAC	haci0
+	.long	do_IRQ	!	haci1
+	.long	do_IRQ	! IIC	iici0
+	.long	do_IRQ	!	iici1
+	.long	do_IRQ	! USB	usbi	/* A00 */
+	.long	do_IRQ	! LCDC	vint
+	.long	exception_error
+	.long	exception_error
+	.long	do_IRQ	! DMABRG dmabrgi0
+	.long	do_IRQ	!        dmabrgi1
+	.long	do_IRQ	!        dmabrgi2
+	.long	exception_error
+	.long	do_IRQ	! SCIF	eri1	/* B00 */
+	.long	do_IRQ	!	rxi1
+	.long	do_IRQ	!	bri1
+	.long	do_IRQ	!	txi1
+	.long	do_IRQ	!	eri2
+	.long	do_IRQ	!	rxi2
+	.long	do_IRQ	!	bri2
+	.long	do_IRQ  !	txi2
+	.long	do_IRQ	! SIM	simeri	/* C00 */
+	.long	do_IRQ	!	simrxi
+	.long	do_IRQ	!	simtxi
+	.long	do_IRQ	!	simtei
+	.long	do_IRQ	! HSPI	spii
+	.long	exception_error
+	.long	exception_error
+	.long	exception_error
+	.long	do_IRQ	! MMCIF	mmci0	/* D00 */
+	.long	do_IRQ	!	mmci1
+	.long	do_IRQ	!	mmci2
+	.long	do_IRQ	!	mmci3
+	.long	exception_error
+	.long	exception_error
+	.long	exception_error
+	.long	exception_error
+	.long	exception_error			/* E00 */
+	.long	exception_error
+	.long	exception_error
+	.long	exception_error
+	.long	do_IRQ	! MFI	mfii
+	.long	exception_error
+	.long	exception_error
+	.long	exception_error
+	.long	exception_error			/* F00 */
+	.long	exception_error
+	.long	exception_error
+	.long	exception_error
+	.long	do_IRQ	! ADC	adi
+	.long	do_IRQ	! CMT	cmti	/* FA0 */
+#elif defined(CONFIG_CPU_SUBTYPE_SH73180)
+	.long	do_IRQ	!  50 0x840
+	.long	do_IRQ	!  51 0x860
+	.long	do_IRQ	!  52 0x880
+	.long	do_IRQ	!  53 0x8a0
+	.long	do_IRQ	!  54 0x8c0
+	.long	do_IRQ	!  55 0x8e0
+	.long	do_IRQ	!  56 0x900
+	.long	do_IRQ	!  57 0x920
+	.long	do_IRQ	!  58 0x940
+	.long	do_IRQ	!  59 0x960
+	.long	do_IRQ	!  60 0x980
+	.long	do_IRQ	!  61 0x9a0
+	.long	do_IRQ	!  62 0x9c0
+	.long	do_IRQ	!  63 0x9e0
+	.long	do_IRQ	!  64 0xa00
+	.long	do_IRQ	!  65 0xa20
+	.long	do_IRQ	!  66 0xa40
+	.long	do_IRQ	!  67 0xa60
+	.long	do_IRQ	!  68 0xa80
+	.long	do_IRQ	!  69 0xaa0
+	.long	do_IRQ	!  70 0xac0
+	.long	do_IRQ	!  71 0xae0
+	.long	do_IRQ	!  72 0xb00
+	.long	do_IRQ	!  73 0xb20
+	.long	do_IRQ	!  74 0xb40
+	.long	do_IRQ	!  75 0xb60
+	.long	do_IRQ	!  76 0xb80
+	.long	do_IRQ	!  77 0xba0
+	.long	do_IRQ	!  78 0xbc0
+	.long	do_IRQ	!  79 0xbe0
+	.long	do_IRQ	!  80 0xc00
+	.long	do_IRQ	!  81 0xc20
+	.long	do_IRQ	!  82 0xc40
+	.long	do_IRQ	!  83 0xc60
+	.long	do_IRQ	!  84 0xc80
+	.long	do_IRQ	!  85 0xca0
+	.long	do_IRQ	!  86 0xcc0
+	.long	do_IRQ	!  87 0xce0
+	.long	do_IRQ	!  88 0xd00
+	.long	do_IRQ	!  89 0xd20
+	.long	do_IRQ	!  90 0xd40
+	.long	do_IRQ	!  91 0xd60
+	.long	do_IRQ	!  92 0xd80
+	.long	do_IRQ	!  93 0xda0
+	.long	do_IRQ	!  94 0xdc0
+	.long	do_IRQ	!  95 0xde0
+	.long	do_IRQ	!  96 0xe00
+	.long	do_IRQ	!  97 0xe20
+	.long	do_IRQ	!  98 0xe40
+	.long	do_IRQ	!  99 0xe60
+	.long	do_IRQ	! 100 0xe80
+	.long	do_IRQ	! 101 0xea0
+	.long	do_IRQ	! 102 0xec0
+	.long	do_IRQ	! 103 0xee0
+	.long	do_IRQ	! 104 0xf00
+	.long	do_IRQ	! 105 0xf20
+	.long	do_IRQ	! 106 0xf40
+	.long	do_IRQ	! 107 0xf60
+	.long	do_IRQ	! 108 0xf80
+#elif defined(CONFIG_CPU_SUBTYPE_ST40STB1)
+	.long	exception_error			!  50 0x840
+	.long	exception_error			!  51 0x860
+	.long	exception_error			!  52 0x880
+	.long	exception_error			!  53 0x8a0
+	.long	exception_error			!  54 0x8c0
+	.long	exception_error			!  55 0x8e0
+	.long	exception_error			!  56 0x900
+	.long	exception_error			!  57 0x920
+	.long	exception_error			!  58 0x940
+	.long	exception_error			!  59 0x960
+	.long	exception_error			!  60 0x980
+	.long	exception_error			!  61 0x9a0
+	.long	exception_error			!  62 0x9c0
+	.long	exception_error			!  63 0x9e0
+	.long	do_IRQ	!  64 0xa00 PCI serr
+	.long	do_IRQ	!  65 0xa20     err
+	.long	do_IRQ	!  66 0xa40     ad
+	.long	do_IRQ	!  67 0xa60     pwr_dwn
+	.long	exception_error			!  68 0xa80
+	.long	exception_error			!  69 0xaa0
+	.long	exception_error			!  70 0xac0
+	.long	exception_error			!  71 0xae0
+	.long	do_IRQ	!  72 0xb00 DMA INT0
+	.long	do_IRQ	!  73 0xb20     INT1
+	.long	do_IRQ	!  74 0xb40     INT2
+	.long	do_IRQ	!  75 0xb60     INT3
+	.long	do_IRQ	!  76 0xb80     INT4
+	.long	exception_error			!  77 0xba0
+	.long	do_IRQ	!  78 0xbc0 DMA ERR
+	.long	exception_error			!  79 0xbe0
+	.long	do_IRQ	!  80 0xc00 PIO0
+	.long	do_IRQ	!  81 0xc20 PIO1
+	.long	do_IRQ	!  82 0xc40 PIO2
+	.long	exception_error			!  83 0xc60
+	.long	exception_error			!  84 0xc80
+	.long	exception_error			!  85 0xca0
+	.long	exception_error			!  86 0xcc0
+	.long	exception_error			!  87 0xce0
+	.long	exception_error			!  88 0xd00
+	.long	exception_error			!  89 0xd20
+	.long	exception_error			!  90 0xd40
+	.long	exception_error			!  91 0xd60
+	.long	exception_error			!  92 0xd80
+	.long	exception_error			!  93 0xda0
+	.long	exception_error			!  94 0xdc0
+	.long	exception_error			!  95 0xde0
+	.long	exception_error			!  96 0xe00
+	.long	exception_error			!  97 0xe20
+	.long	exception_error			!  98 0xe40
+	.long	exception_error			!  99 0xe60
+	.long	exception_error			! 100 0xe80
+	.long	exception_error			! 101 0xea0
+	.long	exception_error			! 102 0xec0
+	.long	exception_error			! 103 0xee0
+	.long	exception_error			! 104 0xf00
+	.long	exception_error			! 105 0xf20
+	.long	exception_error			! 106 0xf40
+	.long	exception_error			! 107 0xf60
+	.long	exception_error			! 108 0xf80
+	.long	exception_error			! 109 0xfa0
+	.long	exception_error			! 110 0xfc0
+	.long	exception_error			! 111 0xfe0
+	.long	do_IRQ	! 112 0x1000 Mailbox
+	.long	exception_error			! 113 0x1020
+	.long	exception_error			! 114 0x1040
+	.long	exception_error			! 115 0x1060
+	.long	exception_error			! 116 0x1080
+	.long	exception_error			! 117 0x10a0
+	.long	exception_error			! 118 0x10c0
+	.long	exception_error			! 119 0x10e0
+	.long	exception_error			! 120 0x1100
+	.long	exception_error			! 121 0x1120
+	.long	exception_error			! 122 0x1140
+	.long	exception_error			! 123 0x1160
+	.long	exception_error			! 124 0x1180
+	.long	exception_error			! 125 0x11a0
+	.long	exception_error			! 126 0x11c0
+	.long	exception_error			! 127 0x11e0
+	.long	exception_error			! 128 0x1200
+	.long	exception_error			! 129 0x1220
+	.long	exception_error			! 130 0x1240
+	.long	exception_error			! 131 0x1260
+	.long	exception_error			! 132 0x1280
+	.long	exception_error			! 133 0x12a0
+	.long	exception_error			! 134 0x12c0
+	.long	exception_error			! 135 0x12e0
+	.long	exception_error			! 136 0x1300
+	.long	exception_error			! 137 0x1320
+	.long	exception_error			! 138 0x1340
+	.long	exception_error			! 139 0x1360
+	.long	do_IRQ	! 140 0x1380 EMPI INV_ADDR
+	.long	exception_error			! 141 0x13a0
+	.long	exception_error			! 142 0x13c0
+	.long	exception_error			! 143 0x13e0
+#endif
+
diff --git a/arch/sh/kernel/cpu/sh4/fpu.c b/arch/sh/kernel/cpu/sh4/fpu.c
new file mode 100644
index 0000000..f486c07
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/fpu.c
@@ -0,0 +1,335 @@
+/* $Id: fpu.c,v 1.4 2004/01/13 05:52:11 kkojima Exp $
+ *
+ * linux/arch/sh/kernel/fpu.c
+ *
+ * Save/restore floating point context for signal handlers.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1999, 2000  Kaz Kojima & Niibe Yutaka
+ *
+ * FIXME! These routines can be optimized in big endian case.
+ */
+
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+
+/* The PR (precision) bit in the FP Status Register must be clear when
+ * an frchg instruction is executed, otherwise the instruction is undefined.
+ * Executing frchg with PR set causes a trap on some SH4 implementations.
+ */
+
+#define FPSCR_RCHG 0x00000000
+
+
+/*
+ * Save FPU registers onto task structure.
+ * Assume called with FPU enabled (SR.FD=0).
+ */
+void
+save_fpu(struct task_struct *tsk, struct pt_regs *regs)
+{
+	unsigned long dummy;
+
+	clear_tsk_thread_flag(tsk, TIF_USEDFPU);
+	enable_fpu();
+	asm volatile("sts.l	fpul, @-%0\n\t"
+		     "sts.l	fpscr, @-%0\n\t"
+		     "lds	%2, fpscr\n\t"
+		     "frchg\n\t"
+		     "fmov.s	fr15, @-%0\n\t"
+		     "fmov.s	fr14, @-%0\n\t"
+		     "fmov.s	fr13, @-%0\n\t"
+		     "fmov.s	fr12, @-%0\n\t"
+		     "fmov.s	fr11, @-%0\n\t"
+		     "fmov.s	fr10, @-%0\n\t"
+		     "fmov.s	fr9, @-%0\n\t"
+		     "fmov.s	fr8, @-%0\n\t"
+		     "fmov.s	fr7, @-%0\n\t"
+		     "fmov.s	fr6, @-%0\n\t"
+		     "fmov.s	fr5, @-%0\n\t"
+		     "fmov.s	fr4, @-%0\n\t"
+		     "fmov.s	fr3, @-%0\n\t"
+		     "fmov.s	fr2, @-%0\n\t"
+		     "fmov.s	fr1, @-%0\n\t"
+		     "fmov.s	fr0, @-%0\n\t"
+		     "frchg\n\t"
+		     "fmov.s	fr15, @-%0\n\t"
+		     "fmov.s	fr14, @-%0\n\t"
+		     "fmov.s	fr13, @-%0\n\t"
+		     "fmov.s	fr12, @-%0\n\t"
+		     "fmov.s	fr11, @-%0\n\t"
+		     "fmov.s	fr10, @-%0\n\t"
+		     "fmov.s	fr9, @-%0\n\t"
+		     "fmov.s	fr8, @-%0\n\t"
+		     "fmov.s	fr7, @-%0\n\t"
+		     "fmov.s	fr6, @-%0\n\t"
+		     "fmov.s	fr5, @-%0\n\t"
+		     "fmov.s	fr4, @-%0\n\t"
+		     "fmov.s	fr3, @-%0\n\t"
+		     "fmov.s	fr2, @-%0\n\t"
+		     "fmov.s	fr1, @-%0\n\t"
+		     "fmov.s	fr0, @-%0\n\t"
+		     "lds	%3, fpscr\n\t"
+		     : "=r" (dummy)
+		     : "0" ((char *)(&tsk->thread.fpu.hard.status)),
+		       "r" (FPSCR_RCHG),
+		       "r" (FPSCR_INIT)
+		     : "memory");
+
+ 	disable_fpu();
+ 	release_fpu(regs);
+}
+
+static void
+restore_fpu(struct task_struct *tsk)
+{
+	unsigned long dummy;
+
+ 	enable_fpu();
+	asm volatile("lds	%2, fpscr\n\t"
+		     "fmov.s	@%0+, fr0\n\t"
+		     "fmov.s	@%0+, fr1\n\t"
+		     "fmov.s	@%0+, fr2\n\t"
+		     "fmov.s	@%0+, fr3\n\t"
+		     "fmov.s	@%0+, fr4\n\t"
+		     "fmov.s	@%0+, fr5\n\t"
+		     "fmov.s	@%0+, fr6\n\t"
+		     "fmov.s	@%0+, fr7\n\t"
+		     "fmov.s	@%0+, fr8\n\t"
+		     "fmov.s	@%0+, fr9\n\t"
+		     "fmov.s	@%0+, fr10\n\t"
+		     "fmov.s	@%0+, fr11\n\t"
+		     "fmov.s	@%0+, fr12\n\t"
+		     "fmov.s	@%0+, fr13\n\t"
+		     "fmov.s	@%0+, fr14\n\t"
+		     "fmov.s	@%0+, fr15\n\t"
+		     "frchg\n\t"
+		     "fmov.s	@%0+, fr0\n\t"
+		     "fmov.s	@%0+, fr1\n\t"
+		     "fmov.s	@%0+, fr2\n\t"
+		     "fmov.s	@%0+, fr3\n\t"
+		     "fmov.s	@%0+, fr4\n\t"
+		     "fmov.s	@%0+, fr5\n\t"
+		     "fmov.s	@%0+, fr6\n\t"
+		     "fmov.s	@%0+, fr7\n\t"
+		     "fmov.s	@%0+, fr8\n\t"
+		     "fmov.s	@%0+, fr9\n\t"
+		     "fmov.s	@%0+, fr10\n\t"
+		     "fmov.s	@%0+, fr11\n\t"
+		     "fmov.s	@%0+, fr12\n\t"
+		     "fmov.s	@%0+, fr13\n\t"
+		     "fmov.s	@%0+, fr14\n\t"
+		     "fmov.s	@%0+, fr15\n\t"
+		     "frchg\n\t"
+		     "lds.l	@%0+, fpscr\n\t"
+		     "lds.l	@%0+, fpul\n\t"
+		     : "=r" (dummy)
+		     : "0" (&tsk->thread.fpu), "r" (FPSCR_RCHG)
+		     : "memory");
+	disable_fpu();
+}
+
+/*
+ * Load the FPU with signalling NANS.  This bit pattern we're using
+ * has the property that no matter wether considered as single or as
+ * double precission represents signaling NANS.  
+ */
+
+static void
+fpu_init(void)
+{
+	enable_fpu();
+	asm volatile("lds	%0, fpul\n\t"
+		     "lds	%1, fpscr\n\t"
+		     "fsts	fpul, fr0\n\t"
+		     "fsts	fpul, fr1\n\t"
+		     "fsts	fpul, fr2\n\t"
+		     "fsts	fpul, fr3\n\t"
+		     "fsts	fpul, fr4\n\t"
+		     "fsts	fpul, fr5\n\t"
+		     "fsts	fpul, fr6\n\t"
+		     "fsts	fpul, fr7\n\t"
+		     "fsts	fpul, fr8\n\t"
+		     "fsts	fpul, fr9\n\t"
+		     "fsts	fpul, fr10\n\t"
+		     "fsts	fpul, fr11\n\t"
+		     "fsts	fpul, fr12\n\t"
+		     "fsts	fpul, fr13\n\t"
+		     "fsts	fpul, fr14\n\t"
+		     "fsts	fpul, fr15\n\t"
+		     "frchg\n\t"
+		     "fsts	fpul, fr0\n\t"
+		     "fsts	fpul, fr1\n\t"
+		     "fsts	fpul, fr2\n\t"
+		     "fsts	fpul, fr3\n\t"
+		     "fsts	fpul, fr4\n\t"
+		     "fsts	fpul, fr5\n\t"
+		     "fsts	fpul, fr6\n\t"
+		     "fsts	fpul, fr7\n\t"
+		     "fsts	fpul, fr8\n\t"
+		     "fsts	fpul, fr9\n\t"
+		     "fsts	fpul, fr10\n\t"
+		     "fsts	fpul, fr11\n\t"
+		     "fsts	fpul, fr12\n\t"
+		     "fsts	fpul, fr13\n\t"
+		     "fsts	fpul, fr14\n\t"
+		     "fsts	fpul, fr15\n\t"
+		     "frchg\n\t"
+		     "lds	%2, fpscr\n\t"
+		     : /* no output */
+		     : "r" (0), "r" (FPSCR_RCHG), "r" (FPSCR_INIT));
+ 	disable_fpu();
+}
+
+/**
+ *	denormal_to_double - Given denormalized float number,
+ *	                     store double float
+ *
+ *	@fpu: Pointer to sh_fpu_hard structure
+ *	@n: Index to FP register
+ */
+static void
+denormal_to_double (struct sh_fpu_hard_struct *fpu, int n)
+{
+	unsigned long du, dl;
+	unsigned long x = fpu->fpul;
+	int exp = 1023 - 126;
+
+	if (x != 0 && (x & 0x7f800000) == 0) {
+		du = (x & 0x80000000);
+		while ((x & 0x00800000) == 0) {
+			x <<= 1;
+			exp--;
+		}
+		x &= 0x007fffff;
+		du |= (exp << 20) | (x >> 3);
+		dl = x << 29;
+
+		fpu->fp_regs[n] = du;
+		fpu->fp_regs[n+1] = dl;
+	}
+}
+
+/**
+ *	ieee_fpe_handler - Handle denormalized number exception
+ *
+ *	@regs: Pointer to register structure
+ *
+ *	Returns 1 when it's handled (should not cause exception).
+ */
+static int
+ieee_fpe_handler (struct pt_regs *regs)
+{
+	unsigned short insn = *(unsigned short *) regs->pc;
+	unsigned short finsn;
+	unsigned long nextpc;
+	int nib[4] = {
+		(insn >> 12) & 0xf,
+		(insn >> 8) & 0xf,
+		(insn >> 4) & 0xf,
+		insn & 0xf};
+
+	if (nib[0] == 0xb ||
+	    (nib[0] == 0x4 && nib[2] == 0x0 && nib[3] == 0xb)) /* bsr & jsr */
+		regs->pr = regs->pc + 4;
+  
+	if (nib[0] == 0xa || nib[0] == 0xb) { /* bra & bsr */
+		nextpc = regs->pc + 4 + ((short) ((insn & 0xfff) << 4) >> 3);
+		finsn = *(unsigned short *) (regs->pc + 2);
+	} else if (nib[0] == 0x8 && nib[1] == 0xd) { /* bt/s */
+		if (regs->sr & 1)
+			nextpc = regs->pc + 4 + ((char) (insn & 0xff) << 1);
+		else
+			nextpc = regs->pc + 4;
+		finsn = *(unsigned short *) (regs->pc + 2);
+	} else if (nib[0] == 0x8 && nib[1] == 0xf) { /* bf/s */
+		if (regs->sr & 1)
+			nextpc = regs->pc + 4;
+		else
+			nextpc = regs->pc + 4 + ((char) (insn & 0xff) << 1);
+		finsn = *(unsigned short *) (regs->pc + 2);
+	} else if (nib[0] == 0x4 && nib[3] == 0xb &&
+		 (nib[2] == 0x0 || nib[2] == 0x2)) { /* jmp & jsr */
+		nextpc = regs->regs[nib[1]];
+		finsn = *(unsigned short *) (regs->pc + 2);
+	} else if (nib[0] == 0x0 && nib[3] == 0x3 &&
+		 (nib[2] == 0x0 || nib[2] == 0x2)) { /* braf & bsrf */
+		nextpc = regs->pc + 4 + regs->regs[nib[1]];
+		finsn = *(unsigned short *) (regs->pc + 2);
+	} else if (insn == 0x000b) { /* rts */
+		nextpc = regs->pr;
+		finsn = *(unsigned short *) (regs->pc + 2);
+	} else {
+		nextpc = regs->pc + 2;
+		finsn = insn;
+	}
+
+	if ((finsn & 0xf1ff) == 0xf0ad) { /* fcnvsd */
+		struct task_struct *tsk = current;
+
+		save_fpu(tsk, regs);
+		if ((tsk->thread.fpu.hard.fpscr & (1 << 17))) {
+			/* FPU error */
+			denormal_to_double (&tsk->thread.fpu.hard,
+					    (finsn >> 8) & 0xf);
+			tsk->thread.fpu.hard.fpscr &=
+				~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK);
+			grab_fpu(regs);
+			restore_fpu(tsk);
+			set_tsk_thread_flag(tsk, TIF_USEDFPU);
+		} else {
+			tsk->thread.trap_no = 11;
+			tsk->thread.error_code = 0;
+			force_sig(SIGFPE, tsk);
+		}
+
+		regs->pc = nextpc;
+		return 1;
+	}
+
+	return 0;
+}
+
+asmlinkage void
+do_fpu_error(unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7,
+	     struct pt_regs regs)
+{
+	struct task_struct *tsk = current;
+
+	if (ieee_fpe_handler (&regs))
+		return;
+
+	regs.pc += 2;
+	save_fpu(tsk, &regs);
+	tsk->thread.trap_no = 11;
+	tsk->thread.error_code = 0;
+	force_sig(SIGFPE, tsk);
+}
+
+asmlinkage void
+do_fpu_state_restore(unsigned long r4, unsigned long r5, unsigned long r6,
+		     unsigned long r7, struct pt_regs regs)
+{
+	struct task_struct *tsk = current;
+
+	grab_fpu(&regs);
+	if (!user_mode(&regs)) {
+		printk(KERN_ERR "BUG: FPU is used in kernel mode.\n");
+		return;
+	}
+
+	if (used_math()) {
+		/* Using the FPU again.  */
+		restore_fpu(tsk);
+	} else	{
+		/* First time FPU user.  */
+		fpu_init();
+		set_used_math();
+	}
+	set_tsk_thread_flag(tsk, TIF_USEDFPU);
+}
diff --git a/arch/sh/kernel/cpu/sh4/irq_intc2.c b/arch/sh/kernel/cpu/sh4/irq_intc2.c
new file mode 100644
index 0000000..099ebbf
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/irq_intc2.c
@@ -0,0 +1,222 @@
+/*
+ * linux/arch/sh/kernel/irq_intc2.c
+ *
+ * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.                            
+ *
+ * Interrupt handling for INTC2-based IRQ.
+ *
+ * These are the "new Hitachi style" interrupts, as present on the 
+ * Hitachi 7751 and the STM ST40 STB1.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/machvec.h>
+
+
+struct intc2_data {
+	unsigned char msk_offset;
+	unsigned char msk_shift;
+#ifdef CONFIG_CPU_SUBTYPE_ST40
+	int (*clear_irq) (int);
+#endif
+};
+
+
+static struct intc2_data intc2_data[NR_INTC2_IRQS];
+
+static void enable_intc2_irq(unsigned int irq);
+static void disable_intc2_irq(unsigned int irq);
+
+/* shutdown is same as "disable" */
+#define shutdown_intc2_irq disable_intc2_irq
+
+static void mask_and_ack_intc2(unsigned int);
+static void end_intc2_irq(unsigned int irq);
+
+static unsigned int startup_intc2_irq(unsigned int irq)
+{ 
+	enable_intc2_irq(irq);
+	return 0; /* never anything pending */
+}
+
+static struct hw_interrupt_type intc2_irq_type = {
+	"INTC2-IRQ",
+	startup_intc2_irq,
+	shutdown_intc2_irq,
+	enable_intc2_irq,
+	disable_intc2_irq,
+	mask_and_ack_intc2,
+	end_intc2_irq
+};
+
+static void disable_intc2_irq(unsigned int irq)
+{
+	int irq_offset = irq - INTC2_FIRST_IRQ;
+	int msk_shift, msk_offset;
+
+	// Sanity check
+	if((irq_offset<0) || (irq_offset>=NR_INTC2_IRQS))
+		return;
+
+	msk_shift = intc2_data[irq_offset].msk_shift;
+	msk_offset = intc2_data[irq_offset].msk_offset;
+
+	ctrl_outl(1<<msk_shift,
+		  INTC2_BASE+INTC2_INTMSK_OFFSET+msk_offset);
+}
+
+static void enable_intc2_irq(unsigned int irq)
+{
+	int irq_offset = irq - INTC2_FIRST_IRQ;
+	int msk_shift, msk_offset;
+
+	/* Sanity check */
+	if((irq_offset<0) || (irq_offset>=NR_INTC2_IRQS))
+		return;
+
+	msk_shift = intc2_data[irq_offset].msk_shift;
+	msk_offset = intc2_data[irq_offset].msk_offset;
+
+	ctrl_outl(1<<msk_shift,
+		  INTC2_BASE+INTC2_INTMSKCLR_OFFSET+msk_offset);
+}
+
+static void mask_and_ack_intc2(unsigned int irq)
+{
+	disable_intc2_irq(irq);
+}
+
+static void end_intc2_irq(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+		enable_intc2_irq(irq);
+
+#ifdef CONFIG_CPU_SUBTYPE_ST40
+	if (intc2_data[irq - INTC2_FIRST_IRQ].clear_irq)
+		intc2_data[irq - INTC2_FIRST_IRQ].clear_irq (irq);
+#endif
+}
+
+/*
+ * Setup an INTC2 style interrupt.
+ * NOTE: Unlike IPR interrupts, parameters are not shifted by this code,
+ * allowing the use of the numbers straight out of the datasheet.
+ * For example:
+ *    PIO1 which is INTPRI00[19,16] and INTMSK00[13]
+ * would be:               ^     ^             ^  ^
+ *                         |     |             |  |
+ *    make_intc2_irq(84,   0,   16,            0, 13);
+ */
+void make_intc2_irq(unsigned int irq,
+		    unsigned int ipr_offset, unsigned int ipr_shift,
+		    unsigned int msk_offset, unsigned int msk_shift,
+		    unsigned int priority)
+{
+	int irq_offset = irq - INTC2_FIRST_IRQ;
+	unsigned int flags;
+	unsigned long ipr;
+
+	if((irq_offset<0) || (irq_offset>=NR_INTC2_IRQS))
+		return;
+
+	disable_irq_nosync(irq);
+
+	/* Fill the data we need */
+	intc2_data[irq_offset].msk_offset = msk_offset;
+	intc2_data[irq_offset].msk_shift  = msk_shift;
+#ifdef CONFIG_CPU_SUBTYPE_ST40
+	intc2_data[irq_offset].clear_irq = NULL;
+#endif
+		
+	/* Set the priority level */
+	local_irq_save(flags);
+
+	ipr=ctrl_inl(INTC2_BASE+INTC2_INTPRI_OFFSET+ipr_offset);
+	ipr&=~(0xf<<ipr_shift);
+	ipr|=(priority)<<ipr_shift;
+	ctrl_outl(ipr, INTC2_BASE+INTC2_INTPRI_OFFSET+ipr_offset);
+
+	local_irq_restore(flags);
+
+	irq_desc[irq].handler=&intc2_irq_type;
+
+	disable_intc2_irq(irq);
+}
+
+#ifdef CONFIG_CPU_SUBTYPE_ST40
+
+struct intc2_init {
+	unsigned short irq;
+	unsigned char ipr_offset, ipr_shift;
+	unsigned char msk_offset, msk_shift;
+};
+
+static struct intc2_init intc2_init_data[]  __initdata = {
+	{64,  0,  0, 0,  0},	/* PCI serr */
+	{65,  0,  4, 0,  1},	/* PCI err */
+	{66,  0,  4, 0,  2},	/* PCI ad */
+	{67,  0,  4, 0,  3},	/* PCI pwd down */
+	{72,  0,  8, 0,  5},	/* DMAC INT0 */
+	{73,  0,  8, 0,  6},	/* DMAC INT1 */
+	{74,  0,  8, 0,  7},	/* DMAC INT2 */
+	{75,  0,  8, 0,  8},	/* DMAC INT3 */
+	{76,  0,  8, 0,  9},	/* DMAC INT4 */
+	{78,  0,  8, 0, 11},	/* DMAC ERR */
+	{80,  0, 12, 0, 12},	/* PIO0 */
+	{84,  0, 16, 0, 13},	/* PIO1 */
+	{88,  0, 20, 0, 14},	/* PIO2 */
+	{112, 4,  0, 4,  0},	/* Mailbox */
+#ifdef CONFIG_CPU_SUBTYPE_ST40GX1
+	{116, 4,  4, 4,  4},	/* SSC0 */
+	{120, 4,  8, 4,  8},	/* IR Blaster */
+	{124, 4, 12, 4, 12},	/* USB host */
+	{128, 4, 16, 4, 16},	/* Video processor BLITTER */
+	{132, 4, 20, 4, 20},	/* UART0 */
+	{134, 4, 20, 4, 22},	/* UART2 */
+	{136, 4, 24, 4, 24},	/* IO_PIO0 */
+	{140, 4, 28, 4, 28},	/* EMPI */
+	{144, 8,  0, 8,  0},	/* MAFE */
+	{148, 8,  4, 8,  4},	/* PWM */
+	{152, 8,  8, 8,  8},	/* SSC1 */
+	{156, 8, 12, 8, 12},	/* IO_PIO1 */
+	{160, 8, 16, 8, 16},	/* USB target */
+	{164, 8, 20, 8, 20},	/* UART1 */
+	{168, 8, 24, 8, 24},	/* Teletext */
+	{172, 8, 28, 8, 28},	/* VideoSync VTG */
+	{173, 8, 28, 8, 29},	/* VideoSync DVP0 */
+	{174, 8, 28, 8, 30},	/* VideoSync DVP1 */
+#endif
+};
+
+void __init init_IRQ_intc2(void)
+{
+	struct intc2_init *p;
+
+	printk(KERN_ALERT "init_IRQ_intc2\n");
+
+	for (p = intc2_init_data;
+	     p<intc2_init_data+ARRAY_SIZE(intc2_init_data);
+	     p++) {
+		make_intc2_irq(p->irq, p->ipr_offset, p->ipr_shift,
+			       p-> msk_offset, p->msk_shift, 13);
+	}
+}
+
+/* Adds a termination callback to the interrupt */
+void intc2_add_clear_irq(int irq, int (*fn)(int))
+{
+	if (irq < INTC2_FIRST_IRQ)
+		return;
+
+	intc2_data[irq - INTC2_FIRST_IRQ].clear_irq = fn;
+}
+
+#endif /* CONFIG_CPU_SUBTYPE_ST40 */
diff --git a/arch/sh/kernel/cpu/sh4/probe.c b/arch/sh/kernel/cpu/sh4/probe.c
new file mode 100644
index 0000000..42427b7
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/probe.c
@@ -0,0 +1,138 @@
+/*
+ * arch/sh/kernel/cpu/sh4/probe.c
+ *
+ * CPU Subtype Probing for SH-4.
+ *
+ * Copyright (C) 2001, 2002, 2003, 2004  Paul Mundt
+ * Copyright (C) 2003  Richard Curnow
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/init.h>
+#include <asm/processor.h>
+#include <asm/cache.h>
+#include <asm/io.h>
+
+int __init detect_cpu_and_cache_system(void)
+{
+	unsigned long pvr, prr, cvr;
+	unsigned long size;
+
+	static unsigned long sizes[16] = {
+		[1] = (1 << 12),
+		[2] = (1 << 13),
+		[4] = (1 << 14),
+		[8] = (1 << 15),
+		[9] = (1 << 16)
+	};
+
+	pvr = (ctrl_inl(CCN_PVR) >> 8) & 0xffff;
+	prr = (ctrl_inl(CCN_PRR) >> 4) & 0xff;
+	cvr = (ctrl_inl(CCN_CVR));
+
+	/*
+	 * Setup some sane SH-4 defaults for the icache
+	 */
+	cpu_data->icache.way_incr	= (1 << 13);
+	cpu_data->icache.entry_shift	= 5;
+	cpu_data->icache.entry_mask	= 0x1fe0;
+	cpu_data->icache.sets		= 256;
+	cpu_data->icache.ways		= 1;
+	cpu_data->icache.linesz		= L1_CACHE_BYTES;
+
+	/*
+	 * And again for the dcache ..
+	 */
+	cpu_data->dcache.way_incr	= (1 << 14);
+	cpu_data->dcache.entry_shift	= 5;
+	cpu_data->dcache.entry_mask	= 0x3fe0;
+	cpu_data->dcache.sets		= 512;
+	cpu_data->dcache.ways		= 1;
+	cpu_data->dcache.linesz		= L1_CACHE_BYTES;
+
+	/* Set the FPU flag, virtually all SH-4's have one */
+	cpu_data->flags |= CPU_HAS_FPU;
+
+	/*
+	 * Probe the underlying processor version/revision and
+	 * adjust cpu_data setup accordingly.
+	 */
+	switch (pvr) {
+	case 0x205:
+		cpu_data->type = CPU_SH7750;
+		cpu_data->flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_PERF_COUNTER;
+		break;
+	case 0x206:
+		cpu_data->type = CPU_SH7750S;
+		cpu_data->flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_PERF_COUNTER;
+		break;
+	case 0x1100:
+		cpu_data->type = CPU_SH7751;
+		break;
+	case 0x2000:
+		cpu_data->type = CPU_SH73180;
+		cpu_data->icache.ways = 4;
+		cpu_data->dcache.ways = 4;
+		cpu_data->flags &= ~CPU_HAS_FPU;
+		break;
+	case 0x8000:
+		cpu_data->type = CPU_ST40RA;
+		break;
+	case 0x8100:
+		cpu_data->type = CPU_ST40GX1;
+		break;
+	case 0x700:
+		cpu_data->type = CPU_SH4_501;
+		cpu_data->icache.ways = 2;
+		cpu_data->dcache.ways = 2;
+
+		/* No FPU on the SH4-500 series.. */
+		cpu_data->flags &= ~CPU_HAS_FPU;
+		break;
+	case 0x600:
+		cpu_data->type = CPU_SH4_202;
+		cpu_data->icache.ways = 2;
+		cpu_data->dcache.ways = 2;
+		break;
+	case 0x500 ... 0x501:
+		switch (prr) {
+		    case 0x10: cpu_data->type = CPU_SH7750R; break;
+		    case 0x11: cpu_data->type = CPU_SH7751R; break;
+		    case 0x50: cpu_data->type = CPU_SH7760;  break;
+		}
+
+		cpu_data->icache.ways = 2;
+		cpu_data->dcache.ways = 2;
+
+		break;
+	default:
+		cpu_data->type = CPU_SH_NONE;
+		break;
+	}
+
+	/*
+	 * On anything that's not a direct-mapped cache, look to the CVR
+	 * for I/D-cache specifics.
+	 */
+	if (cpu_data->icache.ways > 1) {
+		size = sizes[(cvr >> 20) & 0xf];
+		cpu_data->icache.way_incr	= (size >> 1);
+		cpu_data->icache.sets		= (size >> 6);
+		cpu_data->icache.entry_mask	=
+			(cpu_data->icache.way_incr - (1 << 5));
+	}
+
+	if (cpu_data->dcache.ways > 1) {
+		size = sizes[(cvr >> 16) & 0xf];
+		cpu_data->dcache.way_incr	= (size >> 1);
+		cpu_data->dcache.sets		= (size >> 6);
+		cpu_data->dcache.entry_mask	=
+			(cpu_data->dcache.way_incr - (1 << 5));
+	}
+
+	return 0;
+}
+
diff --git a/arch/sh/kernel/cpu/sh4/sq.c b/arch/sh/kernel/cpu/sh4/sq.c
new file mode 100644
index 0000000..8437ea7
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/sq.c
@@ -0,0 +1,453 @@
+/*
+ * arch/sh/kernel/cpu/sq.c
+ *
+ * General management API for SH-4 integrated Store Queues
+ *
+ * Copyright (C) 2001, 2002, 2003, 2004  Paul Mundt
+ * Copyright (C) 2001, 2002  M. R. Brown
+ *
+ * Some of this code has been adopted directly from the old arch/sh/mm/sq.c
+ * hack that was part of the LinuxDC project. For all intents and purposes,
+ * this is a completely new interface that really doesn't have much in common
+ * with the old zone-based approach at all. In fact, it's only listed here for
+ * general completeness.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/proc_fs.h>
+#include <linux/miscdevice.h>
+#include <linux/vmalloc.h>
+
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/mmu_context.h>
+#include <asm/cpu/sq.h>
+
+static LIST_HEAD(sq_mapping_list);
+static DEFINE_SPINLOCK(sq_mapping_lock);
+
+/**
+ * sq_flush - Flush (prefetch) the store queue cache
+ * @addr: the store queue address to flush
+ *
+ * Executes a prefetch instruction on the specified store queue cache,
+ * so that the cached data is written to physical memory.
+ */
+inline void sq_flush(void *addr)
+{
+	__asm__ __volatile__ ("pref @%0" : : "r" (addr) : "memory");
+}
+
+/**
+ * sq_flush_range - Flush (prefetch) a specific SQ range
+ * @start: the store queue address to start flushing from
+ * @len: the length to flush
+ *
+ * Flushes the store queue cache from @start to @start + @len in a
+ * linear fashion.
+ */
+void sq_flush_range(unsigned long start, unsigned int len)
+{
+	volatile unsigned long *sq = (unsigned long *)start;
+	unsigned long dummy;
+
+	/* Flush the queues */
+	for (len >>= 5; len--; sq += 8)
+		sq_flush((void *)sq);
+
+	/* Wait for completion */
+	dummy = ctrl_inl(P4SEG_STORE_QUE);
+
+	ctrl_outl(0, P4SEG_STORE_QUE + 0);
+	ctrl_outl(0, P4SEG_STORE_QUE + 8);
+}
+
+static struct sq_mapping *__sq_alloc_mapping(unsigned long virt, unsigned long phys, unsigned long size, const char *name)
+{
+	struct sq_mapping *map;
+
+	if (virt + size > SQ_ADDRMAX)
+		return ERR_PTR(-ENOSPC);
+
+	map = kmalloc(sizeof(struct sq_mapping), GFP_KERNEL);
+	if (!map)
+		return ERR_PTR(-ENOMEM);
+
+	INIT_LIST_HEAD(&map->list);
+
+	map->sq_addr	= virt;
+	map->addr	= phys;
+	map->size	= size + 1;
+	map->name	= name;
+
+	list_add(&map->list, &sq_mapping_list);
+
+	return map;
+}
+
+static unsigned long __sq_get_next_addr(void)
+{
+	if (!list_empty(&sq_mapping_list)) {
+		struct list_head *pos, *tmp;
+
+		/*
+		 * Read one off the list head, as it will have the highest
+		 * mapped allocation. Set the next one up right above it.
+		 *
+		 * This is somewhat sub-optimal, as we don't look at
+		 * gaps between allocations or anything lower then the
+		 * highest-level allocation.
+		 *
+		 * However, in the interest of performance and the general
+		 * lack of desire to do constant list rebalancing, we don't
+		 * worry about it.
+		 */
+		list_for_each_safe(pos, tmp, &sq_mapping_list) {
+			struct sq_mapping *entry;
+
+			entry = list_entry(pos, typeof(*entry), list);
+
+			return entry->sq_addr + entry->size;
+		}
+	}
+
+	return P4SEG_STORE_QUE;
+}
+
+/**
+ * __sq_remap - Perform a translation from the SQ to a phys addr
+ * @map: sq mapping containing phys and store queue addresses.
+ *
+ * Maps the store queue address specified in the mapping to the physical
+ * address specified in the mapping.
+ */
+static struct sq_mapping *__sq_remap(struct sq_mapping *map)
+{
+	unsigned long flags, pteh, ptel;
+	struct vm_struct *vma;
+	pgprot_t pgprot;
+
+	/*
+	 * Without an MMU (or with it turned off), this is much more
+	 * straightforward, as we can just load up each queue's QACR with
+	 * the physical address appropriately masked.
+	 */
+
+	ctrl_outl(((map->addr >> 26) << 2) & 0x1c, SQ_QACR0);
+	ctrl_outl(((map->addr >> 26) << 2) & 0x1c, SQ_QACR1);
+
+#ifdef CONFIG_MMU
+	/*
+	 * With an MMU on the other hand, things are slightly more involved.
+	 * Namely, we have to have a direct mapping between the SQ addr and
+	 * the associated physical address in the UTLB by way of setting up
+	 * a virt<->phys translation by hand. We do this by simply specifying
+	 * the SQ addr in UTLB.VPN and the associated physical address in
+	 * UTLB.PPN.
+	 *
+	 * Notably, even though this is a special case translation, and some
+	 * of the configuration bits are meaningless, we're still required
+	 * to have a valid ASID context in PTEH.
+	 *
+	 * We could also probably get by without explicitly setting PTEA, but
+	 * we do it here just for good measure.
+	 */
+	spin_lock_irqsave(&sq_mapping_lock, flags);
+
+	pteh = map->sq_addr;
+	ctrl_outl((pteh & MMU_VPN_MASK) | get_asid(), MMU_PTEH);
+
+	ptel = map->addr & PAGE_MASK;
+	ctrl_outl(((ptel >> 28) & 0xe) | (ptel & 0x1), MMU_PTEA);
+
+	pgprot = pgprot_noncached(PAGE_KERNEL);
+
+	ptel &= _PAGE_FLAGS_HARDWARE_MASK;
+	ptel |= pgprot_val(pgprot);
+	ctrl_outl(ptel, MMU_PTEL);
+
+	__asm__ __volatile__ ("ldtlb" : : : "memory");
+
+	spin_unlock_irqrestore(&sq_mapping_lock, flags);
+
+	/*
+	 * Next, we need to map ourselves in the kernel page table, so that
+	 * future accesses after a TLB flush will be handled when we take a
+	 * page fault.
+	 *
+	 * Theoretically we could just do this directly and not worry about
+	 * setting up the translation by hand ahead of time, but for the
+	 * cases where we want a one-shot SQ mapping followed by a quick
+	 * writeout before we hit the TLB flush, we do it anyways. This way
+	 * we at least save ourselves the initial page fault overhead.
+	 */
+	vma = __get_vm_area(map->size, VM_ALLOC, map->sq_addr, SQ_ADDRMAX);
+	if (!vma)
+		return ERR_PTR(-ENOMEM);
+
+	vma->phys_addr = map->addr;
+
+	if (remap_area_pages((unsigned long)vma->addr, vma->phys_addr,
+			     map->size, pgprot_val(pgprot))) {
+		vunmap(vma->addr);
+		return NULL;
+	}
+#endif /* CONFIG_MMU */
+
+	return map;
+}
+
+/**
+ * sq_remap - Map a physical address through the Store Queues
+ * @phys: Physical address of mapping.
+ * @size: Length of mapping.
+ * @name: User invoking mapping.
+ *
+ * Remaps the physical address @phys through the next available store queue
+ * address of @size length. @name is logged at boot time as well as through
+ * the procfs interface.
+ *
+ * A pre-allocated and filled sq_mapping pointer is returned, and must be
+ * cleaned up with a call to sq_unmap() when the user is done with the
+ * mapping.
+ */
+struct sq_mapping *sq_remap(unsigned long phys, unsigned int size, const char *name)
+{
+	struct sq_mapping *map;
+	unsigned long virt, end;
+	unsigned int psz;
+
+	/* Don't allow wraparound or zero size */
+	end = phys + size - 1;
+	if (!size || end < phys)
+		return NULL;
+	/* Don't allow anyone to remap normal memory.. */
+	if (phys < virt_to_phys(high_memory))
+		return NULL;
+
+	phys &= PAGE_MASK;
+
+	size  = PAGE_ALIGN(end + 1) - phys;
+	virt  = __sq_get_next_addr();
+	psz   = (size + (PAGE_SIZE - 1)) / PAGE_SIZE;
+	map   = __sq_alloc_mapping(virt, phys, size, name);
+
+	printk("sqremap: %15s  [%4d page%s]  va 0x%08lx   pa 0x%08lx\n",
+	       map->name ? map->name : "???",
+	       psz, psz == 1 ? " " : "s",
+	       map->sq_addr, map->addr);
+
+	return __sq_remap(map);
+}
+
+/**
+ * sq_unmap - Unmap a Store Queue allocation
+ * @map: Pre-allocated Store Queue mapping.
+ *
+ * Unmaps the store queue allocation @map that was previously created by
+ * sq_remap(). Also frees up the pte that was previously inserted into
+ * the kernel page table and discards the UTLB translation.
+ */
+void sq_unmap(struct sq_mapping *map)
+{
+	if (map->sq_addr > (unsigned long)high_memory)
+		vfree((void *)(map->sq_addr & PAGE_MASK));
+
+	list_del(&map->list);
+	kfree(map);
+}
+
+/**
+ * sq_clear - Clear a store queue range
+ * @addr: Address to start clearing from.
+ * @len: Length to clear.
+ *
+ * A quick zero-fill implementation for clearing out memory that has been
+ * remapped through the store queues.
+ */
+void sq_clear(unsigned long addr, unsigned int len)
+{
+	int i;
+
+	/* Clear out both queues linearly */
+	for (i = 0; i < 8; i++) {
+		ctrl_outl(0, addr + i + 0);
+		ctrl_outl(0, addr + i + 8);
+	}
+
+	sq_flush_range(addr, len);
+}
+
+/**
+ * sq_vma_unmap - Unmap a VMA range
+ * @area: VMA containing range.
+ * @addr: Start of range.
+ * @len: Length of range.
+ *
+ * Searches the sq_mapping_list for a mapping matching the sq addr @addr,
+ * and subsequently frees up the entry. Further cleanup is done by generic
+ * code.
+ */
+static void sq_vma_unmap(struct vm_area_struct *area,
+			 unsigned long addr, size_t len)
+{
+	struct list_head *pos, *tmp;
+
+	list_for_each_safe(pos, tmp, &sq_mapping_list) {
+		struct sq_mapping *entry;
+
+		entry = list_entry(pos, typeof(*entry), list);
+
+		if (entry->sq_addr == addr) {
+			/*
+			 * We could probably get away without doing the tlb flush
+			 * here, as generic code should take care of most of this
+			 * when unmapping the rest of the VMA range for us. Leave
+			 * it in for added sanity for the time being..
+			 */
+			__flush_tlb_page(get_asid(), entry->sq_addr & PAGE_MASK);
+
+			list_del(&entry->list);
+			kfree(entry);
+
+			return;
+		}
+	}
+}
+
+/**
+ * sq_vma_sync - Sync a VMA range
+ * @area: VMA containing range.
+ * @start: Start of range.
+ * @len: Length of range.
+ * @flags: Additional flags.
+ *
+ * Synchronizes an sq mapped range by flushing the store queue cache for
+ * the duration of the mapping.
+ *
+ * Used internally for user mappings, which must use msync() to prefetch
+ * the store queue cache.
+ */
+static int sq_vma_sync(struct vm_area_struct *area,
+		       unsigned long start, size_t len, unsigned int flags)
+{
+	sq_flush_range(start, len);
+
+	return 0;
+}
+
+static struct vm_operations_struct sq_vma_ops = {
+	.unmap	= sq_vma_unmap,
+	.sync	= sq_vma_sync,
+};
+
+/**
+ * sq_mmap - mmap() for /dev/cpu/sq
+ * @file: unused.
+ * @vma: VMA to remap.
+ *
+ * Remap the specified vma @vma through the store queues, and setup associated
+ * information for the new mapping. Also build up the page tables for the new
+ * area.
+ */
+static int sq_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+	unsigned long size = vma->vm_end - vma->vm_start;
+	struct sq_mapping *map;
+
+	/*
+	 * We're not interested in any arbitrary virtual address that has
+	 * been stuck in the VMA, as we already know what addresses we
+	 * want. Save off the size, and reposition the VMA to begin at
+	 * the next available sq address.
+	 */
+	vma->vm_start = __sq_get_next_addr();
+	vma->vm_end   = vma->vm_start + size;
+
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+	vma->vm_flags |= VM_IO | VM_RESERVED;
+
+	map = __sq_alloc_mapping(vma->vm_start, offset, size, "Userspace");
+
+	if (io_remap_pfn_range(vma, map->sq_addr, map->addr >> PAGE_SHIFT,
+				size, vma->vm_page_prot))
+		return -EAGAIN;
+
+	vma->vm_ops = &sq_vma_ops;
+
+	return 0;
+}
+
+#ifdef CONFIG_PROC_FS
+static int sq_mapping_read_proc(char *buf, char **start, off_t off,
+				int len, int *eof, void *data)
+{
+	struct list_head *pos;
+	char *p = buf;
+
+	list_for_each_prev(pos, &sq_mapping_list) {
+		struct sq_mapping *entry;
+
+		entry = list_entry(pos, typeof(*entry), list);
+
+		p += sprintf(p, "%08lx-%08lx [%08lx]: %s\n", entry->sq_addr,
+			     entry->sq_addr + entry->size - 1, entry->addr,
+			     entry->name);
+	}
+
+	return p - buf;
+}
+#endif
+
+static struct file_operations sq_fops = {
+	.owner		= THIS_MODULE,
+	.mmap		= sq_mmap,
+};
+
+static struct miscdevice sq_dev = {
+	.minor		= STORE_QUEUE_MINOR,
+	.name		= "sq",
+	.devfs_name	= "cpu/sq",
+	.fops		= &sq_fops,
+};
+
+static int __init sq_api_init(void)
+{
+	printk(KERN_NOTICE "sq: Registering store queue API.\n");
+
+#ifdef CONFIG_PROC_FS
+	create_proc_read_entry("sq_mapping", 0, 0, sq_mapping_read_proc, 0);
+#endif
+
+	return misc_register(&sq_dev);
+}
+
+static void __exit sq_api_exit(void)
+{
+	misc_deregister(&sq_dev);
+}
+
+module_init(sq_api_init);
+module_exit(sq_api_exit);
+
+MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, M. R. Brown <mrbrown@0xd6.org>");
+MODULE_DESCRIPTION("Simple API for SH-4 integrated Store Queues");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(STORE_QUEUE_MINOR);
+
+EXPORT_SYMBOL(sq_remap);
+EXPORT_SYMBOL(sq_unmap);
+EXPORT_SYMBOL(sq_clear);
+EXPORT_SYMBOL(sq_flush);
+EXPORT_SYMBOL(sq_flush_range);
+
diff --git a/arch/sh/kernel/cpu/ubc.S b/arch/sh/kernel/cpu/ubc.S
new file mode 100644
index 0000000..0c569b2
--- /dev/null
+++ b/arch/sh/kernel/cpu/ubc.S
@@ -0,0 +1,59 @@
+/*
+ * arch/sh/kernel/ubc.S
+ *
+ * Set of management routines for the User Break Controller (UBC)
+ *
+ * Copyright (C) 2002 Paul Mundt
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/linkage.h>
+#include <asm/ubc.h>
+
+#define STBCR2		0xffc00010
+
+ENTRY(ubc_sleep)
+	mov	#0, r0
+
+	mov.l	1f, r1		! Zero out UBC_BBRA ..
+	mov.w	r0, @r1
+
+	mov.l	2f, r1		! .. same for BBRB ..
+	mov.w	r0, @r1
+
+	mov.l	3f, r1		! .. and again for BRCR.
+	mov.w	r0, @r1
+
+	mov.w	@r1, r0		! Dummy read BRCR
+
+	mov.l	4f, r1		! Set MSTP5 in STBCR2
+	mov.b	@r1, r0
+	or	#0x01, r0
+	mov.b	r0, @r1
+
+	mov.b	@r1, r0		! Two dummy reads ..
+	mov.b	@r1, r0
+
+	rts
+	nop
+
+ENTRY(ubc_wakeup)
+	mov.l	4f, r1		! Clear MSTP5
+	mov.b	@r1, r0
+	and	#0xfe, r0
+	mov.b	r0, @r1
+
+	mov.b	@r1, r0		! Two more dummy reads ..
+	mov.b	@r1, r0
+
+	rts
+	nop
+
+1:	.long	UBC_BBRA
+2:	.long	UBC_BBRB
+3:	.long	UBC_BRCR
+4:	.long	STBCR2
+
diff --git a/arch/sh/kernel/cpufreq.c b/arch/sh/kernel/cpufreq.c
new file mode 100644
index 0000000..e0b384b
--- /dev/null
+++ b/arch/sh/kernel/cpufreq.c
@@ -0,0 +1,218 @@
+/*
+ * arch/sh/kernel/cpufreq.c
+ *
+ * cpufreq driver for the SuperH processors.
+ *
+ * Copyright (C) 2002, 2003, 2004, 2005 Paul Mundt
+ * Copyright (C) 2002 M. R. Brown
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/types.h>
+#include <linux/cpufreq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/cpumask.h>
+#include <linux/smp.h>
+
+#include <asm/processor.h>
+#include <asm/watchdog.h>
+#include <asm/freq.h>
+#include <asm/io.h>
+
+/*
+ * For SuperH, each policy change requires that we change the IFC, BFC, and
+ * PFC at the same time.  Here we define sane values that won't trash the
+ * system.
+ *
+ * Note the max set is computed at runtime, we use the divisors that we booted
+ * with to setup our maximum operating frequencies.
+ */
+struct clock_set {
+	unsigned int ifc;
+	unsigned int bfc;
+	unsigned int pfc;
+} clock_sets[] = {
+#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH2)
+	{ 0, 0, 0 },	/* not implemented yet */
+#elif defined(CONFIG_CPU_SH4)
+	{ 4, 8, 8 },	/* min - IFC: 1/4, BFC: 1/8, PFC: 1/8 */
+	{ 1, 2, 2 },	/* max - IFC: 1, BFC: 1/2, PFC: 1/2 */
+#endif
+};
+
+#define MIN_CLOCK_SET	0
+#define MAX_CLOCK_SET	(ARRAY_SIZE(clock_sets) - 1)
+
+/*
+ * For the time being, we only support two frequencies, which in turn are
+ * aimed at the POWERSAVE and PERFORMANCE policies, which in turn are derived
+ * directly from the respective min/max clock sets. Technically we could
+ * support a wider range of frequencies, but these vary far too much for each
+ * CPU subtype (and we'd have to construct a frequency table for each subtype).
+ *
+ * Maybe something to implement in the future..
+ */
+#define SH_FREQ_MAX	0
+#define SH_FREQ_MIN	1
+
+static struct cpufreq_frequency_table sh_freqs[] = {
+	{ SH_FREQ_MAX,	0 },
+	{ SH_FREQ_MIN,	0 },
+	{ 0,		CPUFREQ_TABLE_END },
+};
+
+static void sh_cpufreq_update_clocks(unsigned int set)
+{
+	current_cpu_data.cpu_clock = current_cpu_data.master_clock / clock_sets[set].ifc;
+	current_cpu_data.bus_clock = current_cpu_data.master_clock / clock_sets[set].bfc;
+	current_cpu_data.module_clock = current_cpu_data.master_clock / clock_sets[set].pfc;
+	current_cpu_data.loops_per_jiffy = loops_per_jiffy;
+}
+
+/* XXX: This needs to be split out per CPU and CPU subtype. */
+/*
+ * Here we notify other drivers of the proposed change and the final change.
+ */
+static int sh_cpufreq_setstate(unsigned int cpu, unsigned int set)
+{
+	unsigned short frqcr = ctrl_inw(FRQCR);
+	cpumask_t cpus_allowed;
+	struct cpufreq_freqs freqs;
+
+	if (!cpu_online(cpu))
+		return -ENODEV;
+
+	cpus_allowed = current->cpus_allowed;
+	set_cpus_allowed(current, cpumask_of_cpu(cpu));
+
+	BUG_ON(smp_processor_id() != cpu);
+
+	freqs.cpu = cpu;
+	freqs.old = current_cpu_data.cpu_clock / 1000;
+	freqs.new = (current_cpu_data.master_clock / clock_sets[set].ifc) / 1000;
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+#if defined(CONFIG_CPU_SH3)
+	frqcr |= (newstate & 0x4000) << 14;
+	frqcr |= (newstate & 0x000c) <<  2;
+#elif defined(CONFIG_CPU_SH4)
+	/*
+	 * FRQCR.PLL2EN is 1, we need to allow the PLL to stabilize by
+	 * initializing the WDT.
+	 */
+	if (frqcr & (1 << 9)) {
+		__u8 csr;
+
+		/*
+		 * Set the overflow period to the highest available,
+		 * in this case a 1/4096 division ratio yields a 5.25ms
+		 * overflow period. See asm-sh/watchdog.h for more
+		 * information and a range of other divisors.
+		 */
+		csr = sh_wdt_read_csr();
+		csr |= WTCSR_CKS_4096;
+		sh_wdt_write_csr(csr);
+
+		sh_wdt_write_cnt(0);
+	}
+	frqcr &= 0x0e00;	/* Clear ifc, bfc, pfc */
+	frqcr |= get_ifc_value(clock_sets[set].ifc) << 6;
+	frqcr |= get_bfc_value(clock_sets[set].bfc) << 3;
+	frqcr |= get_pfc_value(clock_sets[set].pfc);
+#endif
+	ctrl_outw(frqcr, FRQCR);
+	sh_cpufreq_update_clocks(set);
+
+	set_cpus_allowed(current, cpus_allowed);
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+	return 0;
+}
+
+static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy)
+{
+	unsigned int min_freq, max_freq;
+	unsigned int ifc, bfc, pfc;
+
+	if (!cpu_online(policy->cpu))
+		return -ENODEV;
+
+	/* Update our maximum clock set */
+	get_current_frequency_divisors(&ifc, &bfc, &pfc);
+	clock_sets[MAX_CLOCK_SET].ifc = ifc;
+	clock_sets[MAX_CLOCK_SET].bfc = bfc;
+	clock_sets[MAX_CLOCK_SET].pfc = pfc;
+
+	/* Convert from Hz to kHz */
+	max_freq = current_cpu_data.cpu_clock / 1000;
+	min_freq = (current_cpu_data.master_clock / clock_sets[MIN_CLOCK_SET].ifc) / 1000;
+	
+	sh_freqs[SH_FREQ_MAX].frequency = max_freq;
+	sh_freqs[SH_FREQ_MIN].frequency = min_freq;
+
+	/* cpuinfo and default policy values */
+	policy->governor                   = CPUFREQ_DEFAULT_GOVERNOR;
+	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
+	policy->cur                        = max_freq;
+
+	return cpufreq_frequency_table_cpuinfo(policy, &sh_freqs[0]);
+}
+
+static int sh_cpufreq_verify(struct cpufreq_policy *policy)
+{
+	return cpufreq_frequency_table_verify(policy, &sh_freqs[0]);
+}
+
+static int sh_cpufreq_target(struct cpufreq_policy *policy,
+			     unsigned int target_freq,
+			     unsigned int relation)
+{
+	unsigned int set, idx = 0;
+
+	if (cpufreq_frequency_table_target(policy, &sh_freqs[0], target_freq, relation, &idx))
+		return -EINVAL;
+
+	set = (idx == SH_FREQ_MIN) ? MIN_CLOCK_SET : MAX_CLOCK_SET;
+
+	sh_cpufreq_setstate(policy->cpu, set);
+
+	return 0;
+}
+
+static struct cpufreq_driver sh_cpufreq_driver = {
+	.owner		= THIS_MODULE,
+	.name		= "SH cpufreq",
+	.init		= sh_cpufreq_cpu_init,
+	.verify		= sh_cpufreq_verify,
+	.target		= sh_cpufreq_target,
+};
+
+static int __init sh_cpufreq_init(void)
+{
+	if (!current_cpu_data.cpu_clock)
+		return -EINVAL;
+	if (cpufreq_register_driver(&sh_cpufreq_driver))
+		return -EINVAL;
+
+	return 0;
+}
+
+static void __exit sh_cpufreq_exit(void)
+{
+	cpufreq_unregister_driver(&sh_cpufreq_driver);
+}
+
+module_init(sh_cpufreq_init);
+module_exit(sh_cpufreq_exit);
+
+MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
+MODULE_DESCRIPTION("cpufreq driver for SuperH");
+MODULE_LICENSE("GPL");
+
diff --git a/arch/sh/kernel/early_printk.c b/arch/sh/kernel/early_printk.c
new file mode 100644
index 0000000..1378db3
--- /dev/null
+++ b/arch/sh/kernel/early_printk.c
@@ -0,0 +1,137 @@
+/*
+ * arch/sh/kernel/early_printk.c
+ *
+ *  Copyright (C) 1999, 2000  Niibe Yutaka
+ *  Copyright (C) 2002  M. R. Brown
+ *  Copyright (C) 2004  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/init.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_SH_STANDARD_BIOS
+#include <asm/sh_bios.h>
+
+/*
+ *	Print a string through the BIOS
+ */
+static void sh_console_write(struct console *co, const char *s,
+				 unsigned count)
+{
+	sh_bios_console_write(s, count);
+}
+
+/*
+ *	Setup initial baud/bits/parity. We do two things here:
+ *	- construct a cflag setting for the first rs_open()
+ *	- initialize the serial port
+ *	Return non-zero if we didn't find a serial port.
+ */
+static int __init sh_console_setup(struct console *co, char *options)
+{
+	int	cflag = CREAD | HUPCL | CLOCAL;
+
+	/*
+	 *	Now construct a cflag setting.
+	 *	TODO: this is a totally bogus cflag, as we have
+	 *	no idea what serial settings the BIOS is using, or
+	 *	even if its using the serial port at all.
+	 */
+	cflag |= B115200 | CS8 | /*no parity*/0;
+
+	co->cflag = cflag;
+
+	return 0;
+}
+
+static struct console early_console = {
+	.name		= "bios",
+	.write		= sh_console_write,
+	.setup		= sh_console_setup,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
+};
+#endif
+
+#ifdef CONFIG_EARLY_SCIF_CONSOLE
+#define SCIF_REG	0xffe80000
+
+static void scif_sercon_putc(int c)
+{
+	while (!(ctrl_inw(SCIF_REG + 0x10) & 0x20)) ;
+
+	ctrl_outb(c, SCIF_REG + 12);
+	ctrl_outw((ctrl_inw(SCIF_REG + 0x10) & 0x9f), SCIF_REG + 0x10);
+
+	if (c == '\n')
+		scif_sercon_putc('\r');
+}
+
+static void scif_sercon_flush(void)
+{
+	ctrl_outw((ctrl_inw(SCIF_REG + 0x10) & 0xbf), SCIF_REG + 0x10);
+
+	while (!(ctrl_inw(SCIF_REG + 0x10) & 0x40)) ;
+
+	ctrl_outw((ctrl_inw(SCIF_REG + 0x10) & 0xbf), SCIF_REG + 0x10);
+}
+
+static void scif_sercon_write(struct console *con, const char *s, unsigned count)
+{
+	while (count-- > 0)
+		scif_sercon_putc(*s++);
+
+	scif_sercon_flush();
+}
+
+static int __init scif_sercon_setup(struct console *con, char *options)
+{
+	con->cflag = CREAD | HUPCL | CLOCAL | B115200 | CS8;
+
+	return 0;
+}
+
+static struct console early_console = {
+	.name		= "sercon",
+	.write		= scif_sercon_write,
+	.setup		= scif_sercon_setup,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
+};
+
+void scif_sercon_init(int baud)
+{
+	ctrl_outw(0, SCIF_REG + 8);
+	ctrl_outw(0, SCIF_REG);
+
+	/* Set baud rate */
+	ctrl_outb((CONFIG_SH_PCLK_FREQ + 16 * baud) /
+		  (32 * baud) - 1, SCIF_REG + 4);
+
+	ctrl_outw(12, SCIF_REG + 24);
+	ctrl_outw(8, SCIF_REG + 24);
+	ctrl_outw(0, SCIF_REG + 32);
+	ctrl_outw(0x60, SCIF_REG + 16);
+	ctrl_outw(0, SCIF_REG + 36);
+	ctrl_outw(0x30, SCIF_REG + 8);
+}
+#endif
+
+void __init enable_early_printk(void)
+{
+#ifdef CONFIG_EARLY_SCIF_CONSOLE
+	scif_sercon_init(115200);
+#endif
+	register_console(&early_console);
+}
+
+void disable_early_printk(void)
+{
+	unregister_console(&early_console);
+}
+
diff --git a/arch/sh/kernel/entry.S b/arch/sh/kernel/entry.S
new file mode 100644
index 0000000..6615e48
--- /dev/null
+++ b/arch/sh/kernel/entry.S
@@ -0,0 +1,1149 @@
+/* $Id: entry.S,v 1.37 2004/06/11 13:02:46 doyu Exp $
+ *
+ *  linux/arch/sh/entry.S
+ *
+ *  Copyright (C) 1999, 2000, 2002  Niibe Yutaka
+ *  Copyright (C) 2003  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ */
+
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <linux/config.h>
+#include <asm/asm-offsets.h>
+#include <asm/thread_info.h>
+#include <asm/unistd.h>
+
+#if !defined(CONFIG_NFSD) && !defined(CONFIG_NFSD_MODULE)
+#define sys_nfsservctl		sys_ni_syscall
+#endif
+
+#if !defined(CONFIG_MMU)
+#define sys_madvise		sys_ni_syscall
+#define sys_readahead		sys_ni_syscall
+#define sys_mprotect		sys_ni_syscall
+#define sys_msync		sys_ni_syscall
+#define sys_mlock		sys_ni_syscall
+#define sys_munlock		sys_ni_syscall
+#define sys_mlockall		sys_ni_syscall
+#define sys_munlockall		sys_ni_syscall
+#define sys_mremap		sys_ni_syscall
+#define sys_mincore		sys_ni_syscall
+#define sys_remap_file_pages	sys_ni_syscall
+#endif
+
+! NOTE:
+! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address
+! to be jumped is too far, but it causes illegal slot exception.
+
+/*	
+ * entry.S contains the system-call and fault low-level handling routines.
+ * This also contains the timer-interrupt handler, as well as all interrupts
+ * and faults that can result in a task-switch.
+ *
+ * NOTE: This code handles signal-recognition, which happens every time
+ * after a timer-interrupt and after each system call.
+ *
+ * NOTE: This code uses a convention that instructions in the delay slot
+ * of a transfer-control instruction are indented by an extra space, thus:
+ *
+ *    jmp	@k0	    ! control-transfer instruction
+ *     ldc	k1, ssr     ! delay slot
+ *
+ * Stack layout in 'ret_from_syscall':
+ * 	ptrace needs to have all regs on the stack.
+ *	if the order here is changed, it needs to be
+ *	updated in ptrace.c and ptrace.h
+ *
+ *	r0
+ *      ...
+ *	r15 = stack pointer
+ *	spc
+ *	pr
+ *	ssr
+ *	gbr
+ *	mach
+ *	macl
+ *	syscall #
+ *
+ */
+
+ENOSYS = 38
+EINVAL = 22
+
+#if defined(CONFIG_CPU_SH3)
+TRA     = 0xffffffd0
+EXPEVT  = 0xffffffd4
+#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
+INTEVT  = 0xa4000000		! INTEVTE2(0xa4000000)
+#else
+INTEVT  = 0xffffffd8
+#endif
+MMU_TEA = 0xfffffffc		! TLB Exception Address Register
+#elif defined(CONFIG_CPU_SH4)
+TRA     = 0xff000020
+EXPEVT  = 0xff000024
+INTEVT  = 0xff000028
+MMU_TEA = 0xff00000c		! TLB Exception Address Register
+#endif
+
+#if defined(CONFIG_KGDB_NMI)
+NMI_VEC = 0x1c0			! Must catch early for debounce
+#endif
+
+/* Offsets to the stack */
+OFF_R0  =  0		/* Return value. New ABI also arg4 */
+OFF_R1  =  4     	/* New ABI: arg5 */
+OFF_R2  =  8     	/* New ABI: arg6 */
+OFF_R3  =  12     	/* New ABI: syscall_nr */
+OFF_R4  =  16     	/* New ABI: arg0 */
+OFF_R5  =  20     	/* New ABI: arg1 */
+OFF_R6  =  24     	/* New ABI: arg2 */
+OFF_R7  =  28     	/* New ABI: arg3 */
+OFF_SP	=  (15*4)
+OFF_PC  =  (16*4)
+OFF_SR	=  (16*4+8)
+OFF_TRA	=  (16*4+6*4)
+
+
+#define k0	r0
+#define k1	r1
+#define k2	r2
+#define k3	r3
+#define k4	r4
+
+#define k_ex_code	r2_bank	/* r2_bank1 */
+#define g_imask		r6	/* r6_bank1 */
+#define k_g_imask	r6_bank	/* r6_bank1 */
+#define current		r7	/* r7_bank1 */
+
+/*
+ * Kernel mode register usage:
+ *	k0	scratch
+ *	k1	scratch
+ *	k2	scratch (Exception code)
+ *	k3	scratch (Return address)
+ *	k4	scratch
+ *	k5	reserved
+ *	k6	Global Interrupt Mask (0--15 << 4)
+ *	k7	CURRENT_THREAD_INFO (pointer to current thread info)
+ */
+
+!
+! TLB Miss / Initial Page write exception handling
+!			_and_
+! TLB hits, but the access violate the protection.
+! It can be valid access, such as stack grow and/or C-O-W.
+!
+!
+! Find the pmd/pte entry and loadtlb
+! If it's not found, cause address error (SEGV)
+!
+! Although this could be written in assembly language (and it'd be faster),
+! this first version depends *much* on C implementation.
+!
+
+#define CLI()				\
+	stc	sr, r0;			\
+	or	#0xf0, r0;		\
+	ldc	r0, sr
+
+#define STI()				\
+	mov.l	__INV_IMASK, r11;	\
+	stc	sr, r10;		\
+	and	r11, r10;		\
+	stc	k_g_imask, r11;		\
+	or	r11, r10;		\
+	ldc	r10, sr
+
+#if defined(CONFIG_PREEMPT)
+#  define preempt_stop()	CLI()
+#else
+#  define preempt_stop()
+#  define resume_kernel		restore_all
+#endif
+
+#if defined(CONFIG_MMU)
+	.align	2
+ENTRY(tlb_miss_load)
+	bra	call_dpf
+	 mov	#0, r5
+
+	.align	2
+ENTRY(tlb_miss_store)
+	bra	call_dpf
+	 mov	#1, r5
+
+	.align	2
+ENTRY(initial_page_write)
+	bra	call_dpf
+	 mov	#1, r5
+
+	.align	2
+ENTRY(tlb_protection_violation_load)
+	bra	call_dpf
+	 mov	#0, r5
+
+	.align	2
+ENTRY(tlb_protection_violation_store)
+	bra	call_dpf
+	 mov	#1, r5
+
+call_dpf:
+	mov.l	1f, r0
+	mov	r5, r8
+	mov.l	@r0, r6
+	mov	r6, r9
+	mov.l	2f, r0
+	sts	pr, r10
+	jsr	@r0
+	 mov	r15, r4
+	!
+	tst	r0, r0
+	bf/s	0f
+	 lds	r10, pr
+	rts
+	 nop
+0:	STI()
+	mov.l	3f, r0
+	mov	r9, r6
+	mov	r8, r5
+	jmp	@r0
+	 mov	r15, r4
+
+	.align 2
+1:	.long	MMU_TEA
+2:	.long	__do_page_fault
+3:	.long	do_page_fault
+
+	.align	2
+ENTRY(address_error_load)
+	bra	call_dae
+	 mov	#0,r5		! writeaccess = 0
+
+	.align	2
+ENTRY(address_error_store)
+	bra	call_dae
+	 mov	#1,r5		! writeaccess = 1
+
+	.align	2
+call_dae:
+	mov.l	1f, r0
+	mov.l	@r0, r6		! address
+	mov.l	2f, r0
+	jmp	@r0
+	 mov	r15, r4		! regs
+
+	.align 2
+1:	.long	MMU_TEA
+2:	.long   do_address_error
+#endif /* CONFIG_MMU */
+
+#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB)
+! Handle kernel debug if either kgdb (SW) or gdb-stub (FW) is present.
+! If both are configured, handle the debug traps (breakpoints) in SW,
+! but still allow BIOS traps to FW.
+
+	.align	2
+debug_kernel:
+#if defined(CONFIG_SH_STANDARD_BIOS) && defined(CONFIG_SH_KGDB)
+	/* Force BIOS call to FW (debug_trap put TRA in r8) */
+	mov	r8,r0
+	shlr2	r0
+	cmp/eq	#0x3f,r0
+	bt	debug_kernel_fw
+#endif /* CONFIG_SH_STANDARD_BIOS && CONFIG_SH_KGDB */
+
+debug_enter:		
+#if defined(CONFIG_SH_KGDB)
+	/* Jump to kgdb, pass stacked regs as arg */
+debug_kernel_sw:
+	mov.l	3f, r0
+	jmp	@r0
+	 mov	r15, r4
+	.align	2
+3:	.long	kgdb_handle_exception
+#endif /* CONFIG_SH_KGDB */
+
+#if defined(CONFIG_SH_STANDARD_BIOS)
+	/* Unwind the stack and jmp to the debug entry */
+debug_kernel_fw:
+	mov.l	@r15+, r0
+	mov.l	@r15+, r1
+	mov.l	@r15+, r2
+	mov.l	@r15+, r3
+	mov.l	@r15+, r4
+	mov.l	@r15+, r5
+	mov.l	@r15+, r6
+	mov.l	@r15+, r7
+	stc	sr, r8
+	mov.l	1f, r9			! BL =1, RB=1, IMASK=0x0F
+	or	r9, r8
+	ldc	r8, sr			! here, change the register bank
+	mov.l	@r15+, r8
+	mov.l	@r15+, r9
+	mov.l	@r15+, r10
+	mov.l	@r15+, r11
+	mov.l	@r15+, r12
+	mov.l	@r15+, r13
+	mov.l	@r15+, r14
+	mov.l	@r15+, k0
+	ldc.l	@r15+, spc
+	lds.l	@r15+, pr
+	mov.l	@r15+, k1
+	ldc.l	@r15+, gbr
+	lds.l	@r15+, mach
+	lds.l	@r15+, macl
+	mov	k0, r15
+	!
+	mov.l	2f, k0
+	mov.l	@k0, k0
+	jmp	@k0
+	 ldc	k1, ssr
+	.align	2
+1:	.long	0x300000f0
+2:	.long	gdb_vbr_vector
+#endif /* CONFIG_SH_STANDARD_BIOS */
+
+#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */
+
+
+	.align	2
+debug_trap:	
+#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB)
+	mov	#OFF_SR, r0
+	mov.l	@(r0,r15), r0		! get status register
+	shll	r0
+	shll	r0			! kernel space?
+	bt/s	debug_kernel
+#endif
+	 mov.l	@r15, r0		! Restore R0 value
+	mov.l	1f, r8
+	jmp	@r8
+	 nop
+
+	.align	2
+ENTRY(exception_error)
+	!
+	STI()
+	mov.l	2f, r0
+	jmp	@r0
+	 nop
+
+!
+	.align	2
+1:	.long	break_point_trap_software
+2:	.long	do_exception_error
+
+	.align	2
+ret_from_exception:
+	preempt_stop()
+ret_from_irq:
+	!
+	mov	#OFF_SR, r0
+	mov.l	@(r0,r15), r0	! get status register
+	shll	r0
+	shll	r0		! kernel space?
+	bt/s	resume_kernel	! Yes, it's from kernel, go back soon
+	 GET_THREAD_INFO(r8)
+
+#ifdef CONFIG_PREEMPT
+	bra	resume_userspace
+	 nop
+ENTRY(resume_kernel)
+	mov.l	@(TI_PRE_COUNT,r8), r0	! current_thread_info->preempt_count
+	tst	r0, r0
+	bf	noresched
+need_resched:
+	mov.l	@(TI_FLAGS,r8), r0	! current_thread_info->flags
+	tst	#_TIF_NEED_RESCHED, r0	! need_resched set?
+	bt	noresched
+
+	mov	#OFF_SR, r0
+	mov.l	@(r0,r15), r0		! get status register
+	and	#0xf0, r0		! interrupts off (exception path)?
+	cmp/eq	#0xf0, r0
+	bt	noresched
+
+	mov.l	1f, r0
+	mov.l	r0, @(TI_PRE_COUNT,r8)
+
+	STI()
+	mov.l	2f, r0
+	jsr	@r0
+	 nop
+	mov	#0, r0
+	mov.l	r0, @(TI_PRE_COUNT,r8)
+	CLI()
+
+	bra	need_resched
+	 nop
+noresched:
+	bra	restore_all
+	 nop
+
+	.align 2
+1:	.long	PREEMPT_ACTIVE
+2:	.long	schedule
+#endif
+
+ENTRY(resume_userspace)
+	! r8: current_thread_info
+	CLI()
+	mov.l	@(TI_FLAGS,r8), r0		! current_thread_info->flags
+	tst	#_TIF_WORK_MASK, r0
+	bt/s	restore_all
+	 tst	#_TIF_NEED_RESCHED, r0
+
+	.align	2
+work_pending:
+	! r0: current_thread_info->flags
+	! r8: current_thread_info
+	! t:  result of "tst	#_TIF_NEED_RESCHED, r0"
+	bf/s	work_resched
+	 tst	#_TIF_SIGPENDING, r0
+work_notifysig:
+	bt/s	restore_all
+	 mov	r15, r4
+	mov	#0, r5
+	mov.l	2f, r1
+	mova	restore_all, r0
+	jmp	@r1
+	 lds	r0, pr
+work_resched:
+#ifndef CONFIG_PREEMPT
+	! gUSA handling
+	mov.l	@(OFF_SP,r15), r0	! get user space stack pointer
+	mov	r0, r1
+	shll	r0
+	bf/s	1f
+	 shll	r0
+	bf/s	1f
+	 mov	#OFF_PC, r0
+	! 				  SP >= 0xc0000000 : gUSA mark
+	mov.l	@(r0,r15), r2		! get user space PC (program counter)
+	mov.l	@(OFF_R0,r15), r3	! end point
+	cmp/hs	r3, r2			! r2 >= r3? 
+	bt	1f
+	add	r3, r1			! rewind point #2
+	mov.l	r1, @(r0,r15)		! reset PC to rewind point #2
+	!
+1:
+#endif
+	mov.l	1f, r1
+	jsr	@r1				! schedule
+	 nop
+	CLI()
+	!
+	mov.l	@(TI_FLAGS,r8), r0		! current_thread_info->flags
+	tst	#_TIF_WORK_MASK, r0
+	bt	restore_all
+	bra	work_pending
+	 tst	#_TIF_NEED_RESCHED, r0
+
+	.align	2
+1:	.long	schedule
+2:	.long	do_signal
+
+	.align	2
+syscall_exit_work:
+	! r0: current_thread_info->flags
+	! r8: current_thread_info
+	tst	#_TIF_SYSCALL_TRACE, r0
+	bt/s	work_pending
+	 tst	#_TIF_NEED_RESCHED, r0
+	STI()
+	! XXX setup arguments...
+	mov.l	4f, r0			! do_syscall_trace
+	jsr	@r0
+	 nop
+	bra	resume_userspace
+	 nop
+
+	.align	2
+syscall_trace_entry:
+	!                     	Yes it is traced.
+	! XXX setup arguments...
+	mov.l	4f, r11		! Call do_syscall_trace which notifies
+	jsr	@r11	    	! superior (will chomp R[0-7])
+	 nop
+	!			Reload R0-R4 from kernel stack, where the
+	!   	    	    	parent may have modified them using
+	!   	    	    	ptrace(POKEUSR).  (Note that R0-R2 are
+	!   	    	    	used by the system call handler directly
+	!   	    	    	from the kernel stack anyway, so don't need
+	!   	    	    	to be reloaded here.)  This allows the parent
+	!   	    	    	to rewrite system calls and args on the fly.
+	mov.l	@(OFF_R4,r15), r4   ! arg0
+	mov.l	@(OFF_R5,r15), r5
+	mov.l	@(OFF_R6,r15), r6
+	mov.l	@(OFF_R7,r15), r7   ! arg3
+	mov.l	@(OFF_R3,r15), r3   ! syscall_nr
+	!   	    	    Arrange for do_syscall_trace to be called
+	!   	    	    again as the system call returns.
+	mov.l	2f, r10			! Number of syscalls
+	cmp/hs	r10, r3
+	bf	syscall_call
+	mov	#-ENOSYS, r0
+	bra	syscall_exit
+	 mov.l	r0, @(OFF_R0,r15)	! Return value
+
+/*
+ * Syscall interface:
+ *
+ *	Syscall #: R3
+ *	Arguments #0 to #3: R4--R7
+ *	Arguments #4 to #6: R0, R1, R2
+ *	TRA: (number of arguments + 0x10) x 4
+ *
+ * This code also handles delegating other traps to the BIOS/gdb stub
+ * according to:
+ *
+ * Trap number
+ * (TRA>>2) 	    Purpose
+ * -------- 	    -------
+ * 0x0-0xf  	    old syscall ABI
+ * 0x10-0x1f  	    new syscall ABI
+ * 0x20-0xff  	    delegated through debug_trap to BIOS/gdb stub.
+ *
+ * Note: When we're first called, the TRA value must be shifted
+ * right 2 bits in order to get the value that was used as the "trapa"
+ * argument.
+ */
+
+	.align	2
+	.globl	ret_from_fork
+ret_from_fork:
+	mov.l	1f, r8
+	jsr	@r8
+	 mov	r0, r4
+	bra	syscall_exit
+	 nop
+	.align	2
+1:	.long	schedule_tail
+	!
+ENTRY(system_call)
+	mov.l	1f, r9
+	mov.l	@r9, r8		! Read from TRA (Trap Address) Register
+	!
+	! Is the trap argument >= 0x20? (TRA will be >= 0x80)
+	mov	#0x7f, r9
+	cmp/hi	r9, r8
+	bt/s	0f
+	 mov	#OFF_TRA, r9
+	add	r15, r9
+	!
+	mov.l	r8, @r9			! set TRA value to tra
+	STI()
+	!   	    	    Call the system call handler through the table.
+	!   	    	    First check for bad syscall number
+	mov	r3, r9
+	mov.l	2f, r8			! Number of syscalls
+	cmp/hs	r8, r9
+	bf/s	good_system_call
+	 GET_THREAD_INFO(r8)
+syscall_badsys:			! Bad syscall number
+	mov	#-ENOSYS, r0
+	bra	resume_userspace
+	 mov.l	r0, @(OFF_R0,r15)	! Return value
+	!
+0:
+	bra	debug_trap
+	 nop
+	!
+good_system_call:		! Good syscall number
+	mov.l	@(TI_FLAGS,r8), r8
+	mov	#_TIF_SYSCALL_TRACE, r10
+	tst	r10, r8
+	bf	syscall_trace_entry
+	!
+syscall_call:
+	shll2	r9		! x4
+	mov.l	3f, r8		! Load the address of sys_call_table
+	add	r8, r9
+	mov.l	@r9, r8
+	jsr	@r8	    	! jump to specific syscall handler
+	 nop
+	mov.l	r0, @(OFF_R0,r15)		! save the return value
+	!
+syscall_exit:
+	CLI()
+	!
+	GET_THREAD_INFO(r8)
+	mov.l	@(TI_FLAGS,r8), r0		! current_thread_info->flags
+	tst	#_TIF_ALLWORK_MASK, r0
+	bf	syscall_exit_work
+restore_all:
+	mov.l	@r15+, r0
+	mov.l	@r15+, r1
+	mov.l	@r15+, r2
+	mov.l	@r15+, r3
+	mov.l	@r15+, r4
+	mov.l	@r15+, r5
+	mov.l	@r15+, r6
+	mov.l	@r15+, r7
+	!
+	stc	sr, r8
+	mov.l	7f, r9
+	or	r9, r8			! BL =1, RB=1
+	ldc	r8, sr			! here, change the register bank
+	!
+	mov.l	@r15+, r8
+	mov.l	@r15+, r9
+	mov.l	@r15+, r10
+	mov.l	@r15+, r11
+	mov.l	@r15+, r12
+	mov.l	@r15+, r13
+	mov.l	@r15+, r14
+	mov.l	@r15+, k4		! original stack pointer
+	ldc.l	@r15+, spc
+	lds.l	@r15+, pr
+	mov.l	@r15+, k3		! original SR
+	ldc.l	@r15+, gbr
+	lds.l	@r15+, mach
+	lds.l	@r15+, macl
+	add	#4, r15			! Skip syscall number
+	!
+#ifdef CONFIG_SH_DSP
+	mov.l	@r15+, k0		! DSP mode marker
+	mov.l	5f, k1
+	cmp/eq	k0, k1			! Do we have a DSP stack frame?
+	bf	skip_restore
+
+	stc	sr, k0			! Enable CPU DSP mode
+	or	k1, k0			! (within kernel it may be disabled)
+	ldc	k0, sr
+	mov	r2, k0			! Backup r2
+
+	! Restore DSP registers from stack
+	mov	r15, r2
+	movs.l	@r2+, a1
+	movs.l	@r2+, a0g
+	movs.l	@r2+, a1g
+	movs.l	@r2+, m0
+	movs.l	@r2+, m1
+	mov	r2, r15
+
+	lds.l	@r15+, a0
+	lds.l	@r15+, x0
+	lds.l	@r15+, x1
+	lds.l	@r15+, y0
+	lds.l	@r15+, y1
+	lds.l	@r15+, dsr
+	ldc.l	@r15+, rs
+	ldc.l	@r15+, re
+	ldc.l	@r15+, mod
+
+	mov	k0, r2			! Restore r2
+skip_restore:
+#endif
+	!
+	! Calculate new SR value
+	mov	k3, k2			! original SR value
+	mov.l	9f, k1
+	and	k1, k2			! Mask orignal SR value
+	!
+	mov	k3, k0			! Calculate IMASK-bits
+	shlr2	k0
+	and	#0x3c, k0
+	cmp/eq	#0x3c, k0
+	bt/s	6f
+	 shll2	k0
+	mov	g_imask, k0
+	!
+6:	or	k0, k2			! Set the IMASK-bits
+	ldc	k2, ssr
+	!
+#if defined(CONFIG_KGDB_NMI)
+	! Clear in_nmi
+	mov.l	4f, k0
+	mov	#0, k1
+	mov.b	k1, @k0
+#endif
+	mov.l	@r15+, k2		! restore EXPEVT
+	mov	k4, r15
+	rte
+	 nop
+
+	.align	2
+1:	.long	TRA
+2:	.long	NR_syscalls
+3:	.long	sys_call_table
+4:	.long	do_syscall_trace
+5:	.long	0x00001000	! DSP
+7:	.long	0x30000000
+9:
+__INV_IMASK:
+	.long	0xffffff0f	! ~(IMASK)
+
+! Exception Vector Base
+!
+!	Should be aligned page boundary.
+!
+	.balign 	4096,0,4096
+ENTRY(vbr_base)
+	.long	0
+!
+	.balign 	256,0,256
+general_exception:
+	mov.l	1f, k2
+	mov.l	2f, k3
+	bra	handle_exception
+	 mov.l	@k2, k2
+	.align	2
+1:	.long	EXPEVT
+2:	.long	ret_from_exception
+!
+!
+	.balign 	1024,0,1024
+tlb_miss:
+	mov.l	1f, k2
+	mov.l	4f, k3
+	bra	handle_exception
+	 mov.l	@k2, k2
+!
+	.balign 	512,0,512
+interrupt:
+	mov.l	2f, k2
+	mov.l	3f, k3
+#if defined(CONFIG_KGDB_NMI)
+	! Debounce (filter nested NMI)
+	mov.l	@k2, k0
+	mov.l	5f, k1
+	cmp/eq	k1, k0
+	bf	0f
+	mov.l	6f, k1
+	tas.b	@k1
+	bt	0f
+	rte
+	 nop
+	.align	2
+5:	.long	NMI_VEC
+6:	.long	in_nmi
+0:
+#endif /* defined(CONFIG_KGDB_NMI) */
+	bra	handle_exception
+	 mov.l	@k2, k2
+
+	.align	2
+1:	.long	EXPEVT
+2:	.long	INTEVT
+3:	.long	ret_from_irq
+4:	.long	ret_from_exception
+
+!
+!
+	.align	2
+handle_exception:
+	! Using k0, k1 for scratch registers (r0_bank1, r1_bank),
+	! save all registers onto stack.
+	!
+	stc	ssr, k0		! Is it from kernel space?
+	shll	k0		! Check MD bit (bit30) by shifting it into...
+	shll	k0		!       ...the T bit
+	bt/s	1f		! It's a kernel to kernel transition.
+	 mov	r15, k0		! save original stack to k0
+	/* User space to kernel */
+	mov	#0x20, k1
+	shll8	k1		! k1 := 8192 (== THREAD_SIZE)
+	add	current, k1
+	mov	k1, r15		! change to kernel stack
+	!
+1:  	mov	#-1, k4
+	mov.l	2f, k1
+	!
+#ifdef CONFIG_SH_DSP
+	mov.l	r2, @-r15		! Save r2, we need another reg
+	stc	sr, k4
+	mov.l	1f, r2
+	tst	r2, k4			! Check if in DSP mode
+	mov.l	@r15+, r2		! Restore r2 now
+	bt/s	skip_save
+	 mov	#0, k4			! Set marker for no stack frame
+
+	mov	r2, k4			! Backup r2 (in k4) for later
+
+	! Save DSP registers on stack
+	stc.l	mod, @-r15
+	stc.l	re, @-r15
+	stc.l	rs, @-r15
+	sts.l	dsr, @-r15
+	sts.l	y1, @-r15
+	sts.l	y0, @-r15
+	sts.l	x1, @-r15
+	sts.l	x0, @-r15
+	sts.l	a0, @-r15
+
+	! GAS is broken, does not generate correct "movs.l Ds,@-As" instr.
+
+	! FIXME: Make sure that this is still the case with newer toolchains,
+	! as we're not at all interested in supporting ancient toolchains at
+	! this point. -- PFM.
+
+	mov	r15, r2
+	.word	0xf653			! movs.l	a1, @-r2
+	.word	0xf6f3			! movs.l	a0g, @-r2
+	.word	0xf6d3			! movs.l	a1g, @-r2
+	.word	0xf6c3			! movs.l	m0, @-r2
+	.word	0xf6e3			! movs.l	m1, @-r2
+	mov	r2, r15
+
+	mov	k4, r2			! Restore r2
+	mov.l	1f, k4			! Force DSP stack frame
+skip_save:
+	mov.l	k4, @-r15		! Push DSP mode marker onto stack
+#endif
+	! Save the user registers on the stack.
+	mov.l	k2, @-r15	! EXPEVT
+	mov.l	k4, @-r15	! set TRA (default: -1)
+	!
+	sts.l	macl, @-r15
+	sts.l	mach, @-r15
+	stc.l	gbr, @-r15
+	stc.l	ssr, @-r15
+	sts.l	pr, @-r15
+	stc.l	spc, @-r15
+	!
+	lds	k3, pr		! Set the return address to pr
+	!
+	mov.l	k0, @-r15	! save orignal stack
+	mov.l	r14, @-r15
+	mov.l	r13, @-r15
+	mov.l	r12, @-r15
+	mov.l	r11, @-r15
+	mov.l	r10, @-r15
+	mov.l	r9, @-r15
+	mov.l	r8, @-r15
+	!
+	stc	sr, r8		! Back to normal register bank, and
+	or	k1, r8		! Block all interrupts
+	mov.l	3f, k1
+	and	k1, r8		! ...
+	ldc	r8, sr		! ...changed here.
+	!
+	mov.l	r7, @-r15
+	mov.l	r6, @-r15
+	mov.l	r5, @-r15
+	mov.l	r4, @-r15
+	mov.l	r3, @-r15
+	mov.l	r2, @-r15
+	mov.l	r1, @-r15
+	mov.l	r0, @-r15
+	! Then, dispatch to the handler, according to the exception code.
+	stc	k_ex_code, r8
+	shlr2	r8
+	shlr	r8
+	mov.l	4f, r9
+	add	r8, r9
+	mov.l	@r9, r9
+	jmp	@r9
+	 nop
+
+	.align	2
+1:	.long	0x00001000	! DSP=1
+2:	.long	0x000080f0	! FD=1, IMASK=15
+3:	.long	0xcfffffff	! RB=0, BL=0
+4:	.long	exception_handling_table
+
+	.align	2
+ENTRY(exception_none)
+	rts
+	 nop
+
+	.data
+ENTRY(sys_call_table)
+	.long sys_ni_syscall	/* 0  -  old "setup()" system call*/
+	.long sys_exit
+	.long sys_fork
+	.long sys_read
+	.long sys_write
+	.long sys_open		/* 5 */
+	.long sys_close
+	.long sys_waitpid
+	.long sys_creat
+	.long sys_link
+	.long sys_unlink		/* 10 */
+	.long sys_execve
+	.long sys_chdir
+	.long sys_time
+	.long sys_mknod
+	.long sys_chmod		/* 15 */
+	.long sys_lchown16
+	.long sys_ni_syscall	/* old break syscall holder */
+	.long sys_stat
+	.long sys_lseek
+	.long sys_getpid		/* 20 */
+	.long sys_mount
+	.long sys_oldumount
+	.long sys_setuid16
+	.long sys_getuid16
+	.long sys_stime		/* 25 */
+	.long sys_ptrace
+	.long sys_alarm
+	.long sys_fstat
+	.long sys_pause
+	.long sys_utime		/* 30 */
+	.long sys_ni_syscall	/* old stty syscall holder */
+	.long sys_ni_syscall	/* old gtty syscall holder */
+	.long sys_access
+	.long sys_nice
+	.long sys_ni_syscall	/* 35 */		/* old ftime syscall holder */
+	.long sys_sync
+	.long sys_kill
+	.long sys_rename
+	.long sys_mkdir
+	.long sys_rmdir		/* 40 */
+	.long sys_dup
+	.long sys_pipe
+	.long sys_times
+	.long sys_ni_syscall	/* old prof syscall holder */
+	.long sys_brk		/* 45 */
+	.long sys_setgid16
+	.long sys_getgid16
+	.long sys_signal
+	.long sys_geteuid16
+	.long sys_getegid16	/* 50 */
+	.long sys_acct
+	.long sys_umount		/* recycled never used phys() */
+	.long sys_ni_syscall	/* old lock syscall holder */
+	.long sys_ioctl
+	.long sys_fcntl		/* 55 */
+	.long sys_ni_syscall	/* old mpx syscall holder */
+	.long sys_setpgid
+	.long sys_ni_syscall	/* old ulimit syscall holder */
+	.long sys_ni_syscall	/* sys_olduname */
+	.long sys_umask		/* 60 */
+	.long sys_chroot
+	.long sys_ustat
+	.long sys_dup2
+	.long sys_getppid
+	.long sys_getpgrp		/* 65 */
+	.long sys_setsid
+	.long sys_sigaction
+	.long sys_sgetmask
+	.long sys_ssetmask
+	.long sys_setreuid16	/* 70 */
+	.long sys_setregid16
+	.long sys_sigsuspend
+	.long sys_sigpending
+	.long sys_sethostname
+	.long sys_setrlimit	/* 75 */
+	.long sys_old_getrlimit
+	.long sys_getrusage
+	.long sys_gettimeofday
+	.long sys_settimeofday
+	.long sys_getgroups16	/* 80 */
+	.long sys_setgroups16
+	.long sys_ni_syscall	/* sys_oldselect */
+	.long sys_symlink
+	.long sys_lstat
+	.long sys_readlink		/* 85 */
+	.long sys_uselib
+	.long sys_swapon
+	.long sys_reboot
+	.long old_readdir
+	.long old_mmap		/* 90 */
+	.long sys_munmap
+	.long sys_truncate
+	.long sys_ftruncate
+	.long sys_fchmod
+	.long sys_fchown16		/* 95 */
+	.long sys_getpriority
+	.long sys_setpriority
+	.long sys_ni_syscall	/* old profil syscall holder */
+	.long sys_statfs
+	.long sys_fstatfs		/* 100 */
+	.long sys_ni_syscall	/* ioperm */
+	.long sys_socketcall
+	.long sys_syslog
+	.long sys_setitimer
+	.long sys_getitimer	/* 105 */
+	.long sys_newstat
+	.long sys_newlstat
+	.long sys_newfstat
+	.long sys_uname
+	.long sys_ni_syscall	/* 110 */ /* iopl */
+	.long sys_vhangup
+	.long sys_ni_syscall	/* idle */
+	.long sys_ni_syscall	/* vm86old */
+	.long sys_wait4
+	.long sys_swapoff		/* 115 */
+	.long sys_sysinfo
+	.long sys_ipc
+	.long sys_fsync
+	.long sys_sigreturn
+	.long sys_clone		/* 120 */
+	.long sys_setdomainname
+	.long sys_newuname
+	.long sys_ni_syscall	/* sys_modify_ldt */
+	.long sys_adjtimex
+	.long sys_mprotect		/* 125 */
+	.long sys_sigprocmask
+	.long sys_ni_syscall	/* old "create_module" */
+	.long sys_init_module
+	.long sys_delete_module
+	.long sys_ni_syscall	/* 130: old "get_kernel_syms" */
+	.long sys_quotactl
+	.long sys_getpgid
+	.long sys_fchdir
+	.long sys_bdflush
+	.long sys_sysfs		/* 135 */
+	.long sys_personality
+	.long sys_ni_syscall	/* for afs_syscall */
+	.long sys_setfsuid16
+	.long sys_setfsgid16
+	.long sys_llseek		/* 140 */
+	.long sys_getdents
+	.long sys_select
+	.long sys_flock
+	.long sys_msync
+	.long sys_readv		/* 145 */
+	.long sys_writev
+	.long sys_getsid
+	.long sys_fdatasync
+	.long sys_sysctl
+	.long sys_mlock		/* 150 */
+	.long sys_munlock
+	.long sys_mlockall
+	.long sys_munlockall
+	.long sys_sched_setparam
+	.long sys_sched_getparam   /* 155 */
+	.long sys_sched_setscheduler
+	.long sys_sched_getscheduler
+	.long sys_sched_yield
+	.long sys_sched_get_priority_max
+	.long sys_sched_get_priority_min  /* 160 */
+	.long sys_sched_rr_get_interval
+	.long sys_nanosleep
+	.long sys_mremap
+	.long sys_setresuid16
+	.long sys_getresuid16	/* 165 */
+	.long sys_ni_syscall	/* vm86 */
+	.long sys_ni_syscall	/* old "query_module" */
+	.long sys_poll
+	.long sys_nfsservctl
+	.long sys_setresgid16	/* 170 */
+	.long sys_getresgid16
+	.long sys_prctl
+	.long sys_rt_sigreturn
+	.long sys_rt_sigaction
+	.long sys_rt_sigprocmask	/* 175 */
+	.long sys_rt_sigpending
+	.long sys_rt_sigtimedwait
+	.long sys_rt_sigqueueinfo
+	.long sys_rt_sigsuspend
+	.long sys_pread_wrapper	   /* 180 */
+	.long sys_pwrite_wrapper
+	.long sys_chown16
+	.long sys_getcwd
+	.long sys_capget
+	.long sys_capset           /* 185 */
+	.long sys_sigaltstack
+	.long sys_sendfile
+	.long sys_ni_syscall	/* streams1 */
+	.long sys_ni_syscall	/* streams2 */
+	.long sys_vfork            /* 190 */
+	.long sys_getrlimit
+	.long sys_mmap2
+	.long sys_truncate64
+	.long sys_ftruncate64
+	.long sys_stat64		/* 195 */
+	.long sys_lstat64
+	.long sys_fstat64
+	.long sys_lchown
+	.long sys_getuid
+	.long sys_getgid		/* 200 */
+	.long sys_geteuid
+	.long sys_getegid
+	.long sys_setreuid
+	.long sys_setregid
+	.long sys_getgroups	/* 205 */
+	.long sys_setgroups
+	.long sys_fchown
+	.long sys_setresuid
+	.long sys_getresuid
+	.long sys_setresgid	/* 210 */
+	.long sys_getresgid
+	.long sys_chown
+	.long sys_setuid
+	.long sys_setgid
+	.long sys_setfsuid		/* 215 */
+	.long sys_setfsgid
+	.long sys_pivot_root
+	.long sys_mincore
+	.long sys_madvise
+	.long sys_getdents64	/* 220 */
+	.long sys_fcntl64
+	.long sys_ni_syscall	/* reserved for TUX */
+	.long sys_ni_syscall	/* Reserved for Security */
+	.long sys_gettid
+	.long sys_readahead	/* 225 */
+	.long sys_setxattr
+	.long sys_lsetxattr
+	.long sys_fsetxattr
+	.long sys_getxattr
+	.long sys_lgetxattr	/* 230 */
+	.long sys_fgetxattr
+	.long sys_listxattr
+	.long sys_llistxattr
+	.long sys_flistxattr
+	.long sys_removexattr	/* 235 */
+	.long sys_lremovexattr
+	.long sys_fremovexattr
+	.long sys_tkill
+	.long sys_sendfile64
+	.long sys_futex		/* 240 */
+	.long sys_sched_setaffinity
+	.long sys_sched_getaffinity
+	.long sys_ni_syscall
+	.long sys_ni_syscall
+	.long sys_io_setup	/* 245 */
+	.long sys_io_destroy
+	.long sys_io_getevents
+	.long sys_io_submit
+	.long sys_io_cancel
+	.long sys_fadvise64	/* 250 */
+	.long sys_ni_syscall
+	.long sys_exit_group
+	.long sys_lookup_dcookie
+	.long sys_epoll_create
+	.long sys_epoll_ctl	/* 255 */
+	.long sys_epoll_wait
+ 	.long sys_remap_file_pages
+ 	.long sys_set_tid_address
+ 	.long sys_timer_create
+ 	.long sys_timer_settime		/* 260 */
+ 	.long sys_timer_gettime
+ 	.long sys_timer_getoverrun
+ 	.long sys_timer_delete
+ 	.long sys_clock_settime
+ 	.long sys_clock_gettime		/* 265 */
+ 	.long sys_clock_getres
+ 	.long sys_clock_nanosleep
+	.long sys_statfs64
+	.long sys_fstatfs64     
+	.long sys_tgkill		/* 270 */
+	.long sys_utimes
+ 	.long sys_fadvise64_64_wrapper
+	.long sys_ni_syscall	/* Reserved for vserver */
+	.long sys_ni_syscall	/* Reserved for mbind */
+	.long sys_ni_syscall	/* 275 - get_mempolicy */
+	.long sys_ni_syscall	/* set_mempolicy */
+	.long sys_mq_open
+	.long sys_mq_unlink
+	.long sys_mq_timedsend
+	.long sys_mq_timedreceive       /* 280 */
+	.long sys_mq_notify
+	.long sys_mq_getsetattr
+	.long sys_ni_syscall	/* Reserved for kexec */
+	.long sys_waitid
+	.long sys_add_key		/* 285 */
+	.long sys_request_key
+	.long sys_keyctl
+
+/* End of entry.S */
diff --git a/arch/sh/kernel/head.S b/arch/sh/kernel/head.S
new file mode 100644
index 0000000..9b9e6ef
--- /dev/null
+++ b/arch/sh/kernel/head.S
@@ -0,0 +1,76 @@
+/* $Id: head.S,v 1.7 2003/09/01 17:58:19 lethal Exp $
+ *
+ *  arch/sh/kernel/head.S
+ *
+ *  Copyright (C) 1999, 2000  Niibe Yutaka & Kaz Kojima
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Head.S contains the SH exception handlers and startup code.
+ */
+#include <linux/linkage.h>
+
+	.section	.empty_zero_page, "aw"
+ENTRY(empty_zero_page)
+	.long	1		/* MOUNT_ROOT_RDONLY */
+	.long	0		/* RAMDISK_FLAGS */
+	.long	0x0200		/* ORIG_ROOT_DEV */
+	.long	1		/* LOADER_TYPE */
+	.long	0x00360000	/* INITRD_START */
+	.long	0x000a0000	/* INITRD_SIZE */
+	.long	0
+	.balign 4096,0,4096
+
+	.text	
+/*
+ * Condition at the entry of _stext:
+ *
+ *   BSC has already been initialized.
+ *   INTC may or may not be initialized.
+ *   VBR may or may not be initialized.
+ *   MMU may or may not be initialized.
+ *   Cache may or may not be initialized.
+ *   Hardware (including on-chip modules) may or may not be initialized. 
+ *
+ */
+ENTRY(_stext)
+	!			Initialize Status Register
+	mov.l	1f, r0		! MD=1, RB=0, BL=0, IMASK=0xF
+	ldc	r0, sr
+	!			Initialize global interrupt mask
+	mov	#0, r0
+	ldc	r0, r6_bank
+	!
+	mov.l	2f, r0
+	mov	r0, r15		! Set initial r15 (stack pointer)
+	mov	#0x20, r1	!
+	shll8	r1		! r1 = 8192
+	sub	r1, r0		!
+	ldc	r0, r7_bank	! ... and initial thread_info
+	!
+	!			Additional CPU initialization
+	mov.l	6f, r0
+	jsr	@r0
+	 nop
+	!			Clear BSS area
+	mov.l	3f, r1
+	add	#4, r1
+	mov.l	4f, r2
+	mov	#0, r0
+9:	cmp/hs	r2, r1
+	bf/s	9b		! while (r1 < r2)
+	 mov.l	r0,@-r2
+	!			Start kernel
+	mov.l	5f, r0
+	jmp	@r0
+	 nop
+
+	.balign 4
+1:	.long	0x400080F0		! MD=1, RB=0, BL=0, FD=1, IMASK=0xF
+2:	.long	stack
+3:	.long	__bss_start
+4:	.long	_end
+5:	.long	start_kernel
+6:	.long	sh_cpu_init
diff --git a/arch/sh/kernel/init_task.c b/arch/sh/kernel/init_task.c
new file mode 100644
index 0000000..44053ea
--- /dev/null
+++ b/arch/sh/kernel/init_task.c
@@ -0,0 +1,36 @@
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/sched.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 having a special
+ * "init_task" linker map entry..
+ */
+union thread_union init_thread_union 
+	__attribute__((__section__(".data.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/sh/kernel/io.c b/arch/sh/kernel/io.c
new file mode 100644
index 0000000..d9932f2
--- /dev/null
+++ b/arch/sh/kernel/io.c
@@ -0,0 +1,59 @@
+/*
+ * linux/arch/sh/kernel/io.c
+ *
+ * Copyright (C) 2000  Stuart Menefy
+ *
+ * Provide real functions which expand to whatever the header file defined.
+ * Also definitions of machine independent IO functions.
+ */
+
+#include <asm/io.h>
+#include <linux/module.h>
+
+/*
+ * Copy data from IO memory space to "real" memory space.
+ * This needs to be optimized.
+ */
+void  memcpy_fromio(void * to, unsigned long from, unsigned long count)
+{
+	char *p = to;
+        while (count) {
+                count--;
+                *p = readb(from);
+                p++;
+                from++;
+        }
+}
+ 
+/*
+ * Copy data from "real" memory space to IO memory space.
+ * This needs to be optimized.
+ */
+void  memcpy_toio(unsigned long to, const void * from, unsigned long count)
+{
+	const char *p = from;
+        while (count) {
+                count--;
+                writeb(*p, to);
+                p++;
+                to++;
+        }
+}
+ 
+/*
+ * "memset" on IO memory space.
+ * This needs to be optimized.
+ */
+void  memset_io(unsigned long dst, int c, unsigned long count)
+{
+        while (count) {
+                count--;
+                writeb(c, dst);
+                dst++;
+        }
+}
+
+EXPORT_SYMBOL(memcpy_fromio);
+EXPORT_SYMBOL(memcpy_toio);
+EXPORT_SYMBOL(memset_io);
+
diff --git a/arch/sh/kernel/io_generic.c b/arch/sh/kernel/io_generic.c
new file mode 100644
index 0000000..a911b01
--- /dev/null
+++ b/arch/sh/kernel/io_generic.c
@@ -0,0 +1,243 @@
+/* $Id: io_generic.c,v 1.2 2003/05/04 19:29:53 lethal Exp $
+ *
+ * linux/arch/sh/kernel/io_generic.c
+ *
+ * Copyright (C) 2000  Niibe Yutaka
+ *
+ * Generic I/O routine. These can be used where a machine specific version
+ * is not required.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ */
+
+#include <asm/io.h>
+#include <asm/machvec.h>
+#include <linux/module.h>
+
+#if defined(CONFIG_CPU_SH3)
+/* I'm not sure SH7709 has this kind of bug */
+#define SH3_PCMCIA_BUG_WORKAROUND 1
+#define DUMMY_READ_AREA6	  0xba000000
+#endif
+
+#define PORT2ADDR(x) (sh_mv.mv_isa_port2addr(x))
+
+unsigned long generic_io_base;
+
+static inline void delay(void)
+{
+	ctrl_inw(0xa0000000);
+}
+
+unsigned char generic_inb(unsigned long port)
+{
+	return *(volatile unsigned char*)PORT2ADDR(port);
+}
+
+unsigned short generic_inw(unsigned long port)
+{
+	return *(volatile unsigned short*)PORT2ADDR(port);
+}
+
+unsigned int generic_inl(unsigned long port)
+{
+	return *(volatile unsigned long*)PORT2ADDR(port);
+}
+
+unsigned char generic_inb_p(unsigned long port)
+{
+	unsigned long v = *(volatile unsigned char*)PORT2ADDR(port);
+
+	delay();
+	return v;
+}
+
+unsigned short generic_inw_p(unsigned long port)
+{
+	unsigned long v = *(volatile unsigned short*)PORT2ADDR(port);
+
+	delay();
+	return v;
+}
+
+unsigned int generic_inl_p(unsigned long port)
+{
+	unsigned long v = *(volatile unsigned long*)PORT2ADDR(port);
+
+	delay();
+	return v;
+}
+
+/*
+ * insb/w/l all read a series of bytes/words/longs from a fixed port
+ * address. However as the port address doesn't change we only need to
+ * convert the port address to real address once.
+ */
+
+void generic_insb(unsigned long port, void *buffer, unsigned long count)
+{
+	volatile unsigned char *port_addr;
+	unsigned char *buf=buffer;
+
+	port_addr = (volatile unsigned char *)PORT2ADDR(port);
+
+	while(count--)
+	    *buf++ = *port_addr;
+}
+
+void generic_insw(unsigned long port, void *buffer, unsigned long count)
+{
+	volatile unsigned short *port_addr;
+	unsigned short *buf=buffer;
+
+	port_addr = (volatile unsigned short *)PORT2ADDR(port);
+
+	while(count--)
+	    *buf++ = *port_addr;
+#ifdef SH3_PCMCIA_BUG_WORKAROUND
+	ctrl_inb (DUMMY_READ_AREA6);
+#endif
+}
+
+void generic_insl(unsigned long port, void *buffer, unsigned long count)
+{
+	volatile unsigned long *port_addr;
+	unsigned long *buf=buffer;
+
+	port_addr = (volatile unsigned long *)PORT2ADDR(port);
+
+	while(count--)
+	    *buf++ = *port_addr;
+#ifdef SH3_PCMCIA_BUG_WORKAROUND
+	ctrl_inb (DUMMY_READ_AREA6);
+#endif
+}
+
+void generic_outb(unsigned char b, unsigned long port)
+{
+	*(volatile unsigned char*)PORT2ADDR(port) = b;
+}
+
+void generic_outw(unsigned short b, unsigned long port)
+{
+	*(volatile unsigned short*)PORT2ADDR(port) = b;
+}
+
+void generic_outl(unsigned int b, unsigned long port)
+{
+        *(volatile unsigned long*)PORT2ADDR(port) = b;
+}
+
+void generic_outb_p(unsigned char b, unsigned long port)
+{
+	*(volatile unsigned char*)PORT2ADDR(port) = b;
+	delay();
+}
+
+void generic_outw_p(unsigned short b, unsigned long port)
+{
+	*(volatile unsigned short*)PORT2ADDR(port) = b;
+	delay();
+}
+
+void generic_outl_p(unsigned int b, unsigned long port)
+{
+	*(volatile unsigned long*)PORT2ADDR(port) = b;
+	delay();
+}
+
+/*
+ * outsb/w/l all write a series of bytes/words/longs to a fixed port
+ * address. However as the port address doesn't change we only need to
+ * convert the port address to real address once.
+ */
+
+void generic_outsb(unsigned long port, const void *buffer, unsigned long count)
+{
+	volatile unsigned char *port_addr;
+	const unsigned char *buf=buffer;
+
+	port_addr = (volatile unsigned char *)PORT2ADDR(port);
+
+	while(count--)
+	    *port_addr = *buf++;
+}
+
+void generic_outsw(unsigned long port, const void *buffer, unsigned long count)
+{
+	volatile unsigned short *port_addr;
+	const unsigned short *buf=buffer;
+
+	port_addr = (volatile unsigned short *)PORT2ADDR(port);
+
+	while(count--)
+	    *port_addr = *buf++;
+
+#ifdef SH3_PCMCIA_BUG_WORKAROUND
+	ctrl_inb (DUMMY_READ_AREA6);
+#endif
+}
+
+void generic_outsl(unsigned long port, const void *buffer, unsigned long count)
+{
+	volatile unsigned long *port_addr;
+	const unsigned long *buf=buffer;
+
+	port_addr = (volatile unsigned long *)PORT2ADDR(port);
+
+	while(count--)
+	    *port_addr = *buf++;
+
+#ifdef SH3_PCMCIA_BUG_WORKAROUND
+	ctrl_inb (DUMMY_READ_AREA6);
+#endif
+}
+
+unsigned char generic_readb(unsigned long addr)
+{
+	return *(volatile unsigned char*)addr;
+}
+
+unsigned short generic_readw(unsigned long addr)
+{
+	return *(volatile unsigned short*)addr;
+}
+
+unsigned int generic_readl(unsigned long addr)
+{
+	return *(volatile unsigned long*)addr;
+}
+
+void generic_writeb(unsigned char b, unsigned long addr)
+{
+	*(volatile unsigned char*)addr = b;
+}
+
+void generic_writew(unsigned short b, unsigned long addr)
+{
+	*(volatile unsigned short*)addr = b;
+}
+
+void generic_writel(unsigned int b, unsigned long addr)
+{
+        *(volatile unsigned long*)addr = b;
+}
+
+void * generic_ioremap(unsigned long offset, unsigned long size)
+{
+	return (void *) P2SEGADDR(offset);
+}
+EXPORT_SYMBOL(generic_ioremap);
+
+void generic_iounmap(void *addr)
+{
+}
+EXPORT_SYMBOL(generic_iounmap);
+
+unsigned long generic_isa_port2addr(unsigned long offset)
+{
+	return offset + generic_io_base;
+}
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c
new file mode 100644
index 0000000..54c1712
--- /dev/null
+++ b/arch/sh/kernel/irq.c
@@ -0,0 +1,106 @@
+/* $Id: irq.c,v 1.20 2004/01/13 05:52:11 kkojima Exp $
+ *
+ * linux/arch/sh/kernel/irq.c
+ *
+ *	Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
+ *
+ *
+ * SuperH version:  Copyright (C) 1999  Niibe Yutaka
+ */
+
+/*
+ * IRQs 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/errno.h>
+#include <linux/kernel_stat.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <linux/seq_file.h>
+#include <linux/kallsyms.h>
+#include <linux/bitops.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/pgalloc.h>
+#include <asm/delay.h>
+#include <asm/irq.h>
+#include <linux/irq.h>
+
+
+/*
+ * 'what should we do if we get a hw irq event on an illegal vector'.
+ * each architecture has to answer this themselves, it doesn't deserve
+ * a generic callback i think.
+ */
+void ack_bad_irq(unsigned int irq)
+{
+	printk("unexpected IRQ trap at vector %02x\n", irq);
+}
+
+#if defined(CONFIG_PROC_FS)
+int show_interrupts(struct seq_file *p, void *v)
+{
+	int i = *(loff_t *) v, j;
+	struct irqaction * action;
+	unsigned long flags;
+
+	if (i == 0) {
+		seq_puts(p, "           ");
+		for (j=0; j<NR_CPUS; j++)
+			if (cpu_online(j))
+				seq_printf(p, "CPU%d       ",j);
+		seq_putc(p, '\n');
+	}
+
+	if (i < ACTUAL_NR_IRQS) {
+		spin_lock_irqsave(&irq_desc[i].lock, flags);
+		action = irq_desc[i].action;
+		if (!action)
+			goto unlock;
+		seq_printf(p, "%3d: ",i);
+		seq_printf(p, "%10u ", kstat_irqs(i));
+		seq_printf(p, " %14s", irq_desc[i].handler->typename);
+		seq_printf(p, "  %s", action->name);
+
+		for (action=action->next; action; action = action->next)
+			seq_printf(p, ", %s", action->name);
+		seq_putc(p, '\n');
+unlock:
+		spin_unlock_irqrestore(&irq_desc[i].lock, flags);
+	}
+	return 0;
+}
+#endif
+
+asmlinkage int do_IRQ(unsigned long r4, unsigned long r5,
+		      unsigned long r6, unsigned long r7,
+		      struct pt_regs regs)
+{	
+	int irq;
+
+	irq_enter();
+	asm volatile("stc	r2_bank, %0\n\t"
+		     "shlr2	%0\n\t"
+		     "shlr2	%0\n\t"
+		     "shlr	%0\n\t"
+		     "add	#-16, %0\n\t"
+		     :"=z" (irq));
+	irq = irq_demux(irq);
+	__do_IRQ(irq, &regs);
+	irq_exit();
+	return 1;
+}
diff --git a/arch/sh/kernel/kgdb_jmp.S b/arch/sh/kernel/kgdb_jmp.S
new file mode 100644
index 0000000..339bb1d
--- /dev/null
+++ b/arch/sh/kernel/kgdb_jmp.S
@@ -0,0 +1,33 @@
+#include <linux/linkage.h>
+
+ENTRY(setjmp)
+	add	#(9*4), r4
+	sts.l	pr, @-r4
+	mov.l	r15, @-r4
+	mov.l	r14, @-r4
+	mov.l	r13, @-r4
+	mov.l	r12, @-r4
+	mov.l	r11, @-r4
+	mov.l	r10, @-r4
+	mov.l	r9, @-r4
+	mov.l	r8, @-r4
+	rts
+	 mov	#0, r0
+
+ENTRY(longjmp)
+	mov.l	@r4+, r8
+	mov.l	@r4+, r9
+	mov.l	@r4+, r10
+	mov.l	@r4+, r11
+	mov.l	@r4+, r12
+	mov.l	@r4+, r13
+	mov.l	@r4+, r14
+	mov.l	@r4+, r15
+	lds.l	@r4+, pr
+	mov	r5, r0
+	tst	r0, r0
+	bf	1f
+	mov	#1, r0	! in case val==0
+1:	rts
+	 nop
+
diff --git a/arch/sh/kernel/kgdb_stub.c b/arch/sh/kernel/kgdb_stub.c
new file mode 100644
index 0000000..42638b9
--- /dev/null
+++ b/arch/sh/kernel/kgdb_stub.c
@@ -0,0 +1,1491 @@
+/*
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * Containes extracts from code by Glenn Engel, Jim Kingdon,
+ * David Grothe <dave@gcom.com>, Tigran Aivazian <tigran@sco.com>,
+ * Amit S. Kale <akale@veritas.com>,  William Gatliff <bgat@open-widgets.com>,
+ * Ben Lee, Steve Chamberlain and Benoit Miller <fulg@iname.com>.
+ * 
+ * This version by Henry Bell <henry.bell@st.com>
+ * Minor modifications by Jeremy Siegel <jsiegel@mvista.com>
+ * 
+ * Contains low-level support for remote debug using GDB. 
+ *
+ * To enable debugger support, two things need to happen. A call to
+ * set_debug_traps() is necessary in order to allow any breakpoints
+ * or error conditions to be properly intercepted and reported to gdb.
+ * A breakpoint also needs to be generated to begin communication.  This
+ * is most easily accomplished by a call to breakpoint() which does
+ * a trapa if the initialisation phase has been successfully completed.
+ *
+ * In this case, set_debug_traps() is not used to "take over" exceptions;
+ * other kernel code is modified instead to enter the kgdb functions here
+ * when appropriate (see entry.S for breakpoint traps and NMI interrupts,
+ * see traps.c for kernel error exceptions).
+ *
+ * The following gdb commands are supported:
+ *
+ *    Command       Function                               Return value
+ *
+ *    g             return the value of the CPU registers  hex data or ENN
+ *    G             set the value of the CPU registers     OK or ENN
+ *
+ *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
+ *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
+ *    XAA..AA,LLLL: Same, but data is binary (not hex)     OK or ENN
+ *
+ *    c             Resume at current address              SNN   ( signal NN)
+ *    cAA..AA       Continue at address AA..AA             SNN
+ *    CNN;          Resume at current address with signal  SNN
+ *    CNN;AA..AA    Resume at address AA..AA with signal   SNN
+ *
+ *    s             Step one instruction                   SNN
+ *    sAA..AA       Step one instruction from AA..AA       SNN
+ *    SNN;          Step one instruction with signal       SNN
+ *    SNNAA..AA     Step one instruction from AA..AA w/NN  SNN
+ *
+ *    k             kill (Detach GDB)
+ *
+ *    d             Toggle debug flag
+ *    D             Detach GDB 
+ *
+ *    Hct           Set thread t for operations,           OK or ENN
+ *                  c = 'c' (step, cont), c = 'g' (other
+ *                  operations)
+ *
+ *    qC            Query current thread ID                QCpid
+ *    qfThreadInfo  Get list of current threads (first)    m<id>
+ *    qsThreadInfo   "    "  "     "      "   (subsequent)
+ *    qOffsets      Get section offsets                  Text=x;Data=y;Bss=z
+ * 
+ *    TXX           Find if thread XX is alive             OK or ENN
+ *    ?             What was the last sigval ?             SNN   (signal NN)
+ *    O             Output to GDB console
+ *
+ * Remote communication protocol.
+ *
+ *    A debug packet whose contents are <data> is encapsulated for
+ *    transmission in the form:
+ *
+ *       $ <data> # CSUM1 CSUM2
+ *
+ *       <data> must be ASCII alphanumeric and cannot include characters
+ *       '$' or '#'.  If <data> starts with two characters followed by
+ *       ':', then the existing stubs interpret this as a sequence number.
+ *
+ *       CSUM1 and CSUM2 are ascii hex representation of an 8-bit 
+ *       checksum of <data>, the most significant nibble is sent first.
+ *       the hex digits 0-9,a-f are used.
+ *
+ *    Receiver responds with:
+ *
+ *       +       - if CSUM is correct and ready for next packet
+ *       -       - if CSUM is incorrect
+ *
+ * Responses can be run-length encoded to save space.  A '*' means that
+ * the next character is an ASCII encoding giving a repeat count which
+ * stands for that many repititions of the character preceding the '*'.
+ * The encoding is n+29, yielding a printable character where n >=3 
+ * (which is where RLE starts to win).  Don't use an n > 126. 
+ *
+ * So "0* " means the same as "0000".
+ */
+
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/linkage.h>
+#include <linux/init.h>
+
+#include <asm/system.h>
+#include <asm/current.h>
+#include <asm/signal.h>
+#include <asm/pgtable.h>
+#include <asm/ptrace.h>
+#include <asm/kgdb.h>
+
+#ifdef CONFIG_SH_KGDB_CONSOLE
+#include <linux/console.h>
+#endif
+
+/* Function pointers for linkage */
+kgdb_debug_hook_t *kgdb_debug_hook;
+kgdb_bus_error_hook_t *kgdb_bus_err_hook;
+
+int (*kgdb_getchar)(void);
+void (*kgdb_putchar)(int);
+
+static void put_debug_char(int c)
+{
+	if (!kgdb_putchar)
+		return;
+	(*kgdb_putchar)(c);
+}
+static int get_debug_char(void)
+{
+	if (!kgdb_getchar)
+		return -1;
+	return (*kgdb_getchar)();
+}
+
+/* Num chars in in/out bound buffers, register packets need NUMREGBYTES * 2 */
+#define BUFMAX 1024
+#define NUMREGBYTES (MAXREG*4)
+#define OUTBUFMAX (NUMREGBYTES*2+512)
+
+enum regs {
+	R0 = 0, R1,  R2,  R3,   R4,   R5,  R6, R7,
+	R8, R9, R10, R11, R12,  R13,  R14, R15,
+	PC, PR, GBR, VBR, MACH, MACL, SR,
+	/*  */
+	MAXREG
+};
+
+static unsigned int registers[MAXREG];
+struct kgdb_regs trap_registers;
+
+char kgdb_in_gdb_mode;
+char in_nmi;			/* Set during NMI to prevent reentry */
+int kgdb_nofault;		/* Boolean to ignore bus errs (i.e. in GDB) */
+int kgdb_enabled = 1;		/* Default to enabled, cmdline can disable */
+int kgdb_halt;
+
+/* Exposed for user access */
+struct task_struct *kgdb_current;
+unsigned int kgdb_g_imask;
+int kgdb_trapa_val;
+int kgdb_excode;
+
+/* Default values for SCI (can override via kernel args in setup.c) */
+#ifndef CONFIG_KGDB_DEFPORT
+#define CONFIG_KGDB_DEFPORT 1
+#endif
+
+#ifndef CONFIG_KGDB_DEFBAUD
+#define CONFIG_KGDB_DEFBAUD 115200
+#endif
+
+#if defined(CONFIG_KGDB_DEFPARITY_E)
+#define CONFIG_KGDB_DEFPARITY 'E'
+#elif defined(CONFIG_KGDB_DEFPARITY_O)
+#define CONFIG_KGDB_DEFPARITY 'O'
+#else /* CONFIG_KGDB_DEFPARITY_N */
+#define CONFIG_KGDB_DEFPARITY 'N'
+#endif
+
+#ifdef CONFIG_KGDB_DEFBITS_7
+#define CONFIG_KGDB_DEFBITS '7'
+#else /* CONFIG_KGDB_DEFBITS_8 */
+#define CONFIG_KGDB_DEFBITS '8'
+#endif
+
+/* SCI/UART settings, used in kgdb_console_setup() */
+int  kgdb_portnum = CONFIG_KGDB_DEFPORT;
+int  kgdb_baud = CONFIG_KGDB_DEFBAUD;
+char kgdb_parity = CONFIG_KGDB_DEFPARITY;
+char kgdb_bits = CONFIG_KGDB_DEFBITS;
+
+/* Jump buffer for setjmp/longjmp */
+static jmp_buf rem_com_env;
+
+/* TRA differs sh3/4 */
+#if defined(CONFIG_CPU_SH3)
+#define TRA 0xffffffd0
+#elif defined(CONFIG_CPU_SH4)
+#define TRA 0xff000020
+#endif
+
+/* Macros for single step instruction identification */
+#define OPCODE_BT(op)         (((op) & 0xff00) == 0x8900)
+#define OPCODE_BF(op)         (((op) & 0xff00) == 0x8b00)
+#define OPCODE_BTF_DISP(op)   (((op) & 0x80) ? (((op) | 0xffffff80) << 1) : \
+			      (((op) & 0x7f ) << 1))
+#define OPCODE_BFS(op)        (((op) & 0xff00) == 0x8f00)
+#define OPCODE_BTS(op)        (((op) & 0xff00) == 0x8d00)
+#define OPCODE_BRA(op)        (((op) & 0xf000) == 0xa000)
+#define OPCODE_BRA_DISP(op)   (((op) & 0x800) ? (((op) | 0xfffff800) << 1) : \
+			      (((op) & 0x7ff) << 1))
+#define OPCODE_BRAF(op)       (((op) & 0xf0ff) == 0x0023)
+#define OPCODE_BRAF_REG(op)   (((op) & 0x0f00) >> 8)
+#define OPCODE_BSR(op)        (((op) & 0xf000) == 0xb000)
+#define OPCODE_BSR_DISP(op)   (((op) & 0x800) ? (((op) | 0xfffff800) << 1) : \
+			      (((op) & 0x7ff) << 1))
+#define OPCODE_BSRF(op)       (((op) & 0xf0ff) == 0x0003)
+#define OPCODE_BSRF_REG(op)   (((op) >> 8) & 0xf)
+#define OPCODE_JMP(op)        (((op) & 0xf0ff) == 0x402b)
+#define OPCODE_JMP_REG(op)    (((op) >> 8) & 0xf)
+#define OPCODE_JSR(op)        (((op) & 0xf0ff) == 0x400b)
+#define OPCODE_JSR_REG(op)    (((op) >> 8) & 0xf)
+#define OPCODE_RTS(op)        ((op) == 0xb)
+#define OPCODE_RTE(op)        ((op) == 0x2b)
+
+#define SR_T_BIT_MASK           0x1
+#define STEP_OPCODE             0xc320
+#define BIOS_CALL_TRAP          0x3f
+
+/* Exception codes as per SH-4 core manual */
+#define ADDRESS_ERROR_LOAD_VEC   7
+#define ADDRESS_ERROR_STORE_VEC  8
+#define TRAP_VEC                 11
+#define INVALID_INSN_VEC         12
+#define INVALID_SLOT_VEC         13
+#define NMI_VEC                  14
+#define USER_BREAK_VEC           15
+#define SERIAL_BREAK_VEC         58
+
+/* Misc static */
+static int stepped_address;
+static short stepped_opcode;
+static const char hexchars[] = "0123456789abcdef";
+static char in_buffer[BUFMAX];
+static char out_buffer[OUTBUFMAX];
+
+static void kgdb_to_gdb(const char *s);
+
+#ifdef CONFIG_KGDB_THREAD
+static struct task_struct *trapped_thread;
+static struct task_struct *current_thread;
+typedef unsigned char threadref[8];
+#define BUF_THREAD_ID_SIZE 16
+#endif
+
+/* Return addr as a real volatile address */
+static inline unsigned int ctrl_inl(const unsigned long addr)
+{
+	return *(volatile unsigned long *) addr;
+}
+
+/* Correctly set *addr using volatile */
+static inline void ctrl_outl(const unsigned int b, unsigned long addr)
+{
+	*(volatile unsigned long *) addr = b;
+}
+
+/* Get high hex bits */
+static char highhex(const int x)
+{
+	return hexchars[(x >> 4) & 0xf];
+}
+
+/* Get low hex bits */
+static char lowhex(const int x)
+{
+	return hexchars[x & 0xf];
+}
+
+/* Convert ch to hex */
+static int hex(const char ch)
+{
+	if ((ch >= 'a') && (ch <= 'f'))
+		return (ch - 'a' + 10);
+	if ((ch >= '0') && (ch <= '9'))
+		return (ch - '0');
+	if ((ch >= 'A') && (ch <= 'F'))
+		return (ch - 'A' + 10);
+	return (-1);
+}
+
+/* Convert the memory pointed to by mem into hex, placing result in buf.
+   Returns a pointer to the last char put in buf (null) */
+static char *mem_to_hex(const char *mem, char *buf, const int count)
+{
+	int i;
+	int ch;
+	unsigned short s_val;
+	unsigned long l_val;
+
+	/* Check for 16 or 32 */
+	if (count == 2 && ((long) mem & 1) == 0) {
+		s_val = *(unsigned short *) mem;
+		mem = (char *) &s_val;
+	} else if (count == 4 && ((long) mem & 3) == 0) {
+		l_val = *(unsigned long *) mem;
+		mem = (char *) &l_val;
+	}
+	for (i = 0; i < count; i++) {
+		ch = *mem++;
+		*buf++ = highhex(ch);
+		*buf++ = lowhex(ch);
+	}
+	*buf = 0;
+	return (buf);
+}
+
+/* Convert the hex array pointed to by buf into binary, to be placed in mem.
+   Return a pointer to the character after the last byte written */
+static char *hex_to_mem(const char *buf, char *mem, const int count)
+{
+	int i;
+	unsigned char ch;
+
+	for (i = 0; i < count; i++) {
+		ch = hex(*buf++) << 4;
+		ch = ch + hex(*buf++);
+		*mem++ = ch;
+	}
+	return (mem);
+}
+
+/* While finding valid hex chars, convert to an integer, then return it */
+static int hex_to_int(char **ptr, int *int_value)
+{
+	int num_chars = 0;
+	int hex_value;
+
+	*int_value = 0;
+
+	while (**ptr) {
+		hex_value = hex(**ptr);
+		if (hex_value >= 0) {
+			*int_value = (*int_value << 4) | hex_value;
+			num_chars++;
+		} else
+			break;
+		(*ptr)++;
+	}
+	return num_chars;
+}
+
+/*  Copy the binary array pointed to by buf into mem.  Fix $, #,
+    and 0x7d escaped with 0x7d.  Return a pointer to the character 
+    after the last byte written. */
+static char *ebin_to_mem(const char *buf, char *mem, int count)
+{
+	for (; count > 0; count--, buf++) {
+		if (*buf == 0x7d)
+			*mem++ = *(++buf) ^ 0x20;
+		else
+			*mem++ = *buf;
+	}
+	return mem;
+}
+
+/* Pack a hex byte */
+static char *pack_hex_byte(char *pkt, int byte)
+{
+	*pkt++ = hexchars[(byte >> 4) & 0xf];
+	*pkt++ = hexchars[(byte & 0xf)];
+	return pkt;
+}
+
+#ifdef CONFIG_KGDB_THREAD
+
+/* Pack a thread ID */
+static char *pack_threadid(char *pkt, threadref * id)
+{
+	char *limit;
+	unsigned char *altid;
+
+	altid = (unsigned char *) id;
+
+	limit = pkt + BUF_THREAD_ID_SIZE;
+	while (pkt < limit)
+		pkt = pack_hex_byte(pkt, *altid++);
+	return pkt;
+}
+
+/* Convert an integer into our threadref */
+static void int_to_threadref(threadref * id, const int value)
+{
+	unsigned char *scan = (unsigned char *) id;
+	int i = 4;
+
+	while (i--)
+		*scan++ = 0;
+
+	*scan++ = (value >> 24) & 0xff;
+	*scan++ = (value >> 16) & 0xff;
+	*scan++ = (value >> 8) & 0xff;
+	*scan++ = (value & 0xff);
+}
+
+/* Return a task structure ptr for a particular pid */
+static struct task_struct *get_thread(int pid)
+{
+	struct task_struct *thread;
+
+	/* Use PID_MAX w/gdb for pid 0 */
+	if (pid == PID_MAX) pid = 0;
+
+	/* First check via PID */
+	thread = find_task_by_pid(pid);
+
+	if (thread)
+		return thread;
+
+	/* Start at the start */
+	thread = init_tasks[0];
+
+	/* Walk along the linked list of tasks */
+	do {
+		if (thread->pid == pid)
+			return thread;
+		thread = thread->next_task;
+	} while (thread != init_tasks[0]);
+
+	return NULL;
+}
+
+#endif /* CONFIG_KGDB_THREAD */
+
+/* Scan for the start char '$', read the packet and check the checksum */
+static void get_packet(char *buffer, int buflen)
+{
+	unsigned char checksum;
+	unsigned char xmitcsum;
+	int i;
+	int count;
+	char ch;
+
+	do {
+		/* Ignore everything until the start character */
+		while ((ch = get_debug_char()) != '$');
+
+		checksum = 0;
+		xmitcsum = -1;
+		count = 0;
+
+		/* Now, read until a # or end of buffer is found */
+		while (count < (buflen - 1)) {
+			ch = get_debug_char();
+
+			if (ch == '#')
+				break;
+
+			checksum = checksum + ch;
+			buffer[count] = ch;
+			count = count + 1;
+		}
+
+		buffer[count] = 0;
+
+		/* Continue to read checksum following # */
+		if (ch == '#') {
+			xmitcsum = hex(get_debug_char()) << 4;
+			xmitcsum += hex(get_debug_char());
+
+			/* Checksum */
+			if (checksum != xmitcsum)
+				put_debug_char('-');	/* Failed checksum */
+			else {
+				/* Ack successful transfer */
+				put_debug_char('+');
+
+				/* If a sequence char is present, reply 
+				   the sequence ID */
+				if (buffer[2] == ':') {
+					put_debug_char(buffer[0]);
+					put_debug_char(buffer[1]);
+
+					/* Remove sequence chars from buffer */
+					count = strlen(buffer);
+					for (i = 3; i <= count; i++)
+						buffer[i - 3] = buffer[i];
+				}
+			}
+		}
+	}
+	while (checksum != xmitcsum);	/* Keep trying while we fail */
+}
+
+/* Send the packet in the buffer with run-length encoding */
+static void put_packet(char *buffer)
+{
+	int checksum;
+	char *src;
+	int runlen;
+	int encode;
+
+	do {
+		src = buffer;
+		put_debug_char('$');
+		checksum = 0;
+
+		/* Continue while we still have chars left */
+		while (*src) {
+			/* Check for runs up to 99 chars long */
+			for (runlen = 1; runlen < 99; runlen++) {
+				if (src[0] != src[runlen])
+					break;
+			}
+
+			if (runlen > 3) {
+				/* Got a useful amount, send encoding */
+				encode = runlen + ' ' - 4;
+				put_debug_char(*src);   checksum += *src;
+				put_debug_char('*');    checksum += '*';
+				put_debug_char(encode); checksum += encode;
+				src += runlen;
+			} else {
+				/* Otherwise just send the current char */
+				put_debug_char(*src);   checksum += *src;
+				src += 1;
+			}
+		}
+
+		/* '#' Separator, put high and low components of checksum */
+		put_debug_char('#');
+		put_debug_char(highhex(checksum));
+		put_debug_char(lowhex(checksum));
+	}
+	while ((get_debug_char()) != '+');	/* While no ack */
+}
+
+/* A bus error has occurred - perform a longjmp to return execution and
+   allow handling of the error */
+static void kgdb_handle_bus_error(void)
+{
+	longjmp(rem_com_env, 1);
+}
+
+/* Translate SH-3/4 exception numbers to unix-like signal values */
+static int compute_signal(const int excep_code)
+{
+	int sigval;
+
+	switch (excep_code) {
+
+	case INVALID_INSN_VEC:
+	case INVALID_SLOT_VEC:
+		sigval = SIGILL;
+		break;
+	case ADDRESS_ERROR_LOAD_VEC:
+	case ADDRESS_ERROR_STORE_VEC:
+		sigval = SIGSEGV;
+		break;
+
+	case SERIAL_BREAK_VEC:
+	case NMI_VEC:
+		sigval = SIGINT;
+		break;
+
+	case USER_BREAK_VEC:
+	case TRAP_VEC:
+		sigval = SIGTRAP;
+		break;
+
+	default:
+		sigval = SIGBUS;	/* "software generated" */
+		break;
+	}
+
+	return (sigval);
+}
+
+/* Make a local copy of the registers passed into the handler (bletch) */
+static void kgdb_regs_to_gdb_regs(const struct kgdb_regs *regs,
+				  int *gdb_regs)
+{
+	gdb_regs[R0] = regs->regs[R0];
+	gdb_regs[R1] = regs->regs[R1];
+	gdb_regs[R2] = regs->regs[R2];
+	gdb_regs[R3] = regs->regs[R3];
+	gdb_regs[R4] = regs->regs[R4];
+	gdb_regs[R5] = regs->regs[R5];
+	gdb_regs[R6] = regs->regs[R6];
+	gdb_regs[R7] = regs->regs[R7];
+	gdb_regs[R8] = regs->regs[R8];
+	gdb_regs[R9] = regs->regs[R9];
+	gdb_regs[R10] = regs->regs[R10];
+	gdb_regs[R11] = regs->regs[R11];
+	gdb_regs[R12] = regs->regs[R12];
+	gdb_regs[R13] = regs->regs[R13];
+	gdb_regs[R14] = regs->regs[R14];
+	gdb_regs[R15] = regs->regs[R15];
+	gdb_regs[PC] = regs->pc;
+	gdb_regs[PR] = regs->pr;
+	gdb_regs[GBR] = regs->gbr;
+	gdb_regs[MACH] = regs->mach;
+	gdb_regs[MACL] = regs->macl;
+	gdb_regs[SR] = regs->sr;
+	gdb_regs[VBR] = regs->vbr;
+}
+
+/* Copy local gdb registers back to kgdb regs, for later copy to kernel */
+static void gdb_regs_to_kgdb_regs(const int *gdb_regs,
+				  struct kgdb_regs *regs)
+{
+	regs->regs[R0] = gdb_regs[R0];
+	regs->regs[R1] = gdb_regs[R1];
+	regs->regs[R2] = gdb_regs[R2];
+	regs->regs[R3] = gdb_regs[R3];
+	regs->regs[R4] = gdb_regs[R4];
+	regs->regs[R5] = gdb_regs[R5];
+	regs->regs[R6] = gdb_regs[R6];
+	regs->regs[R7] = gdb_regs[R7];
+	regs->regs[R8] = gdb_regs[R8];
+	regs->regs[R9] = gdb_regs[R9];
+	regs->regs[R10] = gdb_regs[R10];
+	regs->regs[R11] = gdb_regs[R11];
+	regs->regs[R12] = gdb_regs[R12];
+	regs->regs[R13] = gdb_regs[R13];
+	regs->regs[R14] = gdb_regs[R14];
+	regs->regs[R15] = gdb_regs[R15];
+	regs->pc = gdb_regs[PC];
+	regs->pr = gdb_regs[PR];
+	regs->gbr = gdb_regs[GBR];
+	regs->mach = gdb_regs[MACH];
+	regs->macl = gdb_regs[MACL];
+	regs->sr = gdb_regs[SR];
+	regs->vbr = gdb_regs[VBR];
+}
+
+#ifdef CONFIG_KGDB_THREAD
+/* Make a local copy of registers from the specified thread */
+asmlinkage void ret_from_fork(void);
+static void thread_regs_to_gdb_regs(const struct task_struct *thread,
+				    int *gdb_regs)
+{
+	int regno;
+	int *tregs;
+
+	/* Initialize to zero */
+	for (regno = 0; regno < MAXREG; regno++)
+		gdb_regs[regno] = 0;
+
+	/* Just making sure... */
+	if (thread == NULL)
+		return;
+
+	/* A new fork has pt_regs on the stack from a fork() call */
+	if (thread->thread.pc == (unsigned long)ret_from_fork) {
+
+		int vbr_val;
+		struct pt_regs *kregs;
+		kregs = (struct pt_regs*)thread->thread.sp;
+
+		gdb_regs[R0] = kregs->regs[R0];
+		gdb_regs[R1] = kregs->regs[R1];
+		gdb_regs[R2] = kregs->regs[R2];
+		gdb_regs[R3] = kregs->regs[R3];
+		gdb_regs[R4] = kregs->regs[R4];
+		gdb_regs[R5] = kregs->regs[R5];
+		gdb_regs[R6] = kregs->regs[R6];
+		gdb_regs[R7] = kregs->regs[R7];
+		gdb_regs[R8] = kregs->regs[R8];
+		gdb_regs[R9] = kregs->regs[R9];
+		gdb_regs[R10] = kregs->regs[R10];
+		gdb_regs[R11] = kregs->regs[R11];
+		gdb_regs[R12] = kregs->regs[R12];
+		gdb_regs[R13] = kregs->regs[R13];
+		gdb_regs[R14] = kregs->regs[R14];
+		gdb_regs[R15] = kregs->regs[R15];
+		gdb_regs[PC] = kregs->pc;
+		gdb_regs[PR] = kregs->pr;
+		gdb_regs[GBR] = kregs->gbr;
+		gdb_regs[MACH] = kregs->mach;
+		gdb_regs[MACL] = kregs->macl;
+		gdb_regs[SR] = kregs->sr;
+
+		asm("stc vbr, %0":"=r"(vbr_val));
+		gdb_regs[VBR] = vbr_val;
+		return;
+	}
+
+	/* Otherwise, we have only some registers from switch_to() */
+	tregs = (int *)thread->thread.sp;
+	gdb_regs[R15] = (int)tregs;
+	gdb_regs[R14] = *tregs++;
+	gdb_regs[R13] = *tregs++;
+	gdb_regs[R12] = *tregs++;
+	gdb_regs[R11] = *tregs++;
+	gdb_regs[R10] = *tregs++;
+	gdb_regs[R9] = *tregs++;
+	gdb_regs[R8] = *tregs++;
+	gdb_regs[PR] = *tregs++;
+	gdb_regs[GBR] = *tregs++;
+	gdb_regs[PC] = thread->thread.pc;
+}
+#endif /* CONFIG_KGDB_THREAD */
+
+/* Calculate the new address for after a step */
+static short *get_step_address(void)
+{
+	short op = *(short *) trap_registers.pc;
+	long addr;
+
+	/* BT */
+	if (OPCODE_BT(op)) {
+		if (trap_registers.sr & SR_T_BIT_MASK)
+			addr = trap_registers.pc + 4 + OPCODE_BTF_DISP(op);
+		else
+			addr = trap_registers.pc + 2;
+	}
+
+	/* BTS */
+	else if (OPCODE_BTS(op)) {
+		if (trap_registers.sr & SR_T_BIT_MASK)
+			addr = trap_registers.pc + 4 + OPCODE_BTF_DISP(op);
+		else
+			addr = trap_registers.pc + 4;	/* Not in delay slot */
+	}
+
+	/* BF */
+	else if (OPCODE_BF(op)) {
+		if (!(trap_registers.sr & SR_T_BIT_MASK))
+			addr = trap_registers.pc + 4 + OPCODE_BTF_DISP(op);
+		else
+			addr = trap_registers.pc + 2;
+	}
+
+	/* BFS */
+	else if (OPCODE_BFS(op)) {
+		if (!(trap_registers.sr & SR_T_BIT_MASK))
+			addr = trap_registers.pc + 4 + OPCODE_BTF_DISP(op);
+		else
+			addr = trap_registers.pc + 4;	/* Not in delay slot */
+	}
+
+	/* BRA */
+	else if (OPCODE_BRA(op))
+		addr = trap_registers.pc + 4 + OPCODE_BRA_DISP(op);
+
+	/* BRAF */
+	else if (OPCODE_BRAF(op))
+		addr = trap_registers.pc + 4
+		    + trap_registers.regs[OPCODE_BRAF_REG(op)];
+
+	/* BSR */
+	else if (OPCODE_BSR(op))
+		addr = trap_registers.pc + 4 + OPCODE_BSR_DISP(op);
+
+	/* BSRF */
+	else if (OPCODE_BSRF(op))
+		addr = trap_registers.pc + 4
+		    + trap_registers.regs[OPCODE_BSRF_REG(op)];
+
+	/* JMP */
+	else if (OPCODE_JMP(op))
+		addr = trap_registers.regs[OPCODE_JMP_REG(op)];
+
+	/* JSR */
+	else if (OPCODE_JSR(op))
+		addr = trap_registers.regs[OPCODE_JSR_REG(op)];
+
+	/* RTS */
+	else if (OPCODE_RTS(op))
+		addr = trap_registers.pr;
+
+	/* RTE */
+	else if (OPCODE_RTE(op))
+		addr = trap_registers.regs[15];
+
+	/* Other */
+	else
+		addr = trap_registers.pc + 2;
+
+	kgdb_flush_icache_range(addr, addr + 2);
+	return (short *) addr;
+}
+
+/* Set up a single-step.  Replace the instruction immediately after the 
+   current instruction (i.e. next in the expected flow of control) with a
+   trap instruction, so that returning will cause only a single instruction
+   to be executed. Note that this model is slightly broken for instructions
+   with delay slots (e.g. B[TF]S, BSR, BRA etc), where both the branch
+   and the instruction in the delay slot will be executed. */
+static void do_single_step(void)
+{
+	unsigned short *addr = 0;
+
+	/* Determine where the target instruction will send us to */
+	addr = get_step_address();
+	stepped_address = (int)addr;
+
+	/* Replace it */
+	stepped_opcode = *(short *)addr;
+	*addr = STEP_OPCODE;
+
+	/* Flush and return */
+	kgdb_flush_icache_range((long) addr, (long) addr + 2);
+	return;
+}
+
+/* Undo a single step */
+static void undo_single_step(void)
+{
+	/* If we have stepped, put back the old instruction */
+	/* Use stepped_address in case we stopped elsewhere */
+	if (stepped_opcode != 0) {
+		*(short*)stepped_address = stepped_opcode;
+		kgdb_flush_icache_range(stepped_address, stepped_address + 2);
+	}
+	stepped_opcode = 0;
+}
+
+/* Send a signal message */
+static void send_signal_msg(const int signum)
+{
+#ifndef CONFIG_KGDB_THREAD
+	out_buffer[0] = 'S';
+	out_buffer[1] = highhex(signum);
+	out_buffer[2] = lowhex(signum);
+	out_buffer[3] = 0;
+	put_packet(out_buffer);
+#else /* CONFIG_KGDB_THREAD */
+	int threadid;
+	threadref thref;
+	char *out = out_buffer;
+	const char *tstring = "thread";
+
+	*out++ = 'T';
+	*out++ = highhex(signum);
+	*out++ = lowhex(signum);
+
+	while (*tstring) {
+		*out++ = *tstring++;
+	}
+	*out++ = ':';
+
+	threadid = trapped_thread->pid;
+	if (threadid == 0) threadid = PID_MAX;
+	int_to_threadref(&thref, threadid);
+	pack_threadid(out, &thref);
+	out += BUF_THREAD_ID_SIZE;
+	*out++ = ';';
+
+	*out = 0;
+	put_packet(out_buffer);
+#endif /* CONFIG_KGDB_THREAD */
+}
+
+/* Reply that all was well */
+static void send_ok_msg(void)
+{
+	strcpy(out_buffer, "OK");
+	put_packet(out_buffer);
+}
+
+/* Reply that an error occurred */
+static void send_err_msg(void)
+{
+	strcpy(out_buffer, "E01");
+	put_packet(out_buffer);
+}
+
+/* Empty message indicates unrecognised command */
+static void send_empty_msg(void)
+{
+	put_packet("");
+}
+
+/* Read memory due to 'm' message */
+static void read_mem_msg(void)
+{
+	char *ptr;
+	int addr;
+	int length;
+
+	/* Jmp, disable bus error handler */
+	if (setjmp(rem_com_env) == 0) {
+
+		kgdb_nofault = 1;
+
+		/* Walk through, have m<addr>,<length> */
+		ptr = &in_buffer[1];
+		if (hex_to_int(&ptr, &addr) && (*ptr++ == ','))
+			if (hex_to_int(&ptr, &length)) {
+				ptr = 0;
+				if (length * 2 > OUTBUFMAX)
+					length = OUTBUFMAX / 2;
+				mem_to_hex((char *) addr, out_buffer, length);
+			}
+		if (ptr)
+			send_err_msg();
+		else
+			put_packet(out_buffer);
+	} else
+		send_err_msg();
+
+	/* Restore bus error handler */
+	kgdb_nofault = 0;
+}
+
+/* Write memory due to 'M' or 'X' message */
+static void write_mem_msg(int binary)
+{
+	char *ptr;
+	int addr;
+	int length;
+
+	if (setjmp(rem_com_env) == 0) {
+
+		kgdb_nofault = 1;
+
+		/* Walk through, have M<addr>,<length>:<data> */
+		ptr = &in_buffer[1];
+		if (hex_to_int(&ptr, &addr) && (*ptr++ == ','))
+			if (hex_to_int(&ptr, &length) && (*ptr++ == ':')) {
+				if (binary)
+					ebin_to_mem(ptr, (char*)addr, length);
+				else
+					hex_to_mem(ptr, (char*)addr, length);
+				kgdb_flush_icache_range(addr, addr + length);
+				ptr = 0;
+				send_ok_msg();
+			}
+		if (ptr)
+			send_err_msg();
+	} else
+		send_err_msg();
+
+	/* Restore bus error handler */
+	kgdb_nofault = 0;
+}
+
+/* Continue message  */
+static void continue_msg(void)
+{
+	/* Try to read optional parameter, PC unchanged if none */
+	char *ptr = &in_buffer[1];
+	int addr;
+
+	if (hex_to_int(&ptr, &addr))
+		trap_registers.pc = addr;
+}
+
+/* Continue message with signal */
+static void continue_with_sig_msg(void)
+{
+	int signal;
+	char *ptr = &in_buffer[1];
+	int addr;
+
+	/* Report limitation */
+	kgdb_to_gdb("Cannot force signal in kgdb, continuing anyway.\n");
+
+	/* Signal */
+	hex_to_int(&ptr, &signal);
+	if (*ptr == ';')
+		ptr++;
+
+	/* Optional address */
+	if (hex_to_int(&ptr, &addr))
+		trap_registers.pc = addr;
+}
+
+/* Step message */
+static void step_msg(void)
+{
+	continue_msg();
+	do_single_step();
+}
+
+/* Step message with signal */
+static void step_with_sig_msg(void)
+{
+	continue_with_sig_msg();
+	do_single_step();
+}
+
+/* Send register contents */
+static void send_regs_msg(void)
+{
+#ifdef CONFIG_KGDB_THREAD
+	if (!current_thread)
+		kgdb_regs_to_gdb_regs(&trap_registers, registers);
+	else
+		thread_regs_to_gdb_regs(current_thread, registers);
+#else
+	kgdb_regs_to_gdb_regs(&trap_registers, registers);
+#endif
+
+	mem_to_hex((char *) registers, out_buffer, NUMREGBYTES);
+	put_packet(out_buffer);
+}
+
+/* Set register contents - currently can't set other thread's registers */
+static void set_regs_msg(void)
+{
+#ifdef CONFIG_KGDB_THREAD
+	if (!current_thread) {
+#endif
+		kgdb_regs_to_gdb_regs(&trap_registers, registers);
+		hex_to_mem(&in_buffer[1], (char *) registers, NUMREGBYTES);
+		gdb_regs_to_kgdb_regs(registers, &trap_registers);
+		send_ok_msg();
+#ifdef CONFIG_KGDB_THREAD
+	} else
+		send_err_msg();
+#endif
+}
+
+
+#ifdef CONFIG_KGDB_THREAD
+
+/* Set the status for a thread */
+void set_thread_msg(void)
+{
+	int threadid;
+	struct task_struct *thread = NULL;
+	char *ptr;
+
+	switch (in_buffer[1]) {
+
+       	/* To select which thread for gG etc messages, i.e. supported */
+	case 'g':
+
+		ptr = &in_buffer[2];
+		hex_to_int(&ptr, &threadid);
+		thread = get_thread(threadid);
+
+		/* If we haven't found it */
+		if (!thread) {
+			send_err_msg();
+			break;
+		}
+
+		/* Set current_thread (or not) */
+		if (thread == trapped_thread)
+			current_thread = NULL;
+		else
+			current_thread = thread;
+		send_ok_msg();
+		break;
+
+	/* To select which thread for cCsS messages, i.e. unsupported */
+	case 'c':
+		send_ok_msg();
+		break;
+
+	default:
+		send_empty_msg();
+		break;
+	}
+}
+
+/* Is a thread alive? */
+static void thread_status_msg(void)
+{
+	char *ptr;
+	int threadid;
+	struct task_struct *thread = NULL;
+
+	ptr = &in_buffer[1];
+	hex_to_int(&ptr, &threadid);
+	thread = get_thread(threadid);
+	if (thread)
+		send_ok_msg();
+	else
+		send_err_msg();
+}
+/* Send the current thread ID */
+static void thread_id_msg(void)
+{
+	int threadid;
+	threadref thref;
+
+	out_buffer[0] = 'Q';
+	out_buffer[1] = 'C';
+
+	if (current_thread)
+		threadid = current_thread->pid;
+	else if (trapped_thread)
+		threadid = trapped_thread->pid;
+	else /* Impossible, but just in case! */
+	{
+		send_err_msg();
+		return;
+	}
+
+	/* Translate pid 0 to PID_MAX for gdb */
+	if (threadid == 0) threadid = PID_MAX;
+
+	int_to_threadref(&thref, threadid);
+	pack_threadid(out_buffer + 2, &thref);
+	out_buffer[2 + BUF_THREAD_ID_SIZE] = '\0';
+	put_packet(out_buffer);
+}
+
+/* Send thread info */
+static void thread_info_msg(void)
+{
+	struct task_struct *thread = NULL;
+	int threadid;
+	char *pos;
+	threadref thref;
+
+	/* Start with 'm' */
+	out_buffer[0] = 'm';
+	pos = &out_buffer[1];
+
+	/* For all possible thread IDs - this will overrun if > 44 threads! */
+	/* Start at 1 and include PID_MAX (since GDB won't use pid 0...) */
+	for (threadid = 1; threadid <= PID_MAX; threadid++) {
+
+		read_lock(&tasklist_lock);
+		thread = get_thread(threadid);
+		read_unlock(&tasklist_lock);
+
+		/* If it's a valid thread */
+		if (thread) {
+			int_to_threadref(&thref, threadid);
+			pack_threadid(pos, &thref);
+			pos += BUF_THREAD_ID_SIZE;
+			*pos++ = ',';
+		}
+	}
+	*--pos = 0;		/* Lose final comma */
+	put_packet(out_buffer);
+
+}
+
+/* Return printable info for gdb's 'info threads' command */
+static void thread_extra_info_msg(void)
+{
+	int threadid;
+	struct task_struct *thread = NULL;
+	char buffer[20], *ptr;
+	int i;
+
+	/* Extract thread ID */
+	ptr = &in_buffer[17];
+	hex_to_int(&ptr, &threadid);
+	thread = get_thread(threadid);
+
+	/* If we don't recognise it, say so */
+	if (thread == NULL)
+		strcpy(buffer, "(unknown)");
+	else
+		strcpy(buffer, thread->comm);
+
+	/* Construct packet */
+	for (i = 0, ptr = out_buffer; buffer[i]; i++)
+		ptr = pack_hex_byte(ptr, buffer[i]);
+
+	if (thread->thread.pc == (unsigned long)ret_from_fork) {
+		strcpy(buffer, "<new fork>");
+		for (i = 0; buffer[i]; i++)
+			ptr = pack_hex_byte(ptr, buffer[i]);
+	}
+
+	*ptr = '\0';
+	put_packet(out_buffer);
+}
+
+/* Handle all qFooBarBaz messages - have to use an if statement as
+   opposed to a switch because q messages can have > 1 char id. */
+static void query_msg(void)
+{
+	const char *q_start = &in_buffer[1];
+
+	/* qC = return current thread ID */
+	if (strncmp(q_start, "C", 1) == 0)
+		thread_id_msg();
+
+	/* qfThreadInfo = query all threads (first) */
+	else if (strncmp(q_start, "fThreadInfo", 11) == 0)
+		thread_info_msg();
+
+	/* qsThreadInfo = query all threads (subsequent). We know we have sent
+	   them all after the qfThreadInfo message, so there are no to send */
+	else if (strncmp(q_start, "sThreadInfo", 11) == 0)
+		put_packet("l");	/* el = last */
+
+	/* qThreadExtraInfo = supply printable information per thread */
+	else if (strncmp(q_start, "ThreadExtraInfo", 15) == 0)
+		thread_extra_info_msg();
+
+	/* Unsupported - empty message as per spec */
+	else
+		send_empty_msg();
+}
+#endif /* CONFIG_KGDB_THREAD */
+
+/*
+ * Bring up the ports..
+ */
+static int kgdb_serial_setup(void)
+{
+	extern int kgdb_console_setup(struct console *co, char *options);
+	struct console dummy;
+
+	kgdb_console_setup(&dummy, 0);
+
+	return 0;
+}
+
+/* The command loop, read and act on requests */
+static void kgdb_command_loop(const int excep_code, const int trapa_value)
+{
+	int sigval;
+
+	if (excep_code == NMI_VEC) {
+#ifndef CONFIG_KGDB_NMI
+		KGDB_PRINTK("Ignoring unexpected NMI?\n");
+		return;
+#else /* CONFIG_KGDB_NMI */
+		if (!kgdb_enabled) {
+			kgdb_enabled = 1;
+			kgdb_init();
+		}
+#endif /* CONFIG_KGDB_NMI */
+	}
+
+	/* Ignore if we're disabled */
+	if (!kgdb_enabled)
+		return;
+
+#ifdef CONFIG_KGDB_THREAD
+	/* Until GDB specifies a thread */
+	current_thread = NULL;
+	trapped_thread = current;
+#endif
+
+	/* Enter GDB mode (e.g. after detach) */
+	if (!kgdb_in_gdb_mode) {
+		/* Do serial setup, notify user, issue preemptive ack */
+		kgdb_serial_setup();
+		KGDB_PRINTK("Waiting for GDB (on %s%d at %d baud)\n",
+			    (kgdb_porttype ? kgdb_porttype->name : ""),
+			    kgdb_portnum, kgdb_baud);
+		kgdb_in_gdb_mode = 1;
+		put_debug_char('+');
+	}
+
+	/* Reply to host that an exception has occurred */
+	sigval = compute_signal(excep_code);
+	send_signal_msg(sigval);
+
+	/* TRAP_VEC exception indicates a software trap inserted in place of
+	   code by GDB so back up PC by one instruction, as this instruction
+	   will later be replaced by its original one.  Do NOT do this for
+	   trap 0xff, since that indicates a compiled-in breakpoint which
+	   will not be replaced (and we would retake the trap forever) */
+	if ((excep_code == TRAP_VEC) && (trapa_value != (0xff << 2))) {
+		trap_registers.pc -= 2;
+	}
+
+	/* Undo any stepping we may have done */
+	undo_single_step();
+
+	while (1) {
+
+		out_buffer[0] = 0;
+		get_packet(in_buffer, BUFMAX);
+
+		/* Examine first char of buffer to see what we need to do */
+		switch (in_buffer[0]) {
+
+		case '?':	/* Send which signal we've received */
+			send_signal_msg(sigval);
+			break;
+
+		case 'g':	/* Return the values of the CPU registers */
+			send_regs_msg();
+			break;
+
+		case 'G':	/* Set the value of the CPU registers */
+			set_regs_msg();
+			break;
+
+		case 'm':	/* Read LLLL bytes address AA..AA */
+			read_mem_msg();
+			break;
+
+		case 'M':	/* Write LLLL bytes address AA..AA, ret OK */
+			write_mem_msg(0);	/* 0 = data in hex */
+			break;
+
+		case 'X':	/* Write LLLL bytes esc bin address AA..AA */
+			if (kgdb_bits == '8')
+				write_mem_msg(1); /* 1 = data in binary */
+			else
+				send_empty_msg();
+			break;
+
+		case 'C':	/* Continue, signum included, we ignore it */
+			continue_with_sig_msg();
+			return;
+
+		case 'c':	/* Continue at address AA..AA (optional) */
+			continue_msg();
+			return;
+
+		case 'S':	/* Step, signum included, we ignore it */
+			step_with_sig_msg();
+			return;
+
+		case 's':	/* Step one instruction from AA..AA */
+			step_msg();
+			return;
+
+#ifdef CONFIG_KGDB_THREAD
+
+		case 'H':	/* Task related */
+			set_thread_msg();
+			break;
+
+		case 'T':	/* Query thread status */
+			thread_status_msg();
+			break;
+
+		case 'q':	/* Handle query - currently thread-related */
+			query_msg();
+			break;
+#endif
+
+		case 'k':	/* 'Kill the program' with a kernel ? */
+			break;
+
+		case 'D':	/* Detach from program, send reply OK */
+			kgdb_in_gdb_mode = 0;
+			send_ok_msg();
+			get_debug_char();
+			return;
+
+		default:
+			send_empty_msg();
+			break;
+		}
+	}
+}
+
+/* There has been an exception, most likely a breakpoint. */
+void kgdb_handle_exception(struct pt_regs *regs)
+{
+	int excep_code, vbr_val;
+	int count;
+	int trapa_value = ctrl_inl(TRA);
+
+	/* Copy kernel regs (from stack) */
+	for (count = 0; count < 16; count++)
+		trap_registers.regs[count] = regs->regs[count];
+	trap_registers.pc = regs->pc;
+	trap_registers.pr = regs->pr;
+	trap_registers.sr = regs->sr;
+	trap_registers.gbr = regs->gbr;
+	trap_registers.mach = regs->mach;
+	trap_registers.macl = regs->macl;
+
+	asm("stc vbr, %0":"=r"(vbr_val));
+	trap_registers.vbr = vbr_val;
+
+	/* Get excode for command loop call, user access */
+	asm("stc r2_bank, %0":"=r"(excep_code));
+	kgdb_excode = excep_code;
+
+	/* Other interesting environment items for reference */
+	asm("stc r6_bank, %0":"=r"(kgdb_g_imask));
+	kgdb_current = current;
+	kgdb_trapa_val = trapa_value;
+
+	/* Act on the exception */
+	kgdb_command_loop(excep_code >> 5, trapa_value);
+
+	kgdb_current = NULL;
+
+	/* Copy back the (maybe modified) registers */
+	for (count = 0; count < 16; count++)
+		regs->regs[count] = trap_registers.regs[count];
+	regs->pc = trap_registers.pc;
+	regs->pr = trap_registers.pr;
+	regs->sr = trap_registers.sr;
+	regs->gbr = trap_registers.gbr;
+	regs->mach = trap_registers.mach;
+	regs->macl = trap_registers.macl;
+
+	vbr_val = trap_registers.vbr;
+	asm("ldc %0, vbr": :"r"(vbr_val));
+
+	return;
+}
+
+/* Trigger a breakpoint by function */
+void breakpoint(void)
+{
+	if (!kgdb_enabled) {
+		kgdb_enabled = 1;
+		kgdb_init();
+	}
+	BREAKPOINT();
+}
+
+/* Initialise the KGDB data structures and serial configuration */
+int kgdb_init(void)
+{
+	if (!kgdb_enabled)
+		return 1;
+
+	in_nmi = 0;
+	kgdb_nofault = 0;
+	stepped_opcode = 0;
+	kgdb_in_gdb_mode = 0;
+
+	if (kgdb_serial_setup() != 0) {
+		KGDB_PRINTK("serial setup error\n");
+		return -1;
+	}
+
+	/* Init ptr to exception handler */
+	kgdb_debug_hook = kgdb_handle_exception;
+	kgdb_bus_err_hook = kgdb_handle_bus_error;
+
+	/* Enter kgdb now if requested, or just report init done */
+	if (kgdb_halt) {
+		kgdb_in_gdb_mode = 1;
+		put_debug_char('+');
+		breakpoint();
+	}
+	else
+	{
+		KGDB_PRINTK("stub is initialized.\n");
+	}
+
+	return 0;
+}
+
+/* Make function available for "user messages"; console will use it too. */
+
+char gdbmsgbuf[BUFMAX];
+#define MAXOUT ((BUFMAX-2)/2)
+
+static void kgdb_msg_write(const char *s, unsigned count)
+{
+	int i;
+	int wcount;
+	char *bufptr;
+
+	/* 'O'utput */
+	gdbmsgbuf[0] = 'O';
+
+	/* Fill and send buffers... */
+	while (count > 0) {
+		bufptr = gdbmsgbuf + 1;
+
+		/* Calculate how many this time */
+		wcount = (count > MAXOUT) ? MAXOUT : count;
+		
+		/* Pack in hex chars */
+		for (i = 0; i < wcount; i++)
+			bufptr = pack_hex_byte(bufptr, s[i]);
+		*bufptr = '\0';
+
+		/* Move up */
+		s += wcount;
+		count -= wcount;
+
+		/* Write packet */
+		put_packet(gdbmsgbuf);
+	}
+}
+
+static void kgdb_to_gdb(const char *s)
+{
+	kgdb_msg_write(s, strlen(s));
+}
+
+#ifdef CONFIG_SH_KGDB_CONSOLE
+void kgdb_console_write(struct console *co, const char *s, unsigned count)
+{
+	/* Bail if we're not talking to GDB */
+	if (!kgdb_in_gdb_mode)
+		return;
+
+	kgdb_msg_write(s, count);
+}
+#endif
diff --git a/arch/sh/kernel/module.c b/arch/sh/kernel/module.c
new file mode 100644
index 0000000..142a4e5
--- /dev/null
+++ b/arch/sh/kernel/module.c
@@ -0,0 +1,146 @@
+/*  Kernel module help for SH.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+#include <linux/moduleloader.h>
+#include <linux/elf.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(fmt...)
+#endif
+
+void *module_alloc(unsigned long size)
+{
+	if (size == 0)
+		return NULL;
+	return vmalloc(size);
+}
+
+
+/* Free memory returned from module_alloc */
+void module_free(struct module *mod, void *module_region)
+{
+	vfree(module_region);
+	/* FIXME: If module_region == mod->init_region, trim exception
+           table entries. */
+}
+
+/* We don't need anything special. */
+int module_frob_arch_sections(Elf_Ehdr *hdr,
+			      Elf_Shdr *sechdrs,
+			      char *secstrings,
+			      struct module *mod)
+{
+	return 0;
+}
+
+#define COPY_UNALIGNED_WORD(sw, tw, align) \
+{ \
+	void *__s = &(sw), *__t = &(tw); \
+	unsigned short *__s2 = __s, *__t2 = __t; \
+	unsigned char *__s1 = __s, *__t1 = __t; \
+	switch ((align)) \
+	{ \
+	case 0: \
+		*(unsigned long *) __t = *(unsigned long *) __s; \
+		break; \
+	case 2: \
+		*__t2++ = *__s2++; \
+		*__t2 = *__s2; \
+		break; \
+	default: \
+		*__t1++ = *__s1++; \
+		*__t1++ = *__s1++; \
+		*__t1++ = *__s1++; \
+		*__t1 = *__s1; \
+		break; \
+	} \
+}
+
+int apply_relocate_add(Elf32_Shdr *sechdrs,
+		   const char *strtab,
+		   unsigned int symindex,
+		   unsigned int relsec,
+		   struct module *me)
+{
+	unsigned int i;
+	Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
+	Elf32_Sym *sym;
+	Elf32_Addr relocation;
+	uint32_t *location;
+	uint32_t value;
+	int align;
+
+	DEBUGP("Applying relocate section %u to %u\n", relsec,
+	       sechdrs[relsec].sh_info);
+	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
+		/* This is where to make the change */
+		location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+			+ rel[i].r_offset;
+		/* This is the symbol it is referring to.  Note that all
+		   undefined symbols have been resolved.  */
+		sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
+			+ ELF32_R_SYM(rel[i].r_info);
+		relocation = sym->st_value + rel[i].r_addend;
+		align = (int)location & 3;
+
+		switch (ELF32_R_TYPE(rel[i].r_info)) {
+		case R_SH_DIR32:
+	    		COPY_UNALIGNED_WORD (*location, value, align);
+			value += relocation;
+	    		COPY_UNALIGNED_WORD (value, *location, align);
+			break;
+		case R_SH_REL32:
+	  		relocation = (relocation - (Elf32_Addr) location);
+	    		COPY_UNALIGNED_WORD (*location, value, align);
+			value += relocation;
+	    		COPY_UNALIGNED_WORD (value, *location, align);
+			break;
+		default:
+			printk(KERN_ERR "module %s: Unknown relocation: %u\n",
+			       me->name, ELF32_R_TYPE(rel[i].r_info));
+			return -ENOEXEC;
+		}
+	}
+	return 0;
+}
+
+int apply_relocate(Elf32_Shdr *sechdrs,
+		       const char *strtab,
+		       unsigned int symindex,
+		       unsigned int relsec,
+		       struct module *me)
+{
+	printk(KERN_ERR "module %s: REL RELOCATION unsupported\n",
+	       me->name);
+	return -ENOEXEC;
+}
+
+int module_finalize(const Elf_Ehdr *hdr,
+		    const Elf_Shdr *sechdrs,
+		    struct module *me)
+{
+	return 0;
+}
+
+void module_arch_cleanup(struct module *mod)
+{
+}
diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c
new file mode 100644
index 0000000..3d02459
--- /dev/null
+++ b/arch/sh/kernel/process.c
@@ -0,0 +1,531 @@
+/* $Id: process.c,v 1.28 2004/05/05 16:54:23 lethal Exp $
+ *
+ *  linux/arch/sh/kernel/process.c
+ *
+ *  Copyright (C) 1995  Linus Torvalds
+ *
+ *  SuperH version:  Copyright (C) 1999, 2000  Niibe Yutaka & Kaz Kojima
+ */
+
+/*
+ * This file handles the architecture-dependent parts of process handling..
+ */
+
+#include <linux/module.h>
+#include <linux/unistd.h>
+#include <linux/mm.h>
+#include <linux/elfcore.h>
+#include <linux/slab.h>
+#include <linux/a.out.h>
+#include <linux/ptrace.h>
+#include <linux/platform.h>
+#include <linux/kallsyms.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/mmu_context.h>
+#include <asm/elf.h>
+#if defined(CONFIG_SH_HS7751RVOIP)
+#include <asm/hs7751rvoip/hs7751rvoip.h>
+#elif defined(CONFIG_SH_RTS7751R2D)
+#include <asm/rts7751r2d/rts7751r2d.h>
+#endif
+
+static int hlt_counter=0;
+
+int ubc_usercnt = 0;
+
+#define HARD_IDLE_TIMEOUT (HZ / 3)
+
+void disable_hlt(void)
+{
+	hlt_counter++;
+}
+
+EXPORT_SYMBOL(disable_hlt);
+
+void enable_hlt(void)
+{
+	hlt_counter--;
+}
+
+EXPORT_SYMBOL(enable_hlt);
+
+void default_idle(void)
+{
+	/* endless idle loop with no priority at all */
+	while (1) {
+		if (hlt_counter) {
+			while (1)
+				if (need_resched())
+					break;
+		} else {
+			while (!need_resched())
+				cpu_sleep();
+		}
+
+		schedule();
+	}
+}
+
+void cpu_idle(void)
+{
+	default_idle();
+}
+
+void machine_restart(char * __unused)
+{
+	/* SR.BL=1 and invoke address error to let CPU reset (manual reset) */
+	asm volatile("ldc %0, sr\n\t"
+		     "mov.l @%1, %0" : : "r" (0x10000000), "r" (0x80000001));
+}
+
+EXPORT_SYMBOL(machine_restart);
+
+void machine_halt(void)
+{
+#if defined(CONFIG_SH_HS7751RVOIP)
+	unsigned short value;
+
+	value = ctrl_inw(PA_OUTPORTR);
+	ctrl_outw((value & 0xffdf), PA_OUTPORTR);
+#elif defined(CONFIG_SH_RTS7751R2D)
+	ctrl_outw(0x0001, PA_POWOFF);
+#endif
+	while (1)
+		cpu_sleep();
+}
+
+EXPORT_SYMBOL(machine_halt);
+
+void machine_power_off(void)
+{
+#if defined(CONFIG_SH_HS7751RVOIP)
+	unsigned short value;
+
+	value = ctrl_inw(PA_OUTPORTR);
+	ctrl_outw((value & 0xffdf), PA_OUTPORTR);
+#elif defined(CONFIG_SH_RTS7751R2D)
+	ctrl_outw(0x0001, PA_POWOFF);
+#endif
+}
+
+EXPORT_SYMBOL(machine_power_off);
+
+void show_regs(struct pt_regs * regs)
+{
+	printk("\n");
+	printk("Pid : %d, Comm: %20s\n", current->pid, current->comm);
+	print_symbol("PC is at %s\n", regs->pc);
+	printk("PC  : %08lx SP  : %08lx SR  : %08lx ",
+	       regs->pc, regs->regs[15], regs->sr);
+#ifdef CONFIG_MMU
+	printk("TEA : %08x    ", ctrl_inl(MMU_TEA));
+#else
+	printk("                  ");
+#endif
+	printk("%s\n", print_tainted());
+
+	printk("R0  : %08lx R1  : %08lx R2  : %08lx R3  : %08lx\n",
+	       regs->regs[0],regs->regs[1],
+	       regs->regs[2],regs->regs[3]);
+	printk("R4  : %08lx R5  : %08lx R6  : %08lx R7  : %08lx\n",
+	       regs->regs[4],regs->regs[5],
+	       regs->regs[6],regs->regs[7]);
+	printk("R8  : %08lx R9  : %08lx R10 : %08lx R11 : %08lx\n",
+	       regs->regs[8],regs->regs[9],
+	       regs->regs[10],regs->regs[11]);
+	printk("R12 : %08lx R13 : %08lx R14 : %08lx\n",
+	       regs->regs[12],regs->regs[13],
+	       regs->regs[14]);
+	printk("MACH: %08lx MACL: %08lx GBR : %08lx PR  : %08lx\n",
+	       regs->mach, regs->macl, regs->gbr, regs->pr);
+
+	/*
+	 * If we're in kernel mode, dump the stack too..
+	 */
+	if (!user_mode(regs)) {
+		extern void show_task(unsigned long *sp);
+		unsigned long sp = regs->regs[15];
+
+		show_task((unsigned long *)sp);
+	}
+}
+
+/*
+ * Create a kernel thread
+ */
+
+/*
+ * This is the mechanism for creating a new kernel thread.
+ *
+ */
+extern void kernel_thread_helper(void);
+__asm__(".align 5\n"
+	"kernel_thread_helper:\n\t"
+	"jsr	@r5\n\t"
+	" nop\n\t"
+	"mov.l	1f, r1\n\t"
+	"jsr	@r1\n\t"
+	" mov	r0, r4\n\t"
+	".align 2\n\t"
+	"1:.long do_exit");
+
+int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+{	/* Don't use this in BL=1(cli).  Or else, CPU resets! */
+	struct pt_regs regs;
+
+	memset(&regs, 0, sizeof(regs));
+	regs.regs[4] = (unsigned long) arg;
+	regs.regs[5] = (unsigned long) fn;
+
+	regs.pc = (unsigned long) kernel_thread_helper;
+	regs.sr = (1 << 30);
+
+	/* Ok, create the new process.. */
+	return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
+}
+
+/*
+ * Free current thread data structures etc..
+ */
+void exit_thread(void)
+{
+	if (current->thread.ubc_pc) {
+		current->thread.ubc_pc = 0;
+		ubc_usercnt -= 1;
+	}
+}
+
+void flush_thread(void)
+{
+#if defined(CONFIG_SH_FPU)
+	struct task_struct *tsk = current;
+	struct pt_regs *regs = (struct pt_regs *)
+				((unsigned long)tsk->thread_info
+				 + THREAD_SIZE - sizeof(struct pt_regs)
+				 - sizeof(unsigned long));
+
+	/* Forget lazy FPU state */
+	clear_fpu(tsk, regs);
+	clear_used_math();
+#endif
+}
+
+void release_thread(struct task_struct *dead_task)
+{
+	/* do nothing */
+}
+
+/* Fill in the fpu structure for a core dump.. */
+int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
+{
+	int fpvalid = 0;
+
+#if defined(CONFIG_SH_FPU)
+	struct task_struct *tsk = current;
+
+	fpvalid = !!tsk_used_math(tsk);
+	if (fpvalid) {
+		unlazy_fpu(tsk, regs);
+		memcpy(fpu, &tsk->thread.fpu.hard, sizeof(*fpu));
+	}
+#endif
+
+	return fpvalid;
+}
+
+/* 
+ * Capture the user space registers if the task is not running (in user space)
+ */
+int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs)
+{
+	struct pt_regs ptregs;
+	
+	ptregs = *(struct pt_regs *)
+		((unsigned long)tsk->thread_info + THREAD_SIZE
+		 - sizeof(struct pt_regs)
+#ifdef CONFIG_SH_DSP
+		 - sizeof(struct pt_dspregs)
+#endif
+		 - sizeof(unsigned long));
+	elf_core_copy_regs(regs, &ptregs);
+
+	return 1;
+}
+
+int
+dump_task_fpu (struct task_struct *tsk, elf_fpregset_t *fpu)
+{
+	int fpvalid = 0;
+
+#if defined(CONFIG_SH_FPU)
+	fpvalid = !!tsk_used_math(tsk);
+	if (fpvalid) {
+		struct pt_regs *regs = (struct pt_regs *)
+					((unsigned long)tsk->thread_info
+					 + THREAD_SIZE - sizeof(struct pt_regs)
+					 - sizeof(unsigned long));
+		unlazy_fpu(tsk, regs);
+		memcpy(fpu, &tsk->thread.fpu.hard, sizeof(*fpu));
+	}
+#endif
+
+	return fpvalid;
+}
+
+asmlinkage void ret_from_fork(void);
+
+int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+		unsigned long unused,
+		struct task_struct *p, struct pt_regs *regs)
+{
+	struct pt_regs *childregs;
+#if defined(CONFIG_SH_FPU)
+	struct task_struct *tsk = current;
+
+	unlazy_fpu(tsk, regs);
+	p->thread.fpu = tsk->thread.fpu;
+	copy_to_stopped_child_used_math(p);
+#endif
+
+	childregs = ((struct pt_regs *)
+		(THREAD_SIZE + (unsigned long) p->thread_info)
+#ifdef CONFIG_SH_DSP
+		- sizeof(struct pt_dspregs)
+#endif
+		- sizeof(unsigned long)) - 1;
+	*childregs = *regs;
+
+	if (user_mode(regs)) {
+		childregs->regs[15] = usp;
+	} else {
+		childregs->regs[15] = (unsigned long)p->thread_info + THREAD_SIZE;
+	}
+        if (clone_flags & CLONE_SETTLS) {
+		childregs->gbr = childregs->regs[0];
+	}
+	childregs->regs[0] = 0; /* Set return value for child */
+
+	p->thread.sp = (unsigned long) childregs;
+	p->thread.pc = (unsigned long) ret_from_fork;
+
+	p->thread.ubc_pc = 0;
+
+	return 0;
+}
+
+/*
+ * fill in the user structure for a core dump..
+ */
+void dump_thread(struct pt_regs * regs, struct user * dump)
+{
+	dump->magic = CMAGIC;
+	dump->start_code = current->mm->start_code;
+	dump->start_data  = current->mm->start_data;
+	dump->start_stack = regs->regs[15] & ~(PAGE_SIZE - 1);
+	dump->u_tsize = (current->mm->end_code - dump->start_code) >> PAGE_SHIFT;
+	dump->u_dsize = (current->mm->brk + (PAGE_SIZE-1) - dump->start_data) >> PAGE_SHIFT;
+	dump->u_ssize = (current->mm->start_stack - dump->start_stack +
+			 PAGE_SIZE - 1) >> PAGE_SHIFT;
+	/* Debug registers will come here. */
+
+	dump->regs = *regs;
+
+	dump->u_fpvalid = dump_fpu(regs, &dump->fpu);
+}
+
+/* Tracing by user break controller.  */
+static void
+ubc_set_tracing(int asid, unsigned long pc)
+{
+	ctrl_outl(pc, UBC_BARA);
+
+	/* We don't have any ASID settings for the SH-2! */
+	if (cpu_data->type != CPU_SH7604)
+		ctrl_outb(asid, UBC_BASRA);
+
+	ctrl_outl(0, UBC_BAMRA);
+
+	if (cpu_data->type == CPU_SH7729) {
+		ctrl_outw(BBR_INST | BBR_READ | BBR_CPU, UBC_BBRA);
+		ctrl_outl(BRCR_PCBA | BRCR_PCTE, UBC_BRCR);
+	} else {
+		ctrl_outw(BBR_INST | BBR_READ, UBC_BBRA);
+		ctrl_outw(BRCR_PCBA, UBC_BRCR);
+	}
+}
+
+/*
+ *	switch_to(x,y) should switch tasks from x to y.
+ *
+ */
+struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *next)
+{
+#if defined(CONFIG_SH_FPU)
+	struct pt_regs *regs = (struct pt_regs *)
+				((unsigned long)prev->thread_info
+				 + THREAD_SIZE - sizeof(struct pt_regs)
+				 - sizeof(unsigned long));
+	unlazy_fpu(prev, regs);
+#endif
+
+#ifdef CONFIG_PREEMPT
+	{
+		unsigned long flags;
+		struct pt_regs *regs;
+
+		local_irq_save(flags);
+		regs = (struct pt_regs *)
+			((unsigned long)prev->thread_info
+			 + THREAD_SIZE - sizeof(struct pt_regs)
+#ifdef CONFIG_SH_DSP
+			 - sizeof(struct pt_dspregs)
+#endif
+			 - sizeof(unsigned long));
+		if (user_mode(regs) && regs->regs[15] >= 0xc0000000) {
+			int offset = (int)regs->regs[15];
+
+			/* Reset stack pointer: clear critical region mark */
+			regs->regs[15] = regs->regs[1];
+			if (regs->pc < regs->regs[0])
+				/* Go to rewind point */
+				regs->pc = regs->regs[0] + offset;
+		}
+		local_irq_restore(flags);
+	}
+#endif
+
+	/*
+	 * Restore the kernel mode register
+	 *   	k7 (r7_bank1)
+	 */
+	asm volatile("ldc	%0, r7_bank"
+		     : /* no output */
+		     : "r" (next->thread_info));
+
+#ifdef CONFIG_MMU
+	/* If no tasks are using the UBC, we're done */
+	if (ubc_usercnt == 0)
+		/* If no tasks are using the UBC, we're done */;
+	else if (next->thread.ubc_pc && next->mm) {
+		ubc_set_tracing(next->mm->context & MMU_CONTEXT_ASID_MASK,
+				next->thread.ubc_pc);
+	} else {
+		ctrl_outw(0, UBC_BBRA);
+		ctrl_outw(0, UBC_BBRB);
+	}
+#endif
+
+	return prev;
+}
+
+asmlinkage int sys_fork(unsigned long r4, unsigned long r5,
+			unsigned long r6, unsigned long r7,
+			struct pt_regs regs)
+{
+#ifdef CONFIG_MMU
+	return do_fork(SIGCHLD, regs.regs[15], &regs, 0, NULL, NULL);
+#else
+	/* fork almost works, enough to trick you into looking elsewhere :-( */
+	return -EINVAL;
+#endif
+}
+
+asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
+			 unsigned long parent_tidptr,
+			 unsigned long child_tidptr,
+			 struct pt_regs regs)
+{
+	if (!newsp)
+		newsp = regs.regs[15];
+	return do_fork(clone_flags, newsp, &regs, 0,
+			(int __user *)parent_tidptr, (int __user *)child_tidptr);
+}
+
+/*
+ * This is trivial, and on the face of it looks like it
+ * could equally well be done in user mode.
+ *
+ * Not so, for quite unobvious reasons - register pressure.
+ * In user mode vfork() cannot have a stack frame, and if
+ * done by calling the "clone()" system call directly, you
+ * do not have enough call-clobbered registers to hold all
+ * the information you need.
+ */
+asmlinkage int sys_vfork(unsigned long r4, unsigned long r5,
+			 unsigned long r6, unsigned long r7,
+			 struct pt_regs regs)
+{
+	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.regs[15], &regs,
+		       0, NULL, NULL);
+}
+
+/*
+ * sys_execve() executes a new program.
+ */
+asmlinkage int sys_execve(char *ufilename, char **uargv,
+			  char **uenvp, unsigned long r7,
+			  struct pt_regs regs)
+{
+	int error;
+	char *filename;
+
+	filename = getname((char __user *)ufilename);
+	error = PTR_ERR(filename);
+	if (IS_ERR(filename))
+		goto out;
+
+	error = do_execve(filename,
+			  (char __user * __user *)uargv,
+			  (char __user * __user *)uenvp,
+			  &regs);
+	if (error == 0) {
+		task_lock(current);
+		current->ptrace &= ~PT_DTRACE;
+		task_unlock(current);
+	}
+	putname(filename);
+out:
+	return error;
+}
+
+unsigned long get_wchan(struct task_struct *p)
+{
+	unsigned long schedule_frame;
+	unsigned long pc;
+
+	if (!p || p == current || p->state == TASK_RUNNING)
+		return 0;
+
+	/*
+	 * The same comment as on the Alpha applies here, too ...
+	 */
+	pc = thread_saved_pc(p);
+	if (in_sched_functions(pc)) {
+		schedule_frame = ((unsigned long *)(long)p->thread.sp)[1];
+		return (unsigned long)((unsigned long *)schedule_frame)[1];
+	}
+	return pc;
+}
+
+asmlinkage void break_point_trap(unsigned long r4, unsigned long r5,
+				 unsigned long r6, unsigned long r7,
+				 struct pt_regs regs)
+{
+	/* Clear tracing.  */
+	ctrl_outw(0, UBC_BBRA);
+	ctrl_outw(0, UBC_BBRB);
+	current->thread.ubc_pc = 0;
+	ubc_usercnt -= 1;
+
+	force_sig(SIGTRAP, current);
+}
+
+asmlinkage void break_point_trap_software(unsigned long r4, unsigned long r5,
+					  unsigned long r6, unsigned long r7,
+					  struct pt_regs regs)
+{
+	regs.pc -= 2;
+	force_sig(SIGTRAP, current);
+}
diff --git a/arch/sh/kernel/ptrace.c b/arch/sh/kernel/ptrace.c
new file mode 100644
index 0000000..1b0dfb4
--- /dev/null
+++ b/arch/sh/kernel/ptrace.c
@@ -0,0 +1,320 @@
+/*
+ * linux/arch/sh/kernel/ptrace.c
+ *
+ * Original x86 implementation:
+ *	By Ross Biro 1/23/92
+ *	edited by Linus Torvalds
+ *
+ * SuperH version:   Copyright (C) 1999, 2000  Kaz Kojima & Niibe Yutaka
+ *
+ */
+
+#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/errno.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+#include <linux/slab.h>
+#include <linux/security.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/processor.h>
+#include <asm/mmu_context.h>
+
+/*
+ * does not yet catch signals sent when the child dies.
+ * in exit.c or in signal.c.
+ */
+
+/*
+ * This routine will get a word off of the process kernel stack.
+ */
+static inline int get_stack_long(struct task_struct *task, int offset)
+{
+	unsigned char *stack;
+
+	stack = (unsigned char *)
+		task->thread_info + THREAD_SIZE	- sizeof(struct pt_regs)
+#ifdef CONFIG_SH_DSP
+		- sizeof(struct pt_dspregs)
+#endif
+		- sizeof(unsigned long);
+	stack += offset;
+	return (*((int *)stack));
+}
+
+/*
+ * This routine will put a word on the process kernel stack.
+ */
+static inline int put_stack_long(struct task_struct *task, int offset,
+				 unsigned long data)
+{
+	unsigned char *stack;
+
+	stack = (unsigned char *)
+		task->thread_info + THREAD_SIZE - sizeof(struct pt_regs)
+#ifdef CONFIG_SH_DSP
+		- sizeof(struct pt_dspregs)
+#endif
+		- sizeof(unsigned long);
+	stack += offset;
+	*(unsigned long *) stack = data;
+	return 0;
+}
+
+/*
+ * Called by kernel/ptrace.c when detaching..
+ *
+ * Make sure single step bits etc are not set.
+ */
+void ptrace_disable(struct task_struct *child)
+{
+	/* nothing to do.. */
+}
+
+asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
+{
+	struct task_struct *child;
+	struct user * dummy = NULL;
+	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)
+		goto out_tsk;
+
+	switch (request) {
+	/* when I and D space are separate, these will need to be fixed. */
+	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
+	case PTRACE_PEEKDATA: {
+		unsigned long tmp;
+		int copied;
+
+		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+		ret = -EIO;
+		if (copied != sizeof(tmp))
+			break;
+		ret = put_user(tmp,(unsigned long *) data);
+		break;
+	}
+
+	/* read the word at location addr in the USER area. */
+	case PTRACE_PEEKUSR: {
+		unsigned long tmp;
+
+		ret = -EIO;
+		if ((addr & 3) || addr < 0 || 
+		    addr > sizeof(struct user) - 3)
+			break;
+
+		if (addr < sizeof(struct pt_regs))
+			tmp = get_stack_long(child, addr);
+		else if (addr >= (long) &dummy->fpu &&
+			 addr < (long) &dummy->u_fpvalid) {
+			if (!tsk_used_math(child)) {
+				if (addr == (long)&dummy->fpu.fpscr)
+					tmp = FPSCR_INIT;
+				else
+					tmp = 0;
+			} else
+				tmp = ((long *)&child->thread.fpu)
+					[(addr - (long)&dummy->fpu) >> 2];
+		} else if (addr == (long) &dummy->u_fpvalid)
+			tmp = !!tsk_used_math(child);
+		else
+			tmp = 0;
+		ret = put_user(tmp, (unsigned long *)data);
+		break;
+	}
+
+	/* when I and D space are separate, this will have to be fixed. */
+	case PTRACE_POKETEXT: /* write the word at location addr. */
+	case PTRACE_POKEDATA:
+		ret = 0;
+		if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
+			break;
+		ret = -EIO;
+		break;
+
+	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
+		ret = -EIO;
+		if ((addr & 3) || addr < 0 || 
+		    addr > sizeof(struct user) - 3)
+			break;
+
+		if (addr < sizeof(struct pt_regs))
+			ret = put_stack_long(child, addr, data);
+		else if (addr >= (long) &dummy->fpu &&
+			 addr < (long) &dummy->u_fpvalid) {
+			set_stopped_child_used_math(child);
+			((long *)&child->thread.fpu)
+				[(addr - (long)&dummy->fpu) >> 2] = data;
+			ret = 0;
+		} else if (addr == (long) &dummy->u_fpvalid) {
+			conditional_stopped_child_used_math(data, child);
+			ret = 0;
+		}
+		break;
+
+	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+	case PTRACE_CONT: { /* restart after signal. */
+		ret = -EIO;
+		if ((unsigned long) data > _NSIG)
+			break;
+		if (request == PTRACE_SYSCALL)
+			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+		else
+			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+		child->exit_code = data;
+		wake_up_process(child);
+		ret = 0;
+		break;
+	}
+
+/*
+ * make the child exit.  Best I can do is send it a sigkill. 
+ * perhaps it should be put in the status that it wants to 
+ * exit.
+ */
+	case PTRACE_KILL: {
+		ret = 0;
+		if (child->exit_state == EXIT_ZOMBIE)	/* already dead */
+			break;
+		child->exit_code = SIGKILL;
+		wake_up_process(child);
+		break;
+	}
+
+	case PTRACE_SINGLESTEP: {  /* set the trap flag. */
+		long pc;
+		struct pt_regs *dummy = NULL;
+
+		ret = -EIO;
+		if ((unsigned long) data > _NSIG)
+			break;
+		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+		if ((child->ptrace & PT_DTRACE) == 0) {
+			/* Spurious delayed TF traps may occur */
+			child->ptrace |= PT_DTRACE;
+		}
+
+		pc = get_stack_long(child, (long)&dummy->pc);
+
+		/* Next scheduling will set up UBC */
+		if (child->thread.ubc_pc == 0)
+			ubc_usercnt += 1;
+		child->thread.ubc_pc = pc;
+
+		child->exit_code = data;
+		/* give it a chance to run. */
+		wake_up_process(child);
+		ret = 0;
+		break;
+	}
+
+	case PTRACE_DETACH: /* detach a process that was attached. */
+		ret = ptrace_detach(child, data);
+		break;
+
+#ifdef CONFIG_SH_DSP
+	case PTRACE_GETDSPREGS: {
+		unsigned long dp;
+
+		ret = -EIO;
+		dp = ((unsigned long) child) + THREAD_SIZE -
+			 sizeof(struct pt_dspregs);
+		if (*((int *) (dp - 4)) == SR_FD) {
+			copy_to_user(addr, (void *) dp,
+				sizeof(struct pt_dspregs));
+			ret = 0;
+		}
+		break;
+	}
+
+	case PTRACE_SETDSPREGS: {
+		unsigned long dp;
+		int i;
+
+		ret = -EIO;
+		dp = ((unsigned long) child) + THREAD_SIZE -
+			 sizeof(struct pt_dspregs);
+		if (*((int *) (dp - 4)) == SR_FD) {
+			copy_from_user((void *) dp, addr,
+				sizeof(struct pt_dspregs));
+			ret = 0;
+		}
+		break;
+	}
+#endif
+	default:
+		ret = ptrace_request(child, request, addr, data);
+		break;
+	}
+out_tsk:
+	put_task_struct(child);
+out:
+	unlock_kernel();
+	return ret;
+}
+
+asmlinkage void do_syscall_trace(void)
+{
+	struct task_struct *tsk = current;
+
+	if (!test_thread_flag(TIF_SYSCALL_TRACE))
+		return;
+	if (!(tsk->ptrace & PT_PTRACED))
+		return;
+	/* the 0x80 provides a way for the tracing parent to distinguish
+	   between a syscall stop and SIGTRAP delivery */
+	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+				 ? 0x80 : 0));
+
+	/*
+	 * this isn't the same as continuing with a signal, but it will do
+	 * for normal use.  strace only continues with a signal if the
+	 * stopping signal is not SIGTRAP.  -brl
+	 */
+	if (tsk->exit_code) {
+		send_sig(tsk->exit_code, tsk, 1);
+		tsk->exit_code = 0;
+	}
+}
diff --git a/arch/sh/kernel/semaphore.c b/arch/sh/kernel/semaphore.c
new file mode 100644
index 0000000..a3c24dc
--- /dev/null
+++ b/arch/sh/kernel/semaphore.c
@@ -0,0 +1,139 @@
+/*
+ * Just taken from alpha implementation.
+ * This can't work well, perhaps.
+ */
+/*
+ *  Generic semaphore code. Buyer beware. Do your own
+ * specific changes in <asm/semaphore-helper.h>
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/init.h>
+#include <asm/semaphore.h>
+#include <asm/semaphore-helper.h>
+
+spinlock_t semaphore_wake_lock;
+
+/*
+ * Semaphores are implemented using a two-way counter:
+ * The "count" variable is decremented for each process
+ * that tries to sleep, while the "waking" variable is
+ * incremented when the "up()" code goes to wake up waiting
+ * processes.
+ *
+ * Notably, the inline "up()" and "down()" functions can
+ * efficiently test if they need to do any extra work (up
+ * needs to do something only if count was negative before
+ * the increment operation.
+ *
+ * waking_non_zero() (from asm/semaphore.h) must execute
+ * atomically.
+ *
+ * When __up() is called, the count was negative before
+ * incrementing it, and we need to wake up somebody.
+ *
+ * This routine adds one to the count of processes that need to
+ * wake up and exit.  ALL waiting processes actually wake up but
+ * only the one that gets to the "waking" field first will gate
+ * through and acquire the semaphore.  The others will go back
+ * to sleep.
+ *
+ * Note that these functions are only called when there is
+ * contention on the lock, and as such all this is the
+ * "non-critical" part of the whole semaphore business. The
+ * critical part is the inline stuff in <asm/semaphore.h>
+ * where we want to avoid any extra jumps and calls.
+ */
+void __up(struct semaphore *sem)
+{
+	wake_one_more(sem);
+	wake_up(&sem->wait);
+}
+
+/*
+ * Perform the "down" function.  Return zero for semaphore acquired,
+ * return negative for signalled out of the function.
+ *
+ * If called from __down, the return is ignored and the wait loop is
+ * not interruptible.  This means that a task waiting on a semaphore
+ * using "down()" cannot be killed until someone does an "up()" on
+ * the semaphore.
+ *
+ * If called from __down_interruptible, the return value gets checked
+ * upon return.  If the return value is negative then the task continues
+ * with the negative value in the return register (it can be tested by
+ * the caller).
+ *
+ * Either form may be used in conjunction with "up()".
+ *
+ */
+
+#define DOWN_VAR				\
+	struct task_struct *tsk = current;	\
+	wait_queue_t wait;			\
+	init_waitqueue_entry(&wait, tsk);
+
+#define DOWN_HEAD(task_state)						\
+									\
+									\
+	tsk->state = (task_state);					\
+	add_wait_queue(&sem->wait, &wait);				\
+									\
+	/*								\
+	 * Ok, we're set up.  sem->count is known to be less than zero	\
+	 * so we must wait.						\
+	 *								\
+	 * We can let go the lock for purposes of waiting.		\
+	 * We re-acquire it after awaking so as to protect		\
+	 * all semaphore operations.					\
+	 *								\
+	 * If "up()" is called before we call waking_non_zero() then	\
+	 * we will catch it right away.  If it is called later then	\
+	 * we will have to go through a wakeup cycle to catch it.	\
+	 *								\
+	 * Multiple waiters contend for the semaphore lock to see	\
+	 * who gets to gate through and who has to wait some more.	\
+	 */								\
+	for (;;) {
+
+#define DOWN_TAIL(task_state)			\
+		tsk->state = (task_state);	\
+	}					\
+	tsk->state = TASK_RUNNING;		\
+	remove_wait_queue(&sem->wait, &wait);
+
+void __sched __down(struct semaphore * sem)
+{
+	DOWN_VAR
+	DOWN_HEAD(TASK_UNINTERRUPTIBLE)
+	if (waking_non_zero(sem))
+		break;
+	schedule();
+	DOWN_TAIL(TASK_UNINTERRUPTIBLE)
+}
+
+int __sched __down_interruptible(struct semaphore * sem)
+{
+	int ret = 0;
+	DOWN_VAR
+	DOWN_HEAD(TASK_INTERRUPTIBLE)
+
+	ret = waking_non_zero_interruptible(sem, tsk);
+	if (ret)
+	{
+		if (ret == 1)
+			/* ret != 0 only if we get interrupted -arca */
+			ret = 0;
+		break;
+	}
+	schedule();
+	DOWN_TAIL(TASK_INTERRUPTIBLE)
+	return ret;
+}
+
+int __down_trylock(struct semaphore * sem)
+{
+	return waking_non_zero_trylock(sem);
+}
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
new file mode 100644
index 0000000..25b9d9e
--- /dev/null
+++ b/arch/sh/kernel/setup.c
@@ -0,0 +1,649 @@
+/* $Id: setup.c,v 1.30 2003/10/13 07:21:19 lethal Exp $
+ *
+ *  linux/arch/sh/kernel/setup.c
+ *
+ *  Copyright (C) 1999  Niibe Yutaka
+ *  Copyright (C) 2002, 2003  Paul Mundt
+ */
+
+/*
+ * This file handles the architecture-dependent parts of initialization
+ */
+
+#include <linux/tty.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/initrd.h>
+#include <linux/bootmem.h>
+#include <linux/console.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/utsname.h>
+#include <linux/cpu.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/io_generic.h>
+#include <asm/sections.h>
+#include <asm/irq.h>
+#include <asm/setup.h>
+
+#ifdef CONFIG_SH_KGDB
+#include <asm/kgdb.h>
+static int kgdb_parse_options(char *options);
+#endif
+extern void * __rd_start, * __rd_end;
+/*
+ * Machine setup..
+ */
+
+/*
+ * Initialize loops_per_jiffy as 10000000 (1000MIPS).
+ * This value will be used at the very early stage of serial setup.
+ * The bigger value means no problem.
+ */
+struct sh_cpuinfo boot_cpu_data = { CPU_SH_NONE, 0, 10000000, };
+struct screen_info screen_info;
+
+#if defined(CONFIG_SH_UNKNOWN)
+struct sh_machine_vector sh_mv;
+#endif
+
+/* We need this to satisfy some external references. */
+struct screen_info screen_info = {
+        0, 25,                  /* orig-x, orig-y */
+        0,                      /* unused */
+        0,                      /* orig-video-page */
+        0,                      /* orig-video-mode */
+        80,                     /* orig-video-cols */
+        0,0,0,                  /* ega_ax, ega_bx, ega_cx */
+        25,                     /* orig-video-lines */
+        0,                      /* orig-video-isVGA */
+        16                      /* orig-video-points */
+};
+
+extern void platform_setup(void);
+extern char *get_system_type(void);
+extern int root_mountflags;
+
+#define MV_NAME_SIZE 32
+
+static struct sh_machine_vector* __init get_mv_byname(const char* name);
+
+/*
+ * This is set up by the setup-routine at boot-time
+ */
+#define PARAM	((unsigned char *)empty_zero_page)
+
+#define MOUNT_ROOT_RDONLY (*(unsigned long *) (PARAM+0x000))
+#define RAMDISK_FLAGS (*(unsigned long *) (PARAM+0x004))
+#define ORIG_ROOT_DEV (*(unsigned long *) (PARAM+0x008))
+#define LOADER_TYPE (*(unsigned long *) (PARAM+0x00c))
+#define INITRD_START (*(unsigned long *) (PARAM+0x010))
+#define INITRD_SIZE (*(unsigned long *) (PARAM+0x014))
+/* ... */
+#define COMMAND_LINE ((char *) (PARAM+0x100))
+
+#define RAMDISK_IMAGE_START_MASK  	0x07FF
+#define RAMDISK_PROMPT_FLAG		0x8000
+#define RAMDISK_LOAD_FLAG		0x4000	
+
+static char command_line[COMMAND_LINE_SIZE] = { 0, };
+
+struct resource standard_io_resources[] = {
+	{ "dma1", 0x00, 0x1f },
+	{ "pic1", 0x20, 0x3f },
+	{ "timer", 0x40, 0x5f },
+	{ "keyboard", 0x60, 0x6f },
+	{ "dma page reg", 0x80, 0x8f },
+	{ "pic2", 0xa0, 0xbf },
+	{ "dma2", 0xc0, 0xdf },
+	{ "fpu", 0xf0, 0xff }
+};
+
+#define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource))
+
+/* System RAM - interrupted by the 640kB-1M hole */
+#define code_resource (ram_resources[3])
+#define data_resource (ram_resources[4])
+static struct resource ram_resources[] = {
+	{ "System RAM", 0x000000, 0x09ffff, IORESOURCE_BUSY },
+	{ "System RAM", 0x100000, 0x100000, IORESOURCE_BUSY },
+	{ "Video RAM area", 0x0a0000, 0x0bffff },
+	{ "Kernel code", 0x100000, 0 },
+	{ "Kernel data", 0, 0 }
+};
+
+unsigned long memory_start, memory_end;
+
+static inline void parse_cmdline (char ** cmdline_p, char mv_name[MV_NAME_SIZE],
+				  struct sh_machine_vector** mvp,
+				  unsigned long *mv_io_base,
+				  int *mv_mmio_enable)
+{
+	char c = ' ', *to = command_line, *from = COMMAND_LINE;
+	int len = 0;
+
+	/* Save unparsed command line copy for /proc/cmdline */
+	memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
+	saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
+
+	memory_start = (unsigned long)PAGE_OFFSET+__MEMORY_START;
+	memory_end = memory_start + __MEMORY_SIZE;
+
+	for (;;) {
+		/*
+		 * "mem=XXX[kKmM]" defines a size of memory.
+		 */
+		if (c == ' ' && !memcmp(from, "mem=", 4)) {
+			if (to != command_line)
+				to--;
+			{
+				unsigned long mem_size;
+
+				mem_size = memparse(from+4, &from);
+				memory_end = memory_start + mem_size;
+			}
+		}
+		if (c == ' ' && !memcmp(from, "sh_mv=", 6)) {
+			char* mv_end;
+			char* mv_comma;
+			int mv_len;
+			if (to != command_line)
+				to--;
+			from += 6;
+			mv_end = strchr(from, ' ');
+			if (mv_end == NULL)
+				mv_end = from + strlen(from);
+
+			mv_comma = strchr(from, ',');
+			if ((mv_comma != NULL) && (mv_comma < mv_end)) {
+				int ints[3];
+				get_options(mv_comma+1, ARRAY_SIZE(ints), ints);
+				*mv_io_base = ints[1];
+				*mv_mmio_enable = ints[2];
+				mv_len = mv_comma - from;
+			} else {
+				mv_len = mv_end - from;
+			}
+			if (mv_len > (MV_NAME_SIZE-1))
+				mv_len = MV_NAME_SIZE-1;
+			memcpy(mv_name, from, mv_len);
+			mv_name[mv_len] = '\0';
+			from = mv_end;
+
+			*mvp = get_mv_byname(mv_name);
+		}
+		c = *(from++);
+		if (!c)
+			break;
+		if (COMMAND_LINE_SIZE <= ++len)
+			break;
+		*(to++) = c;
+	}
+	*to = '\0';
+	*cmdline_p = command_line;
+}
+
+static int __init sh_mv_setup(char **cmdline_p)
+{
+#if defined(CONFIG_SH_UNKNOWN)
+	extern struct sh_machine_vector mv_unknown;
+#endif
+	struct sh_machine_vector *mv = NULL;
+	char mv_name[MV_NAME_SIZE] = "";
+	unsigned long mv_io_base = 0;
+	int mv_mmio_enable = 0;
+
+	parse_cmdline(cmdline_p, mv_name, &mv, &mv_io_base, &mv_mmio_enable);
+
+#ifdef CONFIG_SH_GENERIC
+	if (mv == NULL) {
+		mv = &mv_unknown;
+		if (*mv_name != '\0') {
+			printk("Warning: Unsupported machine %s, using unknown\n",
+			       mv_name);
+		}
+	}
+	sh_mv = *mv;
+#endif
+#ifdef CONFIG_SH_UNKNOWN
+	sh_mv = mv_unknown;
+#endif
+
+	/*
+	 * Manually walk the vec, fill in anything that the board hasn't yet
+	 * by hand, wrapping to the generic implementation.
+	 */
+#define mv_set(elem) do { \
+	if (!sh_mv.mv_##elem) \
+		sh_mv.mv_##elem = generic_##elem; \
+} while (0)
+
+	mv_set(inb);	mv_set(inw);	mv_set(inl);
+	mv_set(outb);	mv_set(outw);	mv_set(outl);
+
+	mv_set(inb_p);	mv_set(inw_p);	mv_set(inl_p);
+	mv_set(outb_p);	mv_set(outw_p);	mv_set(outl_p);
+
+	mv_set(insb);	mv_set(insw);	mv_set(insl);
+	mv_set(outsb);	mv_set(outsw);	mv_set(outsl);
+
+	mv_set(readb);	mv_set(readw);	mv_set(readl);
+	mv_set(writeb);	mv_set(writew);	mv_set(writel);
+
+	mv_set(ioremap);
+	mv_set(iounmap);
+
+	mv_set(isa_port2addr);
+	mv_set(irq_demux);
+
+#ifdef CONFIG_SH_UNKNOWN
+	__set_io_port_base(mv_io_base);
+#endif
+
+	return 0;
+}
+
+void __init setup_arch(char **cmdline_p)
+{
+	unsigned long bootmap_size;
+	unsigned long start_pfn, max_pfn, max_low_pfn;
+
+#ifdef CONFIG_EARLY_PRINTK
+	extern void enable_early_printk(void);
+
+	enable_early_printk();
+#endif
+#ifdef CONFIG_CMDLINE_BOOL
+        strcpy(COMMAND_LINE, CONFIG_CMDLINE);
+#endif
+
+	ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV);
+
+#ifdef CONFIG_BLK_DEV_RAM
+	rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
+	rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
+	rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
+#endif
+
+	if (!MOUNT_ROOT_RDONLY)
+		root_mountflags &= ~MS_RDONLY;
+	init_mm.start_code = (unsigned long) _text;
+	init_mm.end_code = (unsigned long) _etext;
+	init_mm.end_data = (unsigned long) _edata;
+	init_mm.brk = (unsigned long) _end;
+
+	code_resource.start = virt_to_bus(_text);
+	code_resource.end = virt_to_bus(_etext)-1;
+	data_resource.start = virt_to_bus(_etext);
+	data_resource.end = virt_to_bus(_edata)-1;
+
+	sh_mv_setup(cmdline_p);
+
+#define PFN_UP(x)	(((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
+#define PFN_DOWN(x)	((x) >> PAGE_SHIFT)
+#define PFN_PHYS(x)	((x) << PAGE_SHIFT)
+
+#ifdef CONFIG_DISCONTIGMEM
+	NODE_DATA(0)->bdata = &discontig_node_bdata[0];
+	NODE_DATA(1)->bdata = &discontig_node_bdata[1];
+
+	bootmap_size = init_bootmem_node(NODE_DATA(1), 
+					 PFN_UP(__MEMORY_START_2ND),
+					 PFN_UP(__MEMORY_START_2ND),
+					 PFN_DOWN(__MEMORY_START_2ND+__MEMORY_SIZE_2ND));
+	free_bootmem_node(NODE_DATA(1), __MEMORY_START_2ND, __MEMORY_SIZE_2ND);
+	reserve_bootmem_node(NODE_DATA(1), __MEMORY_START_2ND, bootmap_size);
+#endif
+
+	/*
+	 * Find the highest page frame number we have available
+	 */
+	max_pfn = PFN_DOWN(__pa(memory_end));
+
+	/*
+	 * Determine low and high memory ranges:
+	 */
+	max_low_pfn = max_pfn;
+
+ 	/*
+	 * Partially used pages are not usable - thus
+	 * we are rounding upwards:
+ 	 */
+	start_pfn = PFN_UP(__pa(_end));
+
+	/*
+	 * Find a proper area for the bootmem bitmap. After this
+	 * bootstrap step all allocations (until the page allocator
+	 * is intact) must be done via bootmem_alloc().
+	 */
+	bootmap_size = init_bootmem_node(NODE_DATA(0), start_pfn,
+					 __MEMORY_START>>PAGE_SHIFT,
+					 max_low_pfn);
+	/*
+	 * Register fully available low RAM pages with the bootmem allocator.
+	 */
+	{
+		unsigned long curr_pfn, last_pfn, pages;
+
+		/*
+		 * We are rounding up the start address of usable memory:
+		 */
+		curr_pfn = PFN_UP(__MEMORY_START);
+		/*
+		 * ... and at the end of the usable range downwards:
+		 */
+		last_pfn = PFN_DOWN(__pa(memory_end));
+
+		if (last_pfn > max_low_pfn)
+			last_pfn = max_low_pfn;
+
+		pages = last_pfn - curr_pfn;
+		free_bootmem_node(NODE_DATA(0), PFN_PHYS(curr_pfn),
+				  PFN_PHYS(pages));
+	}
+
+	/*
+	 * Reserve the kernel text and
+	 * Reserve the bootmem bitmap. We do this in two steps (first step
+	 * was init_bootmem()), because this catches the (definitely buggy)
+	 * case of us accidentally initializing the bootmem allocator with
+	 * an invalid RAM area.
+	 */
+	reserve_bootmem_node(NODE_DATA(0), __MEMORY_START+PAGE_SIZE,
+		(PFN_PHYS(start_pfn)+bootmap_size+PAGE_SIZE-1)-__MEMORY_START);
+
+	/*
+	 * reserve physical page 0 - it's a special BIOS page on many boxes,
+	 * enabling clean reboots, SMP operation, laptop functions.
+	 */
+	reserve_bootmem_node(NODE_DATA(0), __MEMORY_START, PAGE_SIZE);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ 	ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+ 	if (&__rd_start != &__rd_end) {
+		LOADER_TYPE = 1;
+		INITRD_START = PHYSADDR((unsigned long)&__rd_start) - __MEMORY_START;
+		INITRD_SIZE = (unsigned long)&__rd_end - (unsigned long)&__rd_start;
+ 	}
+
+	if (LOADER_TYPE && INITRD_START) {
+		if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) {
+			reserve_bootmem_node(NODE_DATA(0), INITRD_START+__MEMORY_START, INITRD_SIZE);
+			initrd_start =
+				INITRD_START ? INITRD_START + PAGE_OFFSET + __MEMORY_START : 0;
+			initrd_end = initrd_start + INITRD_SIZE;
+		} else {
+			printk("initrd extends beyond end of memory "
+			    "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
+				    INITRD_START + INITRD_SIZE,
+				    max_low_pfn << PAGE_SHIFT);
+			initrd_start = 0;
+		}
+	}
+#endif
+
+#ifdef CONFIG_DUMMY_CONSOLE
+	conswitchp = &dummy_con;
+#endif
+
+	/* Perform the machine specific initialisation */
+	platform_setup();
+
+	paging_init();
+}
+
+struct sh_machine_vector* __init get_mv_byname(const char* name)
+{
+	extern int strcasecmp(const char *, const char *);
+	extern long __machvec_start, __machvec_end;
+	struct sh_machine_vector *all_vecs =
+		(struct sh_machine_vector *)&__machvec_start;
+
+	int i, n = ((unsigned long)&__machvec_end
+		    - (unsigned long)&__machvec_start)/
+		sizeof(struct sh_machine_vector);
+
+	for (i = 0; i < n; ++i) {
+		struct sh_machine_vector *mv = &all_vecs[i];
+		if (mv == NULL)
+			continue;
+		if (strcasecmp(name, get_system_type()) == 0) {
+			return mv;
+		}
+	}
+	return NULL;
+}
+
+static struct cpu cpu[NR_CPUS];
+
+static int __init topology_init(void)
+{
+	int cpu_id;
+
+	for (cpu_id = 0; cpu_id < NR_CPUS; cpu_id++)
+		if (cpu_possible(cpu_id))
+			register_cpu(&cpu[cpu_id], cpu_id, NULL);
+
+	return 0;
+}
+
+subsys_initcall(topology_init);
+
+static const char *cpu_name[] = {
+	[CPU_SH7604]	= "SH7604",
+	[CPU_SH7705]	= "SH7705",
+	[CPU_SH7708]	= "SH7708",
+	[CPU_SH7729]	= "SH7729",
+	[CPU_SH7300]	= "SH7300",
+	[CPU_SH7750]	= "SH7750",
+	[CPU_SH7750S]	= "SH7750S",
+	[CPU_SH7750R]	= "SH7750R",
+	[CPU_SH7751]	= "SH7751",
+	[CPU_SH7751R]	= "SH7751R",
+	[CPU_SH7760]	= "SH7760",
+	[CPU_SH73180]	= "SH73180",
+	[CPU_ST40RA]	= "ST40RA",
+	[CPU_ST40GX1]	= "ST40GX1",
+	[CPU_SH4_202]	= "SH4-202",
+	[CPU_SH4_501]	= "SH4-501",
+	[CPU_SH_NONE]	= "Unknown"
+};
+
+const char *get_cpu_subtype(void)
+{
+	return cpu_name[boot_cpu_data.type];
+}
+
+#ifdef CONFIG_PROC_FS
+static const char *cpu_flags[] = {
+	"none", "fpu", "p2flush", "mmuassoc", "dsp", "perfctr",
+};
+
+static void show_cpuflags(struct seq_file *m)
+{
+	unsigned long i;
+
+	seq_printf(m, "cpu flags\t:");
+
+	if (!cpu_data->flags) {
+		seq_printf(m, " %s\n", cpu_flags[0]);
+		return;
+	}
+
+	for (i = 0; i < cpu_data->flags; i++)
+		if ((cpu_data->flags & (1 << i)))
+			seq_printf(m, " %s", cpu_flags[i+1]);
+
+	seq_printf(m, "\n");
+}
+
+static void show_cacheinfo(struct seq_file *m, const char *type, struct cache_info info)
+{
+	unsigned int cache_size;
+
+	cache_size = info.ways * info.sets * info.linesz;
+
+	seq_printf(m, "%s size\t: %dKiB\n", type, cache_size >> 10);
+}
+
+/*
+ *	Get CPU information for use by the procfs.
+ */
+static int show_cpuinfo(struct seq_file *m, void *v)
+{
+	unsigned int cpu = smp_processor_id();
+
+	if (!cpu && cpu_online(cpu))
+		seq_printf(m, "machine\t\t: %s\n", get_system_type());
+
+	seq_printf(m, "processor\t: %d\n", cpu);
+	seq_printf(m, "cpu family\t: %s\n", system_utsname.machine);
+	seq_printf(m, "cpu type\t: %s\n", get_cpu_subtype());
+
+	show_cpuflags(m);
+
+	seq_printf(m, "cache type\t: ");
+
+	/*
+	 * Check for what type of cache we have, we support both the
+	 * unified cache on the SH-2 and SH-3, as well as the harvard
+	 * style cache on the SH-4.
+	 */
+	if (test_bit(SH_CACHE_COMBINED, &(boot_cpu_data.icache.flags))) {
+		seq_printf(m, "unified\n");
+		show_cacheinfo(m, "cache", boot_cpu_data.icache);
+	} else {
+		seq_printf(m, "split (harvard)\n");
+		show_cacheinfo(m, "icache", boot_cpu_data.icache);
+		show_cacheinfo(m, "dcache", boot_cpu_data.dcache);
+	}
+
+	seq_printf(m, "bogomips\t: %lu.%02lu\n",
+		     boot_cpu_data.loops_per_jiffy/(500000/HZ),
+		     (boot_cpu_data.loops_per_jiffy/(5000/HZ)) % 100);
+
+#define PRINT_CLOCK(name, value) \
+	seq_printf(m, name " clock\t: %d.%02dMHz\n", \
+		     ((value) / 1000000), ((value) % 1000000)/10000)
+	
+	PRINT_CLOCK("cpu", boot_cpu_data.cpu_clock);
+	PRINT_CLOCK("bus", boot_cpu_data.bus_clock);
+#ifdef CONFIG_CPU_SUBTYPE_ST40STB1
+	PRINT_CLOCK("memory", boot_cpu_data.memory_clock);
+#endif
+	PRINT_CLOCK("module", boot_cpu_data.module_clock);
+
+	return 0;
+}
+
+
+static void *c_start(struct seq_file *m, loff_t *pos)
+{
+	return *pos < NR_CPUS ? cpu_data + *pos : NULL;
+}
+static void *c_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	++*pos;
+	return c_start(m, pos);
+}
+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	= show_cpuinfo,
+};
+#endif /* CONFIG_PROC_FS */
+
+#ifdef CONFIG_SH_KGDB
+/*
+ * Parse command-line kgdb options.  By default KGDB is enabled,
+ * entered on error (or other action) using default serial info.
+ * The command-line option can include a serial port specification
+ * and an action to override default or configured behavior.
+ */
+struct kgdb_sermap kgdb_sci_sermap =
+{ "ttySC", 5, kgdb_sci_setup, NULL };
+
+struct kgdb_sermap *kgdb_serlist = &kgdb_sci_sermap;
+struct kgdb_sermap *kgdb_porttype = &kgdb_sci_sermap;
+
+void kgdb_register_sermap(struct kgdb_sermap *map)
+{
+	struct kgdb_sermap *last;
+
+	for (last = kgdb_serlist; last->next; last = last->next)
+		;
+	last->next = map;
+	if (!map->namelen) {
+		map->namelen = strlen(map->name);
+	}
+}
+
+static int __init kgdb_parse_options(char *options)
+{
+	char c;
+	int baud;
+
+	/* Check for port spec (or use default) */
+
+	/* Determine port type and instance */
+	if (!memcmp(options, "tty", 3)) {
+		struct kgdb_sermap *map = kgdb_serlist;
+
+		while (map && memcmp(options, map->name, map->namelen))
+			map = map->next;
+
+		if (!map) {
+			KGDB_PRINTK("unknown port spec in %s\n", options);
+			return -1;
+		}
+
+		kgdb_porttype = map;
+		kgdb_serial_setup = map->setup_fn;
+		kgdb_portnum = options[map->namelen] - '0';
+		options += map->namelen + 1;
+
+		options = (*options == ',') ? options+1 : options;
+		
+		/* Read optional parameters (baud/parity/bits) */
+		baud = simple_strtoul(options, &options, 10);
+		if (baud != 0) {
+			kgdb_baud = baud;
+
+			c = toupper(*options);
+			if (c == 'E' || c == 'O' || c == 'N') {
+				kgdb_parity = c;
+				options++;
+			}
+
+			c = *options;
+			if (c == '7' || c == '8') {
+				kgdb_bits = c;
+				options++;
+			}
+			options = (*options == ',') ? options+1 : options;
+		}
+	}
+
+	/* Check for action specification */
+	if (!memcmp(options, "halt", 4)) {
+		kgdb_halt = 1;
+		options += 4;
+	} else if (!memcmp(options, "disabled", 8)) {
+		kgdb_enabled = 0;
+		options += 8;
+	}
+
+	if (*options) {
+                KGDB_PRINTK("ignored unknown options: %s\n", options);
+		return 0;
+	}
+	return 1;
+}
+__setup("kgdb=", kgdb_parse_options);
+#endif /* CONFIG_SH_KGDB */
+
diff --git a/arch/sh/kernel/sh_bios.c b/arch/sh/kernel/sh_bios.c
new file mode 100644
index 0000000..5b53e10
--- /dev/null
+++ b/arch/sh/kernel/sh_bios.c
@@ -0,0 +1,75 @@
+/*
+ *  linux/arch/sh/kernel/sh_bios.c
+ *  C interface for trapping into the standard LinuxSH BIOS.
+ *
+ *  Copyright (C) 2000 Greg Banks, Mitch Davis
+ *
+ */
+
+#include <asm/sh_bios.h>
+
+#define BIOS_CALL_CONSOLE_WRITE     	0
+#define BIOS_CALL_READ_BLOCK     	1
+#define BIOS_CALL_ETH_NODE_ADDR		10
+#define BIOS_CALL_SHUTDOWN		11
+#define BIOS_CALL_CHAR_OUT     	    	0x1f  	/* TODO: hack */
+#define BIOS_CALL_GDB_GET_MODE_PTR     	0xfe
+#define BIOS_CALL_GDB_DETACH     	0xff
+
+static __inline__ long sh_bios_call(long func, long arg0, long arg1, long arg2, long arg3)
+{
+    register long r0 __asm__("r0") = func;
+    register long r4 __asm__("r4") = arg0;
+    register long r5 __asm__("r5") = arg1;
+    register long r6 __asm__("r6") = arg2;
+    register long r7 __asm__("r7") = arg3;
+    __asm__ __volatile__("trapa	#0x3f"
+	 : "=z" (r0)
+	 : "0" (r0), "r" (r4), "r" (r5), "r" (r6), "r" (r7)
+	 : "memory");
+    return r0;
+}
+
+
+void sh_bios_console_write(const char *buf, unsigned int len)
+{
+    sh_bios_call(BIOS_CALL_CONSOLE_WRITE, (long)buf, (long)len, 0, 0);
+}
+
+
+void sh_bios_char_out(char ch)
+{
+    sh_bios_call(BIOS_CALL_CHAR_OUT, ch, 0, 0, 0);
+}
+
+
+int sh_bios_in_gdb_mode(void)
+{
+    static char queried = 0;
+    static char *gdb_mode_p = 0;
+
+    if (!queried)
+    {
+    	/* Query the gdb stub for address of its gdb mode variable */
+    	long r = sh_bios_call(BIOS_CALL_GDB_GET_MODE_PTR, 0, 0, 0, 0);
+	if (r != ~0)	/* BIOS returns -1 for unknown function */
+	    gdb_mode_p = (char *)r;
+	queried = 1;
+    }
+    return (gdb_mode_p != 0 ? *gdb_mode_p : 0);
+}
+
+void sh_bios_gdb_detach(void)
+{
+    sh_bios_call(BIOS_CALL_GDB_DETACH, 0, 0, 0, 0);
+}
+
+void sh_bios_get_node_addr (unsigned char *node_addr)
+{
+    sh_bios_call(BIOS_CALL_ETH_NODE_ADDR, 0, (long)node_addr, 0, 0);
+}
+
+void sh_bios_shutdown(unsigned int how)
+{
+    sh_bios_call(BIOS_CALL_SHUTDOWN, how, 0, 0, 0);
+}
diff --git a/arch/sh/kernel/sh_ksyms.c b/arch/sh/kernel/sh_ksyms.c
new file mode 100644
index 0000000..6954fd6
--- /dev/null
+++ b/arch/sh/kernel/sh_ksyms.c
@@ -0,0 +1,126 @@
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/smp.h>
+#include <linux/user.h>
+#include <linux/elfcore.h>
+#include <linux/sched.h>
+#include <linux/in6.h>
+#include <linux/interrupt.h>
+#include <linux/smp_lock.h>
+#include <linux/vmalloc.h>
+#include <linux/pci.h>
+#include <linux/irq.h>
+
+#include <asm/semaphore.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+#include <asm/checksum.h>
+#include <asm/io.h>
+#include <asm/delay.h>
+#include <asm/tlbflush.h>
+#include <asm/cacheflush.h>
+#include <asm/checksum.h>
+
+extern void dump_thread(struct pt_regs *, struct user *);
+extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
+extern struct hw_interrupt_type no_irq_type;
+
+EXPORT_SYMBOL(sh_mv);
+
+/* platform dependent support */
+EXPORT_SYMBOL(dump_thread);
+EXPORT_SYMBOL(dump_fpu);
+EXPORT_SYMBOL(iounmap);
+EXPORT_SYMBOL(enable_irq);
+EXPORT_SYMBOL(disable_irq);
+EXPORT_SYMBOL(probe_irq_mask);
+EXPORT_SYMBOL(kernel_thread);
+EXPORT_SYMBOL(disable_irq_nosync);
+EXPORT_SYMBOL(irq_desc);
+EXPORT_SYMBOL(no_irq_type);
+
+EXPORT_SYMBOL(strpbrk);
+EXPORT_SYMBOL(strstr);
+EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(strnlen);
+EXPORT_SYMBOL(strchr);
+EXPORT_SYMBOL(strcat);
+EXPORT_SYMBOL(strncat);
+
+/* PCI exports */
+#ifdef CONFIG_PCI
+EXPORT_SYMBOL(pci_alloc_consistent);
+EXPORT_SYMBOL(pci_free_consistent);
+#endif
+
+/* mem exports */
+EXPORT_SYMBOL(memchr);
+EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(memcpy_fromio);
+EXPORT_SYMBOL(memcpy_toio);
+EXPORT_SYMBOL(memset);
+EXPORT_SYMBOL(memset_io);
+EXPORT_SYMBOL(memmove);
+EXPORT_SYMBOL(memcmp);
+EXPORT_SYMBOL(memscan);
+EXPORT_SYMBOL(__copy_user);
+EXPORT_SYMBOL(boot_cpu_data);
+
+#ifdef CONFIG_MMU
+EXPORT_SYMBOL(get_vm_area);
+#endif
+
+/* semaphore exports */
+EXPORT_SYMBOL(__up);
+EXPORT_SYMBOL(__down);
+EXPORT_SYMBOL(__down_interruptible);
+
+EXPORT_SYMBOL(__udelay);
+EXPORT_SYMBOL(__ndelay);
+EXPORT_SYMBOL(__const_udelay);
+
+EXPORT_SYMBOL(__div64_32);
+
+#define DECLARE_EXPORT(name) extern void name(void);EXPORT_SYMBOL(name)
+
+/* These symbols are generated by the compiler itself */
+DECLARE_EXPORT(__udivsi3);
+DECLARE_EXPORT(__udivdi3);
+DECLARE_EXPORT(__sdivsi3);
+DECLARE_EXPORT(__ashrdi3);
+DECLARE_EXPORT(__ashldi3);
+DECLARE_EXPORT(__lshrdi3);
+DECLARE_EXPORT(__movstr);
+
+EXPORT_SYMBOL(strcpy);
+
+#ifdef CONFIG_CPU_SH4
+DECLARE_EXPORT(__movstr_i4_even);
+DECLARE_EXPORT(__movstr_i4_odd);
+DECLARE_EXPORT(__movstrSI12_i4);
+
+/* needed by some modules */
+EXPORT_SYMBOL(flush_cache_all);
+EXPORT_SYMBOL(flush_cache_range);
+EXPORT_SYMBOL(flush_dcache_page);
+EXPORT_SYMBOL(__flush_purge_region);
+#endif
+
+#if defined(CONFIG_SH7705_CACHE_32KB)
+EXPORT_SYMBOL(flush_cache_all);
+EXPORT_SYMBOL(flush_cache_range);
+EXPORT_SYMBOL(flush_dcache_page);
+EXPORT_SYMBOL(__flush_purge_region);
+#endif
+
+EXPORT_SYMBOL(flush_tlb_page);
+EXPORT_SYMBOL(__down_trylock);
+
+#ifdef CONFIG_SMP
+EXPORT_SYMBOL(synchronize_irq);
+#endif
+
+EXPORT_SYMBOL(csum_partial);
+EXPORT_SYMBOL(csum_ipv6_magic);
+EXPORT_SYMBOL(consistent_sync);
+EXPORT_SYMBOL(clear_page);
diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c
new file mode 100644
index 0000000..06f1b47
--- /dev/null
+++ b/arch/sh/kernel/signal.c
@@ -0,0 +1,607 @@
+/*
+ *  linux/arch/sh/kernel/signal.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  1997-11-28  Modified for POSIX.1b signals by Richard Henderson
+ *
+ *  SuperH version:  Copyright (C) 1999, 2000  Niibe Yutaka & Kaz Kojima
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/unistd.h>
+#include <linux/stddef.h>
+#include <linux/tty.h>
+#include <linux/personality.h>
+#include <linux/binfmts.h>
+
+#include <asm/ucontext.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/cacheflush.h>
+
+#define DEBUG_SIG 0
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset);
+
+/*
+ * Atomically swap in the new signal mask, and wait for a signal.
+ */
+asmlinkage int
+sys_sigsuspend(old_sigset_t mask,
+	       unsigned long r5, unsigned long r6, unsigned long r7,
+	       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.regs[0] = -EINTR;
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		if (do_signal(&regs, &saveset))
+			return -EINTR;
+	}
+}
+
+asmlinkage int
+sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize,
+		  unsigned long r6, unsigned long r7,
+		  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.regs[0] = -EINTR;
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		if (do_signal(&regs, &saveset))
+			return -EINTR;
+	}
+}
+
+asmlinkage int 
+sys_sigaction(int sig, const struct old_sigaction __user *act,
+	      struct old_sigaction __user *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;
+}
+
+asmlinkage int
+sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
+		unsigned long r6, unsigned long r7,
+		struct pt_regs regs)
+{
+	return do_sigaltstack(uss, uoss, regs.regs[15]);
+}
+
+
+/*
+ * Do a signal return; undo the signal stack.
+ */
+
+#define MOVW(n)	 (0x9300|((n)-2))	/* Move mem word at PC+n to R3 */
+#define TRAP16	 0xc310			/* Syscall w/no args (NR in R3) */
+#define OR_R0_R0 0x200b			/* or r0,r0 (insert to avoid hardware bug) */
+
+struct sigframe
+{
+	struct sigcontext sc;
+	unsigned long extramask[_NSIG_WORDS-1];
+	u16 retcode[8];
+};
+
+struct rt_sigframe
+{
+	struct siginfo info;
+	struct ucontext uc;
+	u16 retcode[8];
+};
+
+#ifdef CONFIG_SH_FPU
+static inline int restore_sigcontext_fpu(struct sigcontext __user *sc)
+{
+	struct task_struct *tsk = current;
+
+	if (!(cpu_data->flags & CPU_HAS_FPU))
+		return 0;
+
+	set_used_math();
+	return __copy_from_user(&tsk->thread.fpu.hard, &sc->sc_fpregs[0],
+				sizeof(long)*(16*2+2));
+}
+
+static inline int save_sigcontext_fpu(struct sigcontext __user *sc,
+				      struct pt_regs *regs)
+{
+	struct task_struct *tsk = current;
+
+	if (!(cpu_data->flags & CPU_HAS_FPU))
+		return 0;
+
+	if (!used_math()) {
+		__put_user(0, &sc->sc_ownedfp);
+		return 0;
+	}
+
+	__put_user(1, &sc->sc_ownedfp);
+
+	/* This will cause a "finit" to be triggered by the next
+	   attempted FPU operation by the 'current' process.
+	   */
+	clear_used_math();
+
+	unlazy_fpu(tsk, regs);
+	return __copy_to_user(&sc->sc_fpregs[0], &tsk->thread.fpu.hard,
+			      sizeof(long)*(16*2+2));
+}
+#endif /* CONFIG_SH_FPU */
+
+static int
+restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *r0_p)
+{
+	unsigned int err = 0;
+
+#define COPY(x)		err |= __get_user(regs->x, &sc->sc_##x)
+			COPY(regs[1]);
+	COPY(regs[2]);	COPY(regs[3]);
+	COPY(regs[4]);	COPY(regs[5]);
+	COPY(regs[6]);	COPY(regs[7]);
+	COPY(regs[8]);	COPY(regs[9]);
+	COPY(regs[10]);	COPY(regs[11]);
+	COPY(regs[12]);	COPY(regs[13]);
+	COPY(regs[14]);	COPY(regs[15]);
+	COPY(gbr);	COPY(mach);
+	COPY(macl);	COPY(pr);
+	COPY(sr);	COPY(pc);
+#undef COPY
+
+#ifdef CONFIG_SH_FPU
+	if (cpu_data->flags & CPU_HAS_FPU) {
+		int owned_fp;
+		struct task_struct *tsk = current;
+
+		regs->sr |= SR_FD; /* Release FPU */
+		clear_fpu(tsk, regs);
+		clear_used_math();
+		__get_user (owned_fp, &sc->sc_ownedfp);
+		if (owned_fp)
+			err |= restore_sigcontext_fpu(sc);
+	}
+#endif
+
+	regs->tra = -1;		/* disable syscall checks */
+	err |= __get_user(*r0_p, &sc->sc_regs[0]);
+	return err;
+}
+
+asmlinkage int sys_sigreturn(unsigned long r4, unsigned long r5,
+			     unsigned long r6, unsigned long r7,
+			     struct pt_regs regs)
+{
+	struct sigframe __user *frame = (struct sigframe __user *)regs.regs[15];
+	sigset_t set;
+	int r0;
+
+	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, &r0))
+		goto badframe;
+	return r0;
+
+badframe:
+	force_sig(SIGSEGV, current);
+	return 0;
+}
+
+asmlinkage int sys_rt_sigreturn(unsigned long r4, unsigned long r5,
+				unsigned long r6, unsigned long r7,
+				struct pt_regs regs)
+{
+	struct rt_sigframe __user *frame = (struct rt_sigframe __user *)regs.regs[15];
+	sigset_t set;
+	stack_t st;
+	int r0;
+
+	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, &r0))
+		goto badframe;
+
+	if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
+		goto badframe;
+	/* It is more difficult to avoid calling this function than to
+	   call it and ignore errors.  */
+	do_sigaltstack(&st, NULL, regs.regs[15]);
+
+	return r0;
+
+badframe:
+	force_sig(SIGSEGV, current);
+	return 0;
+}	
+
+/*
+ * Set up a signal frame.
+ */
+
+static int
+setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
+		 unsigned long mask)
+{
+	int err = 0;
+
+#define COPY(x)		err |= __put_user(regs->x, &sc->sc_##x)
+	COPY(regs[0]);	COPY(regs[1]);
+	COPY(regs[2]);	COPY(regs[3]);
+	COPY(regs[4]);	COPY(regs[5]);
+	COPY(regs[6]);	COPY(regs[7]);
+	COPY(regs[8]);	COPY(regs[9]);
+	COPY(regs[10]);	COPY(regs[11]);
+	COPY(regs[12]);	COPY(regs[13]);
+	COPY(regs[14]);	COPY(regs[15]);
+	COPY(gbr);	COPY(mach);
+	COPY(macl);	COPY(pr);
+	COPY(sr);	COPY(pc);
+#undef COPY
+
+#ifdef CONFIG_SH_FPU
+	err |= save_sigcontext_fpu(sc, regs);
+#endif
+
+	/* non-iBCS2 extensions.. */
+	err |= __put_user(mask, &sc->oldmask);
+
+	return err;
+}
+
+/*
+ * Determine which stack to use..
+ */
+static inline void __user *
+get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
+{
+	if (ka->sa.sa_flags & SA_ONSTACK) {
+		if (sas_ss_flags(sp) == 0)
+			sp = current->sas_ss_sp + current->sas_ss_size;
+	}
+
+	return (void __user *)((sp - frame_size) & -8ul);
+}
+
+static void setup_frame(int sig, struct k_sigaction *ka,
+			sigset_t *set, struct pt_regs *regs)
+{
+	struct sigframe __user *frame;
+	int err = 0;
+	int signal;
+
+	frame = get_sigframe(ka, regs->regs[15], sizeof(*frame));
+
+	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+		goto give_sigsegv;
+
+	signal = current_thread_info()->exec_domain
+		&& current_thread_info()->exec_domain->signal_invmap
+		&& sig < 32
+		? current_thread_info()->exec_domain->signal_invmap[sig]
+		: sig;
+
+	err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
+
+	if (_NSIG_WORDS > 1) {
+		err |= __copy_to_user(frame->extramask, &set->sig[1],
+				      sizeof(frame->extramask));
+	}
+
+	/* Set up to return from userspace.  If provided, use a stub
+	   already in userspace.  */
+	if (ka->sa.sa_flags & SA_RESTORER) {
+		regs->pr = (unsigned long) ka->sa.sa_restorer;
+	} else {
+		/* Generate return code (system call to sigreturn) */
+		err |= __put_user(MOVW(7), &frame->retcode[0]);
+		err |= __put_user(TRAP16, &frame->retcode[1]);
+		err |= __put_user(OR_R0_R0, &frame->retcode[2]);
+		err |= __put_user(OR_R0_R0, &frame->retcode[3]);
+		err |= __put_user(OR_R0_R0, &frame->retcode[4]);
+		err |= __put_user(OR_R0_R0, &frame->retcode[5]);
+		err |= __put_user(OR_R0_R0, &frame->retcode[6]);
+		err |= __put_user((__NR_sigreturn), &frame->retcode[7]);
+		regs->pr = (unsigned long) frame->retcode;
+	}
+
+	if (err)
+		goto give_sigsegv;
+
+	/* Set up registers for signal handler */
+	regs->regs[15] = (unsigned long) frame;
+	regs->regs[4] = signal; /* Arg for signal handler */
+	regs->regs[5] = 0;
+	regs->regs[6] = (unsigned long) &frame->sc;
+	regs->pc = (unsigned long) ka->sa.sa_handler;
+
+	set_fs(USER_DS);
+
+#if DEBUG_SIG
+	printk("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
+		current->comm, current->pid, frame, regs->pc, regs->pr);
+#endif
+
+	flush_cache_sigtramp(regs->pr);
+	if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode))
+		flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES);
+	return;
+
+give_sigsegv:
+	force_sigsegv(sig, current);
+}
+
+static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+			   sigset_t *set, struct pt_regs *regs)
+{
+	struct rt_sigframe __user *frame;
+	int err = 0;
+	int signal;
+
+	frame = get_sigframe(ka, regs->regs[15], sizeof(*frame));
+
+	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+		goto give_sigsegv;
+
+	signal = current_thread_info()->exec_domain
+		&& current_thread_info()->exec_domain->signal_invmap
+		&& sig < 32
+		? current_thread_info()->exec_domain->signal_invmap[sig]
+		: sig;
+
+	err |= copy_siginfo_to_user(&frame->info, info);
+
+	/* Create the ucontext.  */
+	err |= __put_user(0, &frame->uc.uc_flags);
+	err |= __put_user(0, &frame->uc.uc_link);
+	err |= __put_user((void *)current->sas_ss_sp,
+			  &frame->uc.uc_stack.ss_sp);
+	err |= __put_user(sas_ss_flags(regs->regs[15]),
+			  &frame->uc.uc_stack.ss_flags);
+	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+	err |= setup_sigcontext(&frame->uc.uc_mcontext,
+			        regs, set->sig[0]);
+	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+
+	/* Set up to return from userspace.  If provided, use a stub
+	   already in userspace.  */
+	if (ka->sa.sa_flags & SA_RESTORER) {
+		regs->pr = (unsigned long) ka->sa.sa_restorer;
+	} else {
+		/* Generate return code (system call to rt_sigreturn) */
+		err |= __put_user(MOVW(7), &frame->retcode[0]);
+		err |= __put_user(TRAP16, &frame->retcode[1]);
+		err |= __put_user(OR_R0_R0, &frame->retcode[2]);
+		err |= __put_user(OR_R0_R0, &frame->retcode[3]);
+		err |= __put_user(OR_R0_R0, &frame->retcode[4]);
+		err |= __put_user(OR_R0_R0, &frame->retcode[5]);
+		err |= __put_user(OR_R0_R0, &frame->retcode[6]);
+		err |= __put_user((__NR_rt_sigreturn), &frame->retcode[7]);
+		regs->pr = (unsigned long) frame->retcode;
+	}
+
+	if (err)
+		goto give_sigsegv;
+
+	/* Set up registers for signal handler */
+	regs->regs[15] = (unsigned long) frame;
+	regs->regs[4] = signal; /* Arg for signal handler */
+	regs->regs[5] = (unsigned long) &frame->info;
+	regs->regs[6] = (unsigned long) &frame->uc;
+	regs->pc = (unsigned long) ka->sa.sa_handler;
+
+	set_fs(USER_DS);
+
+#if DEBUG_SIG
+	printk("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
+		current->comm, current->pid, frame, regs->pc, regs->pr);
+#endif
+
+	flush_cache_sigtramp(regs->pr);
+	if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode))
+		flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES);
+	return;
+
+give_sigsegv:
+	force_sigsegv(sig, current);
+}
+
+/*
+ * OK, we're invoking a handler
+ */
+
+static void
+handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
+	      sigset_t *oldset, struct pt_regs *regs)
+{
+	/* Are we from a system call? */
+	if (regs->tra >= 0) {
+		/* If so, check system call restarting.. */
+		switch (regs->regs[0]) {
+			case -ERESTARTNOHAND:
+				regs->regs[0] = -EINTR;
+				break;
+
+			case -ERESTARTSYS:
+				if (!(ka->sa.sa_flags & SA_RESTART)) {
+					regs->regs[0] = -EINTR;
+					break;
+				}
+			/* fallthrough */
+			case -ERESTARTNOINTR:
+				regs->pc -= 2;
+		}
+	} else {
+		/* gUSA handling */
+#ifdef CONFIG_PREEMPT
+		unsigned long flags;
+
+		local_irq_save(flags);
+#endif
+		if (regs->regs[15] >= 0xc0000000) {
+			int offset = (int)regs->regs[15];
+
+			/* Reset stack pointer: clear critical region mark */
+			regs->regs[15] = regs->regs[1];
+			if (regs->pc < regs->regs[0])
+				/* Go to rewind point #1 */
+				regs->pc = regs->regs[0] + offset - 2;
+		}
+#ifdef CONFIG_PREEMPT
+		local_irq_restore(flags);
+#endif
+	}
+
+	/* Set up the stack frame */
+	if (ka->sa.sa_flags & SA_SIGINFO)
+		setup_rt_frame(sig, ka, info, oldset, regs);
+	else
+		setup_frame(sig, ka, oldset, regs);
+
+	if (ka->sa.sa_flags & SA_ONESHOT)
+		ka->sa.sa_handler = SIG_DFL;
+
+	if (!(ka->sa.sa_flags & SA_NODEFER)) {
+		spin_lock_irq(&current->sighand->siglock);
+		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+		sigaddset(&current->blocked,sig);
+		recalc_sigpending();
+		spin_unlock_irq(&current->sighand->siglock);
+	}
+}
+
+/*
+ * Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ *
+ * Note that we go through the signals twice: once to check the signals that
+ * the kernel can handle, and then we build all the user-level signal handling
+ * stack-frames in one go after that.
+ */
+int do_signal(struct pt_regs *regs, sigset_t *oldset)
+{
+	siginfo_t info;
+	int signr;
+	struct k_sigaction ka;
+
+	/*
+	 * 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 1;
+
+	if (try_to_freeze(0))
+		goto no_signal;
+
+	if (!oldset)
+		oldset = &current->blocked;
+
+	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+	if (signr > 0) {
+		/* Whee!  Actually deliver the signal.  */
+		handle_signal(signr, &ka, &info, oldset, regs);
+		return 1;
+	}
+
+ no_signal:
+	/* Did we come from a system call? */
+	if (regs->tra >= 0) {
+		/* Restart the system call - no handlers present */
+		if (regs->regs[0] == -ERESTARTNOHAND ||
+		    regs->regs[0] == -ERESTARTSYS ||
+		    regs->regs[0] == -ERESTARTNOINTR ||
+		    regs->regs[0] == -ERESTART_RESTARTBLOCK) {
+			regs->pc -= 2;
+		}
+	}
+	return 0;
+}
diff --git a/arch/sh/kernel/smp.c b/arch/sh/kernel/smp.c
new file mode 100644
index 0000000..56a39d6
--- /dev/null
+++ b/arch/sh/kernel/smp.c
@@ -0,0 +1,199 @@
+/*
+ * arch/sh/kernel/smp.c
+ *
+ * SMP support for the SuperH processors.
+ *
+ * Copyright (C) 2002, 2003 Paul Mundt
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/config.h>
+#include <linux/cache.h>
+#include <linux/cpumask.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/threads.h>
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/timex.h>
+#include <linux/sched.h>
+
+#include <asm/atomic.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/mmu_context.h>
+#include <asm/smp.h>
+
+/*
+ * This was written with the Sega Saturn (SMP SH-2 7604) in mind,
+ * but is designed to be usable regardless if there's an MMU
+ * present or not.
+ */
+struct sh_cpuinfo cpu_data[NR_CPUS];
+
+extern void per_cpu_trap_init(void);
+
+cpumask_t cpu_possible_map;
+cpumask_t cpu_online_map;
+static atomic_t cpus_booted = ATOMIC_INIT(0);
+
+/* These are defined by the board-specific code. */
+
+/*
+ * Cause the function described by call_data to be executed on the passed
+ * cpu.  When the function has finished, increment the finished field of
+ * call_data.
+ */
+void __smp_send_ipi(unsigned int cpu, unsigned int action);
+
+/*
+ * Find the number of available processors
+ */
+unsigned int __smp_probe_cpus(void);
+
+/*
+ * Start a particular processor
+ */
+void __smp_slave_init(unsigned int cpu);
+
+/*
+ * Run specified function on a particular processor.
+ */
+void __smp_call_function(unsigned int cpu);
+
+static inline void __init smp_store_cpu_info(unsigned int cpu)
+{
+	cpu_data[cpu].loops_per_jiffy = loops_per_jiffy;
+}
+
+void __init smp_prepare_cpus(unsigned int max_cpus)
+{
+	unsigned int cpu = smp_processor_id();
+	int i;
+
+	atomic_set(&cpus_booted, 1);
+	smp_store_cpu_info(cpu);
+	
+	for (i = 0; i < __smp_probe_cpus(); i++)
+		cpu_set(i, cpu_possible_map);
+}
+
+void __devinit smp_prepare_boot_cpu(void)
+{
+	unsigned int cpu = smp_processor_id();
+
+	cpu_set(cpu, cpu_online_map);
+	cpu_set(cpu, cpu_possible_map);
+}
+
+int __cpu_up(unsigned int cpu)
+{
+	struct task_struct *tsk;
+
+	tsk = fork_idle(cpu);
+
+	if (IS_ERR(tsk))
+		panic("Failed forking idle task for cpu %d\n", cpu);
+	
+	tsk->thread_info->cpu = cpu;
+
+	cpu_set(cpu, cpu_online_map);
+
+	return 0;
+}
+
+int start_secondary(void *unused)
+{
+	unsigned int cpu = smp_processor_id();
+
+	atomic_inc(&init_mm.mm_count);
+	current->active_mm = &init_mm;
+
+	smp_store_cpu_info(cpu);
+
+	__smp_slave_init(cpu);
+	per_cpu_trap_init();
+	
+	atomic_inc(&cpus_booted);
+
+	cpu_idle();
+	return 0;
+}
+
+void __init smp_cpus_done(unsigned int max_cpus)
+{
+	smp_mb();
+}
+
+void smp_send_reschedule(int cpu)
+{
+	__smp_send_ipi(cpu, SMP_MSG_RESCHEDULE);
+}
+
+static void stop_this_cpu(void *unused)
+{
+	cpu_clear(smp_processor_id(), cpu_online_map);
+	local_irq_disable();
+
+	for (;;)
+		cpu_relax();
+}
+
+void smp_send_stop(void)
+{
+	smp_call_function(stop_this_cpu, 0, 1, 0);
+}
+
+
+struct smp_fn_call_struct smp_fn_call = {
+	.lock		= SPIN_LOCK_UNLOCKED,
+	.finished	= ATOMIC_INIT(0),
+};
+
+/*
+ * The caller of this wants the passed function to run on every cpu.  If wait
+ * is set, wait until all cpus have finished the function before returning.
+ * The lock is here to protect the call structure.
+ * You must not call this function with disabled interrupts or from a
+ * hardware interrupt handler or from a bottom half handler.
+ */
+int smp_call_function(void (*func)(void *info), void *info, int retry, int wait)
+{
+	unsigned int nr_cpus = atomic_read(&cpus_booted);
+	int i;
+
+	if (nr_cpus < 2)
+		return 0;
+
+	/* Can deadlock when called with interrupts disabled */
+	WARN_ON(irqs_disabled());
+
+	spin_lock(&smp_fn_call.lock);
+
+	atomic_set(&smp_fn_call.finished, 0);
+	smp_fn_call.fn = func;
+	smp_fn_call.data = info;
+
+	for (i = 0; i < nr_cpus; i++)
+		if (i != smp_processor_id())
+			__smp_call_function(i);
+
+	if (wait)
+		while (atomic_read(&smp_fn_call.finished) != (nr_cpus - 1));
+
+	spin_unlock(&smp_fn_call.lock);
+
+	return 0;
+}
+
+/* Not really SMP stuff ... */
+int setup_profiling_timer(unsigned int multiplier)
+{
+	return 0;
+}
+
diff --git a/arch/sh/kernel/sys_sh.c b/arch/sh/kernel/sys_sh.c
new file mode 100644
index 0000000..df5ac29
--- /dev/null
+++ b/arch/sh/kernel/sys_sh.c
@@ -0,0 +1,289 @@
+/*
+ * linux/arch/sh/kernel/sys_sh.c
+ *
+ * This file contains various random system calls that
+ * have a non-standard calling sequence on the Linux/SuperH
+ * platform.
+ *
+ * Taken from i386 version.
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.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/file.h>
+#include <linux/utsname.h>
+
+#include <asm/uaccess.h>
+#include <asm/ipc.h>
+
+/*
+ * 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 r4, unsigned long r5,
+	unsigned long r6, unsigned long r7,
+	struct pt_regs regs)
+{
+	int fd[2];
+	int error;
+
+	error = do_pipe(fd);
+	if (!error) {
+		regs.regs[1] = fd[1];
+		return fd[0];
+	}
+	return error;
+}
+
+#if defined(HAVE_ARCH_UNMAPPED_AREA)
+/*
+ * To avoid cache alias, we map the shard page with same color.
+ */
+#define COLOUR_ALIGN(addr)	(((addr)+SHMLBA-1)&~(SHMLBA-1))
+
+unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
+	unsigned long len, unsigned long pgoff, unsigned long flags)
+{
+	struct mm_struct *mm = current->mm;
+	struct vm_area_struct *vma;
+	unsigned long start_addr;
+
+	if (flags & MAP_FIXED) {
+		/* We do not accept a shared mapping if it would violate
+		 * cache aliasing constraints.
+		 */
+		if ((flags & MAP_SHARED) && (addr & (SHMLBA - 1)))
+			return -EINVAL;
+		return addr;
+	}
+
+	if (len > TASK_SIZE)
+		return -ENOMEM;
+
+	if (addr) {
+		if (flags & MAP_PRIVATE)
+			addr = PAGE_ALIGN(addr);
+		else
+			addr = COLOUR_ALIGN(addr);
+		vma = find_vma(mm, addr);
+		if (TASK_SIZE - len >= addr &&
+		    (!vma || addr + len <= vma->vm_start))
+			return addr;
+	}
+	if (flags & MAP_PRIVATE)
+		addr = PAGE_ALIGN(mm->free_area_cache);
+	else
+		addr = COLOUR_ALIGN(mm->free_area_cache);
+	start_addr = addr;
+
+full_search:
+	for (vma = find_vma(mm, addr); ; vma = vma->vm_next) {
+		/* At this point:  (!vma || addr < vma->vm_end). */
+		if (TASK_SIZE - len < addr) {
+			/*
+			 * Start a new search - just in case we missed
+			 * some holes.
+			 */
+			if (start_addr != TASK_UNMAPPED_BASE) {
+				start_addr = addr = TASK_UNMAPPED_BASE;
+				goto full_search;
+			}
+			return -ENOMEM;
+		}
+		if (!vma || addr + len <= vma->vm_start) {
+			/*
+			 * Remember the place where we stopped the search:
+			 */
+			mm->free_area_cache = addr + len;
+			return addr;
+		}
+		addr = vma->vm_end;
+		if (!(flags & MAP_PRIVATE))
+			addr = COLOUR_ALIGN(addr);
+	}
+}
+#endif
+
+static inline long
+do_mmap2(unsigned long addr, unsigned long len, unsigned long prot, 
+	 unsigned long flags, int fd, unsigned long pgoff)
+{
+	int error = -EBADF;
+	struct file *file = NULL;
+
+	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+	if (!(flags & MAP_ANONYMOUS)) {
+		file = fget(fd);
+		if (!file)
+			goto out;
+	}
+
+	down_write(&current->mm->mmap_sem);
+	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+	up_write(&current->mm->mmap_sem);
+
+	if (file)
+		fput(file);
+out:
+	return error;
+}
+
+asmlinkage int old_mmap(unsigned long addr, unsigned long len,
+	unsigned long prot, unsigned long flags,
+	int fd, unsigned long off)
+{
+	if (off & ~PAGE_MASK)
+		return -EINVAL;
+	return do_mmap2(addr, len, prot, flags, fd, off>>PAGE_SHIFT);
+}
+
+asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
+	unsigned long prot, unsigned long flags,
+	unsigned long fd, unsigned long pgoff)
+{
+	return do_mmap2(addr, len, prot, flags, fd, pgoff);
+}
+
+/*
+ * 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 __user *ptr, long fifth)
+{
+	int version, ret;
+
+	version = call >> 16; /* hack for backward compatibility */
+	call &= 0xffff;
+
+	if (call <= SEMCTL)
+		switch (call) {
+		case SEMOP:
+			return sys_semtimedop(first, (struct sembuf __user *)ptr,
+					      second, NULL);
+		case SEMTIMEDOP:
+			return sys_semtimedop(first, (struct sembuf __user *)ptr,
+					      second,
+					      (const struct timespec __user *)fifth);
+		case SEMGET:
+			return sys_semget (first, second, third);
+		case SEMCTL: {
+			union semun fourth;
+			if (!ptr)
+				return -EINVAL;
+			if (get_user(fourth.__pad, (void * __user *) ptr))
+				return -EFAULT;
+			return sys_semctl (first, second, third, fourth);
+			}
+		default:
+			return -EINVAL;
+		}
+
+	if (call <= MSGCTL) 
+		switch (call) {
+		case MSGSND:
+			return sys_msgsnd (first, (struct msgbuf __user *) 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 __user *) ptr, 
+						   sizeof (tmp)))
+					return -EFAULT;
+				return sys_msgrcv (first, tmp.msgp, second,
+						   tmp.msgtyp, third);
+				}
+			default:
+				return sys_msgrcv (first,
+						   (struct msgbuf __user *) ptr,
+						   second, fifth, third);
+			}
+		case MSGGET:
+			return sys_msgget ((key_t) first, second);
+		case MSGCTL:
+			return sys_msgctl (first, second,
+					   (struct msqid_ds __user *) ptr);
+		default:
+			return -EINVAL;
+		}
+	if (call <= SHMCTL) 
+		switch (call) {
+		case SHMAT:
+			switch (version) {
+			default: {
+				ulong raddr;
+				ret = do_shmat (first, (char __user *) ptr,
+						 second, &raddr);
+				if (ret)
+					return ret;
+				return put_user (raddr, (ulong __user *) third);
+			}
+			case 1:	/* iBCS2 emulator entry point */
+				if (!segment_eq(get_fs(), get_ds()))
+					return -EINVAL;
+				return do_shmat (first, (char __user *) ptr,
+						  second, (ulong *) third);
+			}
+		case SHMDT: 
+			return sys_shmdt ((char __user *)ptr);
+		case SHMGET:
+			return sys_shmget (first, second, third);
+		case SHMCTL:
+			return sys_shmctl (first, second,
+					   (struct shmid_ds __user *) ptr);
+		default:
+			return -EINVAL;
+		}
+	
+	return -EINVAL;
+}
+
+asmlinkage int sys_uname(struct old_utsname * name)
+{
+	int err;
+	if (!name)
+		return -EFAULT;
+	down_read(&uts_sem);
+	err=copy_to_user(name, &system_utsname, sizeof (*name));
+	up_read(&uts_sem);
+	return err?-EFAULT:0;
+}
+
+asmlinkage ssize_t sys_pread_wrapper(unsigned int fd, char * buf,
+			     size_t count, long dummy, loff_t pos)
+{
+	return sys_pread64(fd, buf, count, pos);
+}
+
+asmlinkage ssize_t sys_pwrite_wrapper(unsigned int fd, const char * buf,
+			      size_t count, long dummy, loff_t pos)
+{
+	return sys_pwrite64(fd, buf, count, pos);
+}
+
+asmlinkage int sys_fadvise64_64_wrapper(int fd, u32 offset0, u32 offset1,
+				u32 len0, u32 len1, int advice)
+{
+#ifdef  __LITTLE_ENDIAN__
+	return sys_fadvise64_64(fd, (u64)offset1 << 32 | offset0,
+				(u64)len1 << 32 | len0,	advice);
+#else
+	return sys_fadvise64_64(fd, (u64)offset0 << 32 | offset1,
+				(u64)len0 << 32 | len1,	advice);
+#endif
+}
diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c
new file mode 100644
index 0000000..df7a9b9
--- /dev/null
+++ b/arch/sh/kernel/time.c
@@ -0,0 +1,657 @@
+/*
+ *  arch/sh/kernel/time.c
+ *
+ *  Copyright (C) 1999  Tetsuya Okada & Niibe Yutaka
+ *  Copyright (C) 2000  Philipp Rumpf <prumpf@tux.org>
+ *  Copyright (C) 2002, 2003, 2004  Paul Mundt
+ *  Copyright (C) 2002  M. R. Brown  <mrbrown@linux-sh.org>
+ *
+ *  Some code taken from i386 version.
+ *    Copyright (C) 1991, 1992, 1995  Linus Torvalds
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/profile.h>
+
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/delay.h>
+#include <asm/machvec.h>
+#include <asm/rtc.h>
+#include <asm/freq.h>
+#include <asm/cpu/timer.h>
+#ifdef CONFIG_SH_KGDB
+#include <asm/kgdb.h>
+#endif
+
+#include <linux/timex.h>
+#include <linux/irq.h>
+
+#define TMU_TOCR_INIT	0x00
+#define TMU0_TCR_INIT	0x0020
+#define TMU_TSTR_INIT	1
+
+#define TMU0_TCR_CALIB	0x0000
+
+#ifdef CONFIG_CPU_SUBTYPE_ST40STB1
+#define CLOCKGEN_MEMCLKCR 0xbb040038
+#define MEMCLKCR_RATIO_MASK 0x7
+#endif /* CONFIG_CPU_SUBTYPE_ST40STB1 */
+
+extern unsigned long wall_jiffies;
+#define TICK_SIZE (tick_nsec / 1000)
+DEFINE_SPINLOCK(tmu0_lock);
+
+u64 jiffies_64 = INITIAL_JIFFIES;
+
+EXPORT_SYMBOL(jiffies_64);
+
+/* XXX: Can we initialize this in a routine somewhere?  Dreamcast doesn't want
+ * these routines anywhere... */
+#ifdef CONFIG_SH_RTC
+void (*rtc_get_time)(struct timespec *) = sh_rtc_gettimeofday;
+int (*rtc_set_time)(const time_t) = sh_rtc_settimeofday;
+#else
+void (*rtc_get_time)(struct timespec *);
+int (*rtc_set_time)(const time_t);
+#endif
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7300)
+static int md_table[] = { 1, 2, 3, 4, 6, 8, 12 };
+#endif
+#if defined(CONFIG_CPU_SH3)
+static int stc_multipliers[] = { 1, 2, 3, 4, 6, 1, 1, 1 };
+static int stc_values[]      = { 0, 1, 4, 2, 5, 0, 0, 0 };
+#define bfc_divisors stc_multipliers
+#define bfc_values stc_values
+static int ifc_divisors[]    = { 1, 2, 3, 4, 1, 1, 1, 1 };
+static int ifc_values[]      = { 0, 1, 4, 2, 0, 0, 0, 0 };
+static int pfc_divisors[]    = { 1, 2, 3, 4, 6, 1, 1, 1 };
+static int pfc_values[]      = { 0, 1, 4, 2, 5, 0, 0, 0 };
+#elif defined(CONFIG_CPU_SH4)
+#if defined(CONFIG_CPU_SUBTYPE_SH73180)
+static int ifc_divisors[] = { 1, 2, 3, 4, 6, 8, 12, 16 };
+static int ifc_values[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
+#define bfc_divisors ifc_divisors	/* Same */
+#define bfc_values ifc_values
+#define pfc_divisors ifc_divisors	/* Same */
+#define pfc_values ifc_values
+#else
+static int ifc_divisors[] = { 1, 2, 3, 4, 6, 8, 1, 1 };
+static int ifc_values[]   = { 0, 1, 2, 3, 0, 4, 0, 5 };
+#define bfc_divisors ifc_divisors	/* Same */
+#define bfc_values ifc_values
+static int pfc_divisors[] = { 2, 3, 4, 6, 8, 2, 2, 2 };
+static int pfc_values[]   = { 0, 0, 1, 2, 0, 3, 0, 4 };
+#endif
+#else
+#error "Unknown ifc/bfc/pfc/stc values for this processor"
+#endif
+
+/*
+ * Scheduler clock - returns current time in nanosec units.
+ */
+unsigned long long sched_clock(void)
+{
+	return (unsigned long long)jiffies * (1000000000 / HZ);
+}
+
+static unsigned long do_gettimeoffset(void)
+{
+	int count;
+	unsigned long flags;
+
+	static int count_p = 0x7fffffff;    /* for the first call after boot */
+	static unsigned long jiffies_p = 0;
+
+	/*
+	 * cache volatile jiffies temporarily; we have IRQs turned off.
+	 */
+	unsigned long jiffies_t;
+
+	spin_lock_irqsave(&tmu0_lock, flags);
+	/* timer count may underflow right here */
+	count = ctrl_inl(TMU0_TCNT);	/* read the latched count */
+
+	jiffies_t = jiffies;
+
+	/*
+	 * avoiding timer inconsistencies (they are rare, but they happen)...
+	 * there is one kind of problem that must be avoided here:
+	 *  1. the timer counter underflows
+	 */
+
+	if( jiffies_t == jiffies_p ) {
+		if( count > count_p ) {
+			/* the nutcase */
+
+			if(ctrl_inw(TMU0_TCR) & 0x100) { /* Check UNF bit */
+				/*
+				 * We cannot detect lost timer interrupts ...
+				 * well, that's why we call them lost, don't we? :)
+				 * [hmm, on the Pentium and Alpha we can ... sort of]
+				 */
+				count -= LATCH;
+			} else {
+				printk("do_slow_gettimeoffset(): hardware timer problem?\n");
+			}
+		}
+	} else
+		jiffies_p = jiffies_t;
+
+	count_p = count;
+	spin_unlock_irqrestore(&tmu0_lock, flags);
+
+	count = ((LATCH-1) - count) * TICK_SIZE;
+	count = (count + LATCH/2) / LATCH;
+
+	return count;
+}
+
+void do_gettimeofday(struct timeval *tv)
+{
+	unsigned long seq;
+	unsigned long usec, sec;
+	unsigned long lost;
+
+	do {
+		seq = read_seqbegin(&xtime_lock);
+		usec = do_gettimeoffset();
+
+		lost = jiffies - wall_jiffies;
+		if (lost)
+			usec += lost * (1000000 / HZ);
+
+		sec = xtime.tv_sec;
+		usec += xtime.tv_nsec / 1000;
+	} while (read_seqretry(&xtime_lock, seq));
+
+	while (usec >= 1000000) {
+		usec -= 1000000;
+		sec++;
+	}
+
+	tv->tv_sec = sec;
+	tv->tv_usec = usec;
+}
+
+EXPORT_SYMBOL(do_gettimeofday);
+
+int do_settimeofday(struct timespec *tv)
+{
+	time_t wtm_sec, sec = tv->tv_sec;
+	long wtm_nsec, nsec = tv->tv_nsec;
+
+	if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
+		return -EINVAL;
+
+	write_seqlock_irq(&xtime_lock);
+	/*
+	 * This is revolting. We need to set "xtime" correctly. However, the
+	 * value in this location is the value at the most recent update of
+	 * wall time.  Discover what correction gettimeofday() would have
+	 * made, and then undo it!
+	 */
+	nsec -= 1000 * (do_gettimeoffset() +
+				(jiffies - wall_jiffies) * (1000000 / HZ));
+
+	wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
+	wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
+
+	set_normalized_timespec(&xtime, sec, nsec);
+	set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
+
+	time_adjust = 0;		/* stop active adjtime() */
+	time_status |= STA_UNSYNC;
+	time_maxerror = NTP_PHASE_LIMIT;
+	time_esterror = NTP_PHASE_LIMIT;
+	write_sequnlock_irq(&xtime_lock);
+	clock_was_set();
+
+	return 0;
+}
+
+EXPORT_SYMBOL(do_settimeofday);
+
+/* last time the RTC clock got updated */
+static long last_rtc_update;
+
+/*
+ * timer_interrupt() needs to keep up the real-time clock,
+ * as well as call the "do_timer()" routine every clocktick
+ */
+static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	do_timer(regs);
+#ifndef CONFIG_SMP
+	update_process_times(user_mode(regs));
+#endif
+	profile_tick(CPU_PROFILING, regs);
+
+#ifdef CONFIG_HEARTBEAT
+	if (sh_mv.mv_heartbeat != NULL)
+		sh_mv.mv_heartbeat();
+#endif
+
+	/*
+	 * If we have an externally synchronized Linux clock, then update
+	 * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
+	 * called as close as possible to 500 ms before the new second starts.
+	 */
+	if ((time_status & STA_UNSYNC) == 0 &&
+	    xtime.tv_sec > last_rtc_update + 660 &&
+	    (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
+	    (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
+		if (rtc_set_time(xtime.tv_sec) == 0)
+			last_rtc_update = xtime.tv_sec;
+		else
+			last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+	}
+}
+
+/*
+ * This is the same as the above, except we _also_ save the current
+ * Time Stamp Counter value at the time of the timer interrupt, so that
+ * we later on can estimate the time of day more exactly.
+ */
+static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned long timer_status;
+
+	/* Clear UNF bit */
+	timer_status = ctrl_inw(TMU0_TCR);
+	timer_status &= ~0x100;
+	ctrl_outw(timer_status, TMU0_TCR);
+
+	/*
+	 * Here we are in the timer irq handler. We just have irqs locally
+	 * disabled but we don't know if the timer_bh is running on the other
+	 * CPU. We need to avoid to SMP race with it. NOTE: we don' t need
+	 * the irq version of write_lock because as just said we have irq
+	 * locally disabled. -arca
+	 */
+	write_seqlock(&xtime_lock);
+	do_timer_interrupt(irq, NULL, regs);
+	write_sequnlock(&xtime_lock);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * Hah!  We'll see if this works (switching from usecs to nsecs).
+ */
+static unsigned int __init get_timer_frequency(void)
+{
+	u32 freq;
+	struct timespec ts1, ts2;
+	unsigned long diff_nsec;
+	unsigned long factor;
+
+	/* Setup the timer:  We don't want to generate interrupts, just
+	 * have it count down at its natural rate.
+	 */
+	ctrl_outb(0, TMU_TSTR);
+#if !defined(CONFIG_CPU_SUBTYPE_SH7300)
+	ctrl_outb(TMU_TOCR_INIT, TMU_TOCR);
+#endif
+	ctrl_outw(TMU0_TCR_CALIB, TMU0_TCR);
+	ctrl_outl(0xffffffff, TMU0_TCOR);
+	ctrl_outl(0xffffffff, TMU0_TCNT);
+
+	rtc_get_time(&ts2);
+
+	do {
+		rtc_get_time(&ts1);
+	} while (ts1.tv_nsec == ts2.tv_nsec && ts1.tv_sec == ts2.tv_sec);
+
+	/* actually start the timer */
+	ctrl_outb(TMU_TSTR_INIT, TMU_TSTR);
+
+	do {
+		rtc_get_time(&ts2);
+	} while (ts1.tv_nsec == ts2.tv_nsec && ts1.tv_sec == ts2.tv_sec);
+
+	freq = 0xffffffff - ctrl_inl(TMU0_TCNT);
+	if (ts2.tv_nsec < ts1.tv_nsec) {
+		ts2.tv_nsec += 1000000000;
+		ts2.tv_sec--;
+	}
+
+	diff_nsec = (ts2.tv_sec - ts1.tv_sec) * 1000000000 + (ts2.tv_nsec - ts1.tv_nsec);
+
+	/* this should work well if the RTC has a precision of n Hz, where
+	 * n is an integer.  I don't think we have to worry about the other
+	 * cases. */
+	factor = (1000000000 + diff_nsec/2) / diff_nsec;
+
+	if (factor * diff_nsec > 1100000000 ||
+	    factor * diff_nsec <  900000000)
+		panic("weird RTC (diff_nsec %ld)", diff_nsec);
+
+	return freq * factor;
+}
+
+void (*board_time_init)(void);
+void (*board_timer_setup)(struct irqaction *irq);
+
+static unsigned int sh_pclk_freq __initdata = CONFIG_SH_PCLK_FREQ;
+
+static int __init sh_pclk_setup(char *str)
+{
+        unsigned int freq;
+
+	if (get_option(&str, &freq))
+		sh_pclk_freq = freq;
+
+	return 1;
+}
+__setup("sh_pclk=", sh_pclk_setup);
+
+static struct irqaction irq0  = { timer_interrupt, SA_INTERRUPT, CPU_MASK_NONE, "timer", NULL, NULL};
+
+void get_current_frequency_divisors(unsigned int *ifc, unsigned int *bfc, unsigned int *pfc)
+{
+	unsigned int frqcr = ctrl_inw(FRQCR);
+
+#if defined(CONFIG_CPU_SH3)
+#if defined(CONFIG_CPU_SUBTYPE_SH7300)
+	*ifc = md_table[((frqcr & 0x0070) >> 4)];
+	*bfc = md_table[((frqcr & 0x0700) >> 8)];
+	*pfc = md_table[frqcr & 0x0007];
+#elif defined(CONFIG_CPU_SUBTYPE_SH7705)
+	*bfc = stc_multipliers[(frqcr & 0x0300) >> 8];
+	*ifc = ifc_divisors[(frqcr & 0x0030) >> 4];
+	*pfc = pfc_divisors[frqcr & 0x0003];
+#else
+	unsigned int tmp;
+
+	tmp  = (frqcr & 0x8000) >> 13;
+	tmp |= (frqcr & 0x0030) >>  4;
+	*bfc = stc_multipliers[tmp];
+	tmp  = (frqcr & 0x4000)  >> 12;
+	tmp |= (frqcr & 0x000c) >> 2;
+	*ifc = ifc_divisors[tmp];
+	tmp  = (frqcr & 0x2000) >> 11;
+	tmp |= frqcr & 0x0003;
+	*pfc = pfc_divisors[tmp];
+#endif
+#elif defined(CONFIG_CPU_SH4)
+#if defined(CONFIG_CPU_SUBTYPE_SH73180)
+	*ifc = ifc_divisors[(frqcr>> 20) & 0x0007];
+	*bfc = bfc_divisors[(frqcr>> 12) & 0x0007];
+	*pfc = pfc_divisors[frqcr & 0x0007];
+#else
+	*ifc = ifc_divisors[(frqcr >> 6) & 0x0007];
+	*bfc = bfc_divisors[(frqcr >> 3) & 0x0007];
+	*pfc = pfc_divisors[frqcr & 0x0007];
+#endif
+#endif
+}
+
+/*
+ * This bit of ugliness builds up accessor routines to get at both
+ * the divisors and the physical values.
+ */
+#define _FREQ_TABLE(x) \
+	unsigned int get_##x##_divisor(unsigned int value)	\
+		{ return x##_divisors[value]; }			\
+								\
+	unsigned int get_##x##_value(unsigned int divisor)	\
+		{ return x##_values[(divisor - 1)]; }
+
+_FREQ_TABLE(ifc);
+_FREQ_TABLE(bfc);
+_FREQ_TABLE(pfc);
+
+#ifdef CONFIG_CPU_SUBTYPE_ST40STB1
+
+/*
+ * The ST40 divisors are totally different so we set the cpu data
+ * clocks using a different algorithm
+ *
+ * I've just plugged this from the 2.4 code
+ *	- Alex Bennee <kernel-hacker@bennee.com>
+ */
+#define CCN_PVR_CHIP_SHIFT 24
+#define CCN_PVR_CHIP_MASK  0xff
+#define CCN_PVR_CHIP_ST40STB1 0x4
+
+
+struct frqcr_data {
+	unsigned short frqcr;
+
+	struct {
+		unsigned char multiplier;
+		unsigned char divisor;
+	} factor[3];
+};
+
+static struct frqcr_data st40_frqcr_table[] = {
+	{ 0x000, {{1,1}, {1,1}, {1,2}}},
+	{ 0x002, {{1,1}, {1,1}, {1,4}}},
+	{ 0x004, {{1,1}, {1,1}, {1,8}}},
+	{ 0x008, {{1,1}, {1,2}, {1,2}}},
+	{ 0x00A, {{1,1}, {1,2}, {1,4}}},
+	{ 0x00C, {{1,1}, {1,2}, {1,8}}},
+	{ 0x011, {{1,1}, {2,3}, {1,6}}},
+	{ 0x013, {{1,1}, {2,3}, {1,3}}},
+	{ 0x01A, {{1,1}, {1,2}, {1,4}}},
+	{ 0x01C, {{1,1}, {1,2}, {1,8}}},
+	{ 0x023, {{1,1}, {2,3}, {1,3}}},
+	{ 0x02C, {{1,1}, {1,2}, {1,8}}},
+	{ 0x048, {{1,2}, {1,2}, {1,4}}},
+	{ 0x04A, {{1,2}, {1,2}, {1,6}}},
+	{ 0x04C, {{1,2}, {1,2}, {1,8}}},
+	{ 0x05A, {{1,2}, {1,3}, {1,6}}},
+	{ 0x05C, {{1,2}, {1,3}, {1,6}}},
+	{ 0x063, {{1,2}, {1,4}, {1,4}}},
+	{ 0x06C, {{1,2}, {1,4}, {1,8}}},
+	{ 0x091, {{1,3}, {1,3}, {1,6}}},
+	{ 0x093, {{1,3}, {1,3}, {1,6}}},
+	{ 0x0A3, {{1,3}, {1,6}, {1,6}}},
+	{ 0x0DA, {{1,4}, {1,4}, {1,8}}},
+	{ 0x0DC, {{1,4}, {1,4}, {1,8}}},
+	{ 0x0EC, {{1,4}, {1,8}, {1,8}}},
+	{ 0x123, {{1,4}, {1,4}, {1,8}}},
+	{ 0x16C, {{1,4}, {1,8}, {1,8}}},
+};
+
+struct memclk_data {
+	unsigned char multiplier;
+	unsigned char divisor;
+};
+
+static struct memclk_data st40_memclk_table[8] = {
+	{1,1},	// 000
+	{1,2},	// 001
+	{1,3},	// 010
+	{2,3},	// 011
+	{1,4},	// 100
+	{1,6},	// 101
+	{1,8},	// 110
+	{1,8}	// 111
+};
+
+static void st40_specific_time_init(unsigned int module_clock, unsigned short frqcr)
+{
+	unsigned int cpu_clock, master_clock, bus_clock, memory_clock;
+	struct frqcr_data *d;
+	int a;
+	unsigned long memclkcr;
+	struct memclk_data *e;
+
+	for (a = 0; a < ARRAY_SIZE(st40_frqcr_table); a++) {
+		d = &st40_frqcr_table[a];
+
+		if (d->frqcr == (frqcr & 0x1ff))
+			break;
+	}
+
+	if (a == ARRAY_SIZE(st40_frqcr_table)) {
+		d = st40_frqcr_table;
+
+		printk("ERROR: Unrecognised FRQCR value (0x%x), "
+		       "using default multipliers\n", frqcr);
+	}
+
+	memclkcr = ctrl_inl(CLOCKGEN_MEMCLKCR);
+	e = &st40_memclk_table[memclkcr & MEMCLKCR_RATIO_MASK];
+
+	printk(KERN_INFO "Clock multipliers: CPU: %d/%d Bus: %d/%d "
+	       "Mem: %d/%d Periph: %d/%d\n",
+	       d->factor[0].multiplier, d->factor[0].divisor,
+	       d->factor[1].multiplier, d->factor[1].divisor,
+	       e->multiplier,           e->divisor,
+	       d->factor[2].multiplier, d->factor[2].divisor);
+
+	master_clock = module_clock * d->factor[2].divisor
+				    / d->factor[2].multiplier;
+	bus_clock    = master_clock * d->factor[1].multiplier
+				    / d->factor[1].divisor;
+	memory_clock = master_clock * e->multiplier
+				    / e->divisor;
+	cpu_clock    = master_clock * d->factor[0].multiplier
+				    / d->factor[0].divisor;
+
+	current_cpu_data.cpu_clock    = cpu_clock;
+	current_cpu_data.master_clock = master_clock;
+	current_cpu_data.bus_clock    = bus_clock;
+	current_cpu_data.memory_clock = memory_clock;
+	current_cpu_data.module_clock = module_clock;
+}
+#endif
+
+void __init time_init(void)
+{
+	unsigned int timer_freq = 0;
+	unsigned int ifc, pfc, bfc;
+	unsigned long interval;
+#ifdef CONFIG_CPU_SUBTYPE_ST40STB1
+	unsigned long pvr;
+	unsigned short frqcr;
+#endif
+
+	if (board_time_init)
+		board_time_init();
+
+	/*
+	 * If we don't have an RTC (such as with the SH7300), don't attempt to
+	 * probe the timer frequency. Rely on an either hardcoded peripheral
+	 * clock value, or on the sh_pclk command line option. Note that we
+	 * still need to have CONFIG_SH_PCLK_FREQ set in order for things like
+	 * CLOCK_TICK_RATE to be sane.
+	 */
+	current_cpu_data.module_clock = sh_pclk_freq;
+
+#ifdef CONFIG_SH_PCLK_CALC
+	/* XXX: Switch this over to a more generic test. */
+	{
+		unsigned int freq;
+
+		/*
+		 * If we've specified a peripheral clock frequency, and we have
+		 * an RTC, compare it against the autodetected value. Complain
+		 * if there's a mismatch.
+		 */
+		timer_freq = get_timer_frequency();
+		freq = timer_freq * 4;
+
+		if (sh_pclk_freq && (sh_pclk_freq/100*99 > freq || sh_pclk_freq/100*101 < freq)) {
+			printk(KERN_NOTICE "Calculated peripheral clock value "
+			       "%d differs from sh_pclk value %d, fixing..\n",
+			       freq, sh_pclk_freq);
+			current_cpu_data.module_clock = freq;
+		}
+	}
+#endif
+
+#ifdef CONFIG_CPU_SUBTYPE_ST40STB1
+	/* XXX: Update ST40 code to use board_time_init() */
+	pvr = ctrl_inl(CCN_PVR);
+	frqcr = ctrl_inw(FRQCR);
+	printk("time.c ST40 Probe: PVR %08lx, FRQCR %04hx\n", pvr, frqcr);
+
+	if (((pvr >> CCN_PVR_CHIP_SHIFT) & CCN_PVR_CHIP_MASK) == CCN_PVR_CHIP_ST40STB1)
+		st40_specific_time_init(current_cpu_data.module_clock, frqcr);
+	else
+#endif
+		get_current_frequency_divisors(&ifc, &bfc, &pfc);
+
+	if (rtc_get_time) {
+		rtc_get_time(&xtime);
+	} else {
+		xtime.tv_sec = mktime(2000, 1, 1, 0, 0, 0);
+		xtime.tv_nsec = 0;
+	}
+
+        set_normalized_timespec(&wall_to_monotonic,
+                                -xtime.tv_sec, -xtime.tv_nsec);
+
+	if (board_timer_setup) {
+		board_timer_setup(&irq0);
+	} else {
+		setup_irq(TIMER_IRQ, &irq0);
+	}
+
+	/*
+	 * for ST40 chips the current_cpu_data should already be set
+	 * so not having valid pfc/bfc/ifc shouldn't be a problem
+	 */
+	if (!current_cpu_data.master_clock)
+		current_cpu_data.master_clock = current_cpu_data.module_clock * pfc;
+	if (!current_cpu_data.bus_clock)
+		current_cpu_data.bus_clock = current_cpu_data.master_clock / bfc;
+	if (!current_cpu_data.cpu_clock)
+		current_cpu_data.cpu_clock = current_cpu_data.master_clock / ifc;
+
+	printk("CPU clock: %d.%02dMHz\n",
+	       (current_cpu_data.cpu_clock / 1000000),
+	       (current_cpu_data.cpu_clock % 1000000)/10000);
+	printk("Bus clock: %d.%02dMHz\n",
+	       (current_cpu_data.bus_clock / 1000000),
+	       (current_cpu_data.bus_clock % 1000000)/10000);
+#ifdef CONFIG_CPU_SUBTYPE_ST40STB1
+	printk("Memory clock: %d.%02dMHz\n",
+	       (current_cpu_data.memory_clock / 1000000),
+	       (current_cpu_data.memory_clock % 1000000)/10000);
+#endif
+	printk("Module clock: %d.%02dMHz\n",
+	       (current_cpu_data.module_clock / 1000000),
+	       (current_cpu_data.module_clock % 1000000)/10000);
+
+	interval = (current_cpu_data.module_clock/4 + HZ/2) / HZ;
+
+	printk("Interval = %ld\n", interval);
+
+	/* Start TMU0 */
+	ctrl_outb(0, TMU_TSTR);
+#if !defined(CONFIG_CPU_SUBTYPE_SH7300)
+	ctrl_outb(TMU_TOCR_INIT, TMU_TOCR);
+#endif
+	ctrl_outw(TMU0_TCR_INIT, TMU0_TCR);
+	ctrl_outl(interval, TMU0_TCOR);
+	ctrl_outl(interval, TMU0_TCNT);
+	ctrl_outb(TMU_TSTR_INIT, TMU_TSTR);
+
+#if defined(CONFIG_SH_KGDB)
+	/*
+	 * Set up kgdb as requested. We do it here because the serial
+	 * init uses the timer vars we just set up for figuring baud.
+	 */
+	kgdb_init();
+#endif
+}
diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c
new file mode 100644
index 0000000..7eb0671
--- /dev/null
+++ b/arch/sh/kernel/traps.c
@@ -0,0 +1,712 @@
+/* $Id: traps.c,v 1.17 2004/05/02 01:46:30 sugioka Exp $
+ *
+ *  linux/arch/sh/traps.c
+ *
+ *  SuperH version: Copyright (C) 1999 Niibe Yutaka
+ *                  Copyright (C) 2000 Philipp Rumpf
+ *                  Copyright (C) 2000 David Howells
+ *                  Copyright (C) 2002, 2003 Paul Mundt
+ */
+
+/*
+ * 'Traps.c' handles hardware traps and faults after we have saved some
+ * state in 'entry.S'.
+ */
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/kallsyms.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include <asm/processor.h>
+#include <asm/sections.h>
+
+#ifdef CONFIG_SH_KGDB
+#include <asm/kgdb.h>
+#define CHK_REMOTE_DEBUG(regs)                                               \
+{                                                                            \
+  if ((kgdb_debug_hook != (kgdb_debug_hook_t *) NULL) && (!user_mode(regs))) \
+  {                                                                          \
+    (*kgdb_debug_hook)(regs);                                                \
+  }                                                                          \
+}
+#else
+#define CHK_REMOTE_DEBUG(regs)
+#endif
+
+#define DO_ERROR(trapnr, signr, str, name, tsk)				\
+asmlinkage void do_##name(unsigned long r4, unsigned long r5,		\
+			  unsigned long r6, unsigned long r7,		\
+			  struct pt_regs regs)				\
+{									\
+	unsigned long error_code;					\
+ 									\
+	/* Check if it's a DSP instruction */				\
+ 	if (is_dsp_inst(&regs)) {					\
+		/* Enable DSP mode, and restart instruction. */		\
+		regs.sr |= SR_DSP;					\
+		return;							\
+	}								\
+									\
+	asm volatile("stc	r2_bank, %0": "=r" (error_code));	\
+	local_irq_enable();						\
+	tsk->thread.error_code = error_code;				\
+	tsk->thread.trap_no = trapnr;					\
+        CHK_REMOTE_DEBUG(&regs);					\
+	force_sig(signr, tsk);						\
+	die_if_no_fixup(str,&regs,error_code);				\
+}
+
+#ifdef CONFIG_CPU_SH2
+#define TRAP_RESERVED_INST	4
+#define TRAP_ILLEGAL_SLOT_INST	6
+#else
+#define TRAP_RESERVED_INST	12
+#define TRAP_ILLEGAL_SLOT_INST	13
+#endif
+
+/*
+ * These constants are for searching for possible module text
+ * segments.  VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is
+ * a guess of how much space is likely to be vmalloced.
+ */
+#define VMALLOC_OFFSET (8*1024*1024)
+#define MODULE_RANGE (8*1024*1024)
+
+spinlock_t die_lock;
+
+void die(const char * str, struct pt_regs * regs, long err)
+{
+	static int die_counter;
+
+	console_verbose();
+	spin_lock_irq(&die_lock);
+	printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
+	CHK_REMOTE_DEBUG(regs);
+	show_regs(regs);
+	spin_unlock_irq(&die_lock);
+	do_exit(SIGSEGV);
+}
+
+static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err)
+{
+	if (!user_mode(regs))
+		die(str, regs, err);
+}
+
+static int handle_unaligned_notify_count = 10;
+
+/*
+ * try and fix up kernelspace address errors
+ * - userspace errors just cause EFAULT to be returned, resulting in SEGV
+ * - kernel/userspace interfaces cause a jump to an appropriate handler
+ * - other kernel errors are bad
+ * - return 0 if fixed-up, -EFAULT if non-fatal (to the kernel) fault
+ */
+static int die_if_no_fixup(const char * str, struct pt_regs * regs, long err)
+{
+	if (!user_mode(regs))
+	{
+		const struct exception_table_entry *fixup;
+		fixup = search_exception_tables(regs->pc);
+		if (fixup) {
+			regs->pc = fixup->fixup;
+			return 0;
+		}
+		die(str, regs, err);
+	}
+	return -EFAULT;
+}
+
+/*
+ * handle an instruction that does an unaligned memory access by emulating the
+ * desired behaviour
+ * - note that PC _may not_ point to the faulting instruction
+ *   (if that instruction is in a branch delay slot)
+ * - return 0 if emulation okay, -EFAULT on existential error
+ */
+static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs)
+{
+	int ret, index, count;
+	unsigned long *rm, *rn;
+	unsigned char *src, *dst;
+
+	index = (instruction>>8)&15;	/* 0x0F00 */
+	rn = &regs->regs[index];
+
+	index = (instruction>>4)&15;	/* 0x00F0 */
+	rm = &regs->regs[index];
+
+	count = 1<<(instruction&3);
+
+	ret = -EFAULT;
+	switch (instruction>>12) {
+	case 0: /* mov.[bwl] to/from memory via r0+rn */
+		if (instruction & 8) {
+			/* from memory */
+			src = (unsigned char*) *rm;
+			src += regs->regs[0];
+			dst = (unsigned char*) rn;
+			*(unsigned long*)dst = 0;
+
+#ifdef __LITTLE_ENDIAN__
+			if (copy_from_user(dst, src, count))
+				goto fetch_fault;
+
+			if ((count == 2) && dst[1] & 0x80) {
+				dst[2] = 0xff;
+				dst[3] = 0xff;
+			}
+#else
+			dst += 4-count;
+
+			if (__copy_user(dst, src, count))
+				goto fetch_fault;
+
+			if ((count == 2) && dst[2] & 0x80) {
+				dst[0] = 0xff;
+				dst[1] = 0xff;
+			}
+#endif
+		} else {
+			/* to memory */
+			src = (unsigned char*) rm;
+#if !defined(__LITTLE_ENDIAN__)
+			src += 4-count;
+#endif
+			dst = (unsigned char*) *rn;
+			dst += regs->regs[0];
+
+			if (copy_to_user(dst, src, count))
+				goto fetch_fault;
+		}
+		ret = 0;
+		break;
+
+	case 1: /* mov.l Rm,@(disp,Rn) */
+		src = (unsigned char*) rm;
+		dst = (unsigned char*) *rn;
+		dst += (instruction&0x000F)<<2;
+
+		if (copy_to_user(dst,src,4))
+			goto fetch_fault;
+		ret = 0;
+ 		break;
+
+	case 2: /* mov.[bwl] to memory, possibly with pre-decrement */
+		if (instruction & 4)
+			*rn -= count;
+		src = (unsigned char*) rm;
+		dst = (unsigned char*) *rn;
+#if !defined(__LITTLE_ENDIAN__)
+		src += 4-count;
+#endif
+		if (copy_to_user(dst, src, count))
+			goto fetch_fault;
+		ret = 0;
+		break;
+
+	case 5: /* mov.l @(disp,Rm),Rn */
+		src = (unsigned char*) *rm;
+		src += (instruction&0x000F)<<2;
+		dst = (unsigned char*) rn;
+		*(unsigned long*)dst = 0;
+
+		if (copy_from_user(dst,src,4))
+			goto fetch_fault;
+		ret = 0;
+ 		break;
+
+	case 6:	/* mov.[bwl] from memory, possibly with post-increment */
+		src = (unsigned char*) *rm;
+		if (instruction & 4)
+			*rm += count;
+		dst = (unsigned char*) rn;
+		*(unsigned long*)dst = 0;
+		
+#ifdef __LITTLE_ENDIAN__
+		if (copy_from_user(dst, src, count))
+			goto fetch_fault;
+
+		if ((count == 2) && dst[1] & 0x80) {
+			dst[2] = 0xff;
+			dst[3] = 0xff;
+		}
+#else
+		dst += 4-count;
+		
+		if (copy_from_user(dst, src, count))
+			goto fetch_fault;
+
+		if ((count == 2) && dst[2] & 0x80) {
+			dst[0] = 0xff;
+			dst[1] = 0xff;
+		}
+#endif
+		ret = 0;
+		break;
+
+	case 8:
+		switch ((instruction&0xFF00)>>8) {
+		case 0x81: /* mov.w R0,@(disp,Rn) */
+			src = (unsigned char*) &regs->regs[0];
+#if !defined(__LITTLE_ENDIAN__)
+			src += 2;
+#endif
+			dst = (unsigned char*) *rm; /* called Rn in the spec */
+			dst += (instruction&0x000F)<<1;
+
+			if (copy_to_user(dst, src, 2))
+				goto fetch_fault;
+			ret = 0;
+			break;
+
+		case 0x85: /* mov.w @(disp,Rm),R0 */
+			src = (unsigned char*) *rm;
+			src += (instruction&0x000F)<<1;
+			dst = (unsigned char*) &regs->regs[0];
+			*(unsigned long*)dst = 0;
+
+#if !defined(__LITTLE_ENDIAN__)
+			dst += 2;
+#endif
+
+			if (copy_from_user(dst, src, 2))
+				goto fetch_fault;
+
+#ifdef __LITTLE_ENDIAN__
+			if (dst[1] & 0x80) {
+				dst[2] = 0xff;
+				dst[3] = 0xff;
+			}
+#else
+			if (dst[2] & 0x80) {
+				dst[0] = 0xff;
+				dst[1] = 0xff;
+			}
+#endif
+			ret = 0;
+			break;
+		}
+		break;
+	}
+	return ret;
+
+ fetch_fault:
+	/* Argh. Address not only misaligned but also non-existent.
+	 * Raise an EFAULT and see if it's trapped
+	 */
+	return die_if_no_fixup("Fault in unaligned fixup", regs, 0);
+}
+
+/*
+ * emulate the instruction in the delay slot
+ * - fetches the instruction from PC+2
+ */
+static inline int handle_unaligned_delayslot(struct pt_regs *regs)
+{
+	u16 instruction;
+
+	if (copy_from_user(&instruction, (u16 *)(regs->pc+2), 2)) {
+		/* the instruction-fetch faulted */
+		if (user_mode(regs))
+			return -EFAULT;
+
+		/* kernel */
+		die("delay-slot-insn faulting in handle_unaligned_delayslot", regs, 0);
+	}
+
+	return handle_unaligned_ins(instruction,regs);
+}
+
+/*
+ * handle an instruction that does an unaligned memory access
+ * - have to be careful of branch delay-slot instructions that fault
+ *  SH3:
+ *   - if the branch would be taken PC points to the branch
+ *   - if the branch would not be taken, PC points to delay-slot
+ *  SH4:
+ *   - PC always points to delayed branch
+ * - return 0 if handled, -EFAULT if failed (may not return if in kernel)
+ */
+
+/* Macros to determine offset from current PC for branch instructions */
+/* Explicit type coercion is used to force sign extension where needed */
+#define SH_PC_8BIT_OFFSET(instr) ((((signed char)(instr))*2) + 4)
+#define SH_PC_12BIT_OFFSET(instr) ((((signed short)(instr<<4))>>3) + 4)
+
+static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
+{
+	u_int rm;
+	int ret, index;
+
+	index = (instruction>>8)&15;	/* 0x0F00 */
+	rm = regs->regs[index];
+
+	/* shout about the first ten userspace fixups */
+	if (user_mode(regs) && handle_unaligned_notify_count>0) {
+		handle_unaligned_notify_count--;
+
+		printk("Fixing up unaligned userspace access in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
+		       current->comm,current->pid,(u16*)regs->pc,instruction);
+	}
+
+	ret = -EFAULT;
+	switch (instruction&0xF000) {
+	case 0x0000:
+		if (instruction==0x000B) {
+			/* rts */
+			ret = handle_unaligned_delayslot(regs);
+			if (ret==0)
+				regs->pc = regs->pr;
+		}
+		else if ((instruction&0x00FF)==0x0023) {
+			/* braf @Rm */
+			ret = handle_unaligned_delayslot(regs);
+			if (ret==0)
+				regs->pc += rm + 4;
+		}
+		else if ((instruction&0x00FF)==0x0003) {
+			/* bsrf @Rm */
+			ret = handle_unaligned_delayslot(regs);
+			if (ret==0) {
+				regs->pr = regs->pc + 4;
+				regs->pc += rm + 4;
+			}
+		}
+		else {
+			/* mov.[bwl] to/from memory via r0+rn */
+			goto simple;
+		}
+		break;
+
+	case 0x1000: /* mov.l Rm,@(disp,Rn) */
+		goto simple;
+
+	case 0x2000: /* mov.[bwl] to memory, possibly with pre-decrement */
+		goto simple;
+
+	case 0x4000:
+		if ((instruction&0x00FF)==0x002B) {
+			/* jmp @Rm */
+			ret = handle_unaligned_delayslot(regs);
+			if (ret==0)
+				regs->pc = rm;
+		}
+		else if ((instruction&0x00FF)==0x000B) {
+			/* jsr @Rm */
+			ret = handle_unaligned_delayslot(regs);
+			if (ret==0) {
+				regs->pr = regs->pc + 4;
+				regs->pc = rm;
+			}
+		}
+		else {
+			/* mov.[bwl] to/from memory via r0+rn */
+			goto simple;
+		}
+		break;
+
+	case 0x5000: /* mov.l @(disp,Rm),Rn */
+		goto simple;
+
+	case 0x6000: /* mov.[bwl] from memory, possibly with post-increment */
+		goto simple;
+
+	case 0x8000: /* bf lab, bf/s lab, bt lab, bt/s lab */
+		switch (instruction&0x0F00) {
+		case 0x0100: /* mov.w R0,@(disp,Rm) */
+			goto simple;
+		case 0x0500: /* mov.w @(disp,Rm),R0 */
+			goto simple;
+		case 0x0B00: /* bf   lab - no delayslot*/
+			break;
+		case 0x0F00: /* bf/s lab */
+			ret = handle_unaligned_delayslot(regs);
+			if (ret==0) {
+#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
+				if ((regs->sr & 0x00000001) != 0)
+					regs->pc += 4; /* next after slot */
+				else
+#endif
+					regs->pc += SH_PC_8BIT_OFFSET(instruction);
+			}
+			break;
+		case 0x0900: /* bt   lab - no delayslot */
+			break;
+		case 0x0D00: /* bt/s lab */
+			ret = handle_unaligned_delayslot(regs);
+			if (ret==0) {
+#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
+				if ((regs->sr & 0x00000001) == 0)
+					regs->pc += 4; /* next after slot */
+				else
+#endif
+					regs->pc += SH_PC_8BIT_OFFSET(instruction);
+			}
+			break;
+		}
+		break;
+
+	case 0xA000: /* bra label */
+		ret = handle_unaligned_delayslot(regs);
+		if (ret==0)
+			regs->pc += SH_PC_12BIT_OFFSET(instruction);
+		break;
+
+	case 0xB000: /* bsr label */
+		ret = handle_unaligned_delayslot(regs);
+		if (ret==0) {
+			regs->pr = regs->pc + 4;
+			regs->pc += SH_PC_12BIT_OFFSET(instruction);
+		}
+		break;
+	}
+	return ret;
+
+	/* handle non-delay-slot instruction */
+ simple:
+	ret = handle_unaligned_ins(instruction,regs);
+	if (ret==0)
+		regs->pc += 2;
+	return ret;
+}
+
+/*
+ * Handle various address error exceptions
+ */
+asmlinkage void do_address_error(struct pt_regs *regs, 
+				 unsigned long writeaccess,
+				 unsigned long address)
+{
+	unsigned long error_code;
+	mm_segment_t oldfs;
+	u16 instruction;
+	int tmp;
+
+	asm volatile("stc       r2_bank,%0": "=r" (error_code));
+
+	oldfs = get_fs();
+
+	if (user_mode(regs)) {
+		local_irq_enable();
+		current->thread.error_code = error_code;
+		current->thread.trap_no = (writeaccess) ? 8 : 7;
+
+		/* bad PC is not something we can fix */
+		if (regs->pc & 1)
+			goto uspace_segv;
+
+		set_fs(USER_DS);
+		if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) {
+			/* Argh. Fault on the instruction itself.
+			   This should never happen non-SMP
+			*/
+			set_fs(oldfs);
+			goto uspace_segv;
+		}
+
+		tmp = handle_unaligned_access(instruction, regs);
+		set_fs(oldfs);
+
+		if (tmp==0)
+			return; /* sorted */
+
+	uspace_segv:
+		printk(KERN_NOTICE "Killing process \"%s\" due to unaligned access\n", current->comm);
+		force_sig(SIGSEGV, current);
+	} else {
+		if (regs->pc & 1)
+			die("unaligned program counter", regs, error_code);
+
+		set_fs(KERNEL_DS);
+		if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) {
+			/* Argh. Fault on the instruction itself.
+			   This should never happen non-SMP
+			*/
+			set_fs(oldfs);
+			die("insn faulting in do_address_error", regs, 0);
+		}
+
+		handle_unaligned_access(instruction, regs);
+		set_fs(oldfs);
+	}
+}
+
+#ifdef CONFIG_SH_DSP
+/*
+ *	SH-DSP support gerg@snapgear.com.
+ */
+int is_dsp_inst(struct pt_regs *regs)
+{
+	unsigned short inst;
+
+	/* 
+	 * Safe guard if DSP mode is already enabled or we're lacking
+	 * the DSP altogether.
+	 */
+	if (!(cpu_data->flags & CPU_HAS_DSP) || (regs->sr & SR_DSP))
+		return 0;
+
+	get_user(inst, ((unsigned short *) regs->pc));
+
+	inst &= 0xf000;
+
+	/* Check for any type of DSP or support instruction */
+	if ((inst == 0xf000) || (inst == 0x4000))
+		return 1;
+
+	return 0;
+}
+#else
+#define is_dsp_inst(regs)	(0)
+#endif /* CONFIG_SH_DSP */
+
+DO_ERROR(TRAP_RESERVED_INST, SIGILL, "reserved instruction", reserved_inst, current)
+DO_ERROR(TRAP_ILLEGAL_SLOT_INST, SIGILL, "illegal slot instruction", illegal_slot_inst, current)
+
+asmlinkage void do_exception_error(unsigned long r4, unsigned long r5,
+				   unsigned long r6, unsigned long r7,
+				   struct pt_regs regs)
+{
+	long ex;
+	asm volatile("stc	r2_bank, %0" : "=r" (ex));
+	die_if_kernel("exception", &regs, ex);
+}
+
+#if defined(CONFIG_SH_STANDARD_BIOS)
+void *gdb_vbr_vector;
+
+static inline void __init gdb_vbr_init(void)
+{
+	register unsigned long vbr;
+
+	/*
+	 * Read the old value of the VBR register to initialise
+	 * the vector through which debug and BIOS traps are
+	 * delegated by the Linux trap handler.
+	 */
+	asm volatile("stc vbr, %0" : "=r" (vbr));
+
+	gdb_vbr_vector = (void *)(vbr + 0x100);
+	printk("Setting GDB trap vector to 0x%08lx\n",
+	       (unsigned long)gdb_vbr_vector);
+}
+#endif
+
+void __init per_cpu_trap_init(void)
+{
+	extern void *vbr_base;
+
+#ifdef CONFIG_SH_STANDARD_BIOS
+	gdb_vbr_init();
+#endif
+
+	/* NOTE: The VBR value should be at P1
+	   (or P2, virtural "fixed" address space).
+	   It's definitely should not in physical address.  */
+
+	asm volatile("ldc	%0, vbr"
+		     : /* no output */
+		     : "r" (&vbr_base)
+		     : "memory");
+}
+
+void __init trap_init(void)
+{
+	extern void *exception_handling_table[];
+
+	exception_handling_table[TRAP_RESERVED_INST]
+		= (void *)do_reserved_inst;
+	exception_handling_table[TRAP_ILLEGAL_SLOT_INST]
+		= (void *)do_illegal_slot_inst;
+
+#ifdef CONFIG_CPU_SH4
+	if (!(cpu_data->flags & CPU_HAS_FPU)) {
+		/* For SH-4 lacking an FPU, treat floating point instructions
+		   as reserved. */
+		/* entry 64 corresponds to EXPEVT=0x800 */
+		exception_handling_table[64] = (void *)do_reserved_inst;
+		exception_handling_table[65] = (void *)do_illegal_slot_inst;
+	}
+#endif
+		
+	/* Setup VBR for boot cpu */
+	per_cpu_trap_init();
+}
+
+void show_stack(struct task_struct *tsk, unsigned long *sp)
+{
+	unsigned long *stack, addr;
+	unsigned long module_start = VMALLOC_START;
+	unsigned long module_end = VMALLOC_END;
+	int i = 1;
+
+	if (tsk && !sp) {
+		sp = (unsigned long *)tsk->thread.sp;
+	}
+
+	if (!sp) {
+		__asm__ __volatile__ (
+			"mov r15, %0\n\t"
+			"stc r7_bank, %1\n\t"
+			: "=r" (module_start),
+			  "=r" (module_end)
+		);
+		
+		sp = (unsigned long *)module_start;
+	}
+
+	stack = sp;
+
+	printk("\nCall trace: ");
+#ifdef CONFIG_KALLSYMS
+	printk("\n");
+#endif
+
+	while (!kstack_end(stack)) {
+		addr = *stack++;
+		if (((addr >= (unsigned long)_text) &&
+		     (addr <= (unsigned long)_etext)) ||
+		    ((addr >= module_start) && (addr <= module_end))) {
+			/*
+			 * For 80-columns display, 6 entry is maximum.
+			 * NOTE: '[<8c00abcd>] ' consumes 13 columns .
+			 */
+#ifndef CONFIG_KALLSYMS
+			if (i && ((i % 6) == 0))
+				printk("\n       ");
+#endif
+			printk("[<%08lx>] ", addr);
+			print_symbol("%s\n", addr);
+			i++;
+		}
+	}
+
+	printk("\n");
+}
+
+void show_task(unsigned long *sp)
+{
+	show_stack(NULL, sp);
+}
+
+void dump_stack(void)
+{
+	show_stack(NULL, NULL);
+}
+EXPORT_SYMBOL(dump_stack);
diff --git a/arch/sh/kernel/vmlinux.lds.S b/arch/sh/kernel/vmlinux.lds.S
new file mode 100644
index 0000000..51bdc1c
--- /dev/null
+++ b/arch/sh/kernel/vmlinux.lds.S
@@ -0,0 +1,155 @@
+/* $Id: vmlinux.lds.S,v 1.8 2003/05/16 17:18:14 lethal Exp $
+ * ld script to make SuperH Linux kernel
+ * Written by Niibe Yutaka
+ */
+#include <linux/config.h>
+#include <asm-generic/vmlinux.lds.h>
+
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
+OUTPUT_FORMAT("elf32-sh-linux", "elf32-sh-linux", "elf32-sh-linux")
+#else
+OUTPUT_FORMAT("elf32-shbig-linux", "elf32-shbig-linux", "elf32-shbig-linux")
+#endif
+OUTPUT_ARCH(sh)
+ENTRY(_start)
+SECTIONS
+{
+  . = 0x80000000 + CONFIG_MEMORY_START + CONFIG_ZERO_PAGE_OFFSET;
+  _text = .;			/* Text and read-only data */
+  text = .;			/* Text and read-only data */
+  .empty_zero_page : {
+	*(.empty_zero_page)
+	} = 0
+  .text : {
+	*(.text)
+	SCHED_TEXT
+	LOCK_TEXT
+	*(.fixup)
+	*(.gnu.warning)
+	} = 0x0009
+
+  . = ALIGN(16);		/* Exception table */
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+
+  RODATA
+
+  _etext = .;			/* End of text section */
+
+  .data : {			/* Data */
+	*(.data)
+
+ 	 /* Align the initial ramdisk image (INITRD) on page boundaries. */
+ 	 . = ALIGN(4096);
+ 	 __rd_start = .;
+ 	 *(.initrd)
+ 	 . = ALIGN(4096);
+ 	 __rd_end = .;
+
+	CONSTRUCTORS
+	}
+
+  . = ALIGN(4096);
+  .data.page_aligned : { *(.data.idt) }
+
+  . = ALIGN(32);
+  __per_cpu_start = .;
+  .data.percpu : { *(.data.percpu) }
+  __per_cpu_end = .;
+  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+
+  _edata = .;			/* End of data section */
+
+  . = ALIGN(8192);		/* init_task */
+  .data.init_task : { *(.data.init_task) }
+  /* stack */
+  .stack : { stack = .;  _stack = .; }
+
+  . = ALIGN(4096);		/* Init code and data */
+  __init_begin = .;
+  _sinittext = .;
+  .init.text : { *(.init.text) }
+  _einittext = .;
+  .init.data : { *(.init.data) }
+  . = ALIGN(16);
+  __setup_start = .;
+  .init.setup : { *(.init.setup) }
+  __setup_end = .;
+  __initcall_start = .;
+  .initcall.init : {
+	*(.initcall1.init) 
+	*(.initcall2.init) 
+	*(.initcall3.init) 
+	*(.initcall4.init) 
+	*(.initcall5.init) 
+	*(.initcall6.init) 
+	*(.initcall7.init)
+  }
+  __initcall_end = .;
+  __con_initcall_start = .;
+  .con_initcall.init : { *(.con_initcall.init) }
+  __con_initcall_end = .;
+  SECURITY_INIT
+  __initramfs_start = .;
+  .init.ramfs : { *(.init.ramfs) }
+  __initramfs_end = .;
+  __machvec_start = .;
+  .init.machvec : { *(.init.machvec) }
+  __machvec_end = .;
+  . = ALIGN(4096);
+  __init_end = .;
+
+  . = ALIGN(4);
+  __bss_start = .;		/* BSS */
+  .bss : { *(.bss) }
+
+  . = ALIGN(4);
+  _end = . ;
+
+  /* When something in the kernel is NOT compiled as a module, the
+   * module cleanup code and data are put into these segments.  Both
+   * can then be thrown away, as cleanup code is never called unless
+   * it's a module.
+   */
+  /DISCARD/ : {
+	*(.exit.text)
+	*(.exit.data)
+	*(.exitcall.exit)
+	}
+
+  /* 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) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging section are relative to the beginning
+     of the section so we begin .debug at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+  /* These must appear regardless of  .  */
+}