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/v850/Kconfig b/arch/v850/Kconfig
new file mode 100644
index 0000000..90cd4ba
--- /dev/null
+++ b/arch/v850/Kconfig
@@ -0,0 +1,316 @@
+#############################################################################
+#
+# For a description of the syntax of this configuration file,
+# see Documentation/kbuild/kconfig-language.txt.
+#
+#############################################################################
+
+mainmenu "uClinux/v850 (w/o MMU) Kernel Configuration"
+
+config MMU
+       	bool
+	default n
+config UID16
+	bool
+	default n
+config RWSEM_GENERIC_SPINLOCK
+	bool
+	default y
+config RWSEM_XCHGADD_ALGORITHM
+	bool
+	default n
+config GENERIC_CALIBRATE_DELAY
+	bool
+	default y
+
+# Turn off some random 386 crap that can affect device config
+config ISA
+	bool
+	default n
+config ISAPNP
+	bool
+	default n
+config EISA
+	bool
+	default n
+config MCA
+	bool
+	default n
+
+
+#############################################################################
+#### v850-specific config
+
+# Define the architecture
+config V850
+	bool
+	default y
+
+menu "Processor type and features"
+
+   choice
+	  prompt "Platform"
+	  default GDB
+      config V850E_SIM
+      	     bool "GDB"
+      config RTE_CB_MA1
+      	     bool "RTE-V850E/MA1-CB"
+      config RTE_CB_NB85E
+      	     bool "RTE-V850E/NB85E-CB"
+      config RTE_CB_ME2
+      	     bool "RTE-V850E/ME2-CB"
+      config V850E_AS85EP1
+      	     bool "AS85EP1"
+      config V850E2_SIM85E2C
+      	     bool "sim85e2c"
+      config V850E2_SIM85E2S
+      	     bool "sim85e2s"
+      config V850E2_FPGA85E2C
+      	     bool "NA85E2C-FPGA"
+      config V850E2_ANNA
+      	     bool "Anna"
+   endchoice
+
+   #### V850E processor-specific config
+
+   # All CPUs currently supported use the v850e architecture
+   config V850E
+   	  bool
+	  default y
+
+   # The RTE-V850E/MA1-CB is the only type of V850E/MA1 platform we
+   # currently support
+   config V850E_MA1
+   	  bool
+	  depends RTE_CB_MA1
+	  default y
+   # Similarly for the RTE-V850E/NB85E-CB - V850E/TEG
+   config V850E_TEG
+   	  bool
+	  depends RTE_CB_NB85E
+	  default y
+   # ... and the RTE-V850E/ME2-CB - V850E/ME2
+   config V850E_ME2
+   	  bool
+	  depends RTE_CB_ME2
+	  default y
+
+
+   #### sim85e2-specific config
+
+   config V850E2_SIM85E2
+   	  bool
+	  depends V850E2_SIM85E2C || V850E2_SIM85E2S
+	  default y
+
+
+   #### V850E2 processor-specific config
+
+   # V850E2 processors
+   config V850E2
+   	  bool
+	  depends V850E2_SIM85E2 || V850E2_FPGA85E2C || V850E2_ANNA
+	  default y
+
+
+   #### RTE-CB platform-specific config
+
+   # Boards in the RTE-x-CB series
+   config RTE_CB
+   	  bool
+	  depends RTE_CB_MA1 || RTE_CB_NB85E || RTE_CB_ME2
+	  default y
+
+   config RTE_CB_MULTI
+   	  bool
+	  # RTE_CB_NB85E can either have multi ROM support or not, but
+	  # other platforms (currently only RTE_CB_MA1) require it.
+	  prompt "Multi monitor ROM support" if RTE_CB_NB85E
+	  depends RTE_CB_MA1 || RTE_CB_NB85E
+	  default y
+
+   config RTE_CB_MULTI_DBTRAP
+   	  bool "Pass illegal insn trap / dbtrap to kernel"
+	  depends RTE_CB_MULTI
+	  default n
+
+   config RTE_CB_MA1_KSRAM
+   	  bool "Kernel in SRAM (limits size of kernel)"
+	  depends RTE_CB_MA1 && RTE_CB_MULTI
+	  default n
+
+   config RTE_MB_A_PCI
+   	  bool "Mother-A PCI support"
+	  depends RTE_CB
+	  default y
+
+   # The GBUS is used to talk to the RTE-MOTHER-A board
+   config RTE_GBUS_INT
+   	  bool
+	  depends RTE_MB_A_PCI
+	  default y
+
+   # The only PCI bus we support is on the RTE-MOTHER-A board
+   config PCI
+   	  bool
+	  default RTE_MB_A_PCI
+
+   #### Some feature-specific configs
+
+   # Everything except for the GDB simulator uses the same interrupt controller
+   config V850E_INTC
+   	  bool
+	  default !V850E_SIM
+
+   # Everything except for the various simulators uses the "Timer D" unit
+   config V850E_TIMER_D
+   	  bool
+	  default !V850E_SIM && !V850E2_SIM85E2
+
+   # Cache control used on some v850e1 processors
+   config V850E_CACHE
+          bool
+	  default V850E_TEG || V850E_ME2
+
+   # Cache control used on v850e2 processors; I think this should
+   # actually apply to more, but currently only the SIM85E2S uses it
+   config V850E2_CACHE
+   	  bool
+	  default V850E2_SIM85E2S
+
+   config NO_CACHE
+   	  bool
+	  default !V850E_CACHE && !V850E2_CACHE
+
+   #### Misc config
+
+   config ROM_KERNEL
+   	  bool "Kernel in ROM"
+	  depends V850E2_ANNA || V850E_AS85EP1 || RTE_CB_ME2
+
+   # Some platforms pre-zero memory, in which case the kernel doesn't need to
+   config ZERO_BSS
+   	  bool
+	  depends !V850E2_SIM85E2C
+	  default y
+
+   # The crappy-ass zone allocator requires that the start of allocatable
+   # memory be aligned to the largest possible allocation.
+   config FORCE_MAX_ZONEORDER
+   	  int
+	  default 8 if V850E2_SIM85E2C || V850E2_FPGA85E2C
+
+   config V850E_HIGHRES_TIMER
+   	  bool "High resolution timer support"
+	  depends V850E_TIMER_D
+   config TIME_BOOTUP
+   	  bool "Time bootup"
+	  depends V850E_HIGHRES_TIMER
+
+   config RESET_GUARD
+   	  bool "Reset Guard"
+
+   config LARGE_ALLOCS
+	  bool "Allow allocating large blocks (> 1MB) of memory"
+	  help
+	     Allow the slab memory allocator to keep chains for very large
+	     memory sizes - upto 32MB. You may need this if your system has
+	     a lot of RAM, and you need to able to allocate very large
+	     contiguous chunks. If unsure, say N.
+
+endmenu
+
+
+#############################################################################
+
+source init/Kconfig
+
+#############################################################################
+
+menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA)"
+
+#    config PCI
+# 	   bool "PCI support"
+# 	   help
+# 	     Support for PCI bus.
+
+source "drivers/pci/Kconfig"
+
+source "drivers/pcmcia/Kconfig"
+
+source "drivers/pci/hotplug/Kconfig"
+
+endmenu
+
+menu "Executable file formats"
+
+source "fs/Kconfig.binfmt"
+
+endmenu
+
+#############################################################################
+
+source "drivers/base/Kconfig"
+
+source drivers/mtd/Kconfig
+
+source drivers/parport/Kconfig
+
+#source drivers/pnp/Kconfig
+
+source drivers/block/Kconfig
+
+#############################################################################
+
+menu "Disk device support"
+
+source "drivers/ide/Kconfig"
+
+source "drivers/scsi/Kconfig"
+
+endmenu
+
+#############################################################################
+
+
+source "drivers/md/Kconfig"
+
+source "drivers/message/fusion/Kconfig"
+
+source "drivers/ieee1394/Kconfig"
+
+source "drivers/message/i2o/Kconfig"
+
+source "net/Kconfig"
+
+source "drivers/isdn/Kconfig"
+
+#source "drivers/telephony/Kconfig"
+
+#
+# input before char - char/joystick depends on it. As does USB.
+#
+source "drivers/input/Kconfig"
+
+source "drivers/char/Kconfig"
+
+#source drivers/misc/Config.in
+source "drivers/media/Kconfig"
+
+source "fs/Kconfig"
+
+source "drivers/video/Kconfig"
+
+source "sound/Kconfig"
+
+source "drivers/usb/Kconfig"
+
+source "arch/v850/Kconfig.debug"
+
+source "security/Kconfig"
+
+source "crypto/Kconfig"
+
+source "lib/Kconfig"
+
+#############################################################################
diff --git a/arch/v850/Kconfig.debug b/arch/v850/Kconfig.debug
new file mode 100644
index 0000000..4acfb9c
--- /dev/null
+++ b/arch/v850/Kconfig.debug
@@ -0,0 +1,10 @@
+menu "Kernel hacking"
+
+source "lib/Kconfig.debug"
+
+config NO_KERNEL_MSG
+	bool "Suppress Kernel BUG Messages"
+	help
+	  Do not output any debug BUG messages within the kernel.
+
+endmenu
diff --git a/arch/v850/Makefile b/arch/v850/Makefile
new file mode 100644
index 0000000..6edaed4
--- /dev/null
+++ b/arch/v850/Makefile
@@ -0,0 +1,63 @@
+#
+# arch/v850/Makefile
+#
+#  Copyright (C) 2001,02,03  NEC Corporation
+#  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
+#
+# This file is included by the global makefile so that you can add your own
+# architecture-specific flags and dependencies. Remember to do have actions
+# for "archclean" and "archdep" for cleaning up and making dependencies for
+# this architecture
+#
+# 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.
+#
+
+arch_dir = arch/v850
+
+CFLAGS += -mv850e
+# r16 is a fixed pointer to the current task
+CFLAGS += -ffixed-r16 -mno-prolog-function
+CFLAGS += -fno-builtin
+CFLAGS += -D__linux__ -DUTS_SYSNAME=\"uClinux\"
+
+# This prevents the linker from consolidating the .gnu.linkonce.this_module
+# section into .text (which the v850 default linker script for -r does for
+# some reason)
+LDFLAGS_MODULE += --unique=.gnu.linkonce.this_module
+
+OBJCOPY_FLAGS_BLOB := -I binary -O elf32-little -B v850e
+
+
+head-y := $(arch_dir)/kernel/head.o $(arch_dir)/kernel/init_task.o
+core-y += $(arch_dir)/kernel/
+libs-y += $(arch_dir)/lib/
+
+
+# Deal with the initial contents of the root device
+ifdef ROOT_FS_IMAGE
+core-y += root_fs_image.o
+
+# Because the kernel build-system erases all explicit .o build rules, we
+# have to use an intermediate target to fool it into building for us.
+# This results in it being built anew each time, but that's alright.
+root_fs_image.o: root_fs_image_force
+
+root_fs_image_force: $(ROOT_FS_IMAGE)
+	$(OBJCOPY) $(OBJCOPY_FLAGS_BLOB) --rename-section .data=.root,alloc,load,readonly,data,contents $< root_fs_image.o
+endif
+
+
+prepare: include/asm-$(ARCH)/asm-consts.h
+
+# Generate constants from C code for use by asm files
+arch/$(ARCH)/kernel/asm-consts.s: include/asm include/linux/version.h \
+				   include/config/MARKER
+
+include/asm-$(ARCH)/asm-consts.h: arch/$(ARCH)/kernel/asm-consts.s
+	$(call filechk,gen-asm-offsets)
+
+CLEAN_FILES += include/asm-$(ARCH)/asm-consts.h \
+	       arch/$(ARCH)/kernel/asm-consts.s \
+	       root_fs_image.o
diff --git a/arch/v850/README b/arch/v850/README
new file mode 100644
index 0000000..01b98e2
--- /dev/null
+++ b/arch/v850/README
@@ -0,0 +1,32 @@
+This port to the NEC V850E processor supports the following platforms:
+
+   + The gdb v850e simulator (CONFIG_V850E_SIM).
+
+   + The Midas labs RTE-V850E/MA1-CB and RTE-V850E/NB85E-CB evaluation boards
+     (CONFIG_RTE_CB_MA1 and CONFIG_RTE_CB_NB85E).  This support has only been
+     tested when running with the Multi-debugger monitor ROM (for the Green
+     Hills Multi debugger).  The optional NEC Solution Gear RTE-MOTHER-A
+     motherboard is also supported, which allows PCI boards to be used
+     (CONFIG_RTE_MB_A_PCI).
+
+   + The Midas labs RTE-V850E/ME2-CB evaluation board (CONFIG_RTE_CB_ME2).
+     This has only been tested using a kernel downloaded via an ICE connection
+     using the Multi debugger.  Support for the RTE-MOTHER-A is present, but
+     hasn't been tested (unlike the other Midas labs cpu boards, the
+     RTE-V850E/ME2-CB includes an ethernet adaptor).
+
+   + The NEC AS85EP1 V850E evaluation chip/board (CONFIG_V850E_AS85EP1).
+
+   + The NEC `Anna' (board/chip) implementation of the V850E2 processor
+     (CONFIG_V850E2_ANNA).
+
+   + The sim85e2c and sim85e2s simulators, which are verilog simulations of
+     the V850E2 NA85E2C/NA85E2S cpu cores (CONFIG_V850E2_SIM85E2C and
+     CONFIG_V850E2_SIM85E2S).
+
+   + A FPGA implementation of the V850E2 NA85E2C cpu core
+     (CONFIG_V850E2_FPGA85E2C).
+
+Porting to anything with a V850E/MA1 or MA2 processor should be simple.
+See the file <asm-v850/machdep.h> and the files it includes for an example of
+how to add platform/chip-specific support.
diff --git a/arch/v850/kernel/Makefile b/arch/v850/kernel/Makefile
new file mode 100644
index 0000000..3930482
--- /dev/null
+++ b/arch/v850/kernel/Makefile
@@ -0,0 +1,40 @@
+#
+# arch/v850/kernel/Makefile
+#
+#  Copyright (C) 2001,02,03  NEC Electronics Corporation
+#  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
+#
+# 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.
+#
+
+extra-y := head.o init_task.o vmlinux.lds
+
+obj-y += intv.o entry.o process.o syscalls.o time.o semaphore.o setup.o \
+	 signal.o irq.o mach.o ptrace.o bug.o
+obj-$(CONFIG_MODULES)		+= module.o v850_ksyms.o
+# chip-specific code
+obj-$(CONFIG_V850E_MA1)		+= ma.o
+obj-$(CONFIG_V850E_ME2)		+= me2.o
+obj-$(CONFIG_V850E_TEG)		+= teg.o
+obj-$(CONFIG_V850E_AS85EP1)	+= as85ep1.o
+obj-$(CONFIG_V850E2_ANNA)	+= anna.o
+# platform-specific code
+obj-$(CONFIG_V850E_SIM)		+= sim.o simcons.o
+obj-$(CONFIG_V850E2_SIM85E2)	+= sim85e2.o memcons.o
+obj-$(CONFIG_V850E2_FPGA85E2C)	+= fpga85e2c.o memcons.o
+obj-$(CONFIG_RTE_CB)		+= rte_cb.o rte_cb_leds.o
+obj-$(CONFIG_RTE_CB_MA1)	+= rte_ma1_cb.o
+obj-$(CONFIG_RTE_CB_ME2)	+= rte_me2_cb.o
+obj-$(CONFIG_RTE_CB_NB85E)	+= rte_nb85e_cb.o
+obj-$(CONFIG_RTE_CB_MULTI)	+= rte_cb_multi.o
+obj-$(CONFIG_RTE_MB_A_PCI)	+= rte_mb_a_pci.o
+obj-$(CONFIG_RTE_GBUS_INT)	+= gbus_int.o
+# feature-specific code
+obj-$(CONFIG_V850E_INTC)	+= v850e_intc.o
+obj-$(CONFIG_V850E_TIMER_D)	+= v850e_timer_d.o v850e_utils.o
+obj-$(CONFIG_V850E_CACHE)	+= v850e_cache.o
+obj-$(CONFIG_V850E2_CACHE)	+= v850e2_cache.o
+obj-$(CONFIG_V850E_HIGHRES_TIMER) += highres_timer.o
+obj-$(CONFIG_PROC_FS)		+= procfs.o
diff --git a/arch/v850/kernel/anna-rom.ld b/arch/v850/kernel/anna-rom.ld
new file mode 100644
index 0000000..7c54e7e
--- /dev/null
+++ b/arch/v850/kernel/anna-rom.ld
@@ -0,0 +1,16 @@
+/* Linker script for the Midas labs Anna V850E2 evaluation board
+   (CONFIG_V850E2_ANNA), with kernel in ROM (CONFIG_ROM_KERNEL).  */
+
+MEMORY {
+	/* 8MB of flash ROM.  */
+	ROM   : ORIGIN = 0,          LENGTH = 0x00800000
+
+	/* 1MB of static RAM.  This memory is mirrored 64 times.  */
+	SRAM  : ORIGIN = SRAM_ADDR,  LENGTH = SRAM_SIZE
+	/* 64MB of DRAM.  */
+	SDRAM : ORIGIN = SDRAM_ADDR, LENGTH = SDRAM_SIZE
+}
+
+SECTIONS {
+	ROMK_SECTIONS(ROM, SRAM)
+}
diff --git a/arch/v850/kernel/anna.c b/arch/v850/kernel/anna.c
new file mode 100644
index 0000000..6aaeab5
--- /dev/null
+++ b/arch/v850/kernel/anna.c
@@ -0,0 +1,208 @@
+/*
+ * arch/v850/kernel/anna.c -- Anna V850E2 evaluation chip/board
+ *
+ *  Copyright (C) 2002,03  NEC Electronics Corporation
+ *  Copyright (C) 2002,03  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/major.h>
+#include <linux/irq.h>
+
+#include <asm/machdep.h>
+#include <asm/atomic.h>
+#include <asm/page.h>
+#include <asm/v850e_timer_d.h>
+#include <asm/v850e_uart.h>
+
+#include "mach.h"
+
+
+/* SRAM and SDRAM are vaguely contiguous (with a big hole in between; see
+   mach_reserve_bootmem for details); use both as one big area.  */
+#define RAM_START 	SRAM_ADDR
+#define RAM_END		(SDRAM_ADDR + SDRAM_SIZE)
+
+/* The bits of this port are connected to an 8-LED bar-graph.  */
+#define LEDS_PORT	0
+
+
+static void anna_led_tick (void);
+
+
+void __init mach_early_init (void)
+{
+	ANNA_ILBEN    = 0;
+
+	V850E2_CSC(0) = 0x402F;
+	V850E2_CSC(1) = 0x4000;
+	V850E2_BPC    = 0;
+	V850E2_BSC    = 0xAAAA;
+	V850E2_BEC    = 0;
+
+#if 0
+	V850E2_BHC    = 0xFFFF;	/* icache all memory, dcache all */
+#else
+	V850E2_BHC    = 0;	/* cache no memory */
+#endif
+	V850E2_BCT(0) = 0xB088;
+	V850E2_BCT(1) = 0x0008;
+	V850E2_DWC(0) = 0x0027;
+	V850E2_DWC(1) = 0;
+	V850E2_BCC    = 0x0006;
+	V850E2_ASC    = 0;
+	V850E2_LBS    = 0x0089;
+	V850E2_SCR(3) = 0x21A9;
+	V850E2_RFS(3) = 0x8121;
+
+	v850e_intc_disable_irqs ();
+}
+
+void __init mach_setup (char **cmdline)
+{
+	ANNA_PORT_PM (LEDS_PORT) = 0;	/* Make all LED pins output pins.  */
+	mach_tick = anna_led_tick;
+}
+
+void __init mach_get_physical_ram (unsigned long *ram_start,
+				   unsigned long *ram_len)
+{
+	*ram_start = RAM_START;
+	*ram_len = RAM_END - RAM_START;
+}
+
+void __init mach_reserve_bootmem ()
+{
+	/* The space between SRAM and SDRAM is filled with duplicate
+	   images of SRAM.  Prevent the kernel from using them.  */
+	reserve_bootmem (SRAM_ADDR + SRAM_SIZE,
+			 SDRAM_ADDR - (SRAM_ADDR + SRAM_SIZE));
+}
+
+void mach_gettimeofday (struct timespec *tv)
+{
+	tv->tv_sec = 0;
+	tv->tv_nsec = 0;
+}
+
+void __init mach_sched_init (struct irqaction *timer_action)
+{
+	/* Start hardware timer.  */
+	v850e_timer_d_configure (0, HZ);
+	/* Install timer interrupt handler.  */
+	setup_irq (IRQ_INTCMD(0), timer_action);
+}
+
+static struct v850e_intc_irq_init irq_inits[] = {
+	{ "IRQ", 0, 		NUM_MACH_IRQS,	1, 7 },
+	{ "PIN", IRQ_INTP(0),   IRQ_INTP_NUM,   1, 4 },
+	{ "CCC", IRQ_INTCCC(0),	IRQ_INTCCC_NUM, 1, 5 },
+	{ "CMD", IRQ_INTCMD(0), IRQ_INTCMD_NUM,	1, 5 },
+	{ "DMA", IRQ_INTDMA(0), IRQ_INTDMA_NUM,	1, 2 },
+	{ "DMXER", IRQ_INTDMXER,1,		1, 2 },
+	{ "SRE", IRQ_INTSRE(0), IRQ_INTSRE_NUM,	3, 3 },
+	{ "SR",	 IRQ_INTSR(0),	IRQ_INTSR_NUM, 	3, 4 },
+	{ "ST",  IRQ_INTST(0), 	IRQ_INTST_NUM, 	3, 5 },
+	{ 0 }
+};
+#define NUM_IRQ_INITS ((sizeof irq_inits / sizeof irq_inits[0]) - 1)
+
+static struct hw_interrupt_type hw_itypes[NUM_IRQ_INITS];
+
+void __init mach_init_irqs (void)
+{
+	v850e_intc_init_irq_types (irq_inits, hw_itypes);
+}
+
+void machine_restart (char *__unused)
+{
+#ifdef CONFIG_RESET_GUARD
+	disable_reset_guard ();
+#endif
+	asm ("jmp r0"); /* Jump to the reset vector.  */
+}
+
+EXPORT_SYMBOL(machine_restart);
+
+void machine_halt (void)
+{
+#ifdef CONFIG_RESET_GUARD
+	disable_reset_guard ();
+#endif
+	local_irq_disable ();	/* Ignore all interrupts.  */
+	ANNA_PORT_IO(LEDS_PORT) = 0xAA;	/* Note that we halted.  */
+	for (;;)
+		asm ("halt; nop; nop; nop; nop; nop");
+}
+
+EXPORT_SYMBOL(machine_halt);
+
+void machine_power_off (void)
+{
+	machine_halt ();
+}
+
+EXPORT_SYMBOL(machine_power_off);
+
+/* Called before configuring an on-chip UART.  */
+void anna_uart_pre_configure (unsigned chan, unsigned cflags, unsigned baud)
+{
+	/* The Anna connects some general-purpose I/O pins on the CPU to
+	   the RTS/CTS lines of UART 1's serial connection.  I/O pins P07
+	   and P37 are RTS and CTS respectively.  */
+	if (chan == 1) {
+		ANNA_PORT_PM(0) &= ~0x80; /* P07 in output mode */
+		ANNA_PORT_PM(3) |=  0x80; /* P37 in input mode */
+	}
+}
+
+/* Minimum and maximum bounds for the moving upper LED boundary in the
+   clock tick display.  We can't use the last bit because it's used for
+   UART0's CTS output.  */
+#define MIN_MAX_POS 0
+#define MAX_MAX_POS 6
+
+/* There are MAX_MAX_POS^2 - MIN_MAX_POS^2 cycles in the animation, so if
+   we pick 6 and 0 as above, we get 49 cycles, which is when divided into
+   the standard 100 value for HZ, gives us an almost 1s total time.  */
+#define TICKS_PER_FRAME \
+	(HZ / (MAX_MAX_POS * MAX_MAX_POS - MIN_MAX_POS * MIN_MAX_POS))
+
+static void anna_led_tick ()
+{
+	static unsigned counter = 0;
+	
+	if (++counter == TICKS_PER_FRAME) {
+		static int pos = 0, max_pos = MAX_MAX_POS, dir = 1;
+
+		if (dir > 0 && pos == max_pos) {
+			dir = -1;
+			if (max_pos == MIN_MAX_POS)
+				max_pos = MAX_MAX_POS;
+			else
+				max_pos--;
+		} else {
+			if (dir < 0 && pos == 0)
+				dir = 1;
+
+			if (pos + dir <= max_pos) {
+				/* Each bit of port 0 has a LED. */
+				clear_bit (pos, &ANNA_PORT_IO(LEDS_PORT));
+				pos += dir;
+				set_bit (pos, &ANNA_PORT_IO(LEDS_PORT));
+			}
+		}
+
+		counter = 0;
+	}
+}
diff --git a/arch/v850/kernel/anna.ld b/arch/v850/kernel/anna.ld
new file mode 100644
index 0000000..df7f80f
--- /dev/null
+++ b/arch/v850/kernel/anna.ld
@@ -0,0 +1,20 @@
+/* Linker script for the Midas labs Anna V850E2 evaluation board
+   (CONFIG_V850E2_ANNA).  */
+
+MEMORY {
+	/* 256KB of internal memory (followed by one mirror).  */
+	iMEM0 : ORIGIN = 0,	     LENGTH = 0x00040000
+	/* 256KB of internal memory (followed by one mirror).  */
+	iMEM1 : ORIGIN = 0x00040000, LENGTH = 0x00040000
+
+	/* 1MB of static RAM.  This memory is mirrored 64 times.  */
+	SRAM  : ORIGIN = SRAM_ADDR,  LENGTH = SRAM_SIZE
+	/* 64MB of DRAM.  */
+	SDRAM : ORIGIN = SDRAM_ADDR, LENGTH = SDRAM_SIZE
+}
+
+SECTIONS {
+	.intv : { INTV_CONTENTS } > iMEM0
+	.sram : { RAMK_KRAM_CONTENTS } > SRAM
+	.root : { ROOT_FS_CONTENTS } > SDRAM
+}
diff --git a/arch/v850/kernel/as85ep1-rom.ld b/arch/v850/kernel/as85ep1-rom.ld
new file mode 100644
index 0000000..fe2a9a3
--- /dev/null
+++ b/arch/v850/kernel/as85ep1-rom.ld
@@ -0,0 +1,21 @@
+/* Linker script for the NEC AS85EP1 V850E evaluation board
+   (CONFIG_V850E_AS85EP1), with kernel in ROM (CONFIG_ROM_KERNEL).  */
+
+MEMORY {
+	/* 4MB of flash ROM.  */
+	ROM   : ORIGIN = 0,          LENGTH = 0x00400000
+
+	/* 1MB of static RAM.  */
+	SRAM  : ORIGIN = SRAM_ADDR,  LENGTH = SRAM_SIZE
+
+	/* About 58MB of DRAM.  This can actually be at one of two
+	   positions, determined by jumper JP3; we have to use the first
+	   position because the second is partially out of processor
+	   instruction addressing range (though in the second position
+	   there's actually 64MB available).  */
+	SDRAM : ORIGIN = SDRAM_ADDR, LENGTH = SDRAM_SIZE
+}
+
+SECTIONS {
+	ROMK_SECTIONS(ROM, SRAM)
+}
diff --git a/arch/v850/kernel/as85ep1.c b/arch/v850/kernel/as85ep1.c
new file mode 100644
index 0000000..4059b1d
--- /dev/null
+++ b/arch/v850/kernel/as85ep1.c
@@ -0,0 +1,240 @@
+/*
+ * arch/v850/kernel/as85ep1.c -- AS85EP1 V850E evaluation chip/board
+ *
+ *  Copyright (C) 2002,03  NEC Electronics Corporation
+ *  Copyright (C) 2002,03  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/major.h>
+#include <linux/irq.h>
+
+#include <asm/machdep.h>
+#include <asm/atomic.h>
+#include <asm/page.h>
+#include <asm/v850e_timer_d.h>
+#include <asm/v850e_uart.h>
+
+#include "mach.h"
+
+
+/* SRAM and SDRAM are vaguely contiguous (with a big hole in between; see
+   mach_reserve_bootmem for details); use both as one big area.  */
+#define RAM_START 	SRAM_ADDR
+#define RAM_END		(SDRAM_ADDR + SDRAM_SIZE)
+
+/* The bits of this port are connected to an 8-LED bar-graph.  */
+#define LEDS_PORT	4
+
+
+static void as85ep1_led_tick (void);
+
+extern char _intv_copy_src_start, _intv_copy_src_end;
+extern char _intv_copy_dst_start;
+
+
+void __init mach_early_init (void)
+{
+#ifndef CONFIG_ROM_KERNEL
+	const u32 *src;
+	register u32 *dst asm ("ep");
+#endif
+
+	AS85EP1_CSC(0) = 0x0403;
+	AS85EP1_BCT(0) = 0xB8B8;
+	AS85EP1_DWC(0) = 0x0104;
+	AS85EP1_BCC    = 0x0012;
+	AS85EP1_ASC    = 0;
+	AS85EP1_LBS    = 0x00A9;
+
+	AS85EP1_PORT_PMC(6)  = 0xFF; /* valid A0,A1,A20-A25 */
+	AS85EP1_PORT_PMC(7)  = 0x0E; /* valid CS1-CS3       */
+	AS85EP1_PORT_PMC(9)  = 0xFF; /* valid D16-D23       */
+	AS85EP1_PORT_PMC(10) = 0xFF; /* valid D24-D31       */
+
+	AS85EP1_RFS(1) = 0x800c;
+	AS85EP1_RFS(3) = 0x800c;
+	AS85EP1_SCR(1) = 0x20A9;
+	AS85EP1_SCR(3) = 0x20A9;
+
+#ifndef CONFIG_ROM_KERNEL
+	/* The early chip we have is buggy, and writing the interrupt
+	   vectors into low RAM may screw up, so for non-ROM kernels, we
+	   only rely on the reset vector being downloaded, and copy the
+	   rest of the interrupt vectors into place here.  The specific bug
+	   is that writing address N, where (N & 0x10) == 0x10, will _also_
+	   write to address (N - 0x10).  We avoid this (effectively) by
+	   writing in 16-byte chunks backwards from the end.  */
+
+	AS85EP1_IRAMM = 0x3;	/* "write-mode" for the internal instruction memory */
+
+	src = (u32 *)(((u32)&_intv_copy_src_end - 1) & ~0xF);
+	dst = (u32 *)&_intv_copy_dst_start
+		+ (src - (u32 *)&_intv_copy_src_start);
+	do {
+		u32 t0 = src[0], t1 = src[1], t2 = src[2], t3 = src[3];
+		dst[0] = t0; dst[1] = t1; dst[2] = t2; dst[3] = t3;
+		dst -= 4;
+		src -= 4;
+	} while (src > (u32 *)&_intv_copy_src_start);
+
+	AS85EP1_IRAMM = 0x0;	/* "read-mode" for the internal instruction memory */
+#endif /* !CONFIG_ROM_KERNEL */
+
+	v850e_intc_disable_irqs ();
+}
+
+void __init mach_setup (char **cmdline)
+{
+	AS85EP1_PORT_PMC (LEDS_PORT) = 0; /* Make the LEDs port an I/O port. */
+	AS85EP1_PORT_PM (LEDS_PORT) = 0; /* Make all the bits output pins.  */
+	mach_tick = as85ep1_led_tick;
+}
+
+void __init mach_get_physical_ram (unsigned long *ram_start,
+				   unsigned long *ram_len)
+{
+	*ram_start = RAM_START;
+	*ram_len = RAM_END - RAM_START;
+}
+
+/* Convenience macros.  */
+#define SRAM_END	(SRAM_ADDR + SRAM_SIZE)
+#define SDRAM_END	(SDRAM_ADDR + SDRAM_SIZE)
+
+void __init mach_reserve_bootmem ()
+{
+	if (SDRAM_ADDR < RAM_END && SDRAM_ADDR > RAM_START)
+		/* We can't use the space between SRAM and SDRAM, so
+		   prevent the kernel from trying.  */
+		reserve_bootmem (SRAM_END, SDRAM_ADDR - SRAM_END);
+}
+
+void mach_gettimeofday (struct timespec *tv)
+{
+	tv->tv_sec = 0;
+	tv->tv_nsec = 0;
+}
+
+void __init mach_sched_init (struct irqaction *timer_action)
+{
+	/* Start hardware timer.  */
+	v850e_timer_d_configure (0, HZ);
+	/* Install timer interrupt handler.  */
+	setup_irq (IRQ_INTCMD(0), timer_action);
+}
+
+static struct v850e_intc_irq_init irq_inits[] = {
+	{ "IRQ", 0, 		NUM_MACH_IRQS,	1, 7 },
+	{ "CCC", IRQ_INTCCC(0),	IRQ_INTCCC_NUM, 1, 5 },
+	{ "CMD", IRQ_INTCMD(0), IRQ_INTCMD_NUM,	1, 5 },
+	{ "SRE", IRQ_INTSRE(0), IRQ_INTSRE_NUM,	3, 3 },
+	{ "SR",	 IRQ_INTSR(0),	IRQ_INTSR_NUM, 	3, 4 },
+	{ "ST",  IRQ_INTST(0), 	IRQ_INTST_NUM, 	3, 5 },
+	{ 0 }
+};
+#define NUM_IRQ_INITS ((sizeof irq_inits / sizeof irq_inits[0]) - 1)
+
+static struct hw_interrupt_type hw_itypes[NUM_IRQ_INITS];
+
+void __init mach_init_irqs (void)
+{
+	v850e_intc_init_irq_types (irq_inits, hw_itypes);
+}
+
+void machine_restart (char *__unused)
+{
+#ifdef CONFIG_RESET_GUARD
+	disable_reset_guard ();
+#endif
+	asm ("jmp r0"); /* Jump to the reset vector.  */
+}
+
+EXPORT_SYMBOL(machine_restart);
+
+void machine_halt (void)
+{
+#ifdef CONFIG_RESET_GUARD
+	disable_reset_guard ();
+#endif
+	local_irq_disable ();	/* Ignore all interrupts.  */
+	AS85EP1_PORT_IO (LEDS_PORT) = 0xAA;	/* Note that we halted.  */
+	for (;;)
+		asm ("halt; nop; nop; nop; nop; nop");
+}
+
+EXPORT_SYMBOL(machine_halt);
+
+void machine_power_off (void)
+{
+	machine_halt ();
+}
+
+EXPORT_SYMBOL(machine_power_off);
+
+/* Called before configuring an on-chip UART.  */
+void as85ep1_uart_pre_configure (unsigned chan, unsigned cflags, unsigned baud)
+{
+	/* Make the shared uart/port pins be uart pins.  */
+	AS85EP1_PORT_PMC(3) |= (0x5 << chan);
+
+	/* The AS85EP1 connects some general-purpose I/O pins on the CPU to
+	   the RTS/CTS lines of UART 1's serial connection.  I/O pins P53
+	   and P54 are RTS and CTS respectively.  */
+	if (chan == 1) {
+		/* Put P53 & P54 in I/O port mode.  */
+		AS85EP1_PORT_PMC(5) &= ~0x18;
+		/* Make P53 an output, and P54 an input.  */
+		AS85EP1_PORT_PM(5) |=  0x10;
+	}
+}
+
+/* Minimum and maximum bounds for the moving upper LED boundary in the
+   clock tick display.  */
+#define MIN_MAX_POS 0
+#define MAX_MAX_POS 7
+
+/* There are MAX_MAX_POS^2 - MIN_MAX_POS^2 cycles in the animation, so if
+   we pick 6 and 0 as above, we get 49 cycles, which is when divided into
+   the standard 100 value for HZ, gives us an almost 1s total time.  */
+#define TICKS_PER_FRAME \
+	(HZ / (MAX_MAX_POS * MAX_MAX_POS - MIN_MAX_POS * MIN_MAX_POS))
+
+static void as85ep1_led_tick ()
+{
+	static unsigned counter = 0;
+	
+	if (++counter == TICKS_PER_FRAME) {
+		static int pos = 0, max_pos = MAX_MAX_POS, dir = 1;
+
+		if (dir > 0 && pos == max_pos) {
+			dir = -1;
+			if (max_pos == MIN_MAX_POS)
+				max_pos = MAX_MAX_POS;
+			else
+				max_pos--;
+		} else {
+			if (dir < 0 && pos == 0)
+				dir = 1;
+
+			if (pos + dir <= max_pos) {
+				/* Each bit of port 0 has a LED. */
+				set_bit (pos, &AS85EP1_PORT_IO(LEDS_PORT));
+				pos += dir;
+				clear_bit (pos, &AS85EP1_PORT_IO(LEDS_PORT));
+			}
+		}
+
+		counter = 0;
+	}
+}
diff --git a/arch/v850/kernel/as85ep1.ld b/arch/v850/kernel/as85ep1.ld
new file mode 100644
index 0000000..ef2c439
--- /dev/null
+++ b/arch/v850/kernel/as85ep1.ld
@@ -0,0 +1,49 @@
+/* Linker script for the NEC AS85EP1 V850E evaluation board
+   (CONFIG_V850E_AS85EP1).  */
+
+MEMORY {
+	/* 1MB of internal instruction memory. */
+	iMEM0 : ORIGIN = 0,	     LENGTH = 0x00100000
+
+	/* 1MB of static RAM.  */
+	SRAM  : ORIGIN = SRAM_ADDR,  LENGTH = SRAM_SIZE
+
+	/* About 58MB of DRAM.  This can actually be at one of two
+	   positions, determined by jump JP3; we have to use the first
+	   position because the second is partially out of processor
+	   instruction addressing range (though in the second position
+	   there's actually 64MB available).  */
+	SDRAM : ORIGIN = SDRAM_ADDR, LENGTH = SDRAM_SIZE
+}
+
+SECTIONS {
+	.resetv : {
+		__intv_start = . ;
+			*(.intv.reset)	/* Reset vector */
+	} > iMEM0
+
+	.sram : {
+		RAMK_KRAM_CONTENTS
+
+		/* We stick most of the interrupt vectors here; they'll be
+		   copied into the proper location by the early init code (we
+		   can't put them directly in the right place because of
+		   hardware bugs).  The vectors shouldn't need to be
+		   relocated, so we don't have to use `> ...  AT> ...' to
+		   split the load/vm addresses (and we can't because of
+		   problems with the loader).  */
+		. = ALIGN (0x10) ;
+		__intv_copy_src_start = . ;
+			*(.intv.common)	/* Vectors common to all v850e proc. */
+			*(.intv.mach)	/* Machine-specific int. vectors.  */
+		. = ALIGN (0x10) ;
+		__intv_copy_src_end = . ;
+	} > SRAM
+
+	/* Where we end up putting the vectors.  */
+	__intv_copy_dst_start = 0x10 ;
+	__intv_copy_dst_end = __intv_copy_dst_start + (__intv_copy_src_end - __intv_copy_src_start) ;
+	__intv_end = __intv_copy_dst_end ;
+
+	.root : { ROOT_FS_CONTENTS } > SDRAM
+}
diff --git a/arch/v850/kernel/asm-consts.c b/arch/v850/kernel/asm-consts.c
new file mode 100644
index 0000000..24f2913
--- /dev/null
+++ b/arch/v850/kernel/asm-consts.c
@@ -0,0 +1,61 @@
+/*
+ * 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/sched.h>
+#include <linux/kernel_stat.h>
+#include <linux/ptrace.h>
+#include <linux/hardirq.h>
+#include <asm/irq.h>
+#include <asm/errno.h>
+
+#define DEFINE(sym, val) \
+	asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+
+#define BLANK() asm volatile("\n->" : : )
+
+int main (void)
+{
+	/* offsets into the task struct */
+	DEFINE (TASK_STATE, offsetof (struct task_struct, state));
+	DEFINE (TASK_FLAGS, offsetof (struct task_struct, flags));
+	DEFINE (TASK_PTRACE, offsetof (struct task_struct, ptrace));
+	DEFINE (TASK_BLOCKED, offsetof (struct task_struct, blocked));
+	DEFINE (TASK_THREAD, offsetof (struct task_struct, thread));
+	DEFINE (TASK_THREAD_INFO, offsetof (struct task_struct, thread_info));
+	DEFINE (TASK_MM, offsetof (struct task_struct, mm));
+	DEFINE (TASK_ACTIVE_MM, offsetof (struct task_struct, active_mm));
+	DEFINE (TASK_PID, offsetof (struct task_struct, pid));
+
+	/* offsets into the kernel_stat struct */
+	DEFINE (STAT_IRQ, offsetof (struct kernel_stat, irqs));
+
+
+	/* signal defines */
+	DEFINE (SIGSEGV, SIGSEGV);
+	DEFINE (SEGV_MAPERR, SEGV_MAPERR);
+	DEFINE (SIGTRAP, SIGTRAP);
+	DEFINE (SIGCHLD, SIGCHLD);
+	DEFINE (SIGILL, SIGILL);
+	DEFINE (TRAP_TRACE, TRAP_TRACE);
+
+	/* ptrace flag bits */
+	DEFINE (PT_PTRACED, PT_PTRACED);
+	DEFINE (PT_DTRACE, PT_DTRACE);
+
+	/* error values */
+	DEFINE (ENOSYS, ENOSYS);
+
+	/* clone flag bits */
+	DEFINE (CLONE_VFORK, CLONE_VFORK);
+	DEFINE (CLONE_VM, CLONE_VM);
+
+	return 0;
+}
diff --git a/arch/v850/kernel/bug.c b/arch/v850/kernel/bug.c
new file mode 100644
index 0000000..c78cf750
--- /dev/null
+++ b/arch/v850/kernel/bug.c
@@ -0,0 +1,142 @@
+/*
+ * arch/v850/kernel/bug.c -- Bug reporting functions
+ *
+ *  Copyright (C) 2001,02,03  NEC Electronics Corporation
+ *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/reboot.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+
+#include <asm/errno.h>
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+#include <asm/current.h>
+
+/* We should use __builtin_return_address, but it doesn't work in gcc-2.90
+   (which is currently our standard compiler on the v850).  */
+#define ret_addr() ({ register u32 lp asm ("lp"); lp; })
+#define stack_addr() ({ register u32 sp asm ("sp"); sp; })
+
+void __bug ()
+{
+	printk (KERN_CRIT "kernel BUG at PC 0x%x (SP ~0x%x)!\n",
+		ret_addr() - 4, /* - 4 for `jarl' */
+		stack_addr());
+	machine_halt ();
+}
+
+int bad_trap (int trap_num, struct pt_regs *regs)
+{
+	printk (KERN_CRIT
+		"unimplemented trap %d called at 0x%08lx, pid %d!\n",
+		trap_num, regs->pc, current->pid);
+	return -ENOSYS;
+}
+
+#ifdef CONFIG_RESET_GUARD
+void unexpected_reset (unsigned long ret_addr, unsigned long kmode,
+		       struct task_struct *task, unsigned long sp)
+{
+	printk (KERN_CRIT
+		"unexpected reset in %s mode, pid %d"
+		" (ret_addr = 0x%lx, sp = 0x%lx)\n",
+		kmode ? "kernel" : "user",
+		task ? task->pid : -1,
+		ret_addr, sp);
+
+	machine_halt ();
+}
+#endif /* CONFIG_RESET_GUARD */
+
+
+
+struct spec_reg_name {
+	const char *name;
+	int gpr;
+};
+
+struct spec_reg_name spec_reg_names[] = {
+	{ "sp", GPR_SP },
+	{ "gp", GPR_GP },
+	{ "tp", GPR_TP },
+	{ "ep", GPR_EP },
+	{ "lp", GPR_LP },
+	{ 0, 0 }
+};
+
+void show_regs (struct pt_regs *regs)
+{
+	int gpr_base, gpr_offs;
+
+	printk ("     pc 0x%08lx    psw 0x%08lx                       kernel_mode %d\n",
+		regs->pc, regs->psw, regs->kernel_mode);
+	printk ("   ctpc 0x%08lx  ctpsw 0x%08lx   ctbp 0x%08lx\n",
+		regs->ctpc, regs->ctpsw, regs->ctbp);
+
+	for (gpr_base = 0; gpr_base < NUM_GPRS; gpr_base += 4) {
+		for (gpr_offs = 0; gpr_offs < 4; gpr_offs++) {
+			int gpr = gpr_base + gpr_offs;
+			long val = regs->gpr[gpr];
+			struct spec_reg_name *srn;
+
+			for (srn = spec_reg_names; srn->name; srn++)
+				if (srn->gpr == gpr)
+					break;
+
+			if (srn->name)
+				printk ("%7s 0x%08lx", srn->name, val);
+			else
+				printk ("    r%02d 0x%08lx", gpr, val);
+		}
+
+		printk ("\n");
+	}
+}
+
+/*
+ * TASK is a pointer to the task whose backtrace we want to see (or NULL
+ * for current task), SP is the stack pointer of the first frame that
+ * should be shown in the back trace (or NULL if the entire call-chain of
+ * the task should be shown).
+ */
+void show_stack (struct task_struct *task, unsigned long *sp)
+{
+	unsigned long addr, end;
+
+	if (sp)
+		addr = (unsigned long)sp;
+	else if (task)
+		addr = task_sp (task);
+	else
+		addr = stack_addr ();
+
+	addr = addr & ~3;
+	end = (addr + THREAD_SIZE - 1) & THREAD_MASK;
+
+	while (addr < end) {
+		printk ("%8lX: ", addr);
+		while (addr < end) {
+			printk (" %8lX", *(unsigned long *)addr);
+			addr += sizeof (unsigned long);
+			if (! (addr & 0xF))
+				break;
+		}
+		printk ("\n");
+	}
+}
+
+void dump_stack ()
+{
+	show_stack (0, 0);
+}
+
+EXPORT_SYMBOL(dump_stack);
diff --git a/arch/v850/kernel/entry.S b/arch/v850/kernel/entry.S
new file mode 100644
index 0000000..895e27b
--- /dev/null
+++ b/arch/v850/kernel/entry.S
@@ -0,0 +1,1121 @@
+/*
+ * arch/v850/kernel/entry.S -- Low-level system-call handling, trap handlers,
+ *	and context-switching
+ *
+ *  Copyright (C) 2001,02,03  NEC Electronics Corporation
+ *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <linux/sys.h>
+
+#include <asm/entry.h>
+#include <asm/current.h>
+#include <asm/thread_info.h>
+#include <asm/clinkage.h>
+#include <asm/processor.h>
+#include <asm/irq.h>
+#include <asm/errno.h>
+
+#include <asm/asm-consts.h>
+
+
+/* Make a slightly more convenient alias for C_SYMBOL_NAME.  */
+#define CSYM	C_SYMBOL_NAME
+
+
+/* The offset of the struct pt_regs in a state-save-frame on the stack.  */
+#define PTO	STATE_SAVE_PT_OFFSET
+
+
+/* Save argument registers to the state-save-frame pointed to by EP.  */
+#define SAVE_ARG_REGS							      \
+	sst.w	r6, PTO+PT_GPR(6)[ep];					      \
+	sst.w	r7, PTO+PT_GPR(7)[ep];					      \
+	sst.w	r8, PTO+PT_GPR(8)[ep];					      \
+	sst.w	r9, PTO+PT_GPR(9)[ep]
+/* Restore argument registers from the state-save-frame pointed to by EP.  */
+#define RESTORE_ARG_REGS						      \
+	sld.w	PTO+PT_GPR(6)[ep], r6;					      \
+	sld.w	PTO+PT_GPR(7)[ep], r7;					      \
+	sld.w	PTO+PT_GPR(8)[ep], r8;					      \
+	sld.w	PTO+PT_GPR(9)[ep], r9
+
+/* Save value return registers to the state-save-frame pointed to by EP.  */
+#define SAVE_RVAL_REGS							      \
+	sst.w	r10, PTO+PT_GPR(10)[ep];				      \
+	sst.w	r11, PTO+PT_GPR(11)[ep]
+/* Restore value return registers from the state-save-frame pointed to by EP.  */
+#define RESTORE_RVAL_REGS						      \
+	sld.w	PTO+PT_GPR(10)[ep], r10;				      \
+	sld.w	PTO+PT_GPR(11)[ep], r11
+
+
+#define SAVE_CALL_CLOBBERED_REGS_BEFORE_ARGS				      \
+	sst.w	r1, PTO+PT_GPR(1)[ep];					      \
+	sst.w	r5, PTO+PT_GPR(5)[ep]
+#define SAVE_CALL_CLOBBERED_REGS_AFTER_RVAL				      \
+	sst.w	r12, PTO+PT_GPR(12)[ep];				      \
+	sst.w	r13, PTO+PT_GPR(13)[ep];				      \
+	sst.w	r14, PTO+PT_GPR(14)[ep];				      \
+	sst.w	r15, PTO+PT_GPR(15)[ep];				      \
+	sst.w	r16, PTO+PT_GPR(16)[ep];				      \
+	sst.w	r17, PTO+PT_GPR(17)[ep];				      \
+	sst.w	r18, PTO+PT_GPR(18)[ep];				      \
+	sst.w	r19, PTO+PT_GPR(19)[ep]
+#define RESTORE_CALL_CLOBBERED_REGS_BEFORE_ARGS				      \
+	sld.w	PTO+PT_GPR(1)[ep], r1;					      \
+	sld.w	PTO+PT_GPR(5)[ep], r5
+#define RESTORE_CALL_CLOBBERED_REGS_AFTER_RVAL				      \
+	sld.w	PTO+PT_GPR(12)[ep], r12;				      \
+	sld.w	PTO+PT_GPR(13)[ep], r13;				      \
+	sld.w	PTO+PT_GPR(14)[ep], r14;				      \
+	sld.w	PTO+PT_GPR(15)[ep], r15;				      \
+	sld.w	PTO+PT_GPR(16)[ep], r16;				      \
+	sld.w	PTO+PT_GPR(17)[ep], r17;				      \
+	sld.w	PTO+PT_GPR(18)[ep], r18;				      \
+	sld.w	PTO+PT_GPR(19)[ep], r19
+
+/* Save `call clobbered' registers to the state-save-frame pointed to by EP.  */
+#define SAVE_CALL_CLOBBERED_REGS					      \
+	SAVE_CALL_CLOBBERED_REGS_BEFORE_ARGS;				      \
+	SAVE_ARG_REGS;							      \
+	SAVE_RVAL_REGS;							      \
+	SAVE_CALL_CLOBBERED_REGS_AFTER_RVAL
+/* Restore `call clobbered' registers from the state-save-frame pointed to
+   by EP.  */
+#define RESTORE_CALL_CLOBBERED_REGS					      \
+	RESTORE_CALL_CLOBBERED_REGS_BEFORE_ARGS;			      \
+	RESTORE_ARG_REGS;						      \
+	RESTORE_RVAL_REGS;						      \
+	RESTORE_CALL_CLOBBERED_REGS_AFTER_RVAL
+
+/* Save `call clobbered' registers except for the return-value registers
+   to the state-save-frame pointed to by EP.  */
+#define SAVE_CALL_CLOBBERED_REGS_NO_RVAL				      \
+	SAVE_CALL_CLOBBERED_REGS_BEFORE_ARGS;				      \
+	SAVE_ARG_REGS;							      \
+	SAVE_CALL_CLOBBERED_REGS_AFTER_RVAL
+/* Restore `call clobbered' registers except for the return-value registers
+   from the state-save-frame pointed to by EP.  */
+#define RESTORE_CALL_CLOBBERED_REGS_NO_RVAL				      \
+	RESTORE_CALL_CLOBBERED_REGS_BEFORE_ARGS;			      \
+	RESTORE_ARG_REGS;						      \
+	RESTORE_CALL_CLOBBERED_REGS_AFTER_RVAL
+
+/* Save `call saved' registers to the state-save-frame pointed to by EP.  */
+#define SAVE_CALL_SAVED_REGS						      \
+	sst.w	r2, PTO+PT_GPR(2)[ep];					      \
+	sst.w	r20, PTO+PT_GPR(20)[ep];				      \
+	sst.w	r21, PTO+PT_GPR(21)[ep];				      \
+	sst.w	r22, PTO+PT_GPR(22)[ep];				      \
+	sst.w	r23, PTO+PT_GPR(23)[ep];				      \
+	sst.w	r24, PTO+PT_GPR(24)[ep];				      \
+	sst.w	r25, PTO+PT_GPR(25)[ep];				      \
+	sst.w	r26, PTO+PT_GPR(26)[ep];				      \
+	sst.w	r27, PTO+PT_GPR(27)[ep];				      \
+	sst.w	r28, PTO+PT_GPR(28)[ep];				      \
+	sst.w	r29, PTO+PT_GPR(29)[ep]
+/* Restore `call saved' registers from the state-save-frame pointed to by EP.  */
+#define RESTORE_CALL_SAVED_REGS						      \
+	sld.w	PTO+PT_GPR(2)[ep], r2;					      \
+	sld.w	PTO+PT_GPR(20)[ep], r20;				      \
+	sld.w	PTO+PT_GPR(21)[ep], r21;				      \
+	sld.w	PTO+PT_GPR(22)[ep], r22;				      \
+	sld.w	PTO+PT_GPR(23)[ep], r23;				      \
+	sld.w	PTO+PT_GPR(24)[ep], r24;				      \
+	sld.w	PTO+PT_GPR(25)[ep], r25;				      \
+	sld.w	PTO+PT_GPR(26)[ep], r26;				      \
+	sld.w	PTO+PT_GPR(27)[ep], r27;				      \
+	sld.w	PTO+PT_GPR(28)[ep], r28;				      \
+	sld.w	PTO+PT_GPR(29)[ep], r29
+
+
+/* Save the PC stored in the special register SAVEREG to the state-save-frame
+   pointed to by EP.  r19 is clobbered.  */
+#define SAVE_PC(savereg)						      \
+	stsr	SR_ ## savereg, r19;					      \
+	sst.w	r19, PTO+PT_PC[ep]
+/* Restore the PC from the state-save-frame pointed to by EP, to the special
+   register SAVEREG.  LP is clobbered (it is used as a scratch register
+   because the POP_STATE macro restores it, and this macro is usually used
+   inside POP_STATE).  */
+#define RESTORE_PC(savereg)						      \
+	sld.w	PTO+PT_PC[ep], lp;					      \
+	ldsr	lp, SR_ ## savereg
+/* Save the PSW register stored in the special register SAVREG to the
+   state-save-frame pointed to by EP.  r19 is clobbered.  */
+#define SAVE_PSW(savereg)						      \
+	stsr	SR_ ## savereg, r19;					      \
+	sst.w	r19, PTO+PT_PSW[ep]
+/* Restore the PSW register from the state-save-frame pointed to by EP, to
+   the special register SAVEREG.  LP is clobbered (it is used as a scratch
+   register because the POP_STATE macro restores it, and this macro is
+   usually used inside POP_STATE).  */
+#define RESTORE_PSW(savereg)						      \
+	sld.w	PTO+PT_PSW[ep], lp;					      \
+	ldsr	lp, SR_ ## savereg
+
+/* Save CTPC/CTPSW/CTBP registers to the state-save-frame pointed to by REG.
+   r19 is clobbered.  */
+#define SAVE_CT_REGS							      \
+	stsr	SR_CTPC, r19;						      \
+	sst.w	r19, PTO+PT_CTPC[ep];					      \
+	stsr	SR_CTPSW, r19;						      \
+	sst.w	r19, PTO+PT_CTPSW[ep];					      \
+	stsr	SR_CTBP, r19;						      \
+	sst.w	r19, PTO+PT_CTBP[ep]
+/* Restore CTPC/CTPSW/CTBP registers from the state-save-frame pointed to by EP.
+   LP is clobbered (it is used as a scratch register because the POP_STATE
+   macro restores it, and this macro is usually used inside POP_STATE).  */
+#define RESTORE_CT_REGS							      \
+	sld.w	PTO+PT_CTPC[ep], lp;					      \
+	ldsr	lp, SR_CTPC;						      \
+	sld.w	PTO+PT_CTPSW[ep], lp;					      \
+	ldsr	lp, SR_CTPSW;						      \
+	sld.w	PTO+PT_CTBP[ep], lp;					      \
+	ldsr	lp, SR_CTBP
+
+
+/* Push register state, except for the stack pointer, on the stack in the
+   form of a state-save-frame (plus some extra padding), in preparation for
+   a system call.  This macro makes sure that the EP, GP, and LP
+   registers are saved, and TYPE identifies the set of extra registers to
+   be saved as well.  Also copies (the new value of) SP to EP.  */
+#define PUSH_STATE(type)						      \
+	addi	-STATE_SAVE_SIZE, sp, sp; /* Make room on the stack.  */      \
+	st.w	ep, PTO+PT_GPR(GPR_EP)[sp];				      \
+	mov	sp, ep;							      \
+	sst.w	gp, PTO+PT_GPR(GPR_GP)[ep];				      \
+	sst.w	lp, PTO+PT_GPR(GPR_LP)[ep];				      \
+	type ## _STATE_SAVER
+/* Pop a register state pushed by PUSH_STATE, except for the stack pointer,
+   from the the stack.  */
+#define POP_STATE(type)							      \
+	mov	sp, ep;							      \
+	type ## _STATE_RESTORER;					      \
+	sld.w	PTO+PT_GPR(GPR_GP)[ep], gp;				      \
+	sld.w	PTO+PT_GPR(GPR_LP)[ep], lp;				      \
+	sld.w	PTO+PT_GPR(GPR_EP)[ep], ep;				      \
+	addi	STATE_SAVE_SIZE, sp, sp /* Clean up our stack space.  */
+
+
+/* Switch to the kernel stack if necessary, and push register state on the
+   stack in the form of a state-save-frame.  Also load the current task
+   pointer if switching from user mode.  The stack-pointer (r3) should have
+   already been saved to the memory location SP_SAVE_LOC (the reason for
+   this is that the interrupt vectors may be beyond a 22-bit signed offset
+   jump from the actual interrupt handler, and this allows them to save the
+   stack-pointer and use that register to do an indirect jump).  This macro
+   makes sure that `special' registers, system registers, and the stack
+   pointer are saved; TYPE identifies the set of extra registers to be
+   saved as well.  SYSCALL_NUM is the register in which the system-call
+   number this state is for is stored (r0 if this isn't a system call).
+   Interrupts should already be disabled when calling this.  */
+#define SAVE_STATE(type, syscall_num, sp_save_loc)			      \
+	tst1	0, KM;			/* See if already in kernel mode.  */ \
+	bz	1f;							      \
+	ld.w	sp_save_loc, sp;	/* ... yes, use saved SP.  */	      \
+	br	2f;							      \
+1:	ld.w	KSP, sp;		/* ... no, switch to kernel stack. */ \
+2:	PUSH_STATE(type);						      \
+	ld.b	KM, r19;		/* Remember old kernel-mode.  */      \
+	sst.w	r19, PTO+PT_KERNEL_MODE[ep];				      \
+	ld.w	sp_save_loc, r19;	/* Remember old SP.  */		      \
+	sst.w	r19, PTO+PT_GPR(GPR_SP)[ep];				      \
+	mov	1, r19;			/* Now definitely in kernel-mode. */  \
+	st.b	r19, KM;						      \
+	GET_CURRENT_TASK(CURRENT_TASK);	/* Fetch the current task pointer. */ \
+	/* Save away the syscall number.  */				      \
+	sst.w	syscall_num, PTO+PT_CUR_SYSCALL[ep]
+
+
+/* Save register state not normally saved by PUSH_STATE for TYPE, to the
+   state-save-frame on the stack; also copies SP to EP.  r19 may be trashed. */
+#define SAVE_EXTRA_STATE(type)						      \
+	mov	sp, ep;							      \
+	type ## _EXTRA_STATE_SAVER
+/* Restore register state not normally restored by POP_STATE for TYPE,
+   from the state-save-frame on the stack; also copies SP to EP.
+   r19 may be trashed.  */
+#define RESTORE_EXTRA_STATE(type)					      \
+	mov	sp, ep;							      \
+	type ## _EXTRA_STATE_RESTORER
+
+/* Save any call-clobbered registers not normally saved by PUSH_STATE for
+   TYPE, to the state-save-frame on the stack.
+   EP may be trashed, but is not guaranteed to contain a copy of SP
+   (unlike after most SAVE_... macros).  r19 may be trashed.  */
+#define SAVE_EXTRA_STATE_FOR_SCHEDULE(type)				      \
+	type ## _SCHEDULE_EXTRA_STATE_SAVER
+/* Restore any call-clobbered registers not normally restored by
+   POP_STATE for TYPE, to the state-save-frame on the stack.
+   EP may be trashed, but is not guaranteed to contain a copy of SP
+   (unlike after most RESTORE_... macros).  r19 may be trashed.  */
+#define RESTORE_EXTRA_STATE_FOR_SCHEDULE(type)				      \
+	type ## _SCHEDULE_EXTRA_STATE_RESTORER
+
+
+/* These are extra_state_saver/restorer values for a user trap.  Note
+   that we save the argument registers so that restarted syscalls will
+   function properly (otherwise it wouldn't be necessary), and we must
+   _not_ restore the return-value registers (so that traps can return a
+   value!), but call-clobbered registers are not saved at all, as the
+   caller of the syscall function should have saved them.  */
+
+#define TRAP_RET reti
+/* Traps don't save call-clobbered registers (but do still save arg regs).
+   We preserve PSw to keep long-term state, namely interrupt status (for traps
+   from kernel-mode), and the single-step flag (for user traps).  */
+#define TRAP_STATE_SAVER						      \
+	SAVE_ARG_REGS;							      \
+	SAVE_PC(EIPC);							      \
+	SAVE_PSW(EIPSW)
+/* When traps return, they just leave call-clobbered registers (except for arg
+   regs) with whatever value they have from the kernel.  Traps don't preserve
+   the PSW, but we zero EIPSW to ensure it doesn't contain anything dangerous
+   (in particular, the single-step flag).  */
+#define TRAP_STATE_RESTORER						      \
+	RESTORE_ARG_REGS;						      \
+	RESTORE_PC(EIPC);						      \
+	RESTORE_PSW(EIPSW)
+/* Save registers not normally saved by traps.  We need to save r12, even
+   though it's nominally call-clobbered, because it's used when restarting
+   a system call (the signal-handling path uses SAVE_EXTRA_STATE, and
+   expects r12 to be restored when the trap returns).  */
+#define TRAP_EXTRA_STATE_SAVER						      \
+	SAVE_RVAL_REGS;							      \
+	sst.w	r12, PTO+PT_GPR(12)[ep];				      \
+	SAVE_CALL_SAVED_REGS;						      \
+	SAVE_CT_REGS
+#define TRAP_EXTRA_STATE_RESTORER					      \
+	RESTORE_RVAL_REGS;						      \
+	sld.w	PTO+PT_GPR(12)[ep], r12;				      \
+	RESTORE_CALL_SAVED_REGS;					      \
+	RESTORE_CT_REGS
+/* Save registers prior to calling scheduler (just before trap returns).
+   We have to save the return-value registers to preserve the trap's return
+   value.  Note that ..._SCHEDULE_EXTRA_STATE_SAVER, unlike most ..._SAVER
+   macros, is required to setup EP itself if EP is needed (this is because
+   in many cases, the macro is empty).  */
+#define TRAP_SCHEDULE_EXTRA_STATE_SAVER					      \
+	mov sp, ep;							      \
+	SAVE_RVAL_REGS
+/* Note that ..._SCHEDULE_EXTRA_STATE_RESTORER, unlike most ..._RESTORER
+   macros, is required to setup EP itself if EP is needed (this is because
+   in many cases, the macro is empty).  */
+#define TRAP_SCHEDULE_EXTRA_STATE_RESTORER				      \
+	mov sp, ep;							      \
+	RESTORE_RVAL_REGS
+
+/* Register saving/restoring for maskable interrupts.  */
+#define IRQ_RET reti
+#define IRQ_STATE_SAVER							      \
+	SAVE_CALL_CLOBBERED_REGS;					      \
+	SAVE_PC(EIPC);							      \
+	SAVE_PSW(EIPSW)
+#define IRQ_STATE_RESTORER						      \
+	RESTORE_CALL_CLOBBERED_REGS;					      \
+	RESTORE_PC(EIPC);						      \
+	RESTORE_PSW(EIPSW)
+#define IRQ_EXTRA_STATE_SAVER						      \
+	SAVE_CALL_SAVED_REGS;						      \
+	SAVE_CT_REGS
+#define IRQ_EXTRA_STATE_RESTORER					      \
+	RESTORE_CALL_SAVED_REGS;					      \
+	RESTORE_CT_REGS
+#define IRQ_SCHEDULE_EXTRA_STATE_SAVER	     /* nothing */
+#define IRQ_SCHEDULE_EXTRA_STATE_RESTORER    /* nothing */
+
+/* Register saving/restoring for non-maskable interrupts.  */
+#define NMI_RET reti
+#define NMI_STATE_SAVER							      \
+	SAVE_CALL_CLOBBERED_REGS;					      \
+	SAVE_PC(FEPC);							      \
+	SAVE_PSW(FEPSW);
+#define NMI_STATE_RESTORER						      \
+	RESTORE_CALL_CLOBBERED_REGS;					      \
+	RESTORE_PC(FEPC);						      \
+	RESTORE_PSW(FEPSW);
+#define NMI_EXTRA_STATE_SAVER						      \
+	SAVE_CALL_SAVED_REGS;						      \
+	SAVE_CT_REGS
+#define NMI_EXTRA_STATE_RESTORER					      \
+	RESTORE_CALL_SAVED_REGS;					      \
+	RESTORE_CT_REGS
+#define NMI_SCHEDULE_EXTRA_STATE_SAVER	     /* nothing */
+#define NMI_SCHEDULE_EXTRA_STATE_RESTORER    /* nothing */
+
+/* Register saving/restoring for debug traps.  */
+#define DBTRAP_RET .long 0x014607E0 /* `dbret', but gas doesn't support it. */
+#define DBTRAP_STATE_SAVER						      \
+	SAVE_CALL_CLOBBERED_REGS;					      \
+	SAVE_PC(DBPC);							      \
+	SAVE_PSW(DBPSW)
+#define DBTRAP_STATE_RESTORER						      \
+	RESTORE_CALL_CLOBBERED_REGS;					      \
+	RESTORE_PC(DBPC);						      \
+	RESTORE_PSW(DBPSW)
+#define DBTRAP_EXTRA_STATE_SAVER					      \
+	SAVE_CALL_SAVED_REGS;						      \
+	SAVE_CT_REGS
+#define DBTRAP_EXTRA_STATE_RESTORER					      \
+	RESTORE_CALL_SAVED_REGS;					      \
+	RESTORE_CT_REGS
+#define DBTRAP_SCHEDULE_EXTRA_STATE_SAVER	/* nothing */
+#define DBTRAP_SCHEDULE_EXTRA_STATE_RESTORER	/* nothing */
+
+/* Register saving/restoring for a context switch.  We don't need to save
+   too many registers, because context-switching looks like a function call
+   (via the function `switch_thread'), so callers will save any
+   call-clobbered registers themselves.  We do need to save the CT regs, as
+   they're normally not saved during kernel entry (the kernel doesn't use
+   them).  We save PSW so that interrupt-status state will correctly follow
+   each thread (mostly NMI vs. normal-IRQ/trap), though for the most part
+   it doesn't matter since threads are always in almost exactly the same
+   processor state during a context switch.  The stack pointer and return
+   value are handled by switch_thread itself.  */
+#define SWITCH_STATE_SAVER						      \
+	SAVE_CALL_SAVED_REGS;						      \
+	SAVE_PSW(PSW);							      \
+	SAVE_CT_REGS
+#define SWITCH_STATE_RESTORER						      \
+	RESTORE_CALL_SAVED_REGS;					      \
+	RESTORE_PSW(PSW);						      \
+	RESTORE_CT_REGS
+
+
+/* Restore register state from the state-save-frame on the stack, switch back
+   to the user stack if necessary, and return from the trap/interrupt.
+   EXTRA_STATE_RESTORER is a sequence of assembly language statements to
+   restore anything not restored by this macro.  Only registers not saved by
+   the C compiler are restored (that is, R3(sp), R4(gp), R31(lp), and
+   anything restored by EXTRA_STATE_RESTORER).  */
+#define RETURN(type)							      \
+	ld.b	PTO+PT_KERNEL_MODE[sp], r19;				      \
+	di;				/* Disable interrupts */	      \
+	cmp	r19, r0;		/* See if returning to kernel mode, */\
+	bne	2f;			/* ... if so, skip resched &c.  */    \
+									      \
+	/* We're returning to user mode, so check for various conditions that \
+	   trigger rescheduling. */					      \
+	GET_CURRENT_THREAD(r18);					      \
+	ld.w	TI_FLAGS[r18], r19;					      \
+	andi	_TIF_NEED_RESCHED, r19, r0;				      \
+	bnz	3f;			/* Call the scheduler.  */	      \
+5:	andi	_TIF_SIGPENDING, r19, r18;				      \
+	ld.w	TASK_PTRACE[CURRENT_TASK], r19; /* ptrace flags */	      \
+	or	r18, r19;		/* see if either is non-zero */	      \
+	bnz	4f;			/* if so, handle them */	      \
+									      \
+/* Return to user state.  */						      \
+1:	st.b	r0, KM;			/* Now officially in user state. */   \
+									      \
+/* Final return.  The stack-pointer fiddling is not needed when returning     \
+   to kernel-mode, but they don't hurt, and this way we can share the	      \
+   (sometimes rather lengthy) POP_STATE macro.  */			      \
+2:	POP_STATE(type);						      \
+	st.w	sp, KSP;		/* Save the kernel stack pointer. */  \
+	ld.w	PT_GPR(GPR_SP)-PT_SIZE[sp], sp; /* Restore stack pointer. */  \
+	type ## _RET;			/* Return from the trap/interrupt. */ \
+									      \
+/* Call the scheduler before returning from a syscall/trap. */		      \
+3:	SAVE_EXTRA_STATE_FOR_SCHEDULE(type); /* Prepare to call scheduler. */ \
+	jarl	call_scheduler, lp;	/* Call scheduler */		      \
+	di;				/* The scheduler enables interrupts */\
+	RESTORE_EXTRA_STATE_FOR_SCHEDULE(type);				      \
+	GET_CURRENT_THREAD(r18);					      \
+	ld.w	TI_FLAGS[r18], r19;					      \
+	br	5b;			/* Continue with return path. */      \
+									      \
+/* Handle a signal or ptraced process return.				      \
+   r18 should be non-zero if there are pending signals.  */		      \
+4:	/* Not all registers are saved by the normal trap/interrupt entry     \
+	   points (for instance, call-saved registers (because the normal     \
+	   C-compiler calling sequence in the kernel makes sure they're	      \
+	   preserved), and call-clobbered registers in the case of	      \
+	   traps), but signal handlers may want to examine or change the      \
+	   complete register state.  Here we save anything not saved by	      \
+	   the normal entry sequence, so that it may be safely restored	      \
+	   (in a possibly modified form) after do_signal returns.  */	      \
+	SAVE_EXTRA_STATE(type);		/* Save state not saved by entry. */  \
+	jarl	handle_signal_or_ptrace_return, lp;			      \
+	RESTORE_EXTRA_STATE(type);	/* Restore extra regs.  */	      \
+	br	1b
+
+
+/* Jump to the appropriate function for the system call number in r12
+   (r12 is not preserved), or return an error if r12 is not valid.  The
+   LP register should point to the location where the called function
+   should return.  [note that MAKE_SYS_CALL uses label 1]  */
+#define MAKE_SYS_CALL							      \
+	/* Figure out which function to use for this system call.  */	      \
+	shl	2, r12;							      \
+	/* See if the system call number is valid.  */			      \
+	addi	lo(CSYM(sys_call_table) - sys_call_table_end), r12, r0;	      \
+	bnh	1f;							      \
+	mov	hilo(CSYM(sys_call_table)), r19;			      \
+	add	r19, r12;						      \
+	ld.w	0[r12], r12;						      \
+	/* Make the system call.  */					      \
+	jmp	[r12];							      \
+	/* The syscall number is invalid, return an error.  */		      \
+1:	addi	-ENOSYS, r0, r10;					      \
+	jmp	[lp]
+
+
+	.text
+
+/*
+ * User trap.
+ *
+ * Trap 0 system calls are also handled here.
+ *
+ * The stack-pointer (r3) should have already been saved to the memory
+ * location ENTRY_SP (the reason for this is that the interrupt vectors may be
+ * beyond a 22-bit signed offset jump from the actual interrupt handler, and
+ * this allows them to save the stack-pointer and use that register to do an
+ * indirect jump).
+ *
+ * Syscall protocol:
+ *   Syscall number in r12, args in r6-r9
+ *   Return value in r10
+ */
+G_ENTRY(trap):
+	SAVE_STATE (TRAP, r12, ENTRY_SP) // Save registers.
+	stsr	SR_ECR, r19		// Find out which trap it was.
+	ei				// Enable interrupts.
+	mov	hilo(ret_from_trap), lp	// where the trap should return
+
+	// The following two shifts (1) clear out extraneous NMI data in the
+	// upper 16-bits, (2) convert the 0x40 - 0x5f range of trap ECR
+	// numbers into the (0-31) << 2 range we want, (3) set the flags.
+	shl	27, r19			// chop off all high bits
+	shr	25, r19			// scale back down and then << 2
+	bnz	2f			// See if not trap 0.
+
+	// Trap 0 is a `short' system call, skip general trap table.
+	MAKE_SYS_CALL			// Jump to the syscall function.
+
+2:	// For other traps, use a table lookup.
+	mov	hilo(CSYM(trap_table)), r18
+	add	r19, r18
+	ld.w	0[r18], r18
+	jmp	[r18]			// Jump to the trap handler.
+END(trap)
+
+/* This is just like ret_from_trap, but first restores extra registers
+   saved by some wrappers.  */
+L_ENTRY(restore_extra_regs_and_ret_from_trap):
+	RESTORE_EXTRA_STATE(TRAP)
+	// fall through
+END(restore_extra_regs_and_ret_from_trap)
+
+/* Entry point used to return from a syscall/trap.  */
+L_ENTRY(ret_from_trap):
+	RETURN(TRAP)
+END(ret_from_trap)
+
+
+/* This the initial entry point for a new child thread, with an appropriate
+   stack in place that makes it look the the child is in the middle of an
+   syscall.  This function is actually `returned to' from switch_thread
+   (copy_thread makes ret_from_fork the return address in each new thread's
+   saved context).  */
+C_ENTRY(ret_from_fork):
+	mov	r10, r6			// switch_thread returns the prev task.
+	jarl	CSYM(schedule_tail), lp	// ...which is schedule_tail's arg
+	mov	r0, r10			// Child's fork call should return 0.
+	br	ret_from_trap		// Do normal trap return.
+C_END(ret_from_fork)
+
+
+/*
+ * Trap 1: `long' system calls
+ * `Long' syscall protocol:
+ *   Syscall number in r12, args in r6-r9, r13-r14
+ *   Return value in r10
+ */
+L_ENTRY(syscall_long):
+	// Push extra arguments on the stack.  Note that by default, the trap
+	// handler reserves enough stack space for 6 arguments, so we don't
+	// have to make any additional room.
+	st.w	r13, 16[sp]		// arg 5
+	st.w	r14, 20[sp]		// arg 6
+
+	// Make sure r13 and r14 are preserved, in case we have to restart a
+	// system call because of a signal (ep has already been set by caller).
+	st.w	r13, PTO+PT_GPR(13)[sp]
+	st.w	r14, PTO+PT_GPR(13)[sp]
+	mov	hilo(ret_from_long_syscall), lp
+
+	MAKE_SYS_CALL			// Jump to the syscall function.
+END(syscall_long)
+
+/* Entry point used to return from a long syscall.  Only needed to restore
+   r13/r14 if the general trap mechanism doesnt' do so.  */
+L_ENTRY(ret_from_long_syscall):
+	ld.w	PTO+PT_GPR(13)[sp], r13 // Restore the extra registers
+	ld.w	PTO+PT_GPR(13)[sp], r14
+	br	ret_from_trap		// The rest is the same as other traps
+END(ret_from_long_syscall)
+
+
+/* These syscalls need access to the struct pt_regs on the stack, so we
+   implement them in assembly (they're basically all wrappers anyway).  */
+
+L_ENTRY(sys_fork_wrapper):
+#ifdef CONFIG_MMU
+	addi	SIGCHLD, r0, r6		   // Arg 0: flags
+	ld.w	PTO+PT_GPR(GPR_SP)[sp], r7 // Arg 1: child SP (use parent's)
+	movea	PTO, sp, r8		   // Arg 2: parent context
+	mov	r0, r9			   // Arg 3/4/5: 0
+	st.w	r0, 16[sp]
+	st.w	r0, 20[sp]
+	mov	hilo(CSYM(do_fork)), r18   // Where the real work gets done
+	br	save_extra_state_tramp	   // Save state and go there
+#else
+	// fork almost works, enough to trick you into looking elsewhere :-(
+	addi	-EINVAL, r0, r10
+	jmp	[lp]
+#endif
+END(sys_fork_wrapper)
+
+L_ENTRY(sys_vfork_wrapper):
+	addi	CLONE_VFORK | CLONE_VM | SIGCHLD, r0, r6 // Arg 0: flags
+	ld.w	PTO+PT_GPR(GPR_SP)[sp], r7 // Arg 1: child SP (use parent's)
+	movea	PTO, sp, r8		   // Arg 2: parent context
+	mov	r0, r9			   // Arg 3/4/5: 0
+	st.w	r0, 16[sp]
+	st.w	r0, 20[sp]
+	mov	hilo(CSYM(do_fork)), r18   // Where the real work gets done
+	br	save_extra_state_tramp	   // Save state and go there
+END(sys_vfork_wrapper)
+
+L_ENTRY(sys_clone_wrapper):
+	ld.w	PTO+PT_GPR(GPR_SP)[sp], r19// parent's stack pointer
+	cmp	r7, r0			   // See if child SP arg (arg 1) is 0.
+	cmov	z, r19, r7, r7		   // ... and use the parent's if so.
+	movea	PTO, sp, r8		   // Arg 2: parent context
+	mov	r0, r9			   // Arg 3/4/5: 0
+	st.w	r0, 16[sp]
+	st.w	r0, 20[sp]
+	mov	hilo(CSYM(do_fork)), r18   // Where the real work gets done
+	br	save_extra_state_tramp	   // Save state and go there
+END(sys_clone_wrapper)
+
+
+L_ENTRY(sys_execve_wrapper):
+	movea	PTO, sp, r9		// add user context as 4th arg
+	jr	CSYM(sys_execve)	// Do real work (tail-call).
+END(sys_execve_wrapper)
+
+
+L_ENTRY(sys_sigsuspend_wrapper):
+	movea	PTO, sp, r7		// add user context as 2nd arg
+	mov	hilo(CSYM(sys_sigsuspend)), r18	// syscall function
+	jarl	save_extra_state_tramp, lp	// Save state and do it
+	br	restore_extra_regs_and_ret_from_trap
+END(sys_sigsuspend_wrapper)
+L_ENTRY(sys_rt_sigsuspend_wrapper):
+	movea	PTO, sp, r8		// add user context as 3rd arg
+	mov	hilo(CSYM(sys_rt_sigsuspend)), r18 // syscall function
+	jarl	save_extra_state_tramp, lp	   // Save state and do it
+	br	restore_extra_regs_and_ret_from_trap
+END(sys_rt_sigsuspend_wrapper)
+
+L_ENTRY(sys_sigreturn_wrapper):
+	movea	PTO, sp, r6		// add user context as 1st arg
+	mov	hilo(CSYM(sys_sigreturn)), r18	// syscall function
+	jarl	save_extra_state_tramp, lp	// Save state and do it
+	br	restore_extra_regs_and_ret_from_trap
+END(sys_sigreturn_wrapper)
+L_ENTRY(sys_rt_sigreturn_wrapper):
+	movea	PTO, sp, r6		// add user context as 1st arg
+	mov	hilo(CSYM(sys_rt_sigreturn)), r18// syscall function
+	jarl	save_extra_state_tramp, lp	 // Save state and do it
+	br	restore_extra_regs_and_ret_from_trap
+END(sys_rt_sigreturn_wrapper)
+
+
+/* Save any state not saved by SAVE_STATE(TRAP), and jump to r18.
+   It's main purpose is to share the rather lengthy code sequence that
+   SAVE_STATE expands into among the above wrapper functions.  */
+L_ENTRY(save_extra_state_tramp):
+	SAVE_EXTRA_STATE(TRAP)		// Save state not saved by entry.
+	jmp	[r18]			// Do the work the caller wants
+END(save_extra_state_tramp)
+
+
+/*
+ * Hardware maskable interrupts.
+ *
+ * The stack-pointer (r3) should have already been saved to the memory
+ * location ENTRY_SP (the reason for this is that the interrupt vectors may be
+ * beyond a 22-bit signed offset jump from the actual interrupt handler, and
+ * this allows them to save the stack-pointer and use that register to do an
+ * indirect jump).
+ */
+G_ENTRY(irq):
+	SAVE_STATE (IRQ, r0, ENTRY_SP)	// Save registers.
+
+	stsr	SR_ECR, r6		// Find out which interrupt it was.
+	movea	PTO, sp, r7		// User regs are arg2
+
+	// All v850 implementations I know about encode their interrupts as
+	// multiples of 0x10, starting at 0x80 (after NMIs and software
+	// interrupts).  Convert this number into a simple IRQ index for the
+	// rest of the kernel.  We also clear the upper 16 bits, which hold
+	// NMI info, and don't appear to be cleared when a NMI returns.
+	shl	16, r6			// clear upper 16 bits
+	shr	20, r6			// shift back, and remove lower nibble
+	add	-8, r6			// remove bias for irqs
+
+	// Call the high-level interrupt handling code.
+	jarl	CSYM(handle_irq), lp
+
+	RETURN(IRQ)
+END(irq)
+
+
+/*
+ * Debug trap / illegal-instruction exception
+ *
+ * The stack-pointer (r3) should have already been saved to the memory
+ * location ENTRY_SP (the reason for this is that the interrupt vectors may be
+ * beyond a 22-bit signed offset jump from the actual interrupt handler, and
+ * this allows them to save the stack-pointer and use that register to do an
+ * indirect jump).
+ */
+G_ENTRY(dbtrap):
+	SAVE_STATE (DBTRAP, r0, ENTRY_SP)// Save registers.
+
+	/* First see if we came from kernel mode; if so, the dbtrap
+	   instruction has a special meaning, to set the DIR (`debug
+	   information register') register.  This is because the DIR register
+	   can _only_ be manipulated/read while in `debug mode,' and debug
+	   mode is only active while we're inside the dbtrap handler.  The
+	   exact functionality is:  { DIR = (DIR | r6) & ~r7; return DIR; }. */
+	ld.b	PTO+PT_KERNEL_MODE[sp], r19
+	cmp	r19, r0
+	bz	1f
+
+	stsr	SR_DIR, r10
+	or	r6, r10
+	not	r7, r7
+	and	r7, r10
+	ldsr	r10, SR_DIR
+	stsr	SR_DIR, r10		// Confirm the value we set
+	st.w	r10, PTO+PT_GPR(10)[sp]	// return it
+	br	3f
+
+1:	ei				// Enable interrupts.
+
+	/* The default signal type we raise.  */
+	mov	SIGTRAP, r6
+
+	/* See if it's a single-step trap.  */
+	stsr	SR_DBPSW, r19
+	andi	0x0800, r19, r19
+	bnz	2f
+
+	/* Look to see if the preceding instruction was is a dbtrap or not,
+	   to decide which signal we should use.  */
+	stsr	SR_DBPC, r19		// PC following trapping insn
+	ld.hu	-2[r19], r19
+	ori	0xf840, r0, r20		// DBTRAP insn
+	cmp	r19, r20		// Was this trap caused by DBTRAP?
+	cmov	ne, SIGILL, r6, r6	// Choose signal appropriately
+
+	/* Raise the desired signal.  */
+2:	mov	CURRENT_TASK, r7	// Arg 1: task
+	jarl	CSYM(send_sig), lp	// tail call
+
+3:	RETURN(DBTRAP)
+END(dbtrap)
+
+
+/*
+ * Hardware non-maskable interrupts.
+ *
+ * The stack-pointer (r3) should have already been saved to the memory
+ * location ENTRY_SP (the reason for this is that the interrupt vectors may be
+ * beyond a 22-bit signed offset jump from the actual interrupt handler, and
+ * this allows them to save the stack-pointer and use that register to do an
+ * indirect jump).
+ */
+G_ENTRY(nmi):
+	SAVE_STATE (NMI, r0, NMI_ENTRY_SP); /* Save registers.  */
+
+	stsr	SR_ECR, r6;		/* Find out which nmi it was.  */
+	shr	20, r6;			/* Extract NMI code in bits 20-24. */
+	movea	PTO, sp, r7;		/* User regs are arg2.  */
+
+	/* Non-maskable interrupts always lie right after maskable interrupts.
+	   Call the generic IRQ handler, with two arguments, the IRQ number,
+	   and a pointer to the user registers, to handle the specifics.
+	   (we subtract one because the first NMI has code 1).  */
+	addi	FIRST_NMI - 1, r6, r6
+	jarl	CSYM(handle_irq), lp
+
+	RETURN(NMI)
+END(nmi)
+
+
+/*
+ * Trap with no handler
+ */
+L_ENTRY(bad_trap_wrapper):
+	mov	r19, r6			// Arg 0: trap number
+	movea	PTO, sp, r7		// Arg 1: user regs
+	jr	CSYM(bad_trap)		// tail call handler
+END(bad_trap_wrapper)
+
+
+/*
+ * Invoke the scheduler, called from the trap/irq kernel exit path.
+ *
+ * This basically just calls `schedule', but also arranges for extra
+ * registers to be saved for ptrace'd processes, so ptrace can modify them.
+ */
+L_ENTRY(call_scheduler):
+	ld.w	TASK_PTRACE[CURRENT_TASK], r19	// See if task is ptrace'd
+	cmp	r19, r0
+	bnz	1f			// ... yes, do special stuff
+	jr	CSYM(schedule)		// ... no, just tail-call scheduler
+
+	// Save extra regs for ptrace'd task.  We want to save anything
+	// that would otherwise only be `implicitly' saved by the normal
+	// compiler calling-convention.
+1:	mov	sp, ep			// Setup EP for SAVE_CALL_SAVED_REGS
+	SAVE_CALL_SAVED_REGS		// Save call-saved registers to stack
+	mov	lp, r20			// Save LP in a callee-saved register
+
+	jarl	CSYM(schedule), lp	// Call scheduler
+
+	mov	r20, lp
+	mov	sp, ep			// We can't rely on EP after return
+	RESTORE_CALL_SAVED_REGS		// Restore (possibly modified) regs
+	jmp	[lp]			// Return to the return path
+END(call_scheduler)
+
+
+/*
+ * This is an out-of-line handler for two special cases during the kernel
+ * trap/irq exit sequence:
+ *
+ *  (1) If r18 is non-zero then a signal needs to be handled, which is
+ *	done, and then the caller returned to.
+ *
+ *  (2) If r18 is non-zero then we're returning to a ptraced process, which
+ *	has several special cases -- single-stepping and trap tracing, both
+ *	of which require using the `dbret' instruction to exit the kernel
+ *	instead of the normal `reti' (this is because the CPU not correctly
+ *	single-step after a reti).  In this case, of course, this handler
+ *	never returns to the caller.
+ *
+ * In either case, all registers should have been saved to the current
+ * state-save-frame on the stack, except for callee-saved registers.
+ *
+ * [These two different cases are combined merely to avoid bloating the
+ * macro-inlined code, not because they really make much sense together!]
+ */
+L_ENTRY(handle_signal_or_ptrace_return):
+	cmp	r18, r0			// See if handling a signal
+	bz	1f			// ... nope, go do ptrace return
+
+	// Handle a signal
+	mov	lp, r20			// Save link-pointer
+	mov	r10, r21		// Save return-values (for trap)
+	mov	r11, r22
+
+	movea	PTO, sp, r6		// Arg 1: struct pt_regs *regs
+	mov	r0, r7			// Arg 2: sigset_t *oldset
+	jarl	CSYM(do_signal), lp	// Handle the signal
+	di				// sig handling enables interrupts
+
+	mov	r20, lp			// Restore link-pointer
+	mov	r21, r10		// Restore return-values (for trap)
+	mov	r22, r11
+	ld.w	TASK_PTRACE[CURRENT_TASK], r19  // check ptrace flags too
+	cmp	r19, r0
+	bnz	1f			// ... some set, so look more
+2:	jmp	[lp]			// ... none set, so return normally
+
+	// ptrace return
+1:	ld.w	PTO+PT_PSW[sp], r19	// Look at user-processes's flags
+	andi	0x0800, r19, r19	// See if single-step flag is set
+	bz	2b			// ... nope, return normally
+
+	// Return as if from a dbtrap insn
+	st.b	r0, KM			// Now officially in user state.
+	POP_STATE(DBTRAP)		// Restore regs
+	st.w	sp, KSP			// Save the kernel stack pointer.
+	ld.w	PT_GPR(GPR_SP)-PT_SIZE[sp], sp // Restore user stack pointer.
+	DBTRAP_RET			// Return from the trap/interrupt.
+END(handle_signal_or_ptrace_return)
+
+
+/*
+ * This is where we switch between two threads.  The arguments are:
+ *   r6 -- pointer to the struct thread for the `current' process
+ *   r7 -- pointer to the struct thread for the `new' process.
+ * when this function returns, it will return to the new thread.
+ */
+C_ENTRY(switch_thread):
+	// Return the previous task (r10 is not clobbered by restore below)
+	mov	CURRENT_TASK, r10
+	// First, push the current processor state on the stack
+	PUSH_STATE(SWITCH)
+	// Now save the location of the kernel stack pointer for this thread;
+	// since we've pushed all other state on the stack, this is enough to
+	// restore it all later.
+	st.w	sp, THREAD_KSP[r6]
+	// Now restore the stack pointer from the new process
+	ld.w	THREAD_KSP[r7], sp
+	// ... and restore all state from that
+	POP_STATE(SWITCH)
+	// Update the current task pointer
+	GET_CURRENT_TASK(CURRENT_TASK)
+	// Now return into the new thread
+	jmp	[lp]
+C_END(switch_thread)
+
+
+	.data
+
+	.align 4
+C_DATA(trap_table):
+	.long bad_trap_wrapper		// trap 0, doesn't use trap table.
+	.long syscall_long		// trap 1, `long' syscall.
+	.long bad_trap_wrapper
+	.long bad_trap_wrapper
+	.long bad_trap_wrapper
+	.long bad_trap_wrapper
+	.long bad_trap_wrapper
+	.long bad_trap_wrapper
+	.long bad_trap_wrapper
+	.long bad_trap_wrapper
+	.long bad_trap_wrapper
+	.long bad_trap_wrapper
+	.long bad_trap_wrapper
+	.long bad_trap_wrapper
+	.long bad_trap_wrapper
+	.long bad_trap_wrapper
+C_END(trap_table)
+
+
+	.section .rodata
+
+	.align 4
+C_DATA(sys_call_table):
+	.long CSYM(sys_restart_syscall)	// 0
+	.long CSYM(sys_exit)
+	.long sys_fork_wrapper
+	.long CSYM(sys_read)
+	.long CSYM(sys_write)
+	.long CSYM(sys_open)		// 5
+	.long CSYM(sys_close)
+	.long CSYM(sys_waitpid)
+	.long CSYM(sys_creat)
+	.long CSYM(sys_link)
+	.long CSYM(sys_unlink)		// 10
+	.long sys_execve_wrapper
+	.long CSYM(sys_chdir)
+	.long CSYM(sys_time)
+	.long CSYM(sys_mknod)
+	.long CSYM(sys_chmod)		// 15
+	.long CSYM(sys_chown)
+	.long CSYM(sys_ni_syscall)	// was: break
+	.long CSYM(sys_ni_syscall)	// was: oldstat (aka stat)
+	.long CSYM(sys_lseek)
+	.long CSYM(sys_getpid)		// 20
+	.long CSYM(sys_mount)
+	.long CSYM(sys_oldumount)
+	.long CSYM(sys_setuid)
+	.long CSYM(sys_getuid)
+	.long CSYM(sys_stime)		// 25
+	.long CSYM(sys_ptrace)
+	.long CSYM(sys_alarm)
+	.long CSYM(sys_ni_syscall)	// was: oldfstat (aka fstat)
+	.long CSYM(sys_pause)
+	.long CSYM(sys_utime)		// 30
+	.long CSYM(sys_ni_syscall)	// was: stty
+	.long CSYM(sys_ni_syscall)	// was: gtty
+	.long CSYM(sys_access)
+	.long CSYM(sys_nice)
+	.long CSYM(sys_ni_syscall)	// 35, was: ftime
+	.long CSYM(sys_sync)
+	.long CSYM(sys_kill)
+	.long CSYM(sys_rename)
+	.long CSYM(sys_mkdir)
+	.long CSYM(sys_rmdir)		// 40
+	.long CSYM(sys_dup)
+	.long CSYM(sys_pipe)
+	.long CSYM(sys_times)
+	.long CSYM(sys_ni_syscall)	// was: prof
+	.long CSYM(sys_brk)		// 45
+	.long CSYM(sys_setgid)
+	.long CSYM(sys_getgid)
+	.long CSYM(sys_signal)
+	.long CSYM(sys_geteuid)
+	.long CSYM(sys_getegid)		// 50
+	.long CSYM(sys_acct)
+	.long CSYM(sys_umount)		// recycled never used phys()
+	.long CSYM(sys_ni_syscall)	// was: lock
+	.long CSYM(sys_ioctl)
+	.long CSYM(sys_fcntl)		// 55
+	.long CSYM(sys_ni_syscall)	// was: mpx
+	.long CSYM(sys_setpgid)
+	.long CSYM(sys_ni_syscall)	// was: ulimit
+	.long CSYM(sys_ni_syscall)
+	.long CSYM(sys_umask)		// 60
+	.long CSYM(sys_chroot)
+	.long CSYM(sys_ustat)
+	.long CSYM(sys_dup2)
+	.long CSYM(sys_getppid)
+	.long CSYM(sys_getpgrp)		// 65
+	.long CSYM(sys_setsid)
+	.long CSYM(sys_sigaction)
+	.long CSYM(sys_sgetmask)
+	.long CSYM(sys_ssetmask)
+	.long CSYM(sys_setreuid)	// 70
+	.long CSYM(sys_setregid)
+	.long sys_sigsuspend_wrapper
+	.long CSYM(sys_sigpending)
+	.long CSYM(sys_sethostname)
+	.long CSYM(sys_setrlimit)	// 75
+	.long CSYM(sys_getrlimit)
+	.long CSYM(sys_getrusage)
+	.long CSYM(sys_gettimeofday)
+	.long CSYM(sys_settimeofday)
+	.long CSYM(sys_getgroups)	// 80
+	.long CSYM(sys_setgroups)
+	.long CSYM(sys_select)
+	.long CSYM(sys_symlink)
+	.long CSYM(sys_ni_syscall)	// was: oldlstat (aka lstat)
+	.long CSYM(sys_readlink)	// 85
+	.long CSYM(sys_uselib)
+	.long CSYM(sys_swapon)
+	.long CSYM(sys_reboot)
+	.long CSYM(old_readdir)
+	.long CSYM(sys_mmap)		// 90
+	.long CSYM(sys_munmap)
+	.long CSYM(sys_truncate)
+	.long CSYM(sys_ftruncate)
+	.long CSYM(sys_fchmod)
+	.long CSYM(sys_fchown)		// 95
+	.long CSYM(sys_getpriority)
+	.long CSYM(sys_setpriority)
+	.long CSYM(sys_ni_syscall)	// was: profil
+	.long CSYM(sys_statfs)
+	.long CSYM(sys_fstatfs)		// 100
+	.long CSYM(sys_ni_syscall)	// i386: ioperm
+	.long CSYM(sys_socketcall)
+	.long CSYM(sys_syslog)
+	.long CSYM(sys_setitimer)
+	.long CSYM(sys_getitimer)	// 105
+	.long CSYM(sys_newstat)
+	.long CSYM(sys_newlstat)
+	.long CSYM(sys_newfstat)
+	.long CSYM(sys_ni_syscall)	// was: olduname (aka uname)
+	.long CSYM(sys_ni_syscall)	// 110, i386: iopl
+	.long CSYM(sys_vhangup)
+	.long CSYM(sys_ni_syscall)	// was: idle
+	.long CSYM(sys_ni_syscall)	// i386: vm86old
+	.long CSYM(sys_wait4)
+	.long CSYM(sys_swapoff)		// 115
+	.long CSYM(sys_sysinfo)
+	.long CSYM(sys_ipc)
+	.long CSYM(sys_fsync)
+	.long sys_sigreturn_wrapper
+	.long sys_clone_wrapper		// 120
+	.long CSYM(sys_setdomainname)
+	.long CSYM(sys_newuname)
+	.long CSYM(sys_ni_syscall)	// i386: modify_ldt, m68k: cacheflush
+	.long CSYM(sys_adjtimex)
+	.long CSYM(sys_ni_syscall)	// 125 - sys_mprotect
+	.long CSYM(sys_sigprocmask)
+	.long CSYM(sys_ni_syscall)	// sys_create_module
+	.long CSYM(sys_init_module)
+	.long CSYM(sys_delete_module)
+	.long CSYM(sys_ni_syscall)	// 130 - sys_get_kernel_syms
+	.long CSYM(sys_quotactl)
+	.long CSYM(sys_getpgid)
+	.long CSYM(sys_fchdir)
+	.long CSYM(sys_bdflush)
+	.long CSYM(sys_sysfs)		// 135
+	.long CSYM(sys_personality)
+	.long CSYM(sys_ni_syscall)	// for afs_syscall
+	.long CSYM(sys_setfsuid)
+	.long CSYM(sys_setfsgid)
+	.long CSYM(sys_llseek)		// 140
+	.long CSYM(sys_getdents)
+	.long CSYM(sys_select)		// for backward compat; remove someday
+	.long CSYM(sys_flock)
+	.long CSYM(sys_ni_syscall)	// sys_msync
+	.long CSYM(sys_readv)		// 145
+	.long CSYM(sys_writev)
+	.long CSYM(sys_getsid)
+	.long CSYM(sys_fdatasync)
+	.long CSYM(sys_sysctl)
+	.long CSYM(sys_ni_syscall)	// 150 - sys_mlock
+	.long CSYM(sys_ni_syscall)	// sys_munlock
+	.long CSYM(sys_ni_syscall)	// sys_mlockall
+	.long CSYM(sys_ni_syscall)	// sys_munlockall
+	.long CSYM(sys_sched_setparam)
+	.long CSYM(sys_sched_getparam)	// 155
+	.long CSYM(sys_sched_setscheduler)
+	.long CSYM(sys_sched_getscheduler)
+	.long CSYM(sys_sched_yield)
+	.long CSYM(sys_sched_get_priority_max)
+	.long CSYM(sys_sched_get_priority_min)	// 160
+	.long CSYM(sys_sched_rr_get_interval)
+	.long CSYM(sys_nanosleep)
+	.long CSYM(sys_ni_syscall)	// sys_mremap
+	.long CSYM(sys_setresuid)
+	.long CSYM(sys_getresuid)	// 165
+	.long CSYM(sys_ni_syscall)	// for vm86
+	.long CSYM(sys_ni_syscall)	// sys_query_module
+	.long CSYM(sys_poll)
+	.long CSYM(sys_nfsservctl)
+	.long CSYM(sys_setresgid)	// 170
+	.long CSYM(sys_getresgid)
+	.long CSYM(sys_prctl)
+	.long sys_rt_sigreturn_wrapper
+	.long CSYM(sys_rt_sigaction)
+	.long CSYM(sys_rt_sigprocmask)	// 175
+	.long CSYM(sys_rt_sigpending)
+	.long CSYM(sys_rt_sigtimedwait)
+	.long CSYM(sys_rt_sigqueueinfo)
+	.long sys_rt_sigsuspend_wrapper
+	.long CSYM(sys_pread64)		// 180
+	.long CSYM(sys_pwrite64)
+	.long CSYM(sys_lchown)
+	.long CSYM(sys_getcwd)
+	.long CSYM(sys_capget)
+	.long CSYM(sys_capset)		// 185
+	.long CSYM(sys_sigaltstack)
+	.long CSYM(sys_sendfile)
+	.long CSYM(sys_ni_syscall)	// streams1
+	.long CSYM(sys_ni_syscall)	// streams2
+	.long sys_vfork_wrapper		// 190
+	.long CSYM(sys_ni_syscall)
+	.long CSYM(sys_mmap2)
+	.long CSYM(sys_truncate64)
+	.long CSYM(sys_ftruncate64)
+	.long CSYM(sys_stat64)		// 195
+	.long CSYM(sys_lstat64)
+	.long CSYM(sys_fstat64)
+	.long CSYM(sys_fcntl64)
+	.long CSYM(sys_getdents64)
+	.long CSYM(sys_pivot_root)	// 200
+	.long CSYM(sys_gettid)
+	.long CSYM(sys_tkill)
+sys_call_table_end:
+C_END(sys_call_table)
diff --git a/arch/v850/kernel/fpga85e2c.c b/arch/v850/kernel/fpga85e2c.c
new file mode 100644
index 0000000..4bac514
--- /dev/null
+++ b/arch/v850/kernel/fpga85e2c.c
@@ -0,0 +1,171 @@
+/*
+ * arch/v850/kernel/fpga85e2c.h -- Machine-dependent defs for
+ *	FPGA implementation of V850E2/NA85E2C
+ *
+ *  Copyright (C) 2002,03  NEC Electronics Corporation
+ *  Copyright (C) 2002,03  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/bootmem.h>
+#include <linux/irq.h>
+#include <linux/bitops.h>
+
+#include <asm/atomic.h>
+#include <asm/page.h>
+#include <asm/machdep.h>
+
+#include "mach.h"
+
+extern void memcons_setup (void);
+
+
+#define REG_DUMP_ADDR		0x220000
+
+
+extern struct irqaction reg_snap_action; /* fwd decl */
+
+
+void __init mach_early_init (void)
+{
+	int i;
+	const u32 *src;
+	register u32 *dst asm ("ep");
+	extern u32 _intv_end, _intv_load_start;
+
+	/* Set bus sizes: CS0 32-bit, CS1 16-bit, CS7 8-bit,
+	   everything else 32-bit.  */
+	V850E2_BSC = 0x2AA6;
+	for (i = 2; i <= 6; i++)
+		CSDEV(i) = 0;	/* 32 bit */
+
+	/* Ensure that the simulator halts on a panic, instead of going
+	   into an infinite loop inside the panic function.  */
+	panic_timeout = -1;
+
+	/* Move the interrupt vectors into their real location.  Note that
+	   any relocations there are relative to the real location, so we
+	   don't have to fix anything up.  We use a loop instead of calling
+	   memcpy to keep this a leaf function (to avoid a function
+	   prologue being generated).  */
+	dst = 0x10;		/* &_intv_start + 0x10.  */
+	src = &_intv_load_start;
+	do {
+		u32 t0 = src[0], t1 = src[1], t2 = src[2], t3 = src[3];
+		u32 t4 = src[4], t5 = src[5], t6 = src[6], t7 = src[7];
+		dst[0] = t0; dst[1] = t1; dst[2] = t2; dst[3] = t3;
+		dst[4] = t4; dst[5] = t5; dst[6] = t6; dst[7] = t7;
+		dst += 8;
+		src += 8;
+	} while (dst < &_intv_end);
+}
+
+void __init mach_setup (char **cmdline)
+{
+	memcons_setup ();
+
+	/* Setup up NMI0 to copy the registers to a known memory location.
+	   The FGPA board has a button that produces NMI0 when pressed, so
+	   this allows us to push the button, and then look at memory to see
+	   what's in the registers (there's no other way to easily do so).
+	   We have to use `setup_irq' instead of `request_irq' because it's
+	   still too early to do memory allocation.  */
+	setup_irq (IRQ_NMI (0), &reg_snap_action);
+}
+
+void mach_get_physical_ram (unsigned long *ram_start, unsigned long *ram_len)
+{
+	*ram_start = ERAM_ADDR;
+	*ram_len = ERAM_SIZE;
+}
+
+void __init mach_sched_init (struct irqaction *timer_action)
+{
+	/* Setup up the timer interrupt.  The FPGA peripheral control
+	   registers _only_ work with single-bit writes (set1/clr1)!  */
+	__clear_bit (RPU_GTMC_CE_BIT, &RPU_GTMC);
+	__clear_bit (RPU_GTMC_CLK_BIT, &RPU_GTMC);
+	__set_bit (RPU_GTMC_CE_BIT, &RPU_GTMC);
+
+	/* We use the first RPU interrupt, which occurs every 8.192ms.  */
+	setup_irq (IRQ_RPU (0), timer_action);
+}
+
+
+void mach_gettimeofday (struct timespec *tv)
+{
+	tv->tv_sec = 0;
+	tv->tv_nsec = 0;
+}
+
+void machine_halt (void) __attribute__ ((noreturn));
+void machine_halt (void)
+{
+	for (;;) {
+		DWC(0) = 0x7777;
+		DWC(1) = 0x7777;
+		ASC = 0xffff;
+		FLGREG(0) = 1;	/* Halt immediately.  */
+		asm ("di; halt; nop; nop; nop; nop; nop");
+	}
+}
+
+EXPORT_SYMBOL(machine_halt);
+
+void machine_restart (char *__unused)
+{
+	machine_halt ();
+}
+
+EXPORT_SYMBOL(machine_restart);
+
+void machine_power_off (void)
+{
+	machine_halt ();
+}
+
+EXPORT_SYMBOL(machine_power_off);
+
+
+/* Interrupts */
+
+struct v850e_intc_irq_init irq_inits[] = {
+	{ "IRQ", 0, 		NUM_MACH_IRQS,	1, 7 },
+	{ "RPU", IRQ_RPU(0),	IRQ_RPU_NUM,	1, 6 },
+	{ 0 }
+};
+#define NUM_IRQ_INITS ((sizeof irq_inits / sizeof irq_inits[0]) - 1)
+
+struct hw_interrupt_type hw_itypes[NUM_IRQ_INITS];
+
+/* Initialize interrupts.  */
+void __init mach_init_irqs (void)
+{
+	v850e_intc_init_irq_types (irq_inits, hw_itypes);
+}
+
+
+/* An interrupt handler that copies the registers to a known memory location,
+   for debugging purposes.  */
+
+static void make_reg_snap (int irq, void *dummy, struct pt_regs *regs)
+{
+	(*(unsigned *)REG_DUMP_ADDR)++;
+	(*(struct pt_regs *)(REG_DUMP_ADDR + sizeof (unsigned))) = *regs;
+}
+
+static int reg_snap_dev_id;
+static struct irqaction reg_snap_action = {
+	make_reg_snap, 0, CPU_MASK_NONE, "reg_snap", &reg_snap_dev_id, 0
+};
diff --git a/arch/v850/kernel/fpga85e2c.ld b/arch/v850/kernel/fpga85e2c.ld
new file mode 100644
index 0000000..b5d4578
--- /dev/null
+++ b/arch/v850/kernel/fpga85e2c.ld
@@ -0,0 +1,62 @@
+/* Linker script for the FPGA implementation of the V850E2 NA85E2C cpu core
+   (CONFIG_V850E2_FPGA85E2C).  */
+
+MEMORY {
+	/* Reset vector.  */
+	RESET	 : ORIGIN = 0, LENGTH = 0x10
+	/* Interrupt vectors.  */
+	INTV      : ORIGIN = 0x10, LENGTH = 0x470
+	/* The `window' in RAM were we're allowed to load stuff.  */
+	RAM_LOW   : ORIGIN = 0x480, LENGTH = 0x0005FB80
+	/* Some more ram above the window were we can put bss &c.  */
+	RAM_HIGH  : ORIGIN = 0x00060000, LENGTH = 0x000A0000
+	/* This is the area visible from the outside world (we can use
+	   this only for uninitialized data).  */
+	VISIBLE   : ORIGIN = 0x00200000, LENGTH = 0x00060000
+}
+
+SECTIONS {
+	.reset : {
+		__kram_start = . ;
+		__intv_start = . ;
+	        	*(.intv.reset)	/* Reset vector */
+	} > RESET
+
+	.ram_low : {
+		__r0_ram = . ;		/* Must be near address 0.  */
+		. = . + 32 ;
+
+		TEXT_CONTENTS
+		DATA_CONTENTS
+		ROOT_FS_CONTENTS
+		RAMK_INIT_CONTENTS_NO_END
+		INITRAMFS_CONTENTS
+	} > RAM_LOW
+
+        /* Where the interrupt vectors are initially loaded.  */
+	__intv_load_start = . ;
+
+	.intv : {
+			*(.intv.common)	/* Vectors common to all v850e proc. */
+			*(.intv.mach)	/* Machine-specific int. vectors.  */
+		__intv_end = . ;
+	} > INTV  AT> RAM_LOW
+
+	.ram_high : {
+		/* This is here so that when we free init memory the
+		   load-time copy of the interrupt vectors and any empty
+		   space at the end of the `RAM_LOW' area is freed too.  */
+		. = ALIGN (4096);
+		__init_end = . ;
+
+		BSS_CONTENTS
+		__kram_end = . ;
+		BOOTMAP_CONTENTS
+	} > RAM_HIGH
+
+	.visible : {
+		_memcons_output = . ;
+		. = . + 0x8000 ;
+		_memcons_output_end = . ;
+	} > VISIBLE
+}
diff --git a/arch/v850/kernel/gbus_int.c b/arch/v850/kernel/gbus_int.c
new file mode 100644
index 0000000..92918b8
--- /dev/null
+++ b/arch/v850/kernel/gbus_int.c
@@ -0,0 +1,271 @@
+/*
+ * arch/v850/kernel/gbus_int.c -- Midas labs GBUS interrupt support
+ *
+ *  Copyright (C) 2001,02,03  NEC Electronics Corporation
+ *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/signal.h>
+
+#include <asm/machdep.h>
+
+
+/* The number of shared GINT interrupts. */
+#define NUM_GINTS   	4
+
+/* For each GINT interrupt, how many GBUS interrupts are using it.  */
+static unsigned gint_num_active_irqs[NUM_GINTS] = { 0 };
+
+/* A table of GINTn interrupts we actually use.
+   Note that we don't use GINT0 because all the boards we support treat it
+   specially.  */
+struct used_gint {
+	unsigned gint;
+	unsigned priority;
+} used_gint[] = {
+	{ 1, GBUS_INT_PRIORITY_HIGH },
+	{ 3, GBUS_INT_PRIORITY_LOW }
+};
+#define NUM_USED_GINTS	(sizeof used_gint / sizeof used_gint[0])
+
+/* A table of which GINT is used by each GBUS interrupts (they are
+   assigned based on priority).  */
+static unsigned char gbus_int_gint[IRQ_GBUS_INT_NUM];
+
+
+/* Interrupt enabling/disabling.  */
+
+/* Enable interrupt handling for interrupt IRQ.  */
+void gbus_int_enable_irq (unsigned irq)
+{
+	unsigned gint = gbus_int_gint[irq - GBUS_INT_BASE_IRQ];
+	GBUS_INT_ENABLE (GBUS_INT_IRQ_WORD(irq), gint)
+		|= GBUS_INT_IRQ_MASK (irq);
+}
+
+/* Disable interrupt handling for interrupt IRQ.  Note that any
+   interrupts received while disabled will be delivered once the
+   interrupt is enabled again, unless they are explicitly cleared using
+   `gbus_int_clear_pending_irq'.  */
+void gbus_int_disable_irq (unsigned irq)
+{
+	unsigned gint = gbus_int_gint[irq - GBUS_INT_BASE_IRQ];
+	GBUS_INT_ENABLE (GBUS_INT_IRQ_WORD(irq), gint)
+		&= ~GBUS_INT_IRQ_MASK (irq);
+}
+
+/* Return true if interrupt handling for interrupt IRQ is enabled.  */
+int gbus_int_irq_enabled (unsigned irq)
+{
+	unsigned gint = gbus_int_gint[irq - GBUS_INT_BASE_IRQ];
+	return (GBUS_INT_ENABLE (GBUS_INT_IRQ_WORD(irq), gint)
+		& GBUS_INT_IRQ_MASK(irq));
+}
+
+/* Disable all GBUS irqs.  */
+void gbus_int_disable_irqs ()
+{
+	unsigned w, n;
+	for (w = 0; w < GBUS_INT_NUM_WORDS; w++)
+		for (n = 0; n < IRQ_GINT_NUM; n++)
+			GBUS_INT_ENABLE (w, n) = 0;
+}
+
+/* Clear any pending interrupts for IRQ.  */
+void gbus_int_clear_pending_irq (unsigned irq)
+{
+	GBUS_INT_CLEAR (GBUS_INT_IRQ_WORD(irq)) = GBUS_INT_IRQ_MASK (irq);
+}
+
+/* Return true if interrupt IRQ is pending (but disabled).  */
+int gbus_int_irq_pending (unsigned irq)
+{
+	return (GBUS_INT_STATUS (GBUS_INT_IRQ_WORD(irq))
+		& GBUS_INT_IRQ_MASK(irq));
+}
+
+
+/* Delegating interrupts.  */
+
+/* Handle a shared GINT interrupt by passing to the appropriate GBUS
+   interrupt handler.  */
+static irqreturn_t gbus_int_handle_irq (int irq, void *dev_id,
+					struct pt_regs *regs)
+{
+	unsigned w;
+	irqreturn_t rval = IRQ_NONE;
+	unsigned gint = irq - IRQ_GINT (0);
+
+	for (w = 0; w < GBUS_INT_NUM_WORDS; w++) {
+		unsigned status = GBUS_INT_STATUS (w);
+		unsigned enable = GBUS_INT_ENABLE (w, gint);
+
+		/* Only pay attention to enabled interrupts.  */
+		status &= enable;
+		if (status) {
+			irq = IRQ_GBUS_INT (w * GBUS_INT_BITS_PER_WORD);
+			do {
+				/* There's an active interrupt in word
+				   W, find out which one, and call its
+				   handler.  */
+
+				while (! (status & 0x1)) {
+					irq++;
+					status >>= 1;
+				}
+				status &= ~0x1;
+
+				/* Recursively call handle_irq to handle it. */
+				handle_irq (irq, regs);
+				rval = IRQ_HANDLED;
+			} while (status);
+		}
+	}
+
+	/* Toggle the `all enable' bit back and forth, which should cause
+	   another edge transition if there are any other interrupts
+	   still pending, and so result in another CPU interrupt.  */
+	GBUS_INT_ENABLE (0, gint) &= ~0x1;
+	GBUS_INT_ENABLE (0, gint) |=  0x1;
+
+	return rval;
+}
+
+
+/* Initialize GBUS interrupt sources.  */
+
+static void irq_nop (unsigned irq) { }
+
+static unsigned gbus_int_startup_irq (unsigned irq)
+{
+	unsigned gint = gbus_int_gint[irq - GBUS_INT_BASE_IRQ];
+
+	if (gint_num_active_irqs[gint] == 0) {
+		/* First enable the CPU interrupt.  */
+		int rval =
+			request_irq (IRQ_GINT(gint), gbus_int_handle_irq,
+				     SA_INTERRUPT,
+				     "gbus_int_handler",
+				     &gint_num_active_irqs[gint]);
+		if (rval != 0)
+			return rval;
+	}
+
+	gint_num_active_irqs[gint]++;
+
+	gbus_int_clear_pending_irq (irq);
+	gbus_int_enable_irq (irq);
+
+	return 0;
+}
+
+static void gbus_int_shutdown_irq (unsigned irq)
+{
+	unsigned gint = gbus_int_gint[irq - GBUS_INT_BASE_IRQ];
+
+	gbus_int_disable_irq (irq);
+
+	if (--gint_num_active_irqs[gint] == 0)
+		/* Disable the CPU interrupt.  */
+		free_irq (IRQ_GINT(gint), &gint_num_active_irqs[gint]);
+}
+
+/* Initialize HW_IRQ_TYPES for INTC-controlled irqs described in array
+   INITS (which is terminated by an entry with the name field == 0).  */
+void __init gbus_int_init_irq_types (struct gbus_int_irq_init *inits,
+				     struct hw_interrupt_type *hw_irq_types)
+{
+	struct gbus_int_irq_init *init;
+	for (init = inits; init->name; init++) {
+		unsigned i;
+		struct hw_interrupt_type *hwit = hw_irq_types++;
+
+		hwit->typename = init->name;
+
+		hwit->startup  = gbus_int_startup_irq;
+		hwit->shutdown = gbus_int_shutdown_irq;
+		hwit->enable   = gbus_int_enable_irq;
+		hwit->disable  = gbus_int_disable_irq;
+		hwit->ack      = irq_nop;
+		hwit->end      = irq_nop;
+		
+		/* Initialize kernel IRQ infrastructure for this interrupt.  */
+		init_irq_handlers(init->base, init->num, init->interval, hwit);
+
+		/* Set the interrupt priorities.  */
+		for (i = 0; i < init->num; i++) {
+			unsigned j;
+			for (j = 0; j < NUM_USED_GINTS; j++)
+				if (used_gint[j].priority > init->priority)
+					break;
+			/* Wherever we stopped looking is one past the
+			   GINT we want. */
+			gbus_int_gint[init->base + i * init->interval
+				      - GBUS_INT_BASE_IRQ]
+				= used_gint[j > 0 ? j - 1 : 0].gint;
+		}
+	}
+}
+
+
+/* Initialize IRQS.  */
+
+/* Chip interrupts (GINTn) shared among GBUS interrupts.  */
+static struct hw_interrupt_type gint_hw_itypes[NUM_USED_GINTS];
+
+
+/* GBUS interrupts themselves.  */
+
+struct gbus_int_irq_init gbus_irq_inits[] __initdata = {
+	/* First set defaults.  */
+	{ "GBUS_INT", IRQ_GBUS_INT(0), IRQ_GBUS_INT_NUM, 1, 6},
+	{ 0 }
+};
+#define NUM_GBUS_IRQ_INITS  \
+   ((sizeof gbus_irq_inits / sizeof gbus_irq_inits[0]) - 1)
+
+static struct hw_interrupt_type gbus_hw_itypes[NUM_GBUS_IRQ_INITS];
+
+
+/* Initialize GBUS interrupts.  */
+void __init gbus_int_init_irqs (void)
+{
+	unsigned i;
+
+	/* First initialize the shared gint interrupts.  */
+	for (i = 0; i < NUM_USED_GINTS; i++) {
+		unsigned gint = used_gint[i].gint;
+		struct v850e_intc_irq_init gint_irq_init[2];
+
+		/* We initialize one GINT interrupt at a time.  */
+		gint_irq_init[0].name = "GINT";
+		gint_irq_init[0].base = IRQ_GINT (gint);
+		gint_irq_init[0].num = 1;
+		gint_irq_init[0].interval = 1;
+		gint_irq_init[0].priority = used_gint[i].priority;
+
+		gint_irq_init[1].name = 0; /* Terminate the vector.  */
+
+		v850e_intc_init_irq_types (gint_irq_init, gint_hw_itypes);
+	}
+
+	/* Then the GBUS interrupts.  */
+	gbus_int_disable_irqs ();
+	gbus_int_init_irq_types (gbus_irq_inits, gbus_hw_itypes);
+	/* Turn on the `all enable' bits, which are ANDed with
+	   individual interrupt enable bits; we only want to bother with
+	   the latter.  They are the first bit in the first word of each
+	   interrupt-enable area.  */
+	for (i = 0; i < NUM_USED_GINTS; i++)
+		GBUS_INT_ENABLE (0, used_gint[i].gint) = 0x1;
+}
diff --git a/arch/v850/kernel/head.S b/arch/v850/kernel/head.S
new file mode 100644
index 0000000..c490b93
--- /dev/null
+++ b/arch/v850/kernel/head.S
@@ -0,0 +1,128 @@
+/*
+ * arch/v850/kernel/head.S -- Lowest-level startup code
+ *
+ *  Copyright (C) 2001,02,03  NEC Electronics Corporation
+ *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <asm/clinkage.h>
+#include <asm/current.h>
+#include <asm/entry.h>
+#include <asm/thread_info.h>
+#include <asm/irq.h>
+
+
+/* Make a slightly more convenient alias for C_SYMBOL_NAME.  */
+#define CSYM	C_SYMBOL_NAME
+
+
+	.text
+
+	// Define `mach_early_init' as a weak symbol
+	.global	CSYM(mach_early_init)
+	.weak	CSYM(mach_early_init)
+
+C_ENTRY(start):
+	// Make sure interrupts are turned off, just in case
+	di
+
+#ifdef CONFIG_RESET_GUARD
+	// See if we got here via an unexpected reset
+	ld.w	RESET_GUARD, r19	// Check current value of reset guard
+	mov	RESET_GUARD_ACTIVE, r20
+	cmp	r19, r20
+	bne	1f			// Guard was not active
+
+	// If we get here, the reset guard was active.  Load up some
+	// interesting values as arguments, and jump to the handler.
+	st.w	r0, RESET_GUARD		// Allow further resets to succeed
+	mov	lp, r6			// Arg 0: return address
+	ld.b	KM, r7			// Arg 1: kernel mode
+	mov	sp, r9			// Arg 3: stack pointer
+	ld.w	KSP, r19		// maybe switch to kernel stack
+	cmp	r7, r0			// see if already in kernel mode
+	cmov	z, r19, sp, sp		//  and switch to kernel stack if not
+	GET_CURRENT_TASK(r8)		// Arg 2: task pointer
+	jr	CSYM(unexpected_reset)
+
+1:	st.w	r20, RESET_GUARD	// Turn on reset guard
+#endif /* CONFIG_RESET_GUARD */
+
+	// Setup a temporary stack for doing pre-initialization function calls.
+	// 
+	// We can't use the initial kernel stack, because (1) it may be
+	// located in memory we're not allowed to touch, and (2) since
+	// it's in the data segment, calling memcpy to initialize that
+	// area from ROM will overwrite memcpy's return address.
+	mov	hilo(CSYM(_init_stack_end) - 4), sp
+
+	// See if there's a platform-specific early-initialization routine
+	// defined; it's a weak symbol, so it will have an address of zero if
+	// there's not.
+	mov	hilo(CSYM(mach_early_init)), r6
+	cmp	r6, r0
+	bz	3f
+
+	// There is one, so call it.  If this function is written in C, it
+	// should be very careful -- the stack pointer is valid, but very
+	// little else is (e.g., bss is not zeroed yet, and initialized data
+	// hasn't been).
+	jarl	2f, lp			// first figure out return address
+2:	add	3f - ., lp
+	jmp	[r6]			// do call
+3:
+
+#ifdef CONFIG_ROM_KERNEL
+	// Copy the data area from ROM to RAM
+	mov	hilo(CSYM(_rom_copy_dst_start)), r6
+	mov	hilo(CSYM(_rom_copy_src_start)), r7
+	mov	hilo(CSYM(_rom_copy_dst_end)), r8
+	sub	r6, r8
+	jarl	CSYM(memcpy), lp
+#endif
+
+	// Load the initial thread's stack, and current task pointer (in r16)
+	mov	hilo(CSYM(init_thread_union)), r19
+	movea	THREAD_SIZE, r19, sp
+	ld.w	TI_TASK[r19], CURRENT_TASK
+
+#ifdef CONFIG_TIME_BOOTUP
+	/* This stuff must come after mach_early_init, because interrupts may
+	   not work until after its been called.  */
+	jarl	CSYM(highres_timer_reset), lp
+	jarl	CSYM(highres_timer_start), lp
+#endif
+
+	// Kernel stack pointer save location
+	st.w	sp, KSP
+
+	// Assert that we're in `kernel mode'
+	mov	1, r19
+	st.w	r19, KM
+
+#ifdef CONFIG_ZERO_BSS
+	// Zero bss area, since we can't rely upon any loader to do so
+	mov	hilo(CSYM(_sbss)), r6
+	mov	r0, r7
+	mov	hilo(CSYM(_ebss)), r8
+	sub	r6, r8
+	jarl	CSYM(memset), lp
+#endif
+
+	// What happens if the main kernel function returns (it shouldn't)
+	mov	hilo(CSYM(machine_halt)), lp
+
+	// Start the linux kernel.  We use an indirect jump to get extra
+	// range, because on some platforms this initial startup code
+	// (and the associated platform-specific code in mach_early_init)
+	// are located far away from the main kernel, e.g. so that they
+	// can initialize RAM first and copy the kernel or something.
+	mov	hilo(CSYM(start_kernel)), r12
+	jmp	[r12]
+C_END(start)
diff --git a/arch/v850/kernel/highres_timer.c b/arch/v850/kernel/highres_timer.c
new file mode 100644
index 0000000..b16ad1e
--- /dev/null
+++ b/arch/v850/kernel/highres_timer.c
@@ -0,0 +1,132 @@
+/*
+ * arch/v850/kernel/highres_timer.c -- High resolution timing routines
+ *
+ *  Copyright (C) 2001,02,03  NEC Electronics Corporation
+ *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <asm/system.h>
+#include <asm/v850e_timer_d.h>
+#include <asm/highres_timer.h>
+
+#define HIGHRES_TIMER_USEC_SHIFT   12
+
+/* Pre-calculated constant used for converting ticks to real time
+   units.  We initialize it to prevent it being put into BSS.  */
+static u32 highres_timer_usec_prescale = 1;
+
+void highres_timer_slow_tick_irq (void) __attribute__ ((noreturn));
+void highres_timer_slow_tick_irq (void)
+{
+	/* This is an interrupt handler, so it must be very careful to
+	   not to trash any registers.  At this point, the stack-pointer
+	   (r3) has been saved in the chip ram location ENTRY_SP by the
+	   interrupt vector, so we can use it as a scratch register; we
+	   must also restore it before returning.  */
+	asm ("ld.w	%0[r0], sp;"
+	     "add	1, sp;"
+	     "st.w	sp, %0[r0];"
+	     "ld.w	%1[r0], sp;" /* restore pre-irq stack-pointer */
+	     "reti"
+	     ::
+	      "i" (HIGHRES_TIMER_SLOW_TICKS_ADDR),
+	      "i" (ENTRY_SP_ADDR)
+	     : "memory");
+}
+
+void highres_timer_reset (void)
+{
+	V850E_TIMER_D_TMD (HIGHRES_TIMER_TIMER_D_UNIT) = 0;
+	HIGHRES_TIMER_SLOW_TICKS = 0;
+}
+
+void highres_timer_start (void)
+{
+	u32 fast_tick_rate;
+
+	/* Start hardware timer.  */
+	v850e_timer_d_configure (HIGHRES_TIMER_TIMER_D_UNIT,
+				 HIGHRES_TIMER_SLOW_TICK_RATE);
+
+	fast_tick_rate =
+		(V850E_TIMER_D_BASE_FREQ
+		 >> V850E_TIMER_D_DIVLOG2 (HIGHRES_TIMER_TIMER_D_UNIT));
+
+	/* The obvious way of calculating microseconds from fast ticks
+	   is to do:
+
+	     usec = fast_ticks * 10^6 / fast_tick_rate
+
+	   However, divisions are much slower than multiplications, and
+	   the above calculation can overflow, so we do this instead:
+
+	     usec = fast_ticks * (10^6 * 2^12 / fast_tick_rate) / 2^12
+
+           since we can pre-calculate (10^6 * (2^12 / fast_tick_rate))
+	   and use a shift for dividing by 2^12, this avoids division,
+	   and is almost as accurate (it differs by about 2 microseconds
+	   at the extreme value of the fast-tick counter's ranger).  */
+	highres_timer_usec_prescale = ((1000000 << HIGHRES_TIMER_USEC_SHIFT)
+				       / fast_tick_rate);
+
+	/* Enable the interrupt (which is hardwired to this use), and
+	   give it the highest priority.  */
+	V850E_INTC_IC (IRQ_INTCMD (HIGHRES_TIMER_TIMER_D_UNIT)) = 0;
+}
+
+void highres_timer_stop (void)
+{
+	/* Stop the timer.  */
+	V850E_TIMER_D_TMCD (HIGHRES_TIMER_TIMER_D_UNIT) =
+		V850E_TIMER_D_TMCD_CAE;
+	/* Disable its interrupt, just in case.  */
+	v850e_intc_disable_irq (IRQ_INTCMD (HIGHRES_TIMER_TIMER_D_UNIT));
+}
+
+inline void highres_timer_read_ticks (u32 *slow_ticks, u32 *fast_ticks)
+{
+	int flags;
+	u32 fast_ticks_1, fast_ticks_2, _slow_ticks;
+
+	local_irq_save (flags);
+	fast_ticks_1 = V850E_TIMER_D_TMD (HIGHRES_TIMER_TIMER_D_UNIT);
+	_slow_ticks = HIGHRES_TIMER_SLOW_TICKS;
+	fast_ticks_2 = V850E_TIMER_D_TMD (HIGHRES_TIMER_TIMER_D_UNIT);
+	local_irq_restore (flags);
+
+	if (fast_ticks_2 < fast_ticks_1)
+		_slow_ticks++;
+
+	*slow_ticks = _slow_ticks;
+	*fast_ticks = fast_ticks_2;
+}
+
+inline void highres_timer_ticks_to_timeval (u32 slow_ticks, u32 fast_ticks,
+					    struct timeval *tv)
+{
+	unsigned long sec, sec_rem, usec;
+
+	usec = ((fast_ticks * highres_timer_usec_prescale)
+		>> HIGHRES_TIMER_USEC_SHIFT);
+
+	sec = slow_ticks / HIGHRES_TIMER_SLOW_TICK_RATE;
+	sec_rem = slow_ticks % HIGHRES_TIMER_SLOW_TICK_RATE;
+
+	usec += sec_rem * (1000000 / HIGHRES_TIMER_SLOW_TICK_RATE);
+
+	tv->tv_sec = sec;
+	tv->tv_usec = usec;
+}
+
+void highres_timer_read (struct timeval *tv)
+{
+	u32 fast_ticks, slow_ticks;
+	highres_timer_read_ticks (&slow_ticks, &fast_ticks);
+	highres_timer_ticks_to_timeval (slow_ticks, fast_ticks, tv);
+}
diff --git a/arch/v850/kernel/init_task.c b/arch/v850/kernel/init_task.c
new file mode 100644
index 0000000..ed2f93c
--- /dev/null
+++ b/arch/v850/kernel/init_task.c
@@ -0,0 +1,49 @@
+/*
+ * arch/v850/kernel/init_task.c -- Initial task/thread structures
+ *
+ *  Copyright (C) 2002,03  NEC Electronics Corporation
+ *  Copyright (C) 2002,03  Miles Bader <miles@gnu.org>
+ *
+ * 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/mm.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/init_task.h>
+#include <linux/fs.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 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);
+
+/*
+ * 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) };
diff --git a/arch/v850/kernel/intv.S b/arch/v850/kernel/intv.S
new file mode 100644
index 0000000..671e4c6
--- /dev/null
+++ b/arch/v850/kernel/intv.S
@@ -0,0 +1,87 @@
+/*
+ * arch/v850/kernel/intv.S -- Interrupt vectors
+ *
+ *  Copyright (C) 2001,02,03  NEC Electronics Corporation
+ *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <asm/clinkage.h>
+#include <asm/irq.h>
+#include <asm/machdep.h>
+#include <asm/entry.h>
+
+#ifdef CONFIG_V850E_HIGHRES_TIMER
+#include <asm/highres_timer.h>
+#endif
+
+/* Jump to an interrupt/trap handler.  These handlers (defined in entry.S)
+   expect the stack-pointer to be saved in ENTRY_SP, so we use sp to do an
+   indirect jump (which avoids problems when the handler is more than a signed
+   22-bit offset away).  */
+#define JUMP_TO_HANDLER(name, sp_save_loc)				      \
+	st.w	sp, sp_save_loc;					      \
+	mov	hilo(name), sp;						      \
+	jmp	[sp]
+
+
+	/* Reset vector.  */
+	.section	.intv.reset, "ax"
+	.org	0x0
+	mov	hilo(C_SYMBOL_NAME(start)), r1;
+	jmp	[r1]
+
+
+	/* Generic interrupt vectors.  */
+	.section	.intv.common, "ax"
+	.balign	0x10
+	JUMP_TO_HANDLER (nmi, NMI_ENTRY_SP)	// 0x10 - NMI0
+	.balign	0x10
+	JUMP_TO_HANDLER (nmi, NMI_ENTRY_SP)	// 0x20 - NMI1
+	.balign	0x10
+	JUMP_TO_HANDLER (nmi, NMI_ENTRY_SP)	// 0x30 - NMI2
+	
+	.balign	0x10
+	JUMP_TO_HANDLER (trap, ENTRY_SP)	// 0x40 - TRAP0n
+	.balign	0x10
+	JUMP_TO_HANDLER (trap, ENTRY_SP)	// 0x50 - TRAP1n
+
+	.balign	0x10
+	JUMP_TO_HANDLER (dbtrap, ENTRY_SP)	// 0x60 - Illegal op / DBTRAP insn
+
+
+	/* Hardware interrupt vectors.  */
+	.section	.intv.mach, "ax"
+	.org	0x0
+
+#if defined (CONFIG_V850E_HIGHRES_TIMER) && defined (IRQ_INTCMD)
+
+	/* Interrupts before the highres timer interrupt.  */
+	.rept	IRQ_INTCMD (HIGHRES_TIMER_TIMER_D_UNIT)
+	.balign	0x10
+	JUMP_TO_HANDLER (irq, ENTRY_SP)
+	.endr
+
+	/* The highres timer interrupt.  */
+	.balign	0x10
+	JUMP_TO_HANDLER (C_SYMBOL_NAME (highres_timer_slow_tick_irq), ENTRY_SP)
+
+	/* Interrupts after the highres timer interrupt.  */
+	.rept	NUM_CPU_IRQS - IRQ_INTCMD (HIGHRES_TIMER_TIMER_D_UNIT) - 1
+	.balign	0x10
+	JUMP_TO_HANDLER (irq, ENTRY_SP)
+	.endr
+
+#else /* No highres timer */
+
+	.rept	NUM_CPU_IRQS
+	.balign	0x10
+	JUMP_TO_HANDLER (irq, ENTRY_SP)
+	.endr
+
+#endif /* Highres timer */
diff --git a/arch/v850/kernel/irq.c b/arch/v850/kernel/irq.c
new file mode 100644
index 0000000..336cbf2
--- /dev/null
+++ b/arch/v850/kernel/irq.c
@@ -0,0 +1,744 @@
+/*
+ * arch/v850/kernel/irq.c -- High-level interrupt handling
+ *
+ *  Copyright (C) 2001,02,03,04  NEC Electronics Corporation
+ *  Copyright (C) 2001,02,03,04  Miles Bader <miles@gnu.org>
+ *  Copyright (C) 1994-2000  Ralf Baechle
+ *  Copyright (C) 1992  Linus Torvalds
+ *
+ * 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.
+ *
+ * This file was was derived from the mips version, arch/mips/kernel/irq.c
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/irq.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/random.h>
+#include <linux/seq_file.h>
+
+#include <asm/system.h>
+
+/*
+ * Controller mappings for all interrupt sources:
+ */
+irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = {
+	[0 ... NR_IRQS-1] = {
+		.handler = &no_irq_type,
+		.lock = SPIN_LOCK_UNLOCKED
+	}
+};
+
+/*
+ * Special irq handlers.
+ */
+
+irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+	return IRQ_NONE;
+}
+
+/*
+ * Generic no controller code
+ */
+
+static void enable_none(unsigned int irq) { }
+static unsigned int startup_none(unsigned int irq) { return 0; }
+static void disable_none(unsigned int irq) { }
+static void ack_none(unsigned int irq)
+{
+	/*
+	 * '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.
+	 */
+	printk("received IRQ %d with unknown interrupt type\n", irq);
+}
+
+/* startup is the same as "enable", shutdown is same as "disable" */
+#define shutdown_none	disable_none
+#define end_none	enable_none
+
+struct hw_interrupt_type no_irq_type = {
+	"none",
+	startup_none,
+	shutdown_none,
+	enable_none,
+	disable_none,
+	ack_none,
+	end_none
+};
+
+volatile unsigned long irq_err_count, spurious_count;
+
+/*
+ * Generic, controller-independent functions:
+ */
+
+int show_interrupts(struct seq_file *p, void *v)
+{
+	int i = *(loff_t *) v;
+	struct irqaction * action;
+	unsigned long flags;
+
+	if (i == 0) {
+		seq_puts(p, "           ");
+		for (i=0; i < 1 /*smp_num_cpus*/; i++)
+			seq_printf(p, "CPU%d       ", i);
+		seq_putc(p, '\n');
+	}
+
+	if (i < NR_IRQS) {
+		int j, count, num;
+		const char *type_name = irq_desc[i].handler->typename;
+		spin_lock_irqsave(&irq_desc[j].lock, flags);
+		action = irq_desc[i].action;
+		if (!action) 
+			goto skip;
+
+		count = 0;
+		num = -1;
+		for (j = 0; j < NR_IRQS; j++)
+			if (irq_desc[j].handler->typename == type_name) {
+				if (i == j)
+					num = count;
+				count++;
+			}
+
+		seq_printf(p, "%3d: ",i);
+		seq_printf(p, "%10u ", kstat_irqs(i));
+		if (count > 1) {
+			int prec = (num >= 100 ? 3 : num >= 10 ? 2 : 1);
+			seq_printf(p, " %*s%d", 14 - prec, type_name, num);
+		} else
+			seq_printf(p, " %14s", type_name);
+		
+		seq_printf(p, "  %s", action->name);
+		for (action=action->next; action; action = action->next)
+			seq_printf(p, ", %s", action->name);
+		seq_putc(p, '\n');
+skip:
+		spin_unlock_irqrestore(&irq_desc[j].lock, flags);
+	} else if (i == NR_IRQS)
+		seq_printf(p, "ERR: %10lu\n", irq_err_count);
+	return 0;
+}
+
+/*
+ * This should really return information about whether
+ * we should do bottom half handling etc. Right now we
+ * end up _always_ checking the bottom half, which is a
+ * waste of time and is not what some drivers would
+ * prefer.
+ */
+int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action)
+{
+	int status = 1; /* Force the "do bottom halves" bit */
+	int ret;
+
+	if (!(action->flags & SA_INTERRUPT))
+		local_irq_enable();
+
+	do {
+		ret = action->handler(irq, action->dev_id, regs);
+		if (ret == IRQ_HANDLED)
+			status |= action->flags;
+		action = action->next;
+	} while (action);
+	if (status & SA_SAMPLE_RANDOM)
+		add_interrupt_randomness(irq);
+	local_irq_disable();
+
+	return status;
+}
+
+/*
+ * Generic enable/disable code: this just calls
+ * down into the PIC-specific version for the actual
+ * hardware disable after having gotten the irq
+ * controller lock. 
+ */
+ 
+/**
+ *	disable_irq_nosync - disable an irq without waiting
+ *	@irq: Interrupt to disable
+ *
+ *	Disable the selected interrupt line. Disables of an interrupt
+ *	stack. Unlike disable_irq(), this function does not ensure existing
+ *	instances of the IRQ handler have completed before returning.
+ *
+ *	This function may be called from IRQ context.
+ */
+ 
+void inline disable_irq_nosync(unsigned int irq)
+{
+	irq_desc_t *desc = irq_desc + irq;
+	unsigned long flags;
+
+	spin_lock_irqsave(&desc->lock, flags);
+	if (!desc->depth++) {
+		desc->status |= IRQ_DISABLED;
+		desc->handler->disable(irq);
+	}
+	spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+/**
+ *	disable_irq - disable an irq and wait for completion
+ *	@irq: Interrupt to disable
+ *
+ *	Disable the selected interrupt line. Disables of an interrupt
+ *	stack. That is for two disables you need two enables. This
+ *	function waits for any pending IRQ handlers for this interrupt
+ *	to complete before returning. If you use this function while
+ *	holding a resource the IRQ handler may need you will deadlock.
+ *
+ *	This function may be called - with care - from IRQ context.
+ */
+ 
+void disable_irq(unsigned int irq)
+{
+	disable_irq_nosync(irq);
+	synchronize_irq(irq);
+}
+
+/**
+ *	enable_irq - enable interrupt handling on an irq
+ *	@irq: Interrupt to enable
+ *
+ *	Re-enables the processing of interrupts on this IRQ line
+ *	providing no disable_irq calls are now in effect.
+ *
+ *	This function may be called from IRQ context.
+ */
+ 
+void enable_irq(unsigned int irq)
+{
+	irq_desc_t *desc = irq_desc + irq;
+	unsigned long flags;
+
+	spin_lock_irqsave(&desc->lock, flags);
+	switch (desc->depth) {
+	case 1: {
+		unsigned int status = desc->status & ~IRQ_DISABLED;
+		desc->status = status;
+		if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
+			desc->status = status | IRQ_REPLAY;
+			hw_resend_irq(desc->handler,irq);
+		}
+		desc->handler->enable(irq);
+		/* fall-through */
+	}
+	default:
+		desc->depth--;
+		break;
+	case 0:
+		printk("enable_irq(%u) unbalanced from %p\n", irq,
+		       __builtin_return_address(0));
+	}
+	spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+/* Handle interrupt IRQ.  REGS are the registers at the time of ther
+   interrupt.  */
+unsigned int handle_irq (int irq, struct pt_regs *regs)
+{
+	/* 
+	 * We ack quickly, we don't want the irq controller
+	 * thinking we're snobs just because some other CPU has
+	 * disabled global interrupts (we have already done the
+	 * INT_ACK cycles, it's too late to try to pretend to the
+	 * controller that we aren't taking the interrupt).
+	 *
+	 * 0 return value means that this irq is already being
+	 * handled by some other CPU. (or is disabled)
+	 */
+	int cpu = smp_processor_id();
+	irq_desc_t *desc = irq_desc + irq;
+	struct irqaction * action;
+	unsigned int status;
+
+	irq_enter();
+	kstat_cpu(cpu).irqs[irq]++;
+	spin_lock(&desc->lock);
+	desc->handler->ack(irq);
+	/*
+	   REPLAY is when Linux resends an IRQ that was dropped earlier
+	   WAITING is used by probe to mark irqs that are being tested
+	   */
+	status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
+	status |= IRQ_PENDING; /* we _want_ to handle it */
+
+	/*
+	 * If the IRQ is disabled for whatever reason, we cannot
+	 * use the action we have.
+	 */
+	action = NULL;
+	if (likely(!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))) {
+		action = desc->action;
+		status &= ~IRQ_PENDING; /* we commit to handling */
+		status |= IRQ_INPROGRESS; /* we are handling it */
+	}
+	desc->status = status;
+
+	/*
+	 * If there is no IRQ handler or it was disabled, exit early.
+	   Since we set PENDING, if another processor is handling
+	   a different instance of this same irq, the other processor
+	   will take care of it.
+	 */
+	if (unlikely(!action))
+		goto out;
+
+	/*
+	 * Edge triggered interrupts need to remember
+	 * pending events.
+	 * This applies to any hw interrupts that allow a second
+	 * instance of the same irq to arrive while we are in handle_irq
+	 * or in the handler. But the code here only handles the _second_
+	 * instance of the irq, not the third or fourth. So it is mostly
+	 * useful for irq hardware that does not mask cleanly in an
+	 * SMP environment.
+	 */
+	for (;;) {
+		spin_unlock(&desc->lock);
+		handle_IRQ_event(irq, regs, action);
+		spin_lock(&desc->lock);
+		
+		if (likely(!(desc->status & IRQ_PENDING)))
+			break;
+		desc->status &= ~IRQ_PENDING;
+	}
+	desc->status &= ~IRQ_INPROGRESS;
+
+out:
+	/*
+	 * The ->end() handler has to deal with interrupts which got
+	 * disabled while the handler was running.
+	 */
+	desc->handler->end(irq);
+	spin_unlock(&desc->lock);
+
+	irq_exit();
+
+	return 1;
+}
+
+/**
+ *	request_irq - allocate an interrupt line
+ *	@irq: Interrupt line to allocate
+ *	@handler: Function to be called when the IRQ occurs
+ *	@irqflags: Interrupt type flags
+ *	@devname: An ascii name for the claiming device
+ *	@dev_id: A cookie passed back to the handler function
+ *
+ *	This call allocates interrupt resources and enables the
+ *	interrupt line and IRQ handling. From the point this
+ *	call is made your handler function may be invoked. Since
+ *	your handler function must clear any interrupt the board 
+ *	raises, you must take care both to initialise your hardware
+ *	and to set up the interrupt handler in the right order.
+ *
+ *	Dev_id must be globally unique. Normally the address of the
+ *	device data structure is used as the cookie. Since the handler
+ *	receives this value it makes sense to use it.
+ *
+ *	If your interrupt is shared you must pass a non NULL dev_id
+ *	as this is required when freeing the interrupt.
+ *
+ *	Flags:
+ *
+ *	SA_SHIRQ		Interrupt is shared
+ *
+ *	SA_INTERRUPT		Disable local interrupts while processing
+ *
+ *	SA_SAMPLE_RANDOM	The interrupt can be used for entropy
+ *
+ */
+ 
+int request_irq(unsigned int irq, 
+		irqreturn_t (*handler)(int, void *, struct pt_regs *),
+		unsigned long irqflags, 
+		const char * devname,
+		void *dev_id)
+{
+	int retval;
+	struct irqaction * action;
+
+#if 1
+	/*
+	 * Sanity-check: shared interrupts should REALLY pass in
+	 * a real dev-ID, otherwise we'll have trouble later trying
+	 * to figure out which interrupt is which (messes up the
+	 * interrupt freeing logic etc).
+	 */
+	if (irqflags & SA_SHIRQ) {
+		if (!dev_id)
+			printk("Bad boy: %s (at 0x%x) called us without a dev_id!\n", devname, (&irq)[-1]);
+	}
+#endif
+
+	if (irq >= NR_IRQS)
+		return -EINVAL;
+	if (!handler)
+		return -EINVAL;
+
+	action = (struct irqaction *)
+			kmalloc(sizeof(struct irqaction), GFP_KERNEL);
+	if (!action)
+		return -ENOMEM;
+
+	action->handler = handler;
+	action->flags = irqflags;
+	cpus_clear(action->mask);
+	action->name = devname;
+	action->next = NULL;
+	action->dev_id = dev_id;
+
+	retval = setup_irq(irq, action);
+	if (retval)
+		kfree(action);
+	return retval;
+}
+
+EXPORT_SYMBOL(request_irq);
+
+/**
+ *	free_irq - free an interrupt
+ *	@irq: Interrupt line to free
+ *	@dev_id: Device identity to free
+ *
+ *	Remove an interrupt handler. The handler is removed and if the
+ *	interrupt line is no longer in use by any driver it is disabled.
+ *	On a shared IRQ the caller must ensure the interrupt is disabled
+ *	on the card it drives before calling this function. The function
+ *	does not return until any executing interrupts for this IRQ
+ *	have completed.
+ *
+ *	This function may be called from interrupt context. 
+ *
+ *	Bugs: Attempting to free an irq in a handler for the same irq hangs
+ *	      the machine.
+ */
+ 
+void free_irq(unsigned int irq, void *dev_id)
+{
+	irq_desc_t *desc;
+	struct irqaction **p;
+	unsigned long flags;
+
+	if (irq >= NR_IRQS)
+		return;
+
+	desc = irq_desc + irq;
+	spin_lock_irqsave(&desc->lock,flags);
+	p = &desc->action;
+	for (;;) {
+		struct irqaction * action = *p;
+		if (action) {
+			struct irqaction **pp = p;
+			p = &action->next;
+			if (action->dev_id != dev_id)
+				continue;
+
+			/* Found it - now remove it from the list of entries */
+			*pp = action->next;
+			if (!desc->action) {
+				desc->status |= IRQ_DISABLED;
+				desc->handler->shutdown(irq);
+			}
+			spin_unlock_irqrestore(&desc->lock,flags);
+
+			synchronize_irq(irq);
+			kfree(action);
+			return;
+		}
+		printk("Trying to free free IRQ%d\n",irq);
+		spin_unlock_irqrestore(&desc->lock,flags);
+		return;
+	}
+}
+
+EXPORT_SYMBOL(free_irq);
+
+/*
+ * IRQ autodetection code..
+ *
+ * This depends on the fact that any interrupt that
+ * comes in on to an unassigned handler will get stuck
+ * with "IRQ_WAITING" cleared and the interrupt
+ * disabled.
+ */
+
+static DECLARE_MUTEX(probe_sem);
+
+/**
+ *	probe_irq_on	- begin an interrupt autodetect
+ *
+ *	Commence probing for an interrupt. The interrupts are scanned
+ *	and a mask of potential interrupt lines is returned.
+ *
+ */
+ 
+unsigned long probe_irq_on(void)
+{
+	unsigned int i;
+	irq_desc_t *desc;
+	unsigned long val;
+	unsigned long delay;
+
+	down(&probe_sem);
+	/* 
+	 * something may have generated an irq long ago and we want to
+	 * flush such a longstanding irq before considering it as spurious. 
+	 */
+	for (i = NR_IRQS-1; i > 0; i--)  {
+		desc = irq_desc + i;
+
+		spin_lock_irq(&desc->lock);
+		if (!irq_desc[i].action) 
+			irq_desc[i].handler->startup(i);
+		spin_unlock_irq(&desc->lock);
+	}
+
+	/* Wait for longstanding interrupts to trigger. */
+	for (delay = jiffies + HZ/50; time_after(delay, jiffies); )
+		/* about 20ms delay */ barrier();
+
+	/*
+	 * enable any unassigned irqs
+	 * (we must startup again here because if a longstanding irq
+	 * happened in the previous stage, it may have masked itself)
+	 */
+	for (i = NR_IRQS-1; i > 0; i--) {
+		desc = irq_desc + i;
+
+		spin_lock_irq(&desc->lock);
+		if (!desc->action) {
+			desc->status |= IRQ_AUTODETECT | IRQ_WAITING;
+			if (desc->handler->startup(i))
+				desc->status |= IRQ_PENDING;
+		}
+		spin_unlock_irq(&desc->lock);
+	}
+
+	/*
+	 * Wait for spurious interrupts to trigger
+	 */
+	for (delay = jiffies + HZ/10; time_after(delay, jiffies); )
+		/* about 100ms delay */ barrier();
+
+	/*
+	 * Now filter out any obviously spurious interrupts
+	 */
+	val = 0;
+	for (i = 0; i < NR_IRQS; i++) {
+		irq_desc_t *desc = irq_desc + i;
+		unsigned int status;
+
+		spin_lock_irq(&desc->lock);
+		status = desc->status;
+
+		if (status & IRQ_AUTODETECT) {
+			/* It triggered already - consider it spurious. */
+			if (!(status & IRQ_WAITING)) {
+				desc->status = status & ~IRQ_AUTODETECT;
+				desc->handler->shutdown(i);
+			} else
+				if (i < 32)
+					val |= 1 << i;
+		}
+		spin_unlock_irq(&desc->lock);
+	}
+
+	return val;
+}
+
+EXPORT_SYMBOL(probe_irq_on);
+
+/*
+ * Return a mask of triggered interrupts (this
+ * can handle only legacy ISA interrupts).
+ */
+ 
+/**
+ *	probe_irq_mask - scan a bitmap of interrupt lines
+ *	@val:	mask of interrupts to consider
+ *
+ *	Scan the ISA bus interrupt lines and return a bitmap of
+ *	active interrupts. The interrupt probe logic state is then
+ *	returned to its previous value.
+ *
+ *	Note: we need to scan all the irq's even though we will
+ *	only return ISA irq numbers - just so that we reset them
+ *	all to a known state.
+ */
+unsigned int probe_irq_mask(unsigned long val)
+{
+	int i;
+	unsigned int mask;
+
+	mask = 0;
+	for (i = 0; i < NR_IRQS; i++) {
+		irq_desc_t *desc = irq_desc + i;
+		unsigned int status;
+
+		spin_lock_irq(&desc->lock);
+		status = desc->status;
+
+		if (status & IRQ_AUTODETECT) {
+			if (i < 16 && !(status & IRQ_WAITING))
+				mask |= 1 << i;
+
+			desc->status = status & ~IRQ_AUTODETECT;
+			desc->handler->shutdown(i);
+		}
+		spin_unlock_irq(&desc->lock);
+	}
+	up(&probe_sem);
+
+	return mask & val;
+}
+
+/*
+ * Return the one interrupt that triggered (this can
+ * handle any interrupt source).
+ */
+
+/**
+ *	probe_irq_off	- end an interrupt autodetect
+ *	@val: mask of potential interrupts (unused)
+ *
+ *	Scans the unused interrupt lines and returns the line which
+ *	appears to have triggered the interrupt. If no interrupt was
+ *	found then zero is returned. If more than one interrupt is
+ *	found then minus the first candidate is returned to indicate
+ *	their is doubt.
+ *
+ *	The interrupt probe logic state is returned to its previous
+ *	value.
+ *
+ *	BUGS: When used in a module (which arguably shouldnt happen)
+ *	nothing prevents two IRQ probe callers from overlapping. The
+ *	results of this are non-optimal.
+ */
+ 
+int probe_irq_off(unsigned long val)
+{
+	int i, irq_found, nr_irqs;
+
+	nr_irqs = 0;
+	irq_found = 0;
+	for (i = 0; i < NR_IRQS; i++) {
+		irq_desc_t *desc = irq_desc + i;
+		unsigned int status;
+
+		spin_lock_irq(&desc->lock);
+		status = desc->status;
+
+		if (status & IRQ_AUTODETECT) {
+			if (!(status & IRQ_WAITING)) {
+				if (!nr_irqs)
+					irq_found = i;
+				nr_irqs++;
+			}
+			desc->status = status & ~IRQ_AUTODETECT;
+			desc->handler->shutdown(i);
+		}
+		spin_unlock_irq(&desc->lock);
+	}
+	up(&probe_sem);
+
+	if (nr_irqs > 1)
+		irq_found = -irq_found;
+	return irq_found;
+}
+
+EXPORT_SYMBOL(probe_irq_off);
+
+/* this was setup_x86_irq but it seems pretty generic */
+int setup_irq(unsigned int irq, struct irqaction * new)
+{
+	int shared = 0;
+	unsigned long flags;
+	struct irqaction *old, **p;
+	irq_desc_t *desc = irq_desc + irq;
+
+	/*
+	 * Some drivers like serial.c use request_irq() heavily,
+	 * so we have to be careful not to interfere with a
+	 * running system.
+	 */
+	if (new->flags & SA_SAMPLE_RANDOM) {
+		/*
+		 * This function might sleep, we want to call it first,
+		 * outside of the atomic block.
+		 * Yes, this might clear the entropy pool if the wrong
+		 * driver is attempted to be loaded, without actually
+		 * installing a new handler, but is this really a problem,
+		 * only the sysadmin is able to do this.
+		 */
+		rand_initialize_irq(irq);
+	}
+
+	/*
+	 * The following block of code has to be executed atomically
+	 */
+	spin_lock_irqsave(&desc->lock,flags);
+	p = &desc->action;
+	if ((old = *p) != NULL) {
+		/* Can't share interrupts unless both agree to */
+		if (!(old->flags & new->flags & SA_SHIRQ)) {
+			spin_unlock_irqrestore(&desc->lock,flags);
+			return -EBUSY;
+		}
+
+		/* add new interrupt at end of irq queue */
+		do {
+			p = &old->next;
+			old = *p;
+		} while (old);
+		shared = 1;
+	}
+
+	*p = new;
+
+	if (!shared) {
+		desc->depth = 0;
+		desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS);
+		desc->handler->startup(irq);
+	}
+	spin_unlock_irqrestore(&desc->lock,flags);
+
+	/* register_irq_proc(irq); */
+	return 0;
+}
+
+/* Initialize irq handling for IRQs.
+   BASE_IRQ, BASE_IRQ+INTERVAL, ..., BASE_IRQ+NUM*INTERVAL
+   to IRQ_TYPE.  An IRQ_TYPE of 0 means to use a generic interrupt type.  */
+void __init
+init_irq_handlers (int base_irq, int num, int interval,
+		   struct hw_interrupt_type *irq_type)
+{
+	while (num-- > 0) {
+		irq_desc[base_irq].status  = IRQ_DISABLED;
+		irq_desc[base_irq].action  = NULL;
+		irq_desc[base_irq].depth   = 1;
+		irq_desc[base_irq].handler = irq_type;
+		base_irq += interval;
+	}
+}
+
+#if defined(CONFIG_PROC_FS) && defined(CONFIG_SYSCTL)
+void init_irq_proc(void)
+{
+}
+#endif /* CONFIG_PROC_FS && CONFIG_SYSCTL */
diff --git a/arch/v850/kernel/ma.c b/arch/v850/kernel/ma.c
new file mode 100644
index 0000000..b3dfbc5
--- /dev/null
+++ b/arch/v850/kernel/ma.c
@@ -0,0 +1,70 @@
+/*
+ * arch/v850/kernel/ma.c -- V850E/MA series of cpu chips
+ *
+ *  Copyright (C) 2001,02,03  NEC Electronics Corporation
+ *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/bootmem.h>
+#include <linux/irq.h>
+
+#include <asm/atomic.h>
+#include <asm/page.h>
+#include <asm/machdep.h>
+#include <asm/v850e_timer_d.h>
+
+#include "mach.h"
+
+void __init mach_sched_init (struct irqaction *timer_action)
+{
+	/* Start hardware timer.  */
+	v850e_timer_d_configure (0, HZ);
+	/* Install timer interrupt handler.  */
+	setup_irq (IRQ_INTCMD(0), timer_action);
+}
+
+static struct v850e_intc_irq_init irq_inits[] = {
+	{ "IRQ", 0, 		NUM_MACH_IRQS,	1, 7 },
+	{ "CMD", IRQ_INTCMD(0), IRQ_INTCMD_NUM,	1, 5 },
+	{ "DMA", IRQ_INTDMA(0), IRQ_INTDMA_NUM,	1, 2 },
+	{ "CSI", IRQ_INTCSI(0), IRQ_INTCSI_NUM,	4, 4 },
+	{ "SER", IRQ_INTSER(0), IRQ_INTSER_NUM,	4, 3 },
+	{ "SR",	 IRQ_INTSR(0),	IRQ_INTSR_NUM, 	4, 4 },
+	{ "ST",  IRQ_INTST(0), 	IRQ_INTST_NUM, 	4, 5 },
+	{ 0 }
+};
+#define NUM_IRQ_INITS ((sizeof irq_inits / sizeof irq_inits[0]) - 1)
+
+static struct hw_interrupt_type hw_itypes[NUM_IRQ_INITS];
+
+/* Initialize MA chip interrupts.  */
+void __init ma_init_irqs (void)
+{
+	v850e_intc_init_irq_types (irq_inits, hw_itypes);
+}
+
+/* Called before configuring an on-chip UART.  */
+void ma_uart_pre_configure (unsigned chan, unsigned cflags, unsigned baud)
+{
+	/* We only know about the first two UART channels (though
+	   specific chips may have more).  */
+	if (chan < 2) {
+		unsigned bits = 0x3 << (chan * 3);
+		/* Specify that the relevant pins on the chip should do
+		   serial I/O, not direct I/O.  */
+		MA_PORT4_PMC |= bits;
+		/* Specify that we're using the UART, not the CSI device.  */
+		MA_PORT4_PFC |= bits;
+	}
+}
diff --git a/arch/v850/kernel/mach.c b/arch/v850/kernel/mach.c
new file mode 100644
index 0000000..b9db278
--- /dev/null
+++ b/arch/v850/kernel/mach.c
@@ -0,0 +1,17 @@
+/*
+ * arch/v850/kernel/mach.c -- Defaults for some things defined by "mach.h"
+ *
+ *  Copyright (C) 2001  NEC Corporation
+ *  Copyright (C) 2001  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include "mach.h"
+
+/* Called with each timer tick, if non-zero.  */
+void (*mach_tick)(void) = 0;
diff --git a/arch/v850/kernel/mach.h b/arch/v850/kernel/mach.h
new file mode 100644
index 0000000..9e0e481
--- /dev/null
+++ b/arch/v850/kernel/mach.h
@@ -0,0 +1,56 @@
+/*
+ * arch/v850/kernel/mach.h -- Machine-dependent functions used by v850 port
+ *
+ *  Copyright (C) 2001,02,03  NEC Electronics Corporation
+ *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#ifndef __V850_MACH_H__
+#define __V850_MACH_H__
+
+#include <linux/kernel.h>
+#include <linux/time.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/fs.h>
+#include <linux/seq_file.h>
+
+#include <asm/ptrace.h>
+#include <asm/entry.h>
+#include <asm/clinkage.h>
+
+void mach_setup (char **cmdline);
+void mach_gettimeofday (struct timespec *tv);
+void mach_sched_init (struct irqaction *timer_action);
+void mach_get_physical_ram (unsigned long *ram_start, unsigned long *ram_len);
+void mach_init_irqs (void);
+
+/* If defined, is called very early in the kernel initialization.  The
+   stack pointer is valid, but very little has been initialized (e.g.,
+   bss is not zeroed yet) when this is called, so care must taken.  */
+void mach_early_init (void);
+
+/* If defined, called after the bootmem allocator has been initialized,
+   to allow the platform-dependent code to reserve any areas of RAM that
+   the kernel shouldn't touch.  */
+void mach_reserve_bootmem (void) __attribute__ ((__weak__));
+
+/* Called with each timer tick, if non-zero.  */
+extern void (*mach_tick) (void);
+
+/* The following establishes aliases for various mach_ functions to the
+   name by which the rest of the kernel calls them.  These statements
+   should only have an effect in the file that defines the actual functions. */
+#define MACH_ALIAS(to, from)						      \
+   asm (".global " macrology_stringify (C_SYMBOL_NAME (to)) ";"		      \
+	macrology_stringify (C_SYMBOL_NAME (to))			      \
+	" = " macrology_stringify (C_SYMBOL_NAME (from)))
+/* e.g.: MACH_ALIAS (kernel_name,	arch_spec_name);  */
+
+#endif /* __V850_MACH_H__ */
diff --git a/arch/v850/kernel/me2.c b/arch/v850/kernel/me2.c
new file mode 100644
index 0000000..6527c21
--- /dev/null
+++ b/arch/v850/kernel/me2.c
@@ -0,0 +1,74 @@
+/*
+ * arch/v850/kernel/me2.c -- V850E/ME2 chip-specific support
+ *
+ *  Copyright (C) 2003  NEC Corporation
+ *  Copyright (C) 2003  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/bootmem.h>
+#include <linux/irq.h>
+
+#include <asm/atomic.h>
+#include <asm/page.h>
+#include <asm/machdep.h>
+#include <asm/v850e_timer_d.h>
+
+#include "mach.h"
+
+void __init mach_sched_init (struct irqaction *timer_action)
+{
+	/* Start hardware timer.  */
+	v850e_timer_d_configure (0, HZ);
+	/* Install timer interrupt handler.  */
+	setup_irq (IRQ_INTCMD(0), timer_action);
+}
+
+static struct v850e_intc_irq_init irq_inits[] = {
+	{ "IRQ",    0,                NUM_CPU_IRQS,      1, 7 },
+	{ "INTP",   IRQ_INTP(0),      IRQ_INTP_NUM,      1, 5 },
+	{ "CMD",    IRQ_INTCMD(0),    IRQ_INTCMD_NUM,    1, 3 },
+	{ "UBTIRE", IRQ_INTUBTIRE(0), IRQ_INTUBTIRE_NUM, 5, 4 },
+	{ "UBTIR",  IRQ_INTUBTIR(0),  IRQ_INTUBTIR_NUM,  5, 4 },
+	{ "UBTIT",  IRQ_INTUBTIT(0),  IRQ_INTUBTIT_NUM,  5, 4 },
+	{ "UBTIF",  IRQ_INTUBTIF(0),  IRQ_INTUBTIF_NUM,  5, 4 },
+	{ "UBTITO", IRQ_INTUBTITO(0), IRQ_INTUBTITO_NUM, 5, 4 },
+	{ 0 }
+};
+#define NUM_IRQ_INITS ((sizeof irq_inits / sizeof irq_inits[0]) - 1)
+
+static struct hw_interrupt_type hw_itypes[NUM_IRQ_INITS];
+
+/* Initialize V850E/ME2 chip interrupts.  */
+void __init me2_init_irqs (void)
+{
+	v850e_intc_init_irq_types (irq_inits, hw_itypes);
+}
+
+/* Called before configuring an on-chip UART.  */
+void me2_uart_pre_configure (unsigned chan, unsigned cflags, unsigned baud)
+{
+	if (chan == 0) {
+		/* Specify that the relevent pins on the chip should do
+		   serial I/O, not direct I/O.  */
+		ME2_PORT1_PMC |= 0xC;
+		/* Specify that we're using the UART, not the CSI device. */
+		ME2_PORT1_PFC |= 0xC;
+	} else if (chan == 1) {
+		/* Specify that the relevent pins on the chip should do
+		   serial I/O, not direct I/O.  */
+		ME2_PORT2_PMC |= 0x6;
+		/* Specify that we're using the UART, not the CSI device. */
+		ME2_PORT2_PFC |= 0x6;
+	}
+}
diff --git a/arch/v850/kernel/memcons.c b/arch/v850/kernel/memcons.c
new file mode 100644
index 0000000..491614c
--- /dev/null
+++ b/arch/v850/kernel/memcons.c
@@ -0,0 +1,135 @@
+/*
+ * arch/v850/kernel/memcons.c -- Console I/O to a memory buffer
+ *
+ *  Copyright (C) 2001,02  NEC Corporation
+ *  Copyright (C) 2001,02  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/init.h>
+
+/* If this device is enabled, the linker map should define start and
+   end points for its buffer. */
+extern char memcons_output[], memcons_output_end;
+
+/* Current offset into the buffer.  */
+static unsigned long memcons_offs = 0;
+
+/* Spinlock protecting memcons_offs.  */
+static DEFINE_SPINLOCK(memcons_lock);
+
+
+static size_t write (const char *buf, size_t len)
+{
+	int flags;
+	char *point;
+
+	spin_lock_irqsave (memcons_lock, flags);
+
+	point = memcons_output + memcons_offs;
+	if (point + len >= &memcons_output_end) {
+		len = &memcons_output_end - point;
+		memcons_offs = 0;
+	} else
+		memcons_offs += len;
+
+	spin_unlock_irqrestore (memcons_lock, flags);
+
+	memcpy (point, buf, len);
+
+	return len;
+}
+
+
+/*  Low-level console. */
+
+static void memcons_write (struct console *co, const char *buf, unsigned len)
+{
+	while (len > 0)
+		len -= write (buf, len);
+}
+
+static struct tty_driver *tty_driver;
+
+static struct tty_driver *memcons_device (struct console *co, int *index)
+{
+	*index = co->index;
+	return tty_driver;
+}
+
+static struct console memcons =
+{
+    .name	= "memcons",
+    .write	= memcons_write,
+    .device	= memcons_device,
+    .flags	= CON_PRINTBUFFER,
+    .index	= -1,
+};
+
+void memcons_setup (void)
+{
+	register_console (&memcons);
+	printk (KERN_INFO "Console: static memory buffer (memcons)\n");
+}
+
+/* Higher level TTY interface.  */
+
+int memcons_tty_open (struct tty_struct *tty, struct file *filp)
+{
+	return 0;
+}
+
+int memcons_tty_write (struct tty_struct *tty, const unsigned char *buf, int len)
+{
+	return write (buf, len);
+}
+
+int memcons_tty_write_room (struct tty_struct *tty)
+{
+	return &memcons_output_end - (memcons_output + memcons_offs);
+}
+
+int memcons_tty_chars_in_buffer (struct tty_struct *tty)
+{
+	/* We have no buffer.  */
+	return 0;
+}
+
+static struct tty_operations ops = {
+	.open = memcons_tty_open,
+	.write = memcons_tty_write,
+	.write_room = memcons_tty_write_room,
+	.chars_in_buffer = memcons_tty_chars_in_buffer,
+};
+
+int __init memcons_tty_init (void)
+{
+	int err;
+	struct tty_driver *driver = alloc_tty_driver(1);
+	if (!driver)
+		return -ENOMEM;
+
+	driver->name = "memcons";
+	driver->major = TTY_MAJOR;
+	driver->minor_start = 64;
+	driver->type = TTY_DRIVER_TYPE_SYSCONS;
+	driver->init_termios = tty_std_termios;
+	tty_set_operations(driver, &ops);
+	err = tty_register_driver(driver);
+	if (err) {
+		put_tty_driver(driver);
+		return err;
+	}
+	tty_driver = driver;
+	return 0;
+}
+__initcall (memcons_tty_init);
diff --git a/arch/v850/kernel/module.c b/arch/v850/kernel/module.c
new file mode 100644
index 0000000..64aeb3e
--- /dev/null
+++ b/arch/v850/kernel/module.c
@@ -0,0 +1,237 @@
+/*
+ * arch/v850/kernel/module.c -- Architecture-specific module functions
+ *
+ *  Copyright (C) 2002,03  NEC Electronics Corporation
+ *  Copyright (C) 2002,03  Miles Bader <miles@gnu.org>
+ *  Copyright (C) 2001,03  Rusty Russell
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ *
+ * Derived in part from arch/ppc/kernel/module.c
+ */
+
+#include <linux/kernel.h>
+#include <linux/vmalloc.h>
+#include <linux/moduleloader.h>
+#include <linux/elf.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(fmt , ...)
+#endif
+
+void *module_alloc (unsigned long size)
+{
+	return size == 0 ? 0 : vmalloc (size);
+}
+
+void module_free (struct module *mod, void *module_region)
+{
+	vfree (module_region);
+	/* FIXME: If module_region == mod->init_region, trim exception
+           table entries. */
+}
+
+int module_finalize (const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
+		     struct module *mod)
+{
+	return 0;
+}
+
+/* Count how many different relocations (different symbol, different
+   addend) */
+static unsigned int count_relocs(const Elf32_Rela *rela, unsigned int num)
+{
+	unsigned int i, j, ret = 0;
+
+	/* Sure, this is order(n^2), but it's usually short, and not
+           time critical */
+	for (i = 0; i < num; i++) {
+		for (j = 0; j < i; j++) {
+			/* If this addend appeared before, it's
+                           already been counted */
+			if (ELF32_R_SYM(rela[i].r_info)
+			    == ELF32_R_SYM(rela[j].r_info)
+			    && rela[i].r_addend == rela[j].r_addend)
+				break;
+		}
+		if (j == i) ret++;
+	}
+	return ret;
+}
+
+/* Get the potential trampolines size required of the init and
+   non-init sections */
+static unsigned long get_plt_size(const Elf32_Ehdr *hdr,
+				  const Elf32_Shdr *sechdrs,
+				  const char *secstrings,
+				  int is_init)
+{
+	unsigned long ret = 0;
+	unsigned i;
+
+	/* Everything marked ALLOC (this includes the exported
+           symbols) */
+	for (i = 1; i < hdr->e_shnum; i++) {
+		/* If it's called *.init*, and we're not init, we're
+                   not interested */
+		if ((strstr(secstrings + sechdrs[i].sh_name, ".init") != 0)
+		    != is_init)
+			continue;
+
+		if (sechdrs[i].sh_type == SHT_RELA) {
+			DEBUGP("Found relocations in section %u\n", i);
+			DEBUGP("Ptr: %p.  Number: %u\n",
+			       (void *)hdr + sechdrs[i].sh_offset,
+			       sechdrs[i].sh_size / sizeof(Elf32_Rela));
+			ret += count_relocs((void *)hdr
+					     + sechdrs[i].sh_offset,
+					     sechdrs[i].sh_size
+					     / sizeof(Elf32_Rela))
+				* sizeof(struct v850_plt_entry);
+		}
+	}
+
+	return ret;
+}
+
+int module_frob_arch_sections(Elf32_Ehdr *hdr,
+			      Elf32_Shdr *sechdrs,
+			      char *secstrings,
+			      struct module *me)
+{
+	unsigned int i;
+
+	/* Find .plt and .pltinit sections */
+	for (i = 0; i < hdr->e_shnum; i++) {
+		if (strcmp(secstrings + sechdrs[i].sh_name, ".init.plt") == 0)
+			me->arch.init_plt_section = i;
+		else if (strcmp(secstrings + sechdrs[i].sh_name, ".plt") == 0)
+			me->arch.core_plt_section = i;
+	}
+	if (!me->arch.core_plt_section || !me->arch.init_plt_section) {
+		printk("Module doesn't contain .plt or .plt.init sections.\n");
+		return -ENOEXEC;
+	}
+
+	/* Override their sizes */
+	sechdrs[me->arch.core_plt_section].sh_size
+		= get_plt_size(hdr, sechdrs, secstrings, 0);
+	sechdrs[me->arch.init_plt_section].sh_size
+		= get_plt_size(hdr, sechdrs, secstrings, 1);
+	return 0;
+}
+
+int apply_relocate (Elf32_Shdr *sechdrs, const char *strtab,
+		    unsigned int symindex, unsigned int relsec,
+		    struct module *mod)
+{
+	printk ("Barf\n");
+	return -ENOEXEC;
+}
+
+/* Set up a trampoline in the PLT to bounce us to the distant function */
+static uint32_t do_plt_call (void *location, Elf32_Addr val,
+			     Elf32_Shdr *sechdrs, struct module *mod)
+{
+	struct v850_plt_entry *entry;
+	/* Instructions used to do the indirect jump.  */
+	uint32_t tramp[2];
+
+	/* We have to trash a register, so we assume that any control
+	   transfer more than 21-bits away must be a function call
+	   (so we can use a call-clobbered register).  */
+	tramp[0] = 0x0621 + ((val & 0xffff) << 16);   /* mov sym, r1 ... */
+	tramp[1] = ((val >> 16) & 0xffff) + 0x610000; /* ...; jmp r1 */
+
+	/* Init, or core PLT? */
+	if (location >= mod->module_core
+	    && location < mod->module_core + mod->core_size)
+		entry = (void *)sechdrs[mod->arch.core_plt_section].sh_addr;
+	else
+		entry = (void *)sechdrs[mod->arch.init_plt_section].sh_addr;
+
+	/* Find this entry, or if that fails, the next avail. entry */
+	while (entry->tramp[0])
+		if (entry->tramp[0] == tramp[0] && entry->tramp[1] == tramp[1])
+			return (uint32_t)entry;
+		else
+			entry++;
+
+	entry->tramp[0] = tramp[0];
+	entry->tramp[1] = tramp[1];
+
+	return (uint32_t)entry;
+}
+
+int apply_relocate_add (Elf32_Shdr *sechdrs, const char *strtab,
+			unsigned int symindex, unsigned int relsec,
+			struct module *mod)
+{
+	unsigned int i;
+	Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr;
+
+	DEBUGP ("Applying relocate section %u to %u\n", relsec,
+		sechdrs[relsec].sh_info);
+
+	for (i = 0; i < sechdrs[relsec].sh_size / sizeof (*rela); i++) {
+		/* This is where to make the change */
+		uint32_t *loc
+			= ((void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+			   + rela[i].r_offset);
+		/* This is the symbol it is referring to.  Note that all
+		   undefined symbols have been resolved.  */
+		Elf32_Sym *sym
+			= ((Elf32_Sym *)sechdrs[symindex].sh_addr
+			   + ELF32_R_SYM (rela[i].r_info));
+		uint32_t val = sym->st_value + rela[i].r_addend;
+
+		switch (ELF32_R_TYPE (rela[i].r_info)) {
+		case R_V850_32:
+			/* We write two shorts instead of a long because even
+			   32-bit insns only need half-word alignment, but
+			   32-bit data writes need to be long-word aligned.  */
+			val += ((uint16_t *)loc)[0];
+			val += ((uint16_t *)loc)[1] << 16;
+			((uint16_t *)loc)[0] = val & 0xffff;
+			((uint16_t *)loc)[1] = (val >> 16) & 0xffff;
+			break;
+
+		case R_V850_22_PCREL:
+			/* Maybe jump indirectly via a PLT table entry.  */
+			if ((int32_t)(val - (uint32_t)loc) > 0x1fffff
+			    || (int32_t)(val - (uint32_t)loc) < -0x200000)
+				val = do_plt_call (loc, val, sechdrs, mod);
+
+			val -= (uint32_t)loc;
+
+			/* We write two shorts instead of a long because
+			   even 32-bit insns only need half-word alignment,
+			   but 32-bit data writes need to be long-word
+			   aligned.  */
+			((uint16_t *)loc)[0] =
+				(*(uint16_t *)loc & 0xffc0) /* opcode + reg */
+				| ((val >> 16) & 0xffc03f); /* offs high */
+			((uint16_t *)loc)[1] =
+				(val & 0xffff);		    /* offs low */
+			break;
+
+		default:
+			printk (KERN_ERR "module %s: Unknown reloc: %u\n",
+				mod->name, ELF32_R_TYPE (rela[i].r_info));
+			return -ENOEXEC;
+		}
+	}
+
+	return 0;
+}
+
+void
+module_arch_cleanup(struct module *mod)
+{
+}
diff --git a/arch/v850/kernel/process.c b/arch/v850/kernel/process.c
new file mode 100644
index 0000000..9c708c3
--- /dev/null
+++ b/arch/v850/kernel/process.c
@@ -0,0 +1,236 @@
+/*
+ * arch/v850/kernel/process.c -- Arch-dependent process handling
+ *
+ *  Copyright (C) 2001,02,03  NEC Electronics Corporation
+ *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/reboot.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+
+extern void ret_from_fork (void);
+
+
+/* The idle loop.  */
+void default_idle (void)
+{
+	while (1) {
+		while (! need_resched ())
+			asm ("halt; nop; nop; nop; nop; nop" ::: "cc");
+		schedule ();
+	}
+}
+
+void (*idle)(void) = default_idle;
+
+/*
+ * The idle thread. There's no useful work to be
+ * done, so just try to conserve power and have a
+ * low exit latency (ie sit in a loop waiting for
+ * somebody to say that they'd like to reschedule)
+ */
+void cpu_idle (void)
+{
+	/* endless idle loop with no priority at all */
+	(*idle) ();
+}
+
+/*
+ * This is the mechanism for creating a new kernel thread.
+ *
+ * NOTE! Only a kernel-only process (ie the swapper or direct descendants who
+ * haven't done an "execve()") should use this: it will work within a system
+ * call from a "real" process, but the process memory space will not be free'd
+ * until both the parent and the child have exited.
+ */
+int kernel_thread (int (*fn)(void *), void *arg, unsigned long flags)
+{
+	register mm_segment_t fs = get_fs ();
+	register unsigned long syscall asm (SYSCALL_NUM);
+	register unsigned long arg0 asm (SYSCALL_ARG0);
+	register unsigned long ret asm (SYSCALL_RET);
+
+	set_fs (KERNEL_DS);
+
+	/* Clone this thread.  Note that we don't pass the clone syscall's
+	   second argument -- it's ignored for calls from kernel mode (the
+	   child's SP is always set to the top of the kernel stack).  */
+	arg0 = flags | CLONE_VM;
+	syscall = __NR_clone;
+	asm volatile ("trap " SYSCALL_SHORT_TRAP
+		      : "=r" (ret), "=r" (syscall)
+		      : "1" (syscall), "r" (arg0)
+		      : SYSCALL_SHORT_CLOBBERS);
+
+	if (ret == 0) {
+		/* In child thread, call FN and exit.  */
+		arg0 = (*fn) (arg);
+		syscall = __NR_exit;
+		asm volatile ("trap " SYSCALL_SHORT_TRAP
+			      : "=r" (ret), "=r" (syscall)
+			      : "1" (syscall), "r" (arg0)
+			      : SYSCALL_SHORT_CLOBBERS);
+	}
+
+	/* In parent.  */
+	set_fs (fs);
+
+	return ret;
+}
+
+void flush_thread (void)
+{
+	set_fs (USER_DS);
+}
+
+int copy_thread (int nr, unsigned long clone_flags,
+		 unsigned long stack_start, unsigned long stack_size,
+		 struct task_struct *p, struct pt_regs *regs)
+{
+	/* Start pushing stuff from the top of the child's kernel stack.  */
+	unsigned long orig_ksp = (unsigned long)p->thread_info + THREAD_SIZE;
+	unsigned long ksp = orig_ksp;
+	/* We push two `state save' stack fames (see entry.S) on the new
+	   kernel stack:
+	     1) The innermost one is what switch_thread would have
+	        pushed, and is used when we context switch to the child
+		thread for the first time.  It's set up to return to
+		ret_from_fork in entry.S.
+	     2) The outermost one (nearest the top) is what a syscall
+	        trap would have pushed, and is set up to return to the
+		same location as the parent thread, but with a return
+		value of 0. */
+	struct pt_regs *child_switch_regs, *child_trap_regs;
+
+	/* Trap frame.  */
+	ksp -= STATE_SAVE_SIZE;
+	child_trap_regs = (struct pt_regs *)(ksp + STATE_SAVE_PT_OFFSET);
+	/* Switch frame.  */
+	ksp -= STATE_SAVE_SIZE;
+	child_switch_regs = (struct pt_regs *)(ksp + STATE_SAVE_PT_OFFSET);
+
+	/* First copy parent's register state to child.  */
+	*child_switch_regs = *regs;
+	*child_trap_regs = *regs;
+
+	/* switch_thread returns to the restored value of the lp
+	   register (r31), so we make that the place where we want to
+	   jump when the child thread begins running.  */
+	child_switch_regs->gpr[GPR_LP] = (v850_reg_t)ret_from_fork;
+
+	if (regs->kernel_mode)
+		/* Since we're returning to kernel-mode, make sure the child's
+		   stored kernel stack pointer agrees with what the actual
+		   stack pointer will be at that point (the trap return code
+		   always restores the SP, even when returning to
+		   kernel-mode).  */
+		child_trap_regs->gpr[GPR_SP] = orig_ksp;
+	else
+		/* Set the child's user-mode stack-pointer (the name
+		   `stack_start' is a misnomer, it's just the initial SP
+		   value).  */
+		child_trap_regs->gpr[GPR_SP] = stack_start;
+
+	/* Thread state for the child (everything else is on the stack).  */
+	p->thread.ksp = ksp;
+
+	return 0;
+}
+
+/*
+ * fill in the user structure for a core dump..
+ */
+void dump_thread (struct pt_regs *regs, struct user *dump)
+{
+#if 0  /* Later.  XXX */
+	dump->magic = CMAGIC;
+	dump->start_code = 0;
+	dump->start_stack = regs->gpr[GPR_SP];
+	dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT;
+	dump->u_dsize = ((unsigned long) (current->mm->brk +
+					  (PAGE_SIZE-1))) >> PAGE_SHIFT;
+	dump->u_dsize -= dump->u_tsize;
+	dump->u_ssize = 0;
+
+	if (dump->start_stack < TASK_SIZE)
+		dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT;
+
+	dump->u_ar0 = (struct user_regs_struct *)((int)&dump->regs - (int)dump);
+	dump->regs = *regs;
+	dump->u_fpvalid = 0;
+#endif
+}
+
+/*
+ * sys_execve() executes a new program.
+ */
+int sys_execve (char *name, char **argv, char **envp, struct pt_regs *regs)
+{
+	char *filename = getname (name);
+	int error = PTR_ERR (filename);
+
+	if (! IS_ERR (filename)) {
+		error = do_execve (filename, argv, envp, regs);
+		putname (filename);
+	}
+
+	return error;
+}
+
+
+/*
+ * These bracket the sleeping functions..
+ */
+#define first_sched	((unsigned long)__sched_text_start)
+#define last_sched	((unsigned long)__sched_text_end)
+
+unsigned long get_wchan (struct task_struct *p)
+{
+#if 0  /* Barf.  Figure out the stack-layout later.  XXX  */
+	unsigned long fp, pc;
+	int count = 0;
+
+	if (!p || p == current || p->state == TASK_RUNNING)
+		return 0;
+
+	pc = thread_saved_pc (p);
+
+	/* This quite disgusting function walks up the stack, following
+	   saved return address, until it something that's out of bounds
+	   (as defined by `first_sched' and `last_sched').  It then
+	   returns the last PC that was in-bounds.  */
+	do {
+		if (fp < stack_page + sizeof (struct task_struct) ||
+		    fp >= 8184+stack_page)
+			return 0;
+		pc = ((unsigned long *)fp)[1];
+		if (pc < first_sched || pc >= last_sched)
+			return pc;
+		fp = *(unsigned long *) fp;
+	} while (count++ < 16);
+#endif
+
+	return 0;
+}
diff --git a/arch/v850/kernel/procfs.c b/arch/v850/kernel/procfs.c
new file mode 100644
index 0000000..e6f9d06
--- /dev/null
+++ b/arch/v850/kernel/procfs.c
@@ -0,0 +1,67 @@
+/*
+ * arch/v850/kernel/procfs.c -- Introspection functions for /proc filesystem
+ *
+ *  Copyright (C) 2001,02  NEC Corporation
+ *  Copyright (C) 2001,02  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include "mach.h"
+
+static int cpuinfo_print (struct seq_file *m, void *v)
+{
+	extern unsigned long loops_per_jiffy;
+	
+	seq_printf (m, "CPU-Family:	v850\nCPU-Arch:	%s\n", CPU_ARCH);
+
+#ifdef CPU_MODEL_LONG
+	seq_printf (m, "CPU-Model:	%s (%s)\n", CPU_MODEL, CPU_MODEL_LONG);
+#else
+	seq_printf (m, "CPU-Model:	%s\n", CPU_MODEL);
+#endif
+
+#ifdef CPU_CLOCK_FREQ
+	seq_printf (m, "CPU-Clock:	%ld (%ld MHz)\n",
+		    (long)CPU_CLOCK_FREQ,
+		    (long)CPU_CLOCK_FREQ / 1000000);
+#endif
+
+	seq_printf (m, "BogoMips:	%lu.%02lu\n",
+		    loops_per_jiffy/(500000/HZ),
+		    (loops_per_jiffy/(5000/HZ)) % 100);
+
+#ifdef PLATFORM_LONG
+	seq_printf (m, "Platform:	%s (%s)\n", PLATFORM, PLATFORM_LONG);
+#elif defined (PLATFORM)
+	seq_printf (m, "Platform:	%s\n", PLATFORM);
+#endif
+
+	return 0;
+}
+
+static void *cpuinfo_start (struct seq_file *m, loff_t *pos)
+{
+	return *pos < NR_CPUS ? ((void *) 0x12345678) : NULL;
+}
+
+static void *cpuinfo_next (struct seq_file *m, void *v, loff_t *pos)
+{
+	++*pos;
+	return cpuinfo_start (m, pos);
+}
+
+static void cpuinfo_stop (struct seq_file *m, void *v)
+{
+}
+
+struct seq_operations cpuinfo_op = {
+	.start	= cpuinfo_start,
+	.next	= cpuinfo_next,
+	.stop	= cpuinfo_stop,
+	.show	= cpuinfo_print
+};
diff --git a/arch/v850/kernel/ptrace.c b/arch/v850/kernel/ptrace.c
new file mode 100644
index 0000000..8fa7807
--- /dev/null
+++ b/arch/v850/kernel/ptrace.c
@@ -0,0 +1,282 @@
+/*
+ * arch/v850/kernel/ptrace.c -- `ptrace' system call
+ *
+ *  Copyright (C) 2002,03,04  NEC Electronics Corporation
+ *  Copyright (C) 2002,03,04  Miles Bader <miles@gnu.org>
+ *
+ * Derived from arch/mips/kernel/ptrace.c:
+ *
+ *  Copyright (C) 1992 Ross Biro
+ *  Copyright (C) Linus Torvalds
+ *  Copyright (C) 1994, 95, 96, 97, 98, 2000 Ralf Baechle
+ *  Copyright (C) 1996 David S. Miller
+ *  Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
+ *  Copyright (C) 1999 MIPS Technologies, Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file COPYING in the main directory of this
+ * archive for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/ptrace.h>
+
+#include <asm/errno.h>
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+
+/* Returns the address where the register at REG_OFFS in P is stashed away.  */
+static v850_reg_t *reg_save_addr (unsigned reg_offs, struct task_struct *t)
+{
+	struct pt_regs *regs;
+
+	/* Three basic cases:
+
+	   (1) A register normally saved before calling the scheduler, is
+	       available in the kernel entry pt_regs structure at the top
+	       of the kernel stack.  The kernel trap/irq exit path takes
+	       care to save/restore almost all registers for ptrace'd
+	       processes.
+
+	   (2) A call-clobbered register, where the process P entered the
+	       kernel via [syscall] trap, is not stored anywhere; that's
+	       OK, because such registers are not expected to be preserved
+	       when the trap returns anyway (so we don't actually bother to
+	       test for this case).
+
+	   (3) A few registers not used at all by the kernel, and so
+	       normally never saved except by context-switches, are in the
+	       context switch state.  */
+
+	if (reg_offs == PT_CTPC || reg_offs == PT_CTPSW || reg_offs == PT_CTBP)
+		/* Register saved during context switch.  */
+		regs = thread_saved_regs (t);
+	else
+		/* Register saved during kernel entry (or not available).  */
+		regs = task_regs (t);
+
+	return (v850_reg_t *)((char *)regs + reg_offs);
+}
+
+/* Set the bits SET and clear the bits CLEAR in the v850e DIR
+   (`debug information register').  Returns the new value of DIR.  */
+static inline v850_reg_t set_dir (v850_reg_t set, v850_reg_t clear)
+{
+	register v850_reg_t rval asm ("r10");
+	register v850_reg_t arg0 asm ("r6") = set;
+	register v850_reg_t arg1 asm ("r7") = clear;
+
+	/* The dbtrap handler has exactly this functionality when called
+	   from kernel mode.  0xf840 is a `dbtrap' insn.  */
+	asm (".short 0xf840" : "=r" (rval) : "r" (arg0), "r" (arg1));
+
+	return rval;
+}
+
+/* Makes sure hardware single-stepping is (globally) enabled.
+   Returns true if successful.  */
+static inline int enable_single_stepping (void)
+{
+	static int enabled = 0;	/* Remember whether we already did it.  */
+	if (! enabled) {
+		/* Turn on the SE (`single-step enable') bit, 0x100, in the
+		   DIR (`debug information register').  This may fail if a
+		   processor doesn't support it or something.  We also try
+		   to clear bit 0x40 (`INI'), which is necessary to use the
+		   debug stuff on the v850e2; on the v850e, clearing 0x40
+		   shouldn't cause any problem.  */
+		v850_reg_t dir = set_dir (0x100, 0x40);
+		/* Make sure it really got set.  */
+		if (dir & 0x100)
+			enabled = 1;
+	}
+	return enabled;
+}
+
+/* Try to set CHILD's single-step flag to VAL.  Returns true if successful.  */
+static int set_single_step (struct task_struct *t, int val)
+{
+	v850_reg_t *psw_addr = reg_save_addr(PT_PSW, t);
+	if (val) {
+		/* Make sure single-stepping is enabled.  */
+		if (! enable_single_stepping ())
+			return 0;
+		/* Set T's single-step flag.  */
+		*psw_addr |= 0x800;
+	} else
+		*psw_addr &= ~0x800;
+	return 1;
+}
+
+int sys_ptrace(long request, long pid, long addr, long data)
+{
+	struct task_struct *child;
+	int rval;
+
+	lock_kernel();
+
+	if (request == PTRACE_TRACEME) {
+		/* are we already being traced? */
+		if (current->ptrace & PT_PTRACED) {
+			rval = -EPERM;
+			goto out;
+		}
+		/* set the ptrace bit in the process flags. */
+		current->ptrace |= PT_PTRACED;
+		rval = 0;
+		goto out;
+	}
+	rval = -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;
+
+	rval = -EPERM;
+	if (pid == 1)		/* you may not mess with init */
+		goto out_tsk;
+
+	if (request == PTRACE_ATTACH) {
+		rval = ptrace_attach(child);
+		goto out_tsk;
+	}
+	rval = ptrace_check_attach(child, request == PTRACE_KILL);
+	if (rval < 0)
+		goto out_tsk;
+
+	switch (request) {
+		unsigned long val, copied;
+
+	case PTRACE_PEEKTEXT: /* read word at location addr. */
+	case PTRACE_PEEKDATA:
+		copied = access_process_vm(child, addr, &val, sizeof(val), 0);
+		rval = -EIO;
+		if (copied != sizeof(val))
+			break;
+		rval = put_user(val, (unsigned long *)data);
+		goto out;
+
+	case PTRACE_POKETEXT: /* write the word at location addr. */
+	case PTRACE_POKEDATA:
+		rval = 0;
+		if (access_process_vm(child, addr, &data, sizeof(data), 1)
+		    == sizeof(data))
+			break;
+		rval = -EIO;
+		goto out;
+
+	/* Read/write the word at location ADDR in the registers.  */
+	case PTRACE_PEEKUSR:
+	case PTRACE_POKEUSR:
+		rval = 0;
+		if (addr >= PT_SIZE && request == PTRACE_PEEKUSR) {
+			/* Special requests that don't actually correspond
+			   to offsets in struct pt_regs.  */
+			if (addr == PT_TEXT_ADDR)
+				val = child->mm->start_code;
+			else if (addr == PT_DATA_ADDR)
+				val = child->mm->start_data;
+			else if (addr == PT_TEXT_LEN)
+				val = child->mm->end_code
+					- child->mm->start_code;
+			else
+				rval = -EIO;
+		} else if (addr >= 0 && addr < PT_SIZE && (addr & 0x3) == 0) {
+			v850_reg_t *reg_addr = reg_save_addr(addr, child);
+			if (request == PTRACE_PEEKUSR)
+				val = *reg_addr;
+			else
+				*reg_addr = data;
+		} else
+			rval = -EIO;
+
+		if (rval == 0 && request == PTRACE_PEEKUSR)
+			rval = put_user (val, (unsigned long *)data);
+		goto out;
+
+	/* Continue and stop at next (return from) syscall */
+	case PTRACE_SYSCALL:
+	/* Restart after a signal.  */
+	case PTRACE_CONT:
+	/* Execute a single instruction. */
+	case PTRACE_SINGLESTEP:
+		rval = -EIO;
+		if ((unsigned long) data > _NSIG)
+			break;
+
+		/* Turn CHILD's single-step flag on or off.  */
+		if (! set_single_step (child, request == PTRACE_SINGLESTEP))
+			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);
+		rval = 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:
+		rval = 0;
+		if (child->exit_state == EXIT_ZOMBIE)	/* already dead */
+			break;
+		child->exit_code = SIGKILL;
+		wake_up_process(child);
+		break;
+
+	case PTRACE_DETACH: /* detach a process that was attached. */
+		set_single_step (child, 0);  /* Clear single-step flag */
+		rval = ptrace_detach(child, data);
+		break;
+
+	default:
+		rval = -EIO;
+		goto out;
+	}
+
+out_tsk:
+	put_task_struct(child);
+out:
+	unlock_kernel();
+	return rval;
+}
+
+asmlinkage void syscall_trace(void)
+{
+	if (!test_thread_flag(TIF_SYSCALL_TRACE))
+		return;
+	if (!(current->ptrace & PT_PTRACED))
+		return;
+	/* The 0x80 provides a way for the tracing parent to distinguish
+	   between a syscall stop and SIGTRAP delivery */
+	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+				 ? 0x80 : 0));
+	/*
+	 * this isn't the same as continuing with a signal, but it will do
+	 * for normal use.  strace only continues with a signal if the
+	 * stopping signal is not SIGTRAP.  -brl
+	 */
+	if (current->exit_code) {
+		send_sig(current->exit_code, current, 1);
+		current->exit_code = 0;
+	}
+}
+
+void ptrace_disable (struct task_struct *child)
+{
+	/* nothing to do */
+}
diff --git a/arch/v850/kernel/rte_cb.c b/arch/v850/kernel/rte_cb.c
new file mode 100644
index 0000000..7ba397f
--- /dev/null
+++ b/arch/v850/kernel/rte_cb.c
@@ -0,0 +1,200 @@
+/*
+ * include/asm-v850/rte_cb.c -- Midas lab RTE-CB series of evaluation boards
+ *
+ *  Copyright (C) 2001,02,03  NEC Electronics Corporation
+ *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+
+#include <asm/machdep.h>
+#include <asm/v850e_uart.h>
+
+#include "mach.h"
+
+static void led_tick (void);
+
+/* LED access routines.  */
+extern unsigned read_leds (int pos, char *buf, int len);
+extern unsigned write_leds (int pos, const char *buf, int len);
+
+#ifdef CONFIG_RTE_CB_MULTI
+extern void multi_init (void);
+#endif
+
+
+void __init rte_cb_early_init (void)
+{
+	v850e_intc_disable_irqs ();
+
+#ifdef CONFIG_RTE_CB_MULTI
+	multi_init ();
+#endif
+}
+
+void __init mach_setup (char **cmdline)
+{
+#ifdef CONFIG_RTE_MB_A_PCI
+	/* Probe for Mother-A, and print a message if we find it.  */
+	*(volatile unsigned long *)MB_A_SRAM_ADDR = 0xDEADBEEF;
+	if (*(volatile unsigned long *)MB_A_SRAM_ADDR == 0xDEADBEEF) {
+		*(volatile unsigned long *)MB_A_SRAM_ADDR = 0x12345678;
+		if (*(volatile unsigned long *)MB_A_SRAM_ADDR == 0x12345678)
+			printk (KERN_INFO
+				"          NEC SolutionGear/Midas lab"
+				" RTE-MOTHER-A motherboard\n");
+	}
+#endif /* CONFIG_RTE_MB_A_PCI */
+
+	mach_tick = led_tick;
+}
+
+void machine_restart (char *__unused)
+{
+#ifdef CONFIG_RESET_GUARD
+	disable_reset_guard ();
+#endif
+	asm ("jmp r0"); /* Jump to the reset vector.  */
+}
+
+EXPORT_SYMBOL(machine_restart);
+
+/* This says `HALt.' in LEDese.  */
+static unsigned char halt_leds_msg[] = { 0x76, 0x77, 0x38, 0xF8 };
+
+void machine_halt (void)
+{
+#ifdef CONFIG_RESET_GUARD
+	disable_reset_guard ();
+#endif
+
+	/* Ignore all interrupts.  */
+	local_irq_disable ();
+
+	/* Write a little message.  */
+	write_leds (0, halt_leds_msg, sizeof halt_leds_msg);
+
+	/* Really halt.  */
+	for (;;)
+		asm ("halt; nop; nop; nop; nop; nop");
+}
+
+EXPORT_SYMBOL(machine_halt);
+
+void machine_power_off (void)
+{
+	machine_halt ();
+}
+
+EXPORT_SYMBOL(machine_power_off);
+
+
+/* Animated LED display for timer tick.  */
+
+#define TICK_UPD_FREQ	6
+static int tick_frames[][10] = {
+	{ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, -1 },
+	{ 0x63, 0x5c, -1 },
+	{ 0x5c, 0x00, -1 },
+	{ 0x63, 0x00, -1 },
+	{ -1 }
+};
+
+static void led_tick ()
+{
+	static unsigned counter = 0;
+	
+	if (++counter == (HZ / TICK_UPD_FREQ)) {
+		/* Which frame we're currently displaying for each digit.  */
+		static unsigned frame_nums[LED_NUM_DIGITS] = { 0 };
+		/* Display image.  */
+		static unsigned char image[LED_NUM_DIGITS] = { 0 };
+		unsigned char prev_image[LED_NUM_DIGITS];
+		int write_to_leds = 1; /* true if we should actually display */
+		int digit;
+
+		/* We check to see if the physical LEDs contains what we last
+		   wrote to them; if not, we suppress display (this is so that
+		   users can write to the LEDs, and not have their output
+		   overwritten).  As a special case, we start writing again if
+		   all the LEDs are blank, or our display image is all zeros
+		   (indicating that this is the initial update, when the actual
+		   LEDs might contain random data).  */
+		read_leds (0, prev_image, LED_NUM_DIGITS);
+		for (digit = 0; digit < LED_NUM_DIGITS; digit++)
+			if (image[digit] != prev_image[digit]
+			    && image[digit] && prev_image[digit])
+			{
+				write_to_leds = 0;
+				break;
+			}
+
+		/* Update display image.  */
+		for (digit = 0;
+		     digit < LED_NUM_DIGITS && tick_frames[digit][0] >= 0;
+		     digit++)
+		{
+			int frame = tick_frames[digit][frame_nums[digit]];
+			if (frame < 0) {
+				image[digit] = tick_frames[digit][0];
+				frame_nums[digit] = 1;
+			} else {
+				image[digit] = frame;
+				frame_nums[digit]++;
+				break;
+			}
+		}
+
+		if (write_to_leds)
+			/* Write the display image to the physical LEDs.  */
+			write_leds (0, image, LED_NUM_DIGITS);
+
+		counter = 0;
+	}
+}
+
+
+/* Mother-A interrupts.  */
+
+#ifdef CONFIG_RTE_GBUS_INT
+
+#define L GBUS_INT_PRIORITY_LOW
+#define M GBUS_INT_PRIORITY_MEDIUM
+#define H GBUS_INT_PRIORITY_HIGH
+
+static struct gbus_int_irq_init gbus_irq_inits[] = {
+#ifdef CONFIG_RTE_MB_A_PCI
+	{ "MB_A_LAN",	IRQ_MB_A_LAN,		1,		     1, L },
+	{ "MB_A_PCI1",	IRQ_MB_A_PCI1(0),	IRQ_MB_A_PCI1_NUM,   1, L },
+	{ "MB_A_PCI2",	IRQ_MB_A_PCI2(0),	IRQ_MB_A_PCI2_NUM,   1, L },
+	{ "MB_A_EXT",	IRQ_MB_A_EXT(0),	IRQ_MB_A_EXT_NUM,    1, L },
+	{ "MB_A_USB_OC",IRQ_MB_A_USB_OC(0),	IRQ_MB_A_USB_OC_NUM, 1, L },
+	{ "MB_A_PCMCIA_OC",IRQ_MB_A_PCMCIA_OC,	1,		     1, L },
+#endif
+	{ 0 }
+};
+#define NUM_GBUS_IRQ_INITS  \
+   ((sizeof gbus_irq_inits / sizeof gbus_irq_inits[0]) - 1)
+
+static struct hw_interrupt_type gbus_hw_itypes[NUM_GBUS_IRQ_INITS];
+
+#endif /* CONFIG_RTE_GBUS_INT */
+
+
+void __init rte_cb_init_irqs (void)
+{
+#ifdef CONFIG_RTE_GBUS_INT
+	gbus_int_init_irqs ();
+	gbus_int_init_irq_types (gbus_irq_inits, gbus_hw_itypes);
+#endif /* CONFIG_RTE_GBUS_INT */
+}
diff --git a/arch/v850/kernel/rte_cb_leds.c b/arch/v850/kernel/rte_cb_leds.c
new file mode 100644
index 0000000..b662ad8
--- /dev/null
+++ b/arch/v850/kernel/rte_cb_leds.c
@@ -0,0 +1,138 @@
+/*
+ * include/asm-v850/rte_cb_leds.c -- Midas lab RTE-CB board LED device support
+ *
+ *  Copyright (C) 2002,03  NEC Electronics Corporation
+ *  Copyright (C) 2002,03  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+
+#include <asm/uaccess.h>
+
+#define LEDS_MINOR	169	/* Minor device number, using misc major.  */
+
+/* The actual LED hardware is write-only, so we hold the contents here too.  */
+static unsigned char leds_image[LED_NUM_DIGITS] = { 0 };
+
+/* Spinlock protecting the above leds.  */
+static DEFINE_SPINLOCK(leds_lock);
+
+/* Common body of LED read/write functions, checks POS and LEN for
+   correctness, declares a variable using IMG_DECL, initialized pointing at
+   the POS position in the LED image buffer, and and iterates COPY_EXPR
+   until BUF is equal to the last buffer position; finally, sets LEN to be
+   the amount actually copied.  IMG should be a variable declaration
+   (without an initializer or a terminating semicolon); POS, BUF, and LEN
+   should all be simple variables.  */
+#define DO_LED_COPY(img_decl, pos, buf, len, copy_expr)			\
+do {									\
+	if (pos > LED_NUM_DIGITS)					\
+		len = 0;						\
+	else {								\
+		if (pos + len > LED_NUM_DIGITS)				\
+			len = LED_NUM_DIGITS - pos;			\
+									\
+		if (len > 0) {						\
+			int _flags;					\
+			const char *_end = buf + len;			\
+			img_decl = &leds_image[pos];			\
+									\
+			spin_lock_irqsave (leds_lock, _flags);		\
+			do						\
+				(copy_expr);				\
+			while (buf != _end);				\
+			spin_unlock_irqrestore (leds_lock, _flags);	\
+		}							\
+	}								\
+} while (0)
+
+/* Read LEN bytes from LEDs at position POS, into BUF.
+   Returns actual amount read.  */
+unsigned read_leds (unsigned pos, char *buf, unsigned len)
+{
+	DO_LED_COPY (const char *img, pos, buf, len, *buf++ = *img++);
+	return len;
+}
+
+/* Write LEN bytes to LEDs at position POS, from BUF.
+   Returns actual amount written.  */
+unsigned write_leds (unsigned pos, const char *buf, unsigned len)
+{
+	/* We write the actual LED values backwards, because
+	   increasing memory addresses reflect LEDs right-to-left. */
+	volatile char *led = &LED (LED_NUM_DIGITS - pos - 1);
+	/* We invert the value written to the hardware, because 1 = off,
+	   and 0 = on.  */
+	DO_LED_COPY (char *img, pos, buf, len,
+		     *led-- = 0xFF ^ (*img++ = *buf++));
+	return len;
+}
+
+
+/* Device functions.  */
+
+static ssize_t leds_dev_read (struct file *file, char *buf, size_t len,
+			      loff_t *pos)
+{
+	char temp_buf[LED_NUM_DIGITS];
+	len = read_leds (*pos, temp_buf, len);
+	if (copy_to_user (buf, temp_buf, len))
+		return -EFAULT;
+	*pos += len;
+	return len;
+}
+
+static ssize_t leds_dev_write (struct file *file, const char *buf, size_t len,
+			       loff_t *pos)
+{
+	char temp_buf[LED_NUM_DIGITS];
+	if (copy_from_user (temp_buf, buf, min_t(size_t, len, LED_NUM_DIGITS)))
+		return -EFAULT;
+	len = write_leds (*pos, temp_buf, len);
+	*pos += len;
+	return len;
+}
+
+static loff_t leds_dev_lseek (struct file *file, loff_t offs, int whence)
+{
+	if (whence == 1)
+		offs += file->f_pos; /* relative */
+	else if (whence == 2)
+		offs += LED_NUM_DIGITS; /* end-relative */
+
+	if (offs < 0 || offs > LED_NUM_DIGITS)
+		return -EINVAL;
+
+	file->f_pos = offs;
+
+	return 0;
+}
+
+static struct file_operations leds_fops = {
+	.read		= leds_dev_read,
+	.write		= leds_dev_write,
+	.llseek		= leds_dev_lseek
+};
+
+static struct miscdevice leds_miscdev = {
+	.name		= "leds",
+	.minor		= LEDS_MINOR,
+	.fops		= &leds_fops
+};
+
+int __init leds_dev_init (void)
+{
+	return misc_register (&leds_miscdev);
+}
+
+__initcall (leds_dev_init);
diff --git a/arch/v850/kernel/rte_cb_multi.c b/arch/v850/kernel/rte_cb_multi.c
new file mode 100644
index 0000000..963d55a
--- /dev/null
+++ b/arch/v850/kernel/rte_cb_multi.c
@@ -0,0 +1,121 @@
+/*
+ * include/asm-v850/rte_multi.c -- Support for Multi debugger monitor ROM
+ * 	on Midas lab RTE-CB series of evaluation boards
+ *
+ *  Copyright (C) 2001,02,03  NEC Electronics Corporation
+ *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <linux/init.h>
+
+#include <asm/machdep.h>
+
+#define IRQ_ADDR(irq) (0x80 + (irq) * 0x10)
+
+/* A table of which interrupt vectors to install, since blindly
+   installing all of them makes the debugger stop working.  This is a
+   list of offsets in the interrupt vector area; each entry means to
+   copy that particular 16-byte vector.  An entry less than zero ends
+   the table.  */
+static long multi_intv_install_table[] = {
+	/* Trap vectors */
+	0x40, 0x50,		
+
+#ifdef CONFIG_RTE_CB_MULTI_DBTRAP
+	/* Illegal insn / dbtrap.  These are used by multi, so only handle
+	   them if configured to do so.  */
+	0x60,
+#endif
+
+	/* GINT1 - GINT3 (note, not GINT0!) */
+	IRQ_ADDR (IRQ_GINT(1)),
+	IRQ_ADDR (IRQ_GINT(2)),
+	IRQ_ADDR (IRQ_GINT(3)),
+
+	/* Timer D interrupts (up to 4 timers) */
+	IRQ_ADDR (IRQ_INTCMD(0)),
+#if IRQ_INTCMD_NUM > 1
+	IRQ_ADDR (IRQ_INTCMD(1)),
+#if IRQ_INTCMD_NUM > 2
+	IRQ_ADDR (IRQ_INTCMD(2)),
+#if IRQ_INTCMD_NUM > 3
+	IRQ_ADDR (IRQ_INTCMD(3)),
+#endif
+#endif
+#endif
+	
+	/* UART interrupts (up to 3 channels) */
+	IRQ_ADDR (IRQ_INTSER (0)), /* err */
+	IRQ_ADDR (IRQ_INTSR  (0)), /* rx */
+	IRQ_ADDR (IRQ_INTST  (0)), /* tx */
+#if IRQ_INTSR_NUM > 1
+	IRQ_ADDR (IRQ_INTSER (1)), /* err */
+	IRQ_ADDR (IRQ_INTSR  (1)), /* rx */
+	IRQ_ADDR (IRQ_INTST  (1)), /* tx */
+#if IRQ_INTSR_NUM > 2
+	IRQ_ADDR (IRQ_INTSER (2)), /* err */
+	IRQ_ADDR (IRQ_INTSR  (2)), /* rx */
+	IRQ_ADDR (IRQ_INTST  (2)), /* tx */
+#endif
+#endif
+
+	-1
+};
+
+/* Early initialization for kernel using Multi debugger ROM monitor.  */
+void __init multi_init (void)
+{
+	/* We're using the Multi debugger monitor, so we have to install
+	   the interrupt vectors.  The monitor doesn't allow them to be
+	   initially downloaded into their final destination because
+	   it's in the monitor's scratch-RAM area.  Unfortunately, Multi
+	   also doesn't deal correctly with ELF sections where the LMA
+	   and VMA differ -- it just ignores the LMA -- so we can't use
+	   that feature to work around the problem.  What we do instead
+	   is just put the interrupt vectors into a normal section, and
+	   do the necessary copying and relocation here.  Since the
+	   interrupt vector basically only contains `jr' instructions
+	   and no-ops, it's not that hard.  */
+	extern unsigned long _intv_load_start, _intv_start;
+	register unsigned long *src = &_intv_load_start;
+	register unsigned long *dst = (unsigned long *)INTV_BASE;
+	register unsigned long jr_fixup = (char *)&_intv_start - (char *)dst;
+	register long *ii;
+
+	/* Copy interrupt vectors as instructed by multi_intv_install_table. */
+	for (ii = multi_intv_install_table; *ii >= 0; ii++) {
+		/* Copy 16-byte interrupt vector at offset *ii.  */
+		int boffs;
+		for (boffs = 0; boffs < 0x10; boffs += sizeof *src) {
+			/* Copy a single word, fixing up the jump offs
+			   if it's a `jr' instruction.  */
+			int woffs = (*ii + boffs) / sizeof *src;
+			unsigned long word = src[woffs];
+
+			if ((word & 0xFC0) == 0x780) {
+				/* A `jr' insn, fix up its offset (and yes, the
+				   weird half-word swapping is intentional). */
+				unsigned short hi = word & 0xFFFF;
+				unsigned short lo = word >> 16;
+				unsigned long udisp22
+					= lo + ((hi & 0x3F) << 16);
+				long disp22 = (long)(udisp22 << 10) >> 10;
+
+				disp22 += jr_fixup;
+
+				hi = ((disp22 >> 16) & 0x3F) | 0x780;
+				lo = disp22 & 0xFFFF;
+
+				word = hi + (lo << 16);
+			}
+
+			dst[woffs] = word;
+		}
+	}
+}
diff --git a/arch/v850/kernel/rte_ma1_cb-rom.ld b/arch/v850/kernel/rte_ma1_cb-rom.ld
new file mode 100644
index 0000000..87b618f
--- /dev/null
+++ b/arch/v850/kernel/rte_ma1_cb-rom.ld
@@ -0,0 +1,14 @@
+/* Linker script for the Midas labs RTE-V850E/MA1-CB evaluation board
+   (CONFIG_RTE_CB_MA1), with kernel in ROM.  */
+
+MEMORY {
+	ROM   : ORIGIN = 0x00000000, LENGTH = 0x00100000
+	/* 1MB of SRAM.  This memory is mirrored 4 times.  */
+	SRAM  : ORIGIN = SRAM_ADDR,  LENGTH = SRAM_SIZE
+	/* 32MB of SDRAM.  */
+	SDRAM : ORIGIN = SDRAM_ADDR, LENGTH = SDRAM_SIZE
+}
+
+SECTIONS {
+	ROMK_SECTIONS(ROM, SRAM)
+}
diff --git a/arch/v850/kernel/rte_ma1_cb.c b/arch/v850/kernel/rte_ma1_cb.c
new file mode 100644
index 0000000..3873e27
--- /dev/null
+++ b/arch/v850/kernel/rte_ma1_cb.c
@@ -0,0 +1,106 @@
+/*
+ * arch/v850/kernel/rte_ma1_cb.c -- Midas labs RTE-V850E/MA1-CB board
+ *
+ *  Copyright (C) 2001,02,03  NEC Electronics Corporation
+ *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+
+#include <asm/atomic.h>
+#include <asm/page.h>
+#include <asm/ma1.h>
+#include <asm/rte_ma1_cb.h>
+#include <asm/v850e_timer_c.h>
+
+#include "mach.h"
+
+
+/* SRAM and SDRAM are almost contiguous (with a small hole in between;
+   see mach_reserve_bootmem for details), so just use both as one big area.  */
+#define RAM_START 	SRAM_ADDR
+#define RAM_END		(SDRAM_ADDR + SDRAM_SIZE)
+
+
+void __init mach_early_init (void)
+{
+	rte_cb_early_init ();
+}
+
+void __init mach_get_physical_ram (unsigned long *ram_start,
+				   unsigned long *ram_len)
+{
+	*ram_start = RAM_START;
+	*ram_len = RAM_END - RAM_START;
+}
+
+void __init mach_reserve_bootmem ()
+{
+#ifdef CONFIG_RTE_CB_MULTI
+	/* Prevent the kernel from touching the monitor's scratch RAM.  */
+	reserve_bootmem (MON_SCRATCH_ADDR, MON_SCRATCH_SIZE);
+#endif
+
+	/* The space between SRAM and SDRAM is filled with duplicate
+	   images of SRAM.  Prevent the kernel from using them.  */
+	reserve_bootmem (SRAM_ADDR + SRAM_SIZE,
+			 SDRAM_ADDR - (SRAM_ADDR + SRAM_SIZE));
+}
+
+void mach_gettimeofday (struct timespec *tv)
+{
+	tv->tv_sec = 0;
+	tv->tv_nsec = 0;
+}
+
+/* Called before configuring an on-chip UART.  */
+void rte_ma1_cb_uart_pre_configure (unsigned chan,
+				    unsigned cflags, unsigned baud)
+{
+	/* The RTE-MA1-CB connects some general-purpose I/O pins on the
+	   CPU to the RTS/CTS lines of UART 0's serial connection.
+	   I/O pins P42 and P43 are RTS and CTS respectively.  */
+	if (chan == 0) {
+		/* Put P42 & P43 in I/O port mode.  */
+		MA_PORT4_PMC &= ~0xC;
+		/* Make P42 an output, and P43 an input.  */
+		MA_PORT4_PM = (MA_PORT4_PM & ~0xC) | 0x8;
+	}
+
+	/* Do pre-configuration for the actual UART.  */
+	ma_uart_pre_configure (chan, cflags, baud);
+}
+
+void __init mach_init_irqs (void)
+{
+	unsigned tc;
+
+	/* Initialize interrupts.  */
+	ma_init_irqs ();
+	rte_cb_init_irqs ();
+
+	/* Use falling-edge-sensitivity for interrupts .  */
+	V850E_TIMER_C_SESC (0) &= ~0xC;
+	V850E_TIMER_C_SESC (1) &= ~0xF;
+
+	/* INTP000-INTP011 are shared with `Timer C', so we have to set
+	   up Timer C to pass them through as raw interrupts.  */
+	for (tc = 0; tc < 2; tc++)
+		/* Turn on the timer.  */
+		V850E_TIMER_C_TMCC0 (tc) |= V850E_TIMER_C_TMCC0_CAE;
+
+	/* Make sure the relevant port0/port1 pins are assigned
+	   interrupt duty.  We used INTP001-INTP011 (don't screw with
+	   INTP000 because the monitor uses it).  */
+	MA_PORT0_PMC |= 0x4;	/* P02 (INTP001) in IRQ mode.  */
+	MA_PORT1_PMC |= 0x6;	/* P11 (INTP010) & P12 (INTP011) in IRQ mode.*/
+}
diff --git a/arch/v850/kernel/rte_ma1_cb.ld b/arch/v850/kernel/rte_ma1_cb.ld
new file mode 100644
index 0000000..c8e16d1
--- /dev/null
+++ b/arch/v850/kernel/rte_ma1_cb.ld
@@ -0,0 +1,57 @@
+/* Linker script for the Midas labs RTE-V850E/MA1-CB evaluation board
+   (CONFIG_RTE_CB_MA1), with kernel in SDRAM, under Multi debugger.  */
+
+MEMORY {
+	/* 1MB of SRAM; we can't use the last 32KB, because it's used by
+	   the monitor scratch-RAM.  This memory is mirrored 4 times.  */
+	SRAM  : ORIGIN = SRAM_ADDR,  LENGTH = (SRAM_SIZE - MON_SCRATCH_SIZE)
+	/* Monitor scratch RAM; only the interrupt vectors should go here.  */
+	MRAM  : ORIGIN = MON_SCRATCH_ADDR,  LENGTH = MON_SCRATCH_SIZE
+	/* 32MB of SDRAM.  */
+	SDRAM : ORIGIN = SDRAM_ADDR, LENGTH = SDRAM_SIZE
+}
+
+#ifdef CONFIG_RTE_CB_MA1_KSRAM
+# define KRAM SRAM
+#else
+# define KRAM SDRAM
+#endif
+
+SECTIONS {
+	/* We can't use RAMK_KRAM_CONTENTS because that puts the whole
+	   kernel in a single ELF segment, and the Multi debugger (which
+	   we use to load the kernel) appears to have bizarre problems
+	   dealing with it.  */
+
+	.text : {
+		__kram_start = . ;
+		TEXT_CONTENTS
+	} > KRAM
+
+	.data : {
+		DATA_CONTENTS
+		BSS_CONTENTS
+		RAMK_INIT_CONTENTS
+		__kram_end = . ;
+		BOOTMAP_CONTENTS
+
+		/* The address at which the interrupt vectors are initially
+		   loaded by the loader.  We can't load the interrupt vectors
+		   directly into their target location, because the monitor
+		   ROM for the GHS Multi debugger barfs if we try.
+		   Unfortunately, Multi also doesn't deal correctly with ELF
+		   sections where the LMA and VMA differ (it just ignores the
+		   LMA), so we can't use that feature to work around the
+		   problem!  What we do instead is just put the interrupt
+		   vectors into a normal section, and have the
+		   `mach_early_init' function for Midas boards do the
+		   necessary copying and relocation at runtime (this section
+		   basically only contains `jr' instructions, so it's not
+		   that hard).  */
+		. = ALIGN (0x10) ;
+		__intv_load_start = . ;
+		INTV_CONTENTS
+	} > KRAM
+
+	.root ALIGN (4096) : { ROOT_FS_CONTENTS } > SDRAM
+}
diff --git a/arch/v850/kernel/rte_mb_a_pci.c b/arch/v850/kernel/rte_mb_a_pci.c
new file mode 100644
index 0000000..074b50a
--- /dev/null
+++ b/arch/v850/kernel/rte_mb_a_pci.c
@@ -0,0 +1,796 @@
+/*
+ * arch/v850/kernel/mb_a_pci.c -- PCI support for Midas lab RTE-MOTHER-A board
+ *
+ *  Copyright (C) 2001,02,03  NEC Electronics Corporation
+ *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+
+#include <asm/machdep.h>
+
+/* __nomods_init is like __devinit, but is a no-op when modules are enabled.
+   This is used by some routines that can be called either during boot
+   or by a module.  */
+#ifdef CONFIG_MODULES
+#define __nomods_init /*nothing*/
+#else
+#define __nomods_init __devinit
+#endif
+
+/* PCI devices on the Mother-A board can only do DMA to/from the MB SRAM
+   (the RTE-V850E/MA1-CB cpu board doesn't support PCI access to
+   CPU-board memory), and since linux DMA buffers are allocated in
+   normal kernel memory, we basically have to copy DMA blocks around
+   (this is like a `bounce buffer').  When a DMA block is `mapped', we
+   allocate an identically sized block in MB SRAM, and if we're doing
+   output to the device, copy the CPU-memory block to the MB-SRAM block.
+   When an active block is `unmapped', we will copy the block back to
+   CPU memory if necessary, and then deallocate the MB SRAM block.
+   Ack.  */
+
+/* Where the motherboard SRAM is in the PCI-bus address space (the
+   first 512K of it is also mapped at PCI address 0).  */
+#define PCI_MB_SRAM_ADDR 0x800000
+
+/* Convert CPU-view MB SRAM address to/from PCI-view addresses of the
+   same memory.  */
+#define MB_SRAM_TO_PCI(mb_sram_addr) \
+   ((dma_addr_t)mb_sram_addr - MB_A_SRAM_ADDR + PCI_MB_SRAM_ADDR)
+#define PCI_TO_MB_SRAM(pci_addr)     \
+   (void *)(pci_addr - PCI_MB_SRAM_ADDR + MB_A_SRAM_ADDR)
+
+static void pcibios_assign_resources (void);
+
+struct mb_pci_dev_irq {
+	unsigned dev;		/* PCI device number */
+	unsigned irq_base;	/* First IRQ  */
+	unsigned query_pin;	/* True if we should read the device's
+				   Interrupt Pin info, and allocate
+				   interrupt IRQ_BASE + PIN.  */
+};
+
+/* PCI interrupts are mapped statically to GBUS interrupts.  */
+static struct mb_pci_dev_irq mb_pci_dev_irqs[] = {
+	/* Motherboard SB82558 ethernet controller */
+	{ 10,	IRQ_MB_A_LAN,		0 },
+	/* PCI slot 1 */
+	{ 8, 	IRQ_MB_A_PCI1(0),	1 },
+	/* PCI slot 2 */
+	{ 9, 	IRQ_MB_A_PCI2(0),	1 }
+};
+#define NUM_MB_PCI_DEV_IRQS \
+  (sizeof mb_pci_dev_irqs / sizeof mb_pci_dev_irqs[0])
+
+
+/* PCI configuration primitives.  */
+
+#define CONFIG_DMCFGA(bus, devfn, offs)					\
+   (0x80000000								\
+    | ((offs) & ~0x3)							\
+    | ((devfn) << 8)							\
+    | ((bus)->number << 16))
+
+static int
+mb_pci_read (struct pci_bus *bus, unsigned devfn, int offs, int size, u32 *rval)
+{
+	u32 addr;
+	int flags;
+
+	local_irq_save (flags);
+
+	MB_A_PCI_PCICR = 0x7;
+	MB_A_PCI_DMCFGA = CONFIG_DMCFGA (bus, devfn, offs);
+
+	addr = MB_A_PCI_IO_ADDR + (offs & 0x3);
+
+	switch (size) {
+	case 1:	*rval = *(volatile  u8 *)addr; break;
+	case 2:	*rval = *(volatile u16 *)addr; break;
+	case 4:	*rval = *(volatile u32 *)addr; break;
+	}
+
+        if (MB_A_PCI_PCISR & 0x2000) {
+		MB_A_PCI_PCISR = 0x2000;
+		*rval = ~0;
+        }
+
+	MB_A_PCI_DMCFGA = 0;
+
+	local_irq_restore (flags);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+mb_pci_write (struct pci_bus *bus, unsigned devfn, int offs, int size, u32 val)
+{
+	u32 addr;
+	int flags;
+
+	local_irq_save (flags);
+
+	MB_A_PCI_PCICR = 0x7;
+	MB_A_PCI_DMCFGA = CONFIG_DMCFGA (bus, devfn, offs);
+
+	addr = MB_A_PCI_IO_ADDR + (offs & 0x3);
+
+	switch (size) {
+	case 1: *(volatile  u8 *)addr = val; break;
+	case 2: *(volatile u16 *)addr = val; break;
+	case 4: *(volatile u32 *)addr = val; break;
+	}
+
+        if (MB_A_PCI_PCISR & 0x2000)
+		MB_A_PCI_PCISR = 0x2000;
+
+	MB_A_PCI_DMCFGA = 0;
+
+	local_irq_restore (flags);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops mb_pci_config_ops = {
+	.read	= mb_pci_read,
+	.write	= mb_pci_write,
+};
+
+
+/* PCI Initialization.  */
+
+static struct pci_bus *mb_pci_bus = 0;
+
+/* Do initial PCI setup.  */
+static int __devinit pcibios_init (void)
+{
+	u32 id = MB_A_PCI_PCIHIDR;
+	u16 vendor = id & 0xFFFF;
+	u16 device = (id >> 16) & 0xFFFF;
+
+	if (vendor == PCI_VENDOR_ID_PLX && device == PCI_DEVICE_ID_PLX_9080) {
+		printk (KERN_INFO
+			"PCI: PLX Technology PCI9080 HOST/PCI bridge\n");
+
+		MB_A_PCI_PCICR = 0x147;
+
+		MB_A_PCI_PCIBAR0 = 0x007FFF00;
+		MB_A_PCI_PCIBAR1 = 0x0000FF00;
+		MB_A_PCI_PCIBAR2 = 0x00800000;
+
+		MB_A_PCI_PCILTR = 0x20;
+
+		MB_A_PCI_PCIPBAM |= 0x3;
+
+		MB_A_PCI_PCISR =  ~0; /* Clear errors.  */
+
+		/* Reprogram the motherboard's IO/config address space,
+		   as we don't support the GCS7 address space that the
+		   default uses.  */
+
+		/* Significant address bits used for decoding PCI GCS5 space
+		   accessess.  */
+		MB_A_PCI_DMRR = ~(MB_A_PCI_MEM_SIZE - 1);
+
+		/* I don't understand this, but the SolutionGear example code
+		   uses such an offset, and it doesn't work without it.  XXX */
+#if GCS5_SIZE == 0x00800000
+#define GCS5_CFG_OFFS 0x00800000
+#else
+#define GCS5_CFG_OFFS 0
+#endif
+
+		/* Address bit values for matching.  Note that we have to give
+		   the address from the motherboard's point of view, which is
+		   different than the CPU's.  */
+		/* PCI memory space.  */
+		MB_A_PCI_DMLBAM = GCS5_CFG_OFFS + 0x0;
+		/* PCI I/O space.  */
+		MB_A_PCI_DMLBAI =
+			GCS5_CFG_OFFS + (MB_A_PCI_IO_ADDR - GCS5_ADDR);
+
+		mb_pci_bus = pci_scan_bus (0, &mb_pci_config_ops, 0);
+
+		pcibios_assign_resources ();
+	} else
+		printk (KERN_ERR "PCI: HOST/PCI bridge not found\n");
+
+	return 0;
+}
+
+subsys_initcall (pcibios_init);
+
+char __devinit *pcibios_setup (char *option)
+{
+	/* Don't handle any options. */
+	return option;
+}
+
+
+int __nomods_init pcibios_enable_device (struct pci_dev *dev, int mask)
+{
+	u16 cmd, old_cmd;
+	int idx;
+	struct resource *r;
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	old_cmd = cmd;
+	for (idx = 0; idx < 6; idx++) {
+		r = &dev->resource[idx];
+		if (!r->start && r->end) {
+			printk(KERN_ERR "PCI: Device %s not available because "
+			       "of resource collisions\n", pci_name(dev));
+			return -EINVAL;
+		}
+		if (r->flags & IORESOURCE_IO)
+			cmd |= PCI_COMMAND_IO;
+		if (r->flags & IORESOURCE_MEM)
+			cmd |= PCI_COMMAND_MEMORY;
+	}
+	if (cmd != old_cmd) {
+		printk("PCI: Enabling device %s (%04x -> %04x)\n",
+		       pci_name(dev), old_cmd, cmd);
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	}
+	return 0;
+}
+
+
+/* Resource allocation.  */
+static void __devinit pcibios_assign_resources (void)
+{
+	struct pci_dev *dev = NULL;
+	struct resource *r;
+
+	for_each_pci_dev(dev) {
+		unsigned di_num;
+		unsigned class = dev->class >> 8;
+
+		if (class && class != PCI_CLASS_BRIDGE_HOST) {
+			unsigned r_num;
+			for(r_num = 0; r_num < 6; r_num++) {
+				r = &dev->resource[r_num];
+				if (!r->start && r->end)
+					pci_assign_resource (dev, r_num);
+			}
+		}
+
+		/* Assign interrupts.  */
+		for (di_num = 0; di_num < NUM_MB_PCI_DEV_IRQS; di_num++) {
+			struct mb_pci_dev_irq *di = &mb_pci_dev_irqs[di_num];
+
+			if (di->dev == PCI_SLOT (dev->devfn)) {
+				unsigned irq = di->irq_base;
+
+				if (di->query_pin) {
+					/* Find out which interrupt pin
+					   this device uses (each PCI
+					   slot has 4).  */
+					u8 irq_pin;
+
+					pci_read_config_byte (dev,
+							     PCI_INTERRUPT_PIN,
+							      &irq_pin);
+
+					if (irq_pin == 0)
+						/* Doesn't use interrupts.  */ 
+						continue;
+					else
+						irq += irq_pin - 1;
+				}
+
+				pcibios_update_irq (dev, irq);
+			}
+		}
+	}
+}
+
+void __devinit pcibios_update_irq (struct pci_dev *dev, int irq)
+{
+	dev->irq = irq;
+	pci_write_config_byte (dev, PCI_INTERRUPT_LINE, irq);
+}
+
+void __devinit
+pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
+			struct resource *res)
+{
+	unsigned long offset = 0;
+
+	if (res->flags & IORESOURCE_IO) {
+		offset = MB_A_PCI_IO_ADDR;
+	} else if (res->flags & IORESOURCE_MEM) {
+		offset = MB_A_PCI_MEM_ADDR;
+	}
+
+	region->start = res->start - offset;
+	region->end = res->end - offset;
+}
+
+
+/* Stubs for things we don't use.  */
+
+/* Called after each bus is probed, but before its children are examined. */
+void pcibios_fixup_bus(struct pci_bus *b)
+{
+}
+
+void
+pcibios_align_resource (void *data, struct resource *res,
+			unsigned long size, unsigned long align)
+{
+}
+
+void pcibios_set_master (struct pci_dev *dev)
+{
+}
+
+
+/* Mother-A SRAM memory allocation.  This is a simple first-fit allocator.  */
+
+/* A memory free-list node.  */
+struct mb_sram_free_area {
+	void *mem;
+	unsigned long size;
+	struct mb_sram_free_area *next;
+};
+
+/* The tail of the free-list, which starts out containing all the SRAM.  */
+static struct mb_sram_free_area mb_sram_free_tail = {
+	(void *)MB_A_SRAM_ADDR, MB_A_SRAM_SIZE, 0
+};
+
+/* The free-list.  */
+static struct mb_sram_free_area *mb_sram_free_areas = &mb_sram_free_tail;
+
+/* The free-list of free free-list nodes. (:-)  */
+static struct mb_sram_free_area *mb_sram_free_free_areas = 0;
+
+/* Spinlock protecting the above globals.  */
+static DEFINE_SPINLOCK(mb_sram_lock);
+
+/* Allocate a memory block at least SIZE bytes long in the Mother-A SRAM
+   space.  */
+static void *alloc_mb_sram (size_t size)
+{
+	struct mb_sram_free_area *prev, *fa;
+	int flags;
+	void *mem = 0;
+
+	spin_lock_irqsave (mb_sram_lock, flags);
+
+	/* Look for a free area that can contain SIZE bytes.  */
+	for (prev = 0, fa = mb_sram_free_areas; fa; prev = fa, fa = fa->next)
+		if (fa->size >= size) {
+			/* Found one!  */
+			mem = fa->mem;
+
+			if (fa->size == size) {
+				/* In fact, it fits exactly, so remove
+				   this node from the free-list.  */
+				if (prev)
+					prev->next = fa->next;
+				else
+					mb_sram_free_areas = fa->next;
+				/* Put it on the free-list-entry-free-list. */
+				fa->next = mb_sram_free_free_areas;
+				mb_sram_free_free_areas = fa;
+			} else {
+				/* FA is bigger than SIZE, so just
+				   reduce its size to account for this
+				   allocation.  */
+				fa->mem += size;
+				fa->size -= size;
+			}
+
+			break;
+		}
+
+	spin_unlock_irqrestore (mb_sram_lock, flags);
+
+	return mem;
+}
+
+/* Return the memory area MEM of size SIZE to the MB SRAM free pool.  */
+static void free_mb_sram (void *mem, size_t size)
+{
+	struct mb_sram_free_area *prev, *fa, *new_fa;
+	int flags;
+	void *end = mem + size;
+
+	spin_lock_irqsave (mb_sram_lock, flags);
+
+ retry:
+	/* Find an adjacent free-list entry.  */
+	for (prev = 0, fa = mb_sram_free_areas; fa; prev = fa, fa = fa->next)
+		if (fa->mem == end) {
+			/* FA is just after MEM, grow down to encompass it. */
+			fa->mem = mem;
+			fa->size += size;
+			goto done;
+		} else if (fa->mem + fa->size == mem) {
+			struct mb_sram_free_area *next_fa = fa->next;
+
+			/* FA is just before MEM, expand to encompass it. */
+			fa->size += size;
+
+			/* See if FA can now be merged with its successor. */
+			if (next_fa && fa->mem + fa->size == next_fa->mem) {
+				/* Yup; merge NEXT_FA's info into FA.  */
+				fa->size += next_fa->size;
+				fa->next = next_fa->next;
+				/* Free NEXT_FA.  */
+				next_fa->next = mb_sram_free_free_areas;
+				mb_sram_free_free_areas = next_fa;
+			}
+			goto done;
+		} else if (fa->mem > mem)
+			/* We've reached the right spot in the free-list
+			   without finding an adjacent free-area, so add
+			   a new free area to hold mem. */
+			break;
+
+	/* Make a new free-list entry.  */
+
+	/* First, get a free-list entry.  */
+	if (! mb_sram_free_free_areas) {
+		/* There are none, so make some.  */
+		void *block;
+		size_t block_size = sizeof (struct mb_sram_free_area) * 8;
+
+		/* Don't hold the lock while calling kmalloc (I'm not
+		   sure whether it would be a problem, since we use
+		   GFP_ATOMIC, but it makes me nervous).  */
+		spin_unlock_irqrestore (mb_sram_lock, flags);
+
+		block = kmalloc (block_size, GFP_ATOMIC);
+		if (! block)
+			panic ("free_mb_sram: can't allocate free-list entry");
+
+		/* Now get the lock back.  */
+		spin_lock_irqsave (mb_sram_lock, flags);
+
+		/* Add the new free free-list entries.  */
+		while (block_size > 0) {
+			struct mb_sram_free_area *nfa = block;
+			nfa->next = mb_sram_free_free_areas;
+			mb_sram_free_free_areas = nfa;
+			block += sizeof *nfa;
+			block_size -= sizeof *nfa;
+		}
+
+		/* Since we dropped the lock to call kmalloc, the
+		   free-list could have changed, so retry from the
+		   beginning.  */
+		goto retry;
+	}
+
+	/* Remove NEW_FA from the free-list of free-list entries.  */
+	new_fa = mb_sram_free_free_areas;
+	mb_sram_free_free_areas = new_fa->next;
+
+	/* NEW_FA initially holds only MEM.  */
+	new_fa->mem = mem;
+	new_fa->size = size;
+
+	/* Insert NEW_FA in the free-list between PREV and FA. */
+	new_fa->next = fa;
+	if (prev)
+		prev->next = new_fa;
+	else
+		mb_sram_free_areas = new_fa;
+
+ done:
+	spin_unlock_irqrestore (mb_sram_lock, flags);
+}
+
+
+/* Maintainence of CPU -> Mother-A DMA mappings.  */
+
+struct dma_mapping {
+	void *cpu_addr;
+	void *mb_sram_addr;
+	size_t size;
+	struct dma_mapping *next;
+};
+
+/* A list of mappings from CPU addresses to MB SRAM addresses for active
+   DMA blocks (that have been `granted' to the PCI device).  */
+static struct dma_mapping *active_dma_mappings = 0;
+
+/* A list of free mapping objects.  */
+static struct dma_mapping *free_dma_mappings = 0;
+
+/* Spinlock protecting the above globals.  */
+static DEFINE_SPINLOCK(dma_mappings_lock);
+
+static struct dma_mapping *new_dma_mapping (size_t size)
+{
+	int flags;
+	struct dma_mapping *mapping;
+	void *mb_sram_block = alloc_mb_sram (size);
+
+	if (! mb_sram_block)
+		return 0;
+
+	spin_lock_irqsave (dma_mappings_lock, flags);
+
+	if (! free_dma_mappings) {
+		/* We're out of mapping structures, make more.  */
+		void *mblock;
+		size_t mblock_size = sizeof (struct dma_mapping) * 8;
+
+		/* Don't hold the lock while calling kmalloc (I'm not
+		   sure whether it would be a problem, since we use
+		   GFP_ATOMIC, but it makes me nervous).  */
+		spin_unlock_irqrestore (dma_mappings_lock, flags);
+
+		mblock = kmalloc (mblock_size, GFP_ATOMIC);
+		if (! mblock) {
+			free_mb_sram (mb_sram_block, size);
+			return 0;
+		}
+
+		/* Get the lock back.  */
+		spin_lock_irqsave (dma_mappings_lock, flags);
+
+		/* Add the new mapping structures to the free-list.  */
+		while (mblock_size > 0) {
+			struct dma_mapping *fm = mblock;
+			fm->next = free_dma_mappings;
+			free_dma_mappings = fm;
+			mblock += sizeof *fm;
+			mblock_size -= sizeof *fm;
+		}
+	}
+
+	/* Get a mapping struct from the freelist.  */
+	mapping = free_dma_mappings;
+	free_dma_mappings = mapping->next;
+
+	/* Initialize the mapping.  Other fields should be filled in by
+	   caller.  */
+	mapping->mb_sram_addr = mb_sram_block;
+	mapping->size = size;
+
+	/* Add it to the list of active mappings.  */
+	mapping->next = active_dma_mappings;
+	active_dma_mappings = mapping;
+
+	spin_unlock_irqrestore (dma_mappings_lock, flags);
+
+	return mapping;
+}
+
+static struct dma_mapping *find_dma_mapping (void *mb_sram_addr)
+{
+	int flags;
+	struct dma_mapping *mapping;
+
+	spin_lock_irqsave (dma_mappings_lock, flags);
+
+	for (mapping = active_dma_mappings; mapping; mapping = mapping->next)
+		if (mapping->mb_sram_addr == mb_sram_addr) {
+			spin_unlock_irqrestore (dma_mappings_lock, flags);
+			return mapping;
+		}
+
+	panic ("find_dma_mapping: unmapped PCI DMA addr 0x%x",
+	       MB_SRAM_TO_PCI (mb_sram_addr));
+}
+
+static struct dma_mapping *deactivate_dma_mapping (void *mb_sram_addr)
+{
+	int flags;
+	struct dma_mapping *mapping, *prev;
+
+	spin_lock_irqsave (dma_mappings_lock, flags);
+
+	for (prev = 0, mapping = active_dma_mappings;
+	     mapping;
+	     prev = mapping, mapping = mapping->next)
+	{
+		if (mapping->mb_sram_addr == mb_sram_addr) {
+			/* This is the MAPPING; deactivate it.  */
+			if (prev)
+				prev->next = mapping->next;
+			else
+				active_dma_mappings = mapping->next;
+
+			spin_unlock_irqrestore (dma_mappings_lock, flags);
+
+			return mapping;
+		}
+	}
+
+	panic ("deactivate_dma_mapping: unmapped PCI DMA addr 0x%x",
+	       MB_SRAM_TO_PCI (mb_sram_addr));
+}
+
+/* Return MAPPING to the freelist.  */
+static inline void
+free_dma_mapping (struct dma_mapping *mapping)
+{
+	int flags;
+
+	free_mb_sram (mapping->mb_sram_addr, mapping->size);
+
+	spin_lock_irqsave (dma_mappings_lock, flags);
+
+	mapping->next = free_dma_mappings;
+	free_dma_mappings = mapping;
+
+	spin_unlock_irqrestore (dma_mappings_lock, flags);
+}
+
+
+/* Single PCI DMA mappings.  */
+
+/* `Grant' to PDEV the memory block at CPU_ADDR, for doing DMA.  The
+   32-bit PCI bus mastering address to use is returned.  the device owns
+   this memory until either pci_unmap_single or pci_dma_sync_single is
+   performed.  */
+dma_addr_t
+pci_map_single (struct pci_dev *pdev, void *cpu_addr, size_t size, int dir)
+{
+	struct dma_mapping *mapping = new_dma_mapping (size);
+
+	if (! mapping)
+		return 0;
+
+	mapping->cpu_addr = cpu_addr;
+
+	if (dir == PCI_DMA_BIDIRECTIONAL || dir == PCI_DMA_TODEVICE)
+		memcpy (mapping->mb_sram_addr, cpu_addr, size);
+
+	return MB_SRAM_TO_PCI (mapping->mb_sram_addr);
+}
+
+/* Return to the CPU the PCI DMA memory block previously `granted' to
+   PDEV, at DMA_ADDR.  */
+void pci_unmap_single (struct pci_dev *pdev, dma_addr_t dma_addr, size_t size,
+		       int dir)
+{
+	void *mb_sram_addr = PCI_TO_MB_SRAM (dma_addr);
+	struct dma_mapping *mapping = deactivate_dma_mapping (mb_sram_addr);
+
+	if (size != mapping->size)
+		panic ("pci_unmap_single: size (%d) doesn't match"
+		       " size of mapping at PCI DMA addr 0x%x (%d)\n",
+		       size, dma_addr, mapping->size);
+
+	/* Copy back the DMA'd contents if necessary.  */
+	if (dir == PCI_DMA_BIDIRECTIONAL || dir == PCI_DMA_FROMDEVICE)
+		memcpy (mapping->cpu_addr, mb_sram_addr, size);
+
+	/* Return mapping to the freelist.  */
+	free_dma_mapping (mapping);
+}
+
+/* Make physical memory consistent for a single streaming mode DMA
+   translation after a transfer.
+
+   If you perform a pci_map_single() but wish to interrogate the
+   buffer using the cpu, yet do not wish to teardown the PCI dma
+   mapping, you must call this function before doing so.  At the next
+   point you give the PCI dma address back to the card, you must first
+   perform a pci_dma_sync_for_device, and then the device again owns
+   the buffer.  */
+void
+pci_dma_sync_single_for_cpu (struct pci_dev *pdev, dma_addr_t dma_addr, size_t size,
+		     int dir)
+{
+	void *mb_sram_addr = PCI_TO_MB_SRAM (dma_addr);
+	struct dma_mapping *mapping = find_dma_mapping (mb_sram_addr);
+
+	/* Synchronize the DMA buffer with the CPU buffer if necessary.  */
+	if (dir == PCI_DMA_FROMDEVICE)
+		memcpy (mapping->cpu_addr, mb_sram_addr, size);
+	else if (dir == PCI_DMA_TODEVICE)
+		; /* nothing to do */
+	else
+		panic("pci_dma_sync_single: unsupported sync dir: %d", dir);
+}
+
+void
+pci_dma_sync_single_for_device (struct pci_dev *pdev, dma_addr_t dma_addr, size_t size,
+				int dir)
+{
+	void *mb_sram_addr = PCI_TO_MB_SRAM (dma_addr);
+	struct dma_mapping *mapping = find_dma_mapping (mb_sram_addr);
+
+	/* Synchronize the DMA buffer with the CPU buffer if necessary.  */
+	if (dir == PCI_DMA_FROMDEVICE)
+		; /* nothing to do */
+	else if (dir == PCI_DMA_TODEVICE)
+		memcpy (mb_sram_addr, mapping->cpu_addr, size);
+	else
+		panic("pci_dma_sync_single: unsupported sync dir: %d", dir);
+}
+
+
+/* Scatter-gather PCI DMA mappings.  */
+
+/* Do multiple DMA mappings at once.  */
+int
+pci_map_sg (struct pci_dev *pdev, struct scatterlist *sg, int sg_len, int dir)
+{
+	BUG ();
+	return 0;
+}
+
+/* Unmap multiple DMA mappings at once.  */
+void
+pci_unmap_sg (struct pci_dev *pdev, struct scatterlist *sg, int sg_len,int dir)
+{
+	BUG ();
+}
+
+/* Make physical memory consistent for a set of streaming mode DMA
+   translations after a transfer.  The same as pci_dma_sync_single_* but
+   for a scatter-gather list, same rules and usage.  */
+
+void
+pci_dma_sync_sg_for_cpu (struct pci_dev *dev, struct scatterlist *sg, int sg_len,
+		 int dir)
+{
+	BUG ();
+}
+
+void
+pci_dma_sync_sg_for_device (struct pci_dev *dev, struct scatterlist *sg, int sg_len,
+		 int dir)
+{
+	BUG ();
+}
+
+
+/* PCI mem mapping.  */
+
+/* Allocate and map kernel buffer using consistent mode DMA for PCI
+   device.  Returns non-NULL cpu-view pointer to the buffer if
+   successful and sets *DMA_ADDR to the pci side dma address as well,
+   else DMA_ADDR is undefined.  */
+void *
+pci_alloc_consistent (struct pci_dev *pdev, size_t size, dma_addr_t *dma_addr)
+{
+	void *mb_sram_mem = alloc_mb_sram (size);
+	if (mb_sram_mem)
+		*dma_addr = MB_SRAM_TO_PCI (mb_sram_mem);
+	return mb_sram_mem;
+}
+
+/* Free and unmap a consistent DMA buffer.  CPU_ADDR and DMA_ADDR must
+   be values that were returned from pci_alloc_consistent.  SIZE must be
+   the same as what as passed into pci_alloc_consistent.  References to
+   the memory and mappings assosciated with CPU_ADDR or DMA_ADDR past
+   this call are illegal.  */
+void
+pci_free_consistent (struct pci_dev *pdev, size_t size, void *cpu_addr,
+		     dma_addr_t dma_addr)
+{
+	void *mb_sram_mem = PCI_TO_MB_SRAM (dma_addr);
+	free_mb_sram (mb_sram_mem, size);
+}
+
+
+/* symbol exports (for modules) */
+
+EXPORT_SYMBOL (pci_map_single);
+EXPORT_SYMBOL (pci_unmap_single);
+EXPORT_SYMBOL (pci_alloc_consistent);
+EXPORT_SYMBOL (pci_free_consistent);
+EXPORT_SYMBOL (pci_dma_sync_single_for_cpu);
+EXPORT_SYMBOL (pci_dma_sync_single_for_device);
diff --git a/arch/v850/kernel/rte_me2_cb.c b/arch/v850/kernel/rte_me2_cb.c
new file mode 100644
index 0000000..faaf3d9
--- /dev/null
+++ b/arch/v850/kernel/rte_me2_cb.c
@@ -0,0 +1,300 @@
+/*
+ * arch/v850/kernel/rte_me2_cb.c -- Midas labs RTE-V850E/ME2-CB board
+ *
+ *  Copyright (C) 2001,02,03  NEC Electronics Corporation
+ *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/irq.h>
+#include <linux/fs.h>
+#include <linux/major.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+
+#include <asm/atomic.h>
+#include <asm/page.h>
+#include <asm/me2.h>
+#include <asm/rte_me2_cb.h>
+#include <asm/machdep.h>
+#include <asm/v850e_intc.h>
+#include <asm/v850e_cache.h>
+#include <asm/irq.h>
+
+#include "mach.h"
+
+extern unsigned long *_intv_start;
+extern unsigned long *_intv_end;
+
+/* LED access routines.  */
+extern unsigned read_leds (int pos, char *buf, int len);
+extern unsigned write_leds (int pos, const char *buf, int len);
+
+
+/* SDRAM are almost contiguous (with a small hole in between;
+   see mach_reserve_bootmem for details), so just use both as one big area.  */
+#define RAM_START 	SDRAM_ADDR
+#define RAM_END		(SDRAM_ADDR + SDRAM_SIZE)
+
+
+void __init mach_get_physical_ram (unsigned long *ram_start,
+				   unsigned long *ram_len)
+{
+	*ram_start = RAM_START;
+	*ram_len = RAM_END - RAM_START;
+}
+
+void mach_gettimeofday (struct timespec *tv)
+{
+	tv->tv_sec = 0;
+	tv->tv_nsec = 0;
+}
+
+/* Called before configuring an on-chip UART.  */
+void rte_me2_cb_uart_pre_configure (unsigned chan,
+				    unsigned cflags, unsigned baud)
+{
+	/* The RTE-V850E/ME2-CB connects some general-purpose I/O
+	   pins on the CPU to the RTS/CTS lines of UARTB channel 0's
+	   serial connection.
+	   I/O pins P21 and P22 are RTS and CTS respectively.  */
+	if (chan == 0) {
+		/* Put P21 & P22 in I/O port mode.  */
+		ME2_PORT2_PMC &= ~0x6;
+		/* Make P21 and output, and P22 an input.  */
+		ME2_PORT2_PM = (ME2_PORT2_PM & ~0xC) | 0x4;
+	}
+
+	me2_uart_pre_configure (chan, cflags, baud);
+}
+
+void __init mach_init_irqs (void)
+{
+	/* Initialize interrupts.  */
+	me2_init_irqs ();
+	rte_me2_cb_init_irqs ();
+}
+
+#ifdef CONFIG_ROM_KERNEL
+/* Initialization for kernel in ROM.  */
+static inline rom_kernel_init (void)
+{
+	/* If the kernel is in ROM, we have to copy any initialized data
+	   from ROM into RAM.  */
+	extern unsigned long _data_load_start, _sdata, _edata;
+	register unsigned long *src = &_data_load_start;
+	register unsigned long *dst = &_sdata, *end = &_edata;
+
+	while (dst != end)
+		*dst++ = *src++;
+}
+#endif /* CONFIG_ROM_KERNEL */
+
+static void install_interrupt_vectors (void)
+{
+	unsigned long *p1, *p2;
+
+	ME2_IRAMM = 0x03; /* V850E/ME2 iRAM write mode */
+
+	/* vector copy to iRAM */
+	p1 = (unsigned long *)0; /* v85x vector start */
+	p2 = (unsigned long *)&_intv_start;
+	while (p2 < (unsigned long *)&_intv_end)
+		*p1++ = *p2++;
+
+	ME2_IRAMM = 0x00; /* V850E/ME2 iRAM read mode */
+}
+
+/* CompactFlash */
+
+static void cf_power_on (void)
+{
+	/* CF card detected? */
+	if (CB_CF_STS0 & 0x0030)
+		return;
+
+	CB_CF_REG0 = 0x0002; /* reest on */
+	mdelay (10);
+	CB_CF_REG0 = 0x0003; /* power on */
+	mdelay (10);
+	CB_CF_REG0 = 0x0001; /* reset off */
+	mdelay (10);
+}
+
+static void cf_power_off (void)
+{
+	CB_CF_REG0 = 0x0003; /* power on */
+	mdelay (10);
+	CB_CF_REG0 = 0x0002; /* reest on */
+	mdelay (10);
+}
+
+void __init mach_early_init (void)
+{
+	install_interrupt_vectors ();
+
+	/* CS1 SDRAM instruction cache enable */
+	v850e_cache_enable (0x04, 0x03, 0);
+
+	rte_cb_early_init ();
+
+	/* CompactFlash power on */
+	cf_power_on ();
+
+#if defined (CONFIG_ROM_KERNEL)
+	rom_kernel_init ();
+#endif
+}
+
+
+/* RTE-V850E/ME2-CB Programmable Interrupt Controller.  */
+
+static struct cb_pic_irq_init cb_pic_irq_inits[] = {
+	{ "CB_EXTTM0",       IRQ_CB_EXTTM0,       1, 1, 6 },
+	{ "CB_EXTSIO",       IRQ_CB_EXTSIO,       1, 1, 6 },
+	{ "CB_TOVER",        IRQ_CB_TOVER,        1, 1, 6 },
+	{ "CB_GINT0",        IRQ_CB_GINT0,        1, 1, 6 },
+	{ "CB_USB",          IRQ_CB_USB,          1, 1, 6 },
+	{ "CB_LANC",         IRQ_CB_LANC,         1, 1, 6 },
+	{ "CB_USB_VBUS_ON",  IRQ_CB_USB_VBUS_ON,  1, 1, 6 },
+	{ "CB_USB_VBUS_OFF", IRQ_CB_USB_VBUS_OFF, 1, 1, 6 },
+	{ "CB_EXTTM1",       IRQ_CB_EXTTM1,       1, 1, 6 },
+	{ "CB_EXTTM2",       IRQ_CB_EXTTM2,       1, 1, 6 },
+	{ 0 }
+};
+#define NUM_CB_PIC_IRQ_INITS  \
+   ((sizeof cb_pic_irq_inits / sizeof cb_pic_irq_inits[0]) - 1)
+
+static struct hw_interrupt_type cb_pic_hw_itypes[NUM_CB_PIC_IRQ_INITS];
+static unsigned char cb_pic_active_irqs = 0;
+
+void __init rte_me2_cb_init_irqs (void)
+{
+	cb_pic_init_irq_types (cb_pic_irq_inits, cb_pic_hw_itypes);
+
+	/* Initalize on board PIC1 (not PIC0) enable */
+	CB_PIC_INT0M  = 0x0000;
+	CB_PIC_INT1M  = 0x0000;
+	CB_PIC_INTR   = 0x0000;
+	CB_PIC_INTEN |= CB_PIC_INT1EN;
+
+	ME2_PORT2_PMC 	 |= 0x08;	/* INTP23/SCK1 mode */
+	ME2_PORT2_PFC 	 &= ~0x08;	/* INTP23 mode */
+	ME2_INTR(2) 	 &= ~0x08;	/* INTP23 falling-edge detect */
+	ME2_INTF(2) 	 &= ~0x08;	/*   " */
+
+	rte_cb_init_irqs ();	/* gbus &c */
+}
+
+
+/* Enable interrupt handling for interrupt IRQ.  */
+void cb_pic_enable_irq (unsigned irq)
+{
+	CB_PIC_INT1M |= 1 << (irq - CB_PIC_BASE_IRQ);
+}
+
+void cb_pic_disable_irq (unsigned irq)
+{
+	CB_PIC_INT1M &= ~(1 << (irq - CB_PIC_BASE_IRQ));
+}
+
+void cb_pic_shutdown_irq (unsigned irq)
+{
+	cb_pic_disable_irq (irq);
+
+	if (--cb_pic_active_irqs == 0)
+		free_irq (IRQ_CB_PIC, 0);
+
+	CB_PIC_INT1M &= ~(1 << (irq - CB_PIC_BASE_IRQ));
+}
+
+static irqreturn_t cb_pic_handle_irq (int irq, void *dev_id,
+				      struct pt_regs *regs)
+{
+	irqreturn_t rval = IRQ_NONE;
+	unsigned status = CB_PIC_INTR;
+	unsigned enable = CB_PIC_INT1M;
+
+	/* Only pay attention to enabled interrupts.  */
+	status &= enable;
+
+	CB_PIC_INTEN &= ~CB_PIC_INT1EN;
+
+	if (status) {
+		unsigned mask = 1;
+
+		irq = CB_PIC_BASE_IRQ;
+		do {
+			/* There's an active interrupt, find out which one,
+			   and call its handler.  */
+			while (! (status & mask)) {
+				irq++;
+				mask <<= 1;
+			}
+			status &= ~mask;
+
+			CB_PIC_INTR = mask;
+
+			/* Recursively call handle_irq to handle it. */
+			handle_irq (irq, regs);
+			rval = IRQ_HANDLED;
+		} while (status);
+	}
+
+	CB_PIC_INTEN |= CB_PIC_INT1EN;
+
+	return rval;
+}
+
+
+static void irq_nop (unsigned irq) { }
+
+static unsigned cb_pic_startup_irq (unsigned irq)
+{
+	int rval;
+
+	if (cb_pic_active_irqs == 0) {
+		rval = request_irq (IRQ_CB_PIC, cb_pic_handle_irq,
+				    SA_INTERRUPT, "cb_pic_handler", 0);
+		if (rval != 0)
+			return rval;
+	}
+
+	cb_pic_active_irqs++;
+
+	cb_pic_enable_irq (irq);
+
+	return 0;
+}
+
+/* Initialize HW_IRQ_TYPES for INTC-controlled irqs described in array
+   INITS (which is terminated by an entry with the name field == 0).  */
+void __init cb_pic_init_irq_types (struct cb_pic_irq_init *inits,
+				   struct hw_interrupt_type *hw_irq_types)
+{
+	struct cb_pic_irq_init *init;
+	for (init = inits; init->name; init++) {
+		struct hw_interrupt_type *hwit = hw_irq_types++;
+
+		hwit->typename = init->name;
+
+		hwit->startup  = cb_pic_startup_irq;
+		hwit->shutdown = cb_pic_shutdown_irq;
+		hwit->enable   = cb_pic_enable_irq;
+		hwit->disable  = cb_pic_disable_irq;
+		hwit->ack      = irq_nop;
+		hwit->end      = irq_nop;
+
+		/* Initialize kernel IRQ infrastructure for this interrupt.  */
+		init_irq_handlers(init->base, init->num, init->interval, hwit);
+	}
+}
diff --git a/arch/v850/kernel/rte_me2_cb.ld b/arch/v850/kernel/rte_me2_cb.ld
new file mode 100644
index 0000000..cf07660
--- /dev/null
+++ b/arch/v850/kernel/rte_me2_cb.ld
@@ -0,0 +1,30 @@
+/* Linker script for the Midas labs RTE-V850E/ME2-CB evaluation board
+   (CONFIG_RTE_CB_ME2), with kernel in SDRAM.  */
+
+MEMORY {
+	/* 128Kbyte of IRAM */
+	IRAM : ORIGIN = 0x00000000, LENGTH = 0x00020000
+
+	/* 32MB of SDRAM.  */
+	SDRAM : ORIGIN = SDRAM_ADDR, LENGTH = SDRAM_SIZE
+}
+
+#define KRAM SDRAM
+
+SECTIONS {
+	.text : {
+		__kram_start = . ;
+		TEXT_CONTENTS
+		INTV_CONTENTS	/* copy to iRAM (0x0-0x620) */
+	} > KRAM
+
+	.data : {
+		DATA_CONTENTS
+		BSS_CONTENTS
+		RAMK_INIT_CONTENTS
+		__kram_end = . ;
+		BOOTMAP_CONTENTS
+	} > KRAM
+	
+	.root ALIGN (4096) : { ROOT_FS_CONTENTS } > SDRAM
+}
diff --git a/arch/v850/kernel/rte_nb85e_cb-multi.ld b/arch/v850/kernel/rte_nb85e_cb-multi.ld
new file mode 100644
index 0000000..de347b4
--- /dev/null
+++ b/arch/v850/kernel/rte_nb85e_cb-multi.ld
@@ -0,0 +1,57 @@
+/* Linker script for the Midas labs RTE-NB85E-CB evaluation board
+   (CONFIG_RTE_CB_NB85E), with the Multi debugger ROM monitor .  */
+
+MEMORY {
+	/* 1MB of SRAM; we can't use the last 96KB, because it's used by
+	   the monitor scratch-RAM.  This memory is mirrored 4 times.  */
+	SRAM  : ORIGIN = SRAM_ADDR,  LENGTH = (SRAM_SIZE - MON_SCRATCH_SIZE)
+	/* Monitor scratch RAM; only the interrupt vectors should go here.  */
+	MRAM  : ORIGIN = MON_SCRATCH_ADDR,  LENGTH = MON_SCRATCH_SIZE
+	/* 16MB of SDRAM.  */
+	SDRAM : ORIGIN = SDRAM_ADDR, LENGTH = SDRAM_SIZE
+}
+
+#ifdef CONFIG_RTE_CB_NB85E_KSRAM
+# define KRAM SRAM
+#else
+# define KRAM SDRAM
+#endif
+
+SECTIONS {
+	/* We can't use RAMK_KRAM_CONTENTS because that puts the whole
+	   kernel in a single ELF segment, and the Multi debugger (which
+	   we use to load the kernel) appears to have bizarre problems
+	   dealing with it.  */
+
+	.text : {
+		__kram_start = . ;
+		TEXT_CONTENTS
+	} > KRAM
+
+	.data : {
+		DATA_CONTENTS
+		BSS_CONTENTS
+		RAMK_INIT_CONTENTS
+		__kram_end = . ;
+		BOOTMAP_CONTENTS
+
+		/* The address at which the interrupt vectors are initially
+		   loaded by the loader.  We can't load the interrupt vectors
+		   directly into their target location, because the monitor
+		   ROM for the GHS Multi debugger barfs if we try.
+		   Unfortunately, Multi also doesn't deal correctly with ELF
+		   sections where the LMA and VMA differ (it just ignores the
+		   LMA), so we can't use that feature to work around the
+		   problem!  What we do instead is just put the interrupt
+		   vectors into a normal section, and have the
+		   `mach_early_init' function for Midas boards do the
+		   necessary copying and relocation at runtime (this section
+		   basically only contains `jr' instructions, so it's not
+		   that hard).  */
+		. = ALIGN (0x10) ;
+		__intv_load_start = . ;
+		INTV_CONTENTS
+	} > KRAM
+
+	.root ALIGN (4096) : { ROOT_FS_CONTENTS } > SDRAM
+}
diff --git a/arch/v850/kernel/rte_nb85e_cb.c b/arch/v850/kernel/rte_nb85e_cb.c
new file mode 100644
index 0000000..990b20b
--- /dev/null
+++ b/arch/v850/kernel/rte_nb85e_cb.c
@@ -0,0 +1,82 @@
+/*
+ * arch/v850/kernel/rte_nb85e_cb.c -- Midas labs RTE-V850E/NB85E-CB board
+ *
+ *  Copyright (C) 2001,02,03  NEC Electronics Corporation
+ *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/bootmem.h>
+#include <linux/irq.h>
+
+#include <asm/atomic.h>
+#include <asm/page.h>
+#include <asm/v850e.h>
+#include <asm/rte_nb85e_cb.h>
+
+#include "mach.h"
+
+void __init mach_early_init (void)
+{
+	/* Configure caching; some possible settings:
+
+	     BHC = 0x0000, DCC = 0x0000	 -- all caching disabled
+	     BHC = 0x0040, DCC = 0x0000	 -- SDRAM: icache only
+	     BHC = 0x0080, DCC = 0x0C00	 -- SDRAM: write-back dcache only
+	     BHC = 0x00C0, DCC = 0x0C00	 -- SDRAM: icache + write-back dcache
+	     BHC = 0x00C0, DCC = 0x0800	 -- SDRAM: icache + write-thru dcache
+
+	   We can only cache SDRAM (we can't use cache SRAM because it's in
+	   the same memory region as the on-chip RAM and I/O space).
+
+	   Unfortunately, the dcache seems to be buggy, so we only use the
+	   icache for now.  */
+	v850e_cache_enable (0x0040 /*BHC*/, 0x0003 /*ICC*/, 0x0000 /*DCC*/);
+
+	rte_cb_early_init ();
+}
+
+void __init mach_get_physical_ram (unsigned long *ram_start,
+				   unsigned long *ram_len)
+{
+	/* We just use SDRAM here.  */
+	*ram_start = SDRAM_ADDR;
+	*ram_len = SDRAM_SIZE;
+}
+
+void mach_gettimeofday (struct timespec *tv)
+{
+	tv->tv_sec = 0;
+	tv->tv_nsec = 0;
+}
+
+/* Called before configuring an on-chip UART.  */
+void rte_nb85e_cb_uart_pre_configure (unsigned chan,
+				    unsigned cflags, unsigned baud)
+{
+	/* The RTE-NB85E-CB connects some general-purpose I/O pins on the
+	   CPU to the RTS/CTS lines the UART's serial connection, as follows:
+	   P00 = CTS (in), P01 = DSR (in), P02 = RTS (out), P03 = DTR (out). */
+
+	TEG_PORT0_PM = 0x03;	/* P00 and P01 inputs, P02 and P03 outputs */
+	TEG_PORT0_IO = 0x03;	/* Accept input */
+
+	/* Do pre-configuration for the actual UART.  */
+	teg_uart_pre_configure (chan, cflags, baud);
+}
+
+void __init mach_init_irqs (void)
+{
+	teg_init_irqs ();
+	rte_cb_init_irqs ();
+}
diff --git a/arch/v850/kernel/rte_nb85e_cb.ld b/arch/v850/kernel/rte_nb85e_cb.ld
new file mode 100644
index 0000000..b672f48
--- /dev/null
+++ b/arch/v850/kernel/rte_nb85e_cb.ld
@@ -0,0 +1,22 @@
+/* Linker script for the Midas labs RTE-NB85E-CB evaluation board
+   (CONFIG_RTE_CB_NB85E).  */
+
+MEMORY {
+	LOW   : ORIGIN = 0x0,	     LENGTH = 0x00100000
+	/* 1MB of SRAM  This memory is mirrored 4 times.  */
+	SRAM  : ORIGIN = SRAM_ADDR,  LENGTH = SRAM_SIZE
+	/* 16MB of SDRAM.  */
+	SDRAM : ORIGIN = SDRAM_ADDR, LENGTH = SDRAM_SIZE
+}
+
+#ifdef CONFIG_RTE_CB_NB85E_KSRAM
+# define KRAM SRAM
+#else
+# define KRAM SDRAM
+#endif
+
+SECTIONS {
+	.intv : { INTV_CONTENTS } > LOW
+	.sram : { RAMK_KRAM_CONTENTS } > KRAM
+	.root : { ROOT_FS_CONTENTS } > SDRAM
+}
diff --git a/arch/v850/kernel/semaphore.c b/arch/v850/kernel/semaphore.c
new file mode 100644
index 0000000..fc89fd6
--- /dev/null
+++ b/arch/v850/kernel/semaphore.c
@@ -0,0 +1,166 @@
+/*
+ * arch/v850/kernel/semaphore.c -- Semaphore support
+ *
+ *  Copyright (C) 1998-2000  IBM Corporation
+ *  Copyright (C) 1999  Linus Torvalds
+ *
+ * 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.
+ *
+ * This file is a copy of the s390 version, arch/s390/kernel/semaphore.c
+ *    Author(s): Martin Schwidefsky
+ * which was derived from the i386 version, linux/arch/i386/kernel/semaphore.c
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+
+#include <asm/semaphore.h>
+
+/*
+ * Semaphores are implemented using a two-way counter:
+ * The "count" variable is decremented for each process
+ * that tries to acquire the semaphore, while the "sleeping"
+ * variable is a count of such acquires.
+ *
+ * Notably, the inline "up()" and "down()" functions can
+ * efficiently test if they need to do any extra work (up
+ * needs to do something only if count was negative before
+ * the increment operation.
+ *
+ * "sleeping" and the contention routine ordering is
+ * protected by the semaphore spinlock.
+ *
+ * Note that these functions are only called when there is
+ * contention on the lock, and as such all this is the
+ * "non-critical" part of the whole semaphore business. The
+ * critical part is the inline stuff in <asm/semaphore.h>
+ * where we want to avoid any extra jumps and calls.
+ */
+
+/*
+ * Logic:
+ *  - only on a boundary condition do we need to care. When we go
+ *    from a negative count to a non-negative, we wake people up.
+ *  - when we go from a non-negative count to a negative do we
+ *    (a) synchronize with the "sleeper" count and (b) make sure
+ *    that we're on the wakeup list before we synchronize so that
+ *    we cannot lose wakeup events.
+ */
+
+void __up(struct semaphore *sem)
+{
+	wake_up(&sem->wait);
+}
+
+static DEFINE_SPINLOCK(semaphore_lock);
+
+void __sched __down(struct semaphore * sem)
+{
+	struct task_struct *tsk = current;
+	DECLARE_WAITQUEUE(wait, tsk);
+	tsk->state = TASK_UNINTERRUPTIBLE;
+	add_wait_queue_exclusive(&sem->wait, &wait);
+
+	spin_lock_irq(&semaphore_lock);
+	sem->sleepers++;
+	for (;;) {
+		int sleepers = sem->sleepers;
+
+		/*
+		 * Add "everybody else" into it. They aren't
+		 * playing, because we own the spinlock.
+		 */
+		if (!atomic_add_negative(sleepers - 1, &sem->count)) {
+			sem->sleepers = 0;
+			break;
+		}
+		sem->sleepers = 1;	/* us - see -1 above */
+		spin_unlock_irq(&semaphore_lock);
+
+		schedule();
+		tsk->state = TASK_UNINTERRUPTIBLE;
+		spin_lock_irq(&semaphore_lock);
+	}
+	spin_unlock_irq(&semaphore_lock);
+	remove_wait_queue(&sem->wait, &wait);
+	tsk->state = TASK_RUNNING;
+	wake_up(&sem->wait);
+}
+
+int __sched __down_interruptible(struct semaphore * sem)
+{
+	int retval = 0;
+	struct task_struct *tsk = current;
+	DECLARE_WAITQUEUE(wait, tsk);
+	tsk->state = TASK_INTERRUPTIBLE;
+	add_wait_queue_exclusive(&sem->wait, &wait);
+
+	spin_lock_irq(&semaphore_lock);
+	sem->sleepers ++;
+	for (;;) {
+		int sleepers = sem->sleepers;
+
+		/*
+		 * With signals pending, this turns into
+		 * the trylock failure case - we won't be
+		 * sleeping, and we* can't get the lock as
+		 * it has contention. Just correct the count
+		 * and exit.
+		 */
+		if (signal_pending(current)) {
+			retval = -EINTR;
+			sem->sleepers = 0;
+			atomic_add(sleepers, &sem->count);
+			break;
+		}
+
+		/*
+		 * Add "everybody else" into it. They aren't
+		 * playing, because we own the spinlock. The
+		 * "-1" is because we're still hoping to get
+		 * the lock.
+		 */
+		if (!atomic_add_negative(sleepers - 1, &sem->count)) {
+			sem->sleepers = 0;
+			break;
+		}
+		sem->sleepers = 1;	/* us - see -1 above */
+		spin_unlock_irq(&semaphore_lock);
+
+		schedule();
+		tsk->state = TASK_INTERRUPTIBLE;
+		spin_lock_irq(&semaphore_lock);
+	}
+	spin_unlock_irq(&semaphore_lock);
+	tsk->state = TASK_RUNNING;
+	remove_wait_queue(&sem->wait, &wait);
+	wake_up(&sem->wait);
+	return retval;
+}
+
+/*
+ * Trylock failed - make sure we correct for
+ * having decremented the count.
+ */
+int __down_trylock(struct semaphore * sem)
+{
+        unsigned long flags;
+	int sleepers;
+
+	spin_lock_irqsave(&semaphore_lock, flags);
+	sleepers = sem->sleepers + 1;
+	sem->sleepers = 0;
+
+	/*
+	 * Add "everybody else" and us into it. They aren't
+	 * playing, because we own the spinlock.
+	 */
+	if (!atomic_add_negative(sleepers, &sem->count))
+		wake_up(&sem->wait);
+
+	spin_unlock_irqrestore(&semaphore_lock, flags);
+	return 1;
+}
diff --git a/arch/v850/kernel/setup.c b/arch/v850/kernel/setup.c
new file mode 100644
index 0000000..c41d72b
--- /dev/null
+++ b/arch/v850/kernel/setup.c
@@ -0,0 +1,286 @@
+/*
+ * arch/v850/kernel/setup.c -- Arch-dependent initialization functions
+ *
+ *  Copyright (C) 2001,02,03  NEC Electronics Corporation
+ *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <linux/mm.h>
+#include <linux/bootmem.h>
+#include <linux/swap.h>		/* we don't have swap, but for nr_free_pages */
+#include <linux/irq.h>
+#include <linux/reboot.h>
+#include <linux/personality.h>
+#include <linux/major.h>
+#include <linux/root_dev.h>
+#include <linux/mtd/mtd.h>
+#include <linux/init.h>
+
+#include <asm/irq.h>
+#include <asm/setup.h>
+
+#include "mach.h"
+
+/* These symbols are all defined in the linker map to delineate various
+   statically allocated regions of memory.  */
+
+extern char _intv_start, _intv_end;
+/* `kram' is only used if the kernel uses part of normal user RAM.  */
+extern char _kram_start __attribute__ ((__weak__));
+extern char _kram_end __attribute__ ((__weak__));
+extern char _init_start, _init_end;
+extern char _bootmap;
+extern char _stext, _etext, _sdata, _edata, _sbss, _ebss;
+/* Many platforms use an embedded root image.  */
+extern char _root_fs_image_start __attribute__ ((__weak__));
+extern char _root_fs_image_end __attribute__ ((__weak__));
+
+
+char command_line[COMMAND_LINE_SIZE];
+
+/* Memory not used by the kernel.  */
+static unsigned long total_ram_pages;
+
+/* System RAM.  */
+static unsigned long ram_start = 0, ram_len = 0;
+
+
+#define ADDR_TO_PAGE_UP(x)   ((((unsigned long)x) + PAGE_SIZE-1) >> PAGE_SHIFT)
+#define ADDR_TO_PAGE(x)	     (((unsigned long)x) >> PAGE_SHIFT)
+#define PAGE_TO_ADDR(x)	     (((unsigned long)x) << PAGE_SHIFT)
+
+static void init_mem_alloc (unsigned long ram_start, unsigned long ram_len);
+
+void set_mem_root (void *addr, size_t len, char *cmd_line);
+
+
+void __init setup_arch (char **cmdline)
+{
+	/* Keep a copy of command line */
+	*cmdline = command_line;
+	memcpy (saved_command_line, command_line, COMMAND_LINE_SIZE);
+	saved_command_line[COMMAND_LINE_SIZE - 1] = '\0';
+
+	console_verbose ();
+
+	init_mm.start_code = (unsigned long) &_stext;
+	init_mm.end_code = (unsigned long) &_etext;
+	init_mm.end_data = (unsigned long) &_edata;
+	init_mm.brk = (unsigned long) &_kram_end;
+
+	/* Find out what mem this machine has.  */
+	mach_get_physical_ram (&ram_start, &ram_len);
+	/* ... and tell the kernel about it.  */
+	init_mem_alloc (ram_start, ram_len);
+
+	printk (KERN_INFO "CPU: %s\nPlatform: %s\n",
+		CPU_MODEL_LONG, PLATFORM_LONG);
+
+	/* do machine-specific setups.  */
+	mach_setup (cmdline);
+
+#ifdef CONFIG_MTD
+	if (!ROOT_DEV && &_root_fs_image_end > &_root_fs_image_start)
+		set_mem_root (&_root_fs_image_start,
+			      &_root_fs_image_end - &_root_fs_image_start,
+			      *cmdline);
+#endif
+}
+
+void __init trap_init (void)
+{
+}
+
+#ifdef CONFIG_MTD
+/* Set the root filesystem to be the given memory region.
+   Some parameter may be appended to CMD_LINE.  */
+void set_mem_root (void *addr, size_t len, char *cmd_line)
+{
+	/* The only way to pass info to the MTD slram driver is via
+	   the command line.  */
+	if (*cmd_line) {
+		cmd_line += strlen (cmd_line);
+		*cmd_line++ = ' ';
+	}
+	sprintf (cmd_line, "slram=root,0x%x,+0x%x", (u32)addr, (u32)len);
+
+	ROOT_DEV = MKDEV (MTD_BLOCK_MAJOR, 0);
+}
+#endif
+
+
+static void irq_nop (unsigned irq) { }
+static unsigned irq_zero (unsigned irq) { return 0; }
+
+static void nmi_end (unsigned irq)
+{
+	if (irq != IRQ_NMI (0)) {
+		printk (KERN_CRIT "NMI %d is unrecoverable; restarting...",
+			irq - IRQ_NMI (0));
+		machine_restart (0);
+	}
+}
+
+static struct hw_interrupt_type nmi_irq_type = {
+	"NMI",
+	irq_zero,		/* startup */
+	irq_nop,		/* shutdown */
+	irq_nop,		/* enable */
+	irq_nop,		/* disable */
+	irq_nop,		/* ack */
+	nmi_end,		/* end */
+};
+
+void __init init_IRQ (void)
+{
+	init_irq_handlers (0, NUM_MACH_IRQS, 1, 0);
+	init_irq_handlers (IRQ_NMI (0), NUM_NMIS, 1, &nmi_irq_type);
+	mach_init_irqs ();
+}
+
+
+void __init mem_init (void)
+{
+	max_mapnr = MAP_NR (ram_start + ram_len);
+
+	num_physpages = ADDR_TO_PAGE (ram_len);
+
+	total_ram_pages = free_all_bootmem ();
+
+	printk (KERN_INFO
+		"Memory: %luK/%luK available"
+		" (%luK kernel code, %luK data)\n",
+		PAGE_TO_ADDR (nr_free_pages()) / 1024,
+		ram_len / 1024,
+		((unsigned long)&_etext - (unsigned long)&_stext) / 1024,
+		((unsigned long)&_ebss - (unsigned long)&_sdata) / 1024);
+}
+
+void free_initmem (void)
+{
+	unsigned long ram_end = ram_start + ram_len;
+	unsigned long start = PAGE_ALIGN ((unsigned long)(&_init_start));
+
+	if (start >= ram_start && start < ram_end) {
+		unsigned long addr;
+		unsigned long end = PAGE_ALIGN ((unsigned long)(&_init_end));
+
+		if (end > ram_end)
+			end = ram_end;
+
+		printk("Freeing unused kernel memory: %ldK freed\n",
+		       (end - start) / 1024);
+
+		for (addr = start; addr < end; addr += PAGE_SIZE) {
+			struct page *page = virt_to_page (addr);
+			ClearPageReserved (page);
+			set_page_count (page, 1);
+			__free_page (page);
+			total_ram_pages++;
+		}
+	}
+}
+
+
+/* Initialize the `bootmem allocator'.  RAM_START and RAM_LEN identify
+   what RAM may be used.  */
+static void __init
+init_bootmem_alloc (unsigned long ram_start, unsigned long ram_len)
+{
+	/* The part of the kernel that's in the same managed RAM space
+	   used for general allocation.  */
+	unsigned long kram_start = (unsigned long)&_kram_start;
+	unsigned long kram_end = (unsigned long)&_kram_end;
+	/* End of the managed RAM space.  */
+	unsigned long ram_end = ram_start + ram_len;
+	/* Address range of the interrupt vector table.  */
+	unsigned long intv_start = (unsigned long)&_intv_start;
+	unsigned long intv_end = (unsigned long)&_intv_end;
+	/* True if the interrupt vectors are in the managed RAM area.  */
+	int intv_in_ram = (intv_end > ram_start && intv_start < ram_end);
+	/* True if the interrupt vectors are inside the kernel's RAM.  */
+	int intv_in_kram = (intv_end > kram_start && intv_start < kram_end);
+	/* A pointer to an optional function that reserves platform-specific
+	   memory regions.  We declare the pointer `volatile' to avoid gcc
+	   turning the call into a static call (the problem is that since
+	   it's a weak symbol, a static call may end up trying to reference
+	   the location 0x0, which is not always reachable).  */
+	void (*volatile mrb) (void) = mach_reserve_bootmem;
+	/* The bootmem allocator's allocation bitmap.  */
+	unsigned long bootmap = (unsigned long)&_bootmap;
+	unsigned long bootmap_len;
+
+	/* Round bootmap location up to next page.  */
+	bootmap = PAGE_TO_ADDR (ADDR_TO_PAGE_UP (bootmap));
+
+	/* Initialize bootmem allocator.  */
+	bootmap_len = init_bootmem_node (NODE_DATA (0),
+					 ADDR_TO_PAGE (bootmap),
+					 ADDR_TO_PAGE (PAGE_OFFSET),
+					 ADDR_TO_PAGE (ram_end));
+
+	/* Now make the RAM actually allocatable (it starts out `reserved'). */
+	free_bootmem (ram_start, ram_len);
+
+	if (kram_end > kram_start)
+		/* Reserve the RAM part of the kernel's address space, so it
+		   doesn't get allocated.  */
+		reserve_bootmem (kram_start, kram_end - kram_start);
+	
+	if (intv_in_ram && !intv_in_kram)
+		/* Reserve the interrupt vector space.  */
+		reserve_bootmem (intv_start, intv_end - intv_start);
+
+	if (bootmap >= ram_start && bootmap < ram_end)
+		/* Reserve the bootmap space.  */
+		reserve_bootmem (bootmap, bootmap_len);
+
+	/* Reserve the memory used by the root filesystem image if it's
+	   in RAM.  */
+	if (&_root_fs_image_end > &_root_fs_image_start
+	    && (unsigned long)&_root_fs_image_start >= ram_start
+	    && (unsigned long)&_root_fs_image_start < ram_end)
+		reserve_bootmem ((unsigned long)&_root_fs_image_start,
+				 &_root_fs_image_end - &_root_fs_image_start);
+
+	/* Let the platform-dependent code reserve some too.  */
+	if (mrb)
+		(*mrb) ();
+}
+
+/* Tell the kernel about what RAM it may use for memory allocation.  */
+static void __init
+init_mem_alloc (unsigned long ram_start, unsigned long ram_len)
+{
+	unsigned i;
+	unsigned long zones_size[MAX_NR_ZONES];
+
+	init_bootmem_alloc (ram_start, ram_len);
+
+	for (i = 0; i < MAX_NR_ZONES; i++)
+		zones_size[i] = 0;
+
+	/* We stuff all the memory into one area, which includes the
+	   initial gap from PAGE_OFFSET to ram_start.  */
+	zones_size[ZONE_DMA]
+		= ADDR_TO_PAGE (ram_len + (ram_start - PAGE_OFFSET));
+
+	/* The allocator is very picky about the address of the first
+	   allocatable page -- it must be at least as aligned as the
+	   maximum allocation -- so try to detect cases where it will get
+	   confused and signal them at compile time (this is a common
+	   problem when porting to a new platform with ).  There is a
+	   similar runtime check in free_area_init_core.  */
+#if ((PAGE_OFFSET >> PAGE_SHIFT) & ((1UL << (MAX_ORDER - 1)) - 1))
+#error MAX_ORDER is too large for given PAGE_OFFSET (use CONFIG_FORCE_MAX_ZONEORDER to change it)
+#endif
+	NODE_DATA(0)->node_mem_map = NULL;
+	free_area_init_node (0, NODE_DATA(0), zones_size,
+			     ADDR_TO_PAGE (PAGE_OFFSET), 0);
+}
diff --git a/arch/v850/kernel/signal.c b/arch/v850/kernel/signal.c
new file mode 100644
index 0000000..37061e3
--- /dev/null
+++ b/arch/v850/kernel/signal.c
@@ -0,0 +1,525 @@
+/*
+ * arch/v850/kernel/signal.c -- Signal handling
+ *
+ *  Copyright (C) 2001,02,03  NEC Electronics Corporation
+ *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
+ *  Copyright (C) 1999,2000,2002  Niibe Yutaka & Kaz Kojima
+ *  Copyright (C) 1991,1992  Linus Torvalds
+ *
+ * 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.
+ *
+ * 1997-11-28  Modified for POSIX.1b signals by Richard Henderson
+ *
+ * This file was derived from the sh version, arch/sh/kernel/signal.c
+ */
+
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/unistd.h>
+#include <linux/stddef.h>
+#include <linux/personality.h>
+#include <linux/tty.h>
+
+#include <asm/ucontext.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/thread_info.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, 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->gpr[GPR_RVAL] = -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,
+		  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->gpr[GPR_RVAL] = -EINTR;
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		if (do_signal(regs, &saveset))
+			return -EINTR;
+	}
+}
+
+asmlinkage int 
+sys_sigaction(int sig, const struct old_sigaction *act,
+	      struct old_sigaction *oact)
+{
+	struct k_sigaction new_ka, old_ka;
+	int ret;
+
+	if (act) {
+		old_sigset_t mask;
+		if (!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 *uss, stack_t *uoss,
+		struct pt_regs *regs)
+{
+	return do_sigaltstack(uss, uoss, regs->gpr[GPR_SP]);
+}
+
+
+/*
+ * Do a signal return; undo the signal stack.
+ */
+
+struct sigframe
+{
+	struct sigcontext sc;
+	unsigned long extramask[_NSIG_WORDS-1];
+	unsigned long tramp[2];	/* signal trampoline */
+};
+
+struct rt_sigframe
+{
+	struct siginfo info;
+	struct ucontext uc;
+	unsigned long tramp[2];	/* signal trampoline */
+};
+
+static int
+restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, int *rval_p)
+{
+	unsigned int err = 0;
+
+#define COPY(x)		err |= __get_user(regs->x, &sc->regs.x)
+	COPY(gpr[0]);	COPY(gpr[1]);	COPY(gpr[2]);	COPY(gpr[3]);
+	COPY(gpr[4]);	COPY(gpr[5]);	COPY(gpr[6]);	COPY(gpr[7]);
+	COPY(gpr[8]);	COPY(gpr[9]);	COPY(gpr[10]);	COPY(gpr[11]);
+	COPY(gpr[12]);	COPY(gpr[13]);	COPY(gpr[14]);	COPY(gpr[15]);
+	COPY(gpr[16]);	COPY(gpr[17]);	COPY(gpr[18]);	COPY(gpr[19]);
+	COPY(gpr[20]);	COPY(gpr[21]);	COPY(gpr[22]);	COPY(gpr[23]);
+	COPY(gpr[24]);	COPY(gpr[25]);	COPY(gpr[26]);	COPY(gpr[27]);
+	COPY(gpr[28]);	COPY(gpr[29]);	COPY(gpr[30]);	COPY(gpr[31]);
+	COPY(pc);	COPY(psw);
+	COPY(ctpc);	COPY(ctpsw);	COPY(ctbp);
+#undef COPY
+
+	return err;
+}
+
+asmlinkage int sys_sigreturn(struct pt_regs *regs)
+{
+	struct sigframe *frame = (struct sigframe *)regs->gpr[GPR_SP];
+	sigset_t set;
+	int rval;
+
+	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, &rval))
+		goto badframe;
+	return rval;
+
+badframe:
+	force_sig(SIGSEGV, current);
+	return 0;
+}
+
+asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
+{
+	struct rt_sigframe *frame = (struct rt_sigframe *)regs->gpr[GPR_SP];
+	sigset_t set;
+	stack_t st;
+	int rval;
+
+	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, &rval))
+		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->gpr[GPR_SP]);
+
+	return rval;
+
+badframe:
+	force_sig(SIGSEGV, current);
+	return 0;
+}	
+
+/*
+ * Set up a signal frame.
+ */
+
+static int
+setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
+		 unsigned long mask)
+{
+	int err = 0;
+
+#define COPY(x)		err |= __put_user(regs->x, &sc->regs.x)
+	COPY(gpr[0]);	COPY(gpr[1]);	COPY(gpr[2]);	COPY(gpr[3]);
+	COPY(gpr[4]);	COPY(gpr[5]);	COPY(gpr[6]);	COPY(gpr[7]);
+	COPY(gpr[8]);	COPY(gpr[9]);	COPY(gpr[10]);	COPY(gpr[11]);
+	COPY(gpr[12]);	COPY(gpr[13]);	COPY(gpr[14]);	COPY(gpr[15]);
+	COPY(gpr[16]);	COPY(gpr[17]);	COPY(gpr[18]);	COPY(gpr[19]);
+	COPY(gpr[20]);	COPY(gpr[21]);	COPY(gpr[22]);	COPY(gpr[23]);
+	COPY(gpr[24]);	COPY(gpr[25]);	COPY(gpr[26]);	COPY(gpr[27]);
+	COPY(gpr[28]);	COPY(gpr[29]);	COPY(gpr[30]);	COPY(gpr[31]);
+	COPY(pc);	COPY(psw);
+	COPY(ctpc);	COPY(ctpsw);	COPY(ctbp);
+#undef COPY
+
+	err |= __put_user(mask, &sc->oldmask);
+
+	return err;
+}
+
+/*
+ * Determine which stack to use..
+ */
+static inline void *
+get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
+{
+	/* Default to using normal stack */
+	unsigned long sp = regs->gpr[GPR_SP];
+
+	if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! on_sig_stack(sp))
+		sp = current->sas_ss_sp + current->sas_ss_size;
+
+	return (void *)((sp - frame_size) & -8UL);
+}
+
+static void setup_frame(int sig, struct k_sigaction *ka,
+			sigset_t *set, struct pt_regs *regs)
+{
+	struct sigframe *frame;
+	int err = 0;
+	int signal;
+
+	frame = get_sigframe(ka, regs, 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->gpr[GPR_LP] = (unsigned long) ka->sa.sa_restorer;
+	} else {
+		/* Note, these encodings are _little endian_!  */
+
+		/* addi  __NR_sigreturn, r0, r12  */
+		err |= __put_user(0x6600 | (__NR_sigreturn << 16),
+				  frame->tramp + 0);
+		/* trap 0 */
+		err |= __put_user(0x010007e0,
+				  frame->tramp + 1);
+
+		regs->gpr[GPR_LP] = (unsigned long)frame->tramp;
+
+		flush_cache_sigtramp (regs->gpr[GPR_LP]);
+	}
+
+	if (err)
+		goto give_sigsegv;
+
+	/* Set up registers for signal handler.  */
+	regs->pc = (v850_reg_t) ka->sa.sa_handler;
+	regs->gpr[GPR_SP] = (v850_reg_t)frame;
+	/* Signal handler args:  */
+	regs->gpr[GPR_ARG0] = signal; /* arg 0: signum */
+	regs->gpr[GPR_ARG1] = (v850_reg_t)&frame->sc;/* arg 1: sigcontext */
+
+	set_fs(USER_DS);
+
+#if DEBUG_SIG
+	printk("SIG deliver (%s:%d): sp=%p pc=%08lx ra=%08lx\n",
+		current->comm, current->pid, frame, regs->pc, );
+#endif
+
+	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 *frame;
+	int err = 0;
+	int signal;
+
+	frame = get_sigframe(ka, regs, 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->gpr[GPR_SP]),
+			  &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->gpr[GPR_LP] = (unsigned long) ka->sa.sa_restorer;
+	} else {
+		/* Note, these encodings are _little endian_!  */
+
+		/* addi  __NR_sigreturn, r0, r12  */
+		err |= __put_user(0x6600 | (__NR_sigreturn << 16),
+				  frame->tramp + 0);
+		/* trap 0 */
+		err |= __put_user(0x010007e0,
+				  frame->tramp + 1);
+
+		regs->gpr[GPR_LP] = (unsigned long)frame->tramp;
+
+		flush_cache_sigtramp (regs->gpr[GPR_LP]);
+	}
+
+	if (err)
+		goto give_sigsegv;
+
+	/* Set up registers for signal handler.  */
+	regs->pc = (v850_reg_t) ka->sa.sa_handler;
+	regs->gpr[GPR_SP] = (v850_reg_t)frame;
+	/* Signal handler args:  */
+	regs->gpr[GPR_ARG0] = signal; /* arg 0: signum */
+	regs->gpr[GPR_ARG1] = (v850_reg_t)&frame->info; /* arg 1: siginfo */
+	regs->gpr[GPR_ARG2] = (v850_reg_t)&frame->uc; /* arg 2: ucontext */
+
+	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
+
+	return;
+
+give_sigsegv:
+	force_sigsegv(sig, current);
+}
+
+/*
+ * OK, we're invoking a handler
+ */	
+
+static void
+handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
+	      sigset_t *oldset,	struct pt_regs * regs)
+{
+	/* Are we from a system call? */
+	if (PT_REGS_SYSCALL (regs)) {
+		/* If so, check system call restarting.. */
+		switch (regs->gpr[GPR_RVAL]) {
+		case -ERESTART_RESTARTBLOCK:
+			current_thread_info()->restart_block.fn =
+				do_no_restart_syscall;
+			/* fall through */
+		case -ERESTARTNOHAND:
+			regs->gpr[GPR_RVAL] = -EINTR;
+			break;
+
+		case -ERESTARTSYS:
+			if (!(ka->sa.sa_flags & SA_RESTART)) {
+				regs->gpr[GPR_RVAL] = -EINTR;
+				break;
+			}
+			/* fallthrough */
+		case -ERESTARTNOINTR:
+			regs->gpr[12] = PT_REGS_SYSCALL (regs);
+			regs->pc -= 4; /* Size of `trap 0' insn.  */
+		}
+
+		PT_REGS_SET_SYSCALL (regs, 0);
+	}
+
+	/* 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_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 (!oldset)
+		oldset = &current->blocked;
+
+	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+	if (signr > 0) {
+		/* Whee!  Actually deliver the signal.  */
+		handle_signal(signr, &info, &ka, oldset, regs);
+		return 1;
+	}
+
+	/* Did we come from a system call? */
+	if (PT_REGS_SYSCALL (regs)) {
+		int rval = (int)regs->gpr[GPR_RVAL];
+		/* Restart the system call - no handlers present */
+		if (rval == -ERESTARTNOHAND
+		    || rval == -ERESTARTSYS
+		    || rval == -ERESTARTNOINTR)
+		{
+			regs->gpr[12] = PT_REGS_SYSCALL (regs);
+			regs->pc -= 4; /* Size of `trap 0' insn.  */
+		}
+		else if (rval == -ERESTART_RESTARTBLOCK) {
+			regs->gpr[12] = __NR_restart_syscall;
+			regs->pc -= 4; /* Size of `trap 0' insn.  */
+		}
+	}
+	return 0;
+}
diff --git a/arch/v850/kernel/sim.c b/arch/v850/kernel/sim.c
new file mode 100644
index 0000000..4f31da9
--- /dev/null
+++ b/arch/v850/kernel/sim.c
@@ -0,0 +1,179 @@
+/*
+ * arch/v850/kernel/sim.c -- Machine-specific stuff for GDB v850e simulator
+ *
+ *  Copyright (C) 2001,02  NEC Corporation
+ *  Copyright (C) 2001,02  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/bootmem.h>
+#include <linux/irq.h>
+
+#include <asm/atomic.h>
+#include <asm/page.h>
+#include <asm/machdep.h>
+#include <asm/simsyscall.h>
+
+#include "mach.h"
+
+/* The name of a file containing the root filesystem.  */
+#define ROOT_FS "rootfs.image"
+
+extern void simcons_setup (void);
+extern void simcons_poll_ttys (void);
+extern void set_mem_root (void *addr, size_t len, char *cmd_line);
+
+static int read_file (const char *name,
+		      unsigned long *addr, unsigned long *len,
+		      const char **err);
+
+void __init mach_setup (char **cmdline)
+{
+	const char *err;
+	unsigned long root_dev_addr, root_dev_len;
+
+	simcons_setup ();
+
+	printk (KERN_INFO "Reading root filesystem: %s", ROOT_FS);
+
+	if (read_file (ROOT_FS, &root_dev_addr, &root_dev_len, &err)) {
+		printk (" (size %luK)\n", root_dev_len / 1024);
+		set_mem_root ((void *)root_dev_addr, (size_t)root_dev_len,
+			      *cmdline);
+	} else
+		printk ("...%s failed!\n", err);
+}
+
+void mach_get_physical_ram (unsigned long *ram_start, unsigned long *ram_len)
+{
+	*ram_start = RAM_ADDR;
+	*ram_len = RAM_SIZE;
+}
+
+void __init mach_sched_init (struct irqaction *timer_action)
+{
+	/* ...do magic timer initialization?...  */
+	mach_tick = simcons_poll_ttys;
+	setup_irq (0, timer_action);
+}
+
+
+static void irq_nop (unsigned irq) { }
+static unsigned irq_zero (unsigned irq) { return 0; }
+
+static struct hw_interrupt_type sim_irq_type = {
+	"IRQ",
+	irq_zero,		/* startup */
+	irq_nop,		/* shutdown */
+	irq_nop,		/* enable */
+	irq_nop,		/* disable */
+	irq_nop,		/* ack */
+	irq_nop,		/* end */
+};
+
+void __init mach_init_irqs (void)
+{
+	init_irq_handlers (0, NUM_MACH_IRQS, 1, &sim_irq_type);
+}
+
+
+void mach_gettimeofday (struct timespec *tv)
+{
+	long timeval[2], timezone[2];
+	int rval = V850_SIM_SYSCALL (gettimeofday, timeval, timezone);
+	if (rval == 0) {
+		tv->tv_sec = timeval[0];
+		tv->tv_nsec = timeval[1] * 1000;
+	}
+}
+
+void machine_restart (char *__unused)
+{
+	V850_SIM_SYSCALL (write, 1, "RESTART\n", 8);
+	V850_SIM_SYSCALL (exit, 0);
+}
+
+EXPORT_SYMBOL(machine_restart);
+
+void machine_halt (void)
+{
+	V850_SIM_SYSCALL (write, 1, "HALT\n", 5);
+	V850_SIM_SYSCALL (exit, 0);
+}
+
+EXPORT_SYMBOL(machine_halt);
+
+void machine_power_off (void)
+{
+	V850_SIM_SYSCALL (write, 1, "POWER OFF\n", 10);
+	V850_SIM_SYSCALL (exit, 0);
+}
+
+EXPORT_SYMBOL(machine_power_off);
+
+
+/* Load data from a file called NAME into ram.  The address and length
+   of the data image are returned in ADDR and LEN.  */
+static int __init
+read_file (const char *name,
+	   unsigned long *addr, unsigned long *len,
+	   const char **err)
+{
+	int rval, fd;
+	unsigned long cur, left;
+	/* Note this is not a normal stat buffer, it's an ad-hoc
+	   structure defined by the simulator.  */
+	unsigned long stat_buf[10];
+
+	/* Stat the file to find out the length.  */
+	rval = V850_SIM_SYSCALL (stat, name, stat_buf);
+	if (rval < 0) {
+		if (err) *err = "stat";
+		return 0;
+	}
+	*len = stat_buf[4];
+
+	/* Open the file; `0' is O_RDONLY.  */
+	fd = V850_SIM_SYSCALL (open, name, 0);
+	if (fd < 0) {
+		if (err) *err = "open";
+		return 0;
+	}
+
+	*addr = (unsigned long)alloc_bootmem(*len);
+	if (! *addr) {
+		V850_SIM_SYSCALL (close, fd);
+		if (err) *err = "alloc_bootmem";
+		return 0;
+	}
+
+	cur = *addr;
+	left = *len;
+	while (left > 0) {
+		int chunk = V850_SIM_SYSCALL (read, fd, cur, left);
+		if (chunk <= 0)
+			break;
+		cur += chunk;
+		left -= chunk;
+	}
+	V850_SIM_SYSCALL (close, fd);
+	if (left > 0) {
+		/* Some read failed.  */
+		free_bootmem (*addr, *len);
+		if (err) *err = "read";
+		return 0;
+	}
+
+	return 1;
+}
diff --git a/arch/v850/kernel/sim.ld b/arch/v850/kernel/sim.ld
new file mode 100644
index 0000000..101885f
--- /dev/null
+++ b/arch/v850/kernel/sim.ld
@@ -0,0 +1,13 @@
+/* Linker script for the gdb v850e simulator (CONFIG_V850E_SIM).  */
+
+MEMORY {
+	/* Interrupt vectors.  */
+	INTV  : ORIGIN = 0x0, LENGTH = 0xe0
+	/* Main RAM.  */
+	RAM   : ORIGIN = RAM_ADDR, LENGTH = RAM_SIZE
+}
+
+SECTIONS {
+	.intv : { INTV_CONTENTS } > INTV
+	.ram : { RAMK_KRAM_CONTENTS } > RAM
+}
diff --git a/arch/v850/kernel/sim85e2.c b/arch/v850/kernel/sim85e2.c
new file mode 100644
index 0000000..93a722b
--- /dev/null
+++ b/arch/v850/kernel/sim85e2.c
@@ -0,0 +1,201 @@
+/*
+ * arch/v850/kernel/sim85e2.c -- Machine-specific stuff for
+ *	V850E2 RTL simulator
+ *
+ *  Copyright (C) 2002,03  NEC Electronics Corporation
+ *  Copyright (C) 2002,03  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/bootmem.h>
+#include <linux/irq.h>
+
+#include <asm/atomic.h>
+#include <asm/page.h>
+#include <asm/machdep.h>
+
+#include "mach.h"
+
+
+/* There are 4 possible areas we can use:
+
+     IRAM (1MB) is fast for instruction fetches, but slow for data
+     DRAM (1020KB) is fast for data, but slow for instructions
+     ERAM is cached, so should be fast for both insns and data
+     SDRAM is external DRAM, similar to ERAM
+*/
+
+#define INIT_MEMC_FOR_SDRAM
+#define USE_SDRAM_AREA
+#define KERNEL_IN_SDRAM_AREA
+
+#define DCACHE_MODE	V850E2_CACHE_BTSC_DCM_WT
+/*#define DCACHE_MODE	V850E2_CACHE_BTSC_DCM_WB_ALLOC*/
+
+#ifdef USE_SDRAM_AREA
+#define RAM_START 	SDRAM_ADDR
+#define RAM_END		(SDRAM_ADDR + SDRAM_SIZE)
+#else
+/* When we use DRAM, we need to account for the fact that the end of it is
+   used for R0_RAM.  */
+#define RAM_START	DRAM_ADDR
+#define RAM_END		R0_RAM_ADDR
+#endif
+
+
+extern void memcons_setup (void);
+
+
+#ifdef KERNEL_IN_SDRAM_AREA
+#define EARLY_INIT_SECTION_ATTR __attribute__ ((section (".early.text")))
+#else
+#define EARLY_INIT_SECTION_ATTR __init
+#endif
+
+void EARLY_INIT_SECTION_ATTR mach_early_init (void)
+{
+	/* The sim85e2 simulator tracks `undefined' values, so to make
+	   debugging easier, we begin by zeroing out all otherwise
+	   undefined registers.  This is not strictly necessary.
+
+	   The registers we zero are:
+	       Every GPR except:
+	           stack-pointer (r3)
+		   task-pointer (r16)
+		   our return addr (r31)
+	       Every system register (SPR) that we know about except for
+	       the PSW (SPR 5), which we zero except for the
+	       disable-interrupts bit.
+	*/
+
+	/* GPRs */
+	asm volatile ("             mov r0, r1 ; mov r0, r2              ");
+	asm volatile ("mov r0, r4 ; mov r0, r5 ; mov r0, r6 ; mov r0, r7 ");
+	asm volatile ("mov r0, r8 ; mov r0, r9 ; mov r0, r10; mov r0, r11");
+	asm volatile ("mov r0, r12; mov r0, r13; mov r0, r14; mov r0, r15");
+	asm volatile ("             mov r0, r17; mov r0, r18; mov r0, r19");
+	asm volatile ("mov r0, r20; mov r0, r21; mov r0, r22; mov r0, r23");
+	asm volatile ("mov r0, r24; mov r0, r25; mov r0, r26; mov r0, r27");
+	asm volatile ("mov r0, r28; mov r0, r29; mov r0, r30");
+
+	/* SPRs */
+	asm volatile ("ldsr r0, 0;  ldsr r0, 1;  ldsr r0, 2;  ldsr r0, 3");
+	asm volatile ("ldsr r0, 4");
+	asm volatile ("addi 0x20, r0, r1; ldsr r1, 5"); /* PSW */
+	asm volatile ("ldsr r0, 16; ldsr r0, 17; ldsr r0, 18; ldsr r0, 19");
+	asm volatile ("ldsr r0, 20");
+
+
+#ifdef INIT_MEMC_FOR_SDRAM
+	/* Settings for SDRAM controller.  */
+	V850E2_VSWC   = 0x0042;
+	V850E2_BSC    = 0x9286;
+	V850E2_BCT(0) = 0xb000;	/* was: 0 */
+	V850E2_BCT(1) = 0x000b;
+	V850E2_ASC    = 0;
+	V850E2_LBS    = 0xa9aa;	/* was: 0xaaaa */
+	V850E2_LBC(0) = 0;
+	V850E2_LBC(1) = 0;	/* was: 0x3 */
+	V850E2_BCC    = 0;
+	V850E2_RFS(4) = 0x800a;	/* was: 0xf109 */
+	V850E2_SCR(4) = 0x2091;	/* was: 0x20a1 */
+	V850E2_RFS(3) = 0x800c;
+	V850E2_SCR(3) = 0x20a1;
+	V850E2_DWC(0) = 0;
+	V850E2_DWC(1) = 0;
+#endif
+
+#if 0
+#ifdef CONFIG_V850E2_SIM85E2S
+	/* Turn on the caches.  */
+	V850E2_CACHE_BTSC = V850E2_CACHE_BTSC_ICM | DCACHE_MODE;
+	V850E2_BHC  = 0x1010;
+#elif CONFIG_V850E2_SIM85E2C
+	V850E2_CACHE_BTSC |= (V850E2_CACHE_BTSC_ICM | V850E2_CACHE_BTSC_DCM0);
+	V850E2_BUSM_BHC = 0xFFFF;
+#endif
+#else
+	V850E2_BHC  = 0;
+#endif
+
+	/* Don't stop the simulator at `halt' instructions.  */
+	SIM85E2_NOTHAL = 1;
+
+	/* Ensure that the simulator halts on a panic, instead of going
+	   into an infinite loop inside the panic function.  */
+	panic_timeout = -1;
+}
+
+void __init mach_setup (char **cmdline)
+{
+	memcons_setup ();
+}
+
+void mach_get_physical_ram (unsigned long *ram_start, unsigned long *ram_len)
+{
+	*ram_start = RAM_START;
+	*ram_len = RAM_END - RAM_START;
+}
+
+void __init mach_sched_init (struct irqaction *timer_action)
+{
+	/* The simulator actually cycles through all interrupts
+	   periodically.  We just pay attention to IRQ0, which gives us
+	   1/64 the rate of the periodic interrupts.  */
+	setup_irq (0, timer_action);
+}
+
+void mach_gettimeofday (struct timespec *tv)
+{
+	tv->tv_sec = 0;
+	tv->tv_nsec = 0;
+}
+
+/* Interrupts */
+
+struct v850e_intc_irq_init irq_inits[] = {
+	{ "IRQ", 0, NUM_MACH_IRQS, 1, 7 },
+	{ 0 }
+};
+struct hw_interrupt_type hw_itypes[1];
+
+/* Initialize interrupts.  */
+void __init mach_init_irqs (void)
+{
+	v850e_intc_init_irq_types (irq_inits, hw_itypes);
+}
+
+
+void machine_halt (void) __attribute__ ((noreturn));
+void machine_halt (void)
+{
+	SIM85E2_SIMFIN = 0;	/* Halt immediately.  */
+	for (;;) {}
+}
+
+EXPORT_SYMBOL(machine_halt);
+
+void machine_restart (char *__unused)
+{
+	machine_halt ();
+}
+
+EXPORT_SYMBOL(machine_restart);
+
+void machine_power_off (void)
+{
+	machine_halt ();
+}
+
+EXPORT_SYMBOL(machine_power_off);
diff --git a/arch/v850/kernel/sim85e2.ld b/arch/v850/kernel/sim85e2.ld
new file mode 100644
index 0000000..7470fd2
--- /dev/null
+++ b/arch/v850/kernel/sim85e2.ld
@@ -0,0 +1,36 @@
+/* Linker script for the sim85e2c simulator, which is a verilog simulation of
+   the V850E2 NA85E2C cpu core (CONFIG_V850E2_SIM85E2C).  */
+
+MEMORY {
+	/* 1MB of `instruction RAM', starting at 0.
+	   Instruction fetches are much faster from IRAM than from DRAM.  */
+	IRAM : ORIGIN = IRAM_ADDR, LENGTH = IRAM_SIZE
+
+	/* 1MB of `data RAM', below and contiguous with the I/O space.
+	   Data fetches are much faster from DRAM than from IRAM.  */
+	DRAM : ORIGIN = DRAM_ADDR, LENGTH = DRAM_SIZE
+
+	/* `external ram' (CS1 area), comes after IRAM.  */
+	ERAM : ORIGIN = ERAM_ADDR, LENGTH = ERAM_SIZE
+
+	/* Dynamic RAM; uses memory controller.  */
+	SDRAM : ORIGIN = SDRAM_ADDR, LENGTH = SDRAM_SIZE
+}
+
+SECTIONS {
+	.iram : {
+		INTV_CONTENTS
+		*arch/v850/kernel/head.o
+		*(.early.text)
+	} > IRAM
+	.dram : {
+		_memcons_output = . ;
+		. = . + 0x8000 ;
+		_memcons_output_end = . ;
+	} > DRAM
+	.sdram : {
+		/* We stick console output into a buffer here.  */
+		RAMK_KRAM_CONTENTS
+		ROOT_FS_CONTENTS
+	} > SDRAM
+}
diff --git a/arch/v850/kernel/simcons.c b/arch/v850/kernel/simcons.c
new file mode 100644
index 0000000..7f0efaa
--- /dev/null
+++ b/arch/v850/kernel/simcons.c
@@ -0,0 +1,166 @@
+/*
+ * arch/v850/kernel/simcons.c -- Console I/O for GDB v850e simulator
+ *
+ *  Copyright (C) 2001,02,03  NEC Electronics Corporation
+ *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/tty_driver.h>
+#include <linux/init.h>
+
+#include <asm/poll.h>
+#include <asm/string.h>
+#include <asm/simsyscall.h>
+
+
+/*  Low-level console. */
+
+static void simcons_write (struct console *co, const char *buf, unsigned len)
+{
+	V850_SIM_SYSCALL (write, 1, buf, len);
+}
+
+static int simcons_read (struct console *co, char *buf, unsigned len)
+{
+	return V850_SIM_SYSCALL (read, 0, buf, len);
+}
+
+static struct tty_driver *tty_driver;
+static struct tty_driver *simcons_device (struct console *c, int *index)
+{
+	*index = c->index;
+	return tty_driver;
+}
+
+static struct console simcons =
+{
+    .name	= "simcons",
+    .write	= simcons_write,
+    .read	= simcons_read,
+    .device	= simcons_device,
+    .flags	= CON_PRINTBUFFER,
+    .index	= -1,
+};
+
+/* Higher level TTY interface.  */
+
+int simcons_tty_open (struct tty_struct *tty, struct file *filp)
+{
+	return 0;
+}
+
+int simcons_tty_write (struct tty_struct *tty,
+		       const unsigned char *buf, int count)
+{
+	return V850_SIM_SYSCALL (write, 1, buf, count);
+}
+
+int simcons_tty_write_room (struct tty_struct *tty)
+{
+	/* Completely arbitrary.  */
+	return 0x100000;
+}
+
+int simcons_tty_chars_in_buffer (struct tty_struct *tty)
+{
+	/* We have no buffer.  */
+	return 0;
+}
+
+static struct tty_operations ops = {
+	.open = simcons_tty_open,
+	.write = simcons_tty_write,
+	.write_room = simcons_tty_write_room,
+	.chars_in_buffer = simcons_tty_chars_in_buffer,
+};
+
+int __init simcons_tty_init (void)
+{
+	struct tty_driver *driver = alloc_tty_driver(1);
+	int err;
+	if (!driver)
+		return -ENOMEM;
+	driver->name = "simcons";
+	driver->major = TTY_MAJOR;
+	driver->minor_start = 64;
+	driver->type = TTY_DRIVER_TYPE_SYSCONS;
+	driver->init_termios = tty_std_termios;
+	tty_set_operations(driver, &ops);
+	err = tty_register_driver(driver);
+	if (err) {
+		put_tty_driver(driver);
+		return err;
+	}
+	tty_driver = driver;
+	return 0;
+}
+/* We use `late_initcall' instead of just `__initcall' as a workaround for
+   the fact that (1) simcons_tty_init can't be called before tty_init,
+   (2) tty_init is called via `module_init', (3) if statically linked,
+   module_init == device_init, and (4) there's no ordering of init lists.
+   We can do this easily because simcons is always statically linked, but
+   other tty drivers that depend on tty_init and which must use
+   `module_init' to declare their init routines are likely to be broken.  */
+late_initcall(simcons_tty_init);
+
+/* Poll for input on the console, and if there's any, deliver it to the
+   tty driver.  */
+void simcons_poll_tty (struct tty_struct *tty)
+{
+	int flip = 0, send_break = 0;
+	struct pollfd pfd;
+	pfd.fd = 0;
+	pfd.events = POLLIN;
+
+	if (V850_SIM_SYSCALL (poll, &pfd, 1, 0) > 0) {
+		if (pfd.revents & POLLIN) {
+			int left = TTY_FLIPBUF_SIZE - tty->flip.count;
+
+			if (left > 0) {
+				unsigned char *buf = tty->flip.char_buf_ptr;
+				int rd = V850_SIM_SYSCALL (read, 0, buf, left);
+
+				if (rd > 0) {
+					tty->flip.count += rd;
+					tty->flip.char_buf_ptr += rd;
+					memset (tty->flip.flag_buf_ptr, 0, rd);
+					tty->flip.flag_buf_ptr += rd;
+					flip = 1;
+				} else
+					send_break = 1;
+			}
+		} else if (pfd.revents & POLLERR)
+			send_break = 1;
+	}
+
+	if (send_break) {
+		tty_insert_flip_char (tty, 0, TTY_BREAK);		
+		flip = 1;
+	}
+
+	if (flip)
+		tty_schedule_flip (tty);
+}
+
+void simcons_poll_ttys (void)
+{
+	if (tty_driver && tty_driver->ttys[0])
+		simcons_poll_tty (tty_driver->ttys[0]);
+}
+
+void simcons_setup (void)
+{
+	V850_SIM_SYSCALL (make_raw, 0);
+	register_console (&simcons);
+	printk (KERN_INFO "Console: GDB V850E simulator stdio\n");
+}
diff --git a/arch/v850/kernel/syscalls.c b/arch/v850/kernel/syscalls.c
new file mode 100644
index 0000000..9224cb6
--- /dev/null
+++ b/arch/v850/kernel/syscalls.c
@@ -0,0 +1,197 @@
+/*
+ * arch/v850/kernel/syscalls.c -- Various system-call definitions not
+ * 	defined in machine-independent code
+ *
+ *  Copyright (C) 2001,02  NEC Corporation
+ *  Copyright (C) 2001,02  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * This file was derived the ppc version, arch/ppc/kernel/syscalls.c
+ * ... which was derived from "arch/i386/kernel/sys_i386.c" by Gary Thomas;
+ *     modified by Cort Dougan (cort@cs.nmt.edu)
+ *     and Paul Mackerras (paulus@cs.anu.edu.au).
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/syscalls.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/stat.h>
+#include <linux/mman.h>
+#include <linux/sys.h>
+#include <linux/ipc.h>
+#include <linux/utsname.h>
+#include <linux/file.h>
+
+#include <asm/uaccess.h>
+#include <asm/ipc.h>
+#include <asm/semaphore.h>
+
+/*
+ * sys_ipc() is the de-multiplexer for the SysV IPC calls..
+ *
+ * This is really horribly ugly.
+ */
+int
+sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth)
+{
+	int version, ret;
+
+	version = call >> 16; /* hack for backward compatibility */
+	call &= 0xffff;
+
+	ret = -EINVAL;
+	switch (call) {
+	case SEMOP:
+		ret = sys_semop (first, (struct sembuf *)ptr, second);
+		break;
+	case SEMGET:
+		ret = sys_semget (first, second, third);
+		break;
+	case SEMCTL:
+	{
+		union semun fourth;
+
+		if (!ptr)
+			break;
+		if ((ret = access_ok(VERIFY_READ, ptr, sizeof(long)) ? 0 : -EFAULT)
+		    || (ret = get_user(fourth.__pad, (void **)ptr)))
+			break;
+		ret = sys_semctl (first, second, third, fourth);
+		break;
+	}
+	case MSGSND:
+		ret = sys_msgsnd (first, (struct msgbuf *) ptr, second, third);
+		break;
+	case MSGRCV:
+		switch (version) {
+		case 0: {
+			struct ipc_kludge tmp;
+
+			if (!ptr)
+				break;
+			if ((ret = access_ok(VERIFY_READ, ptr, sizeof(tmp)) ? 0 : -EFAULT)
+			    || (ret = copy_from_user(&tmp,
+						(struct ipc_kludge *) ptr,
+						sizeof (tmp))))
+				break;
+			ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp,
+					  third);
+			break;
+			}
+		default:
+			ret = sys_msgrcv (first, (struct msgbuf *) ptr,
+					  second, fifth, third);
+			break;
+		}
+		break;
+	case MSGGET:
+		ret = sys_msgget ((key_t) first, second);
+		break;
+	case MSGCTL:
+		ret = sys_msgctl (first, second, (struct msqid_ds *) ptr);
+		break;
+	case SHMAT:
+		switch (version) {
+		default: {
+			ulong raddr;
+
+			if ((ret = access_ok(VERIFY_WRITE, (ulong*) third,
+					       sizeof(ulong)) ? 0 : -EFAULT))
+				break;
+			ret = do_shmat (first, (char *) ptr, second, &raddr);
+			if (ret)
+				break;
+			ret = put_user (raddr, (ulong *) third);
+			break;
+			}
+		case 1:	/* iBCS2 emulator entry point */
+			if (!segment_eq(get_fs(), get_ds()))
+				break;
+			ret = do_shmat (first, (char *) ptr, second,
+					 (ulong *) third);
+			break;
+		}
+		break;
+	case SHMDT: 
+		ret = sys_shmdt ((char *)ptr);
+		break;
+	case SHMGET:
+		ret = sys_shmget (first, second, third);
+		break;
+	case SHMCTL:
+		ret = sys_shmctl (first, second, (struct shmid_ds *) ptr);
+		break;
+	}
+
+	return ret;
+}
+
+/*
+ * sys_pipe() is the normal C calling standard for creating
+ * a pipe. It's not the way unix traditionally does this, though.
+ */
+int sys_pipe (int *fildes)
+{
+	int fd[2];
+	int error;
+
+	error = do_pipe (fd);
+	if (!error) {
+		if (copy_to_user (fildes, fd, 2*sizeof (int)))
+			error = -EFAULT;
+	}
+	return error;
+}
+
+static inline unsigned long
+do_mmap2 (unsigned long addr, size_t len,
+	 unsigned long prot, unsigned long flags,
+	 unsigned long fd, unsigned long pgoff)
+{
+	struct file * file = NULL;
+	int ret = -EBADF;
+
+	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+	if (! (flags & MAP_ANONYMOUS)) {
+		if (!(file = fget (fd)))
+			goto out;
+	}
+	
+	down_write (&current->mm->mmap_sem);
+	ret = do_mmap_pgoff (file, addr, len, prot, flags, pgoff);
+	up_write (&current->mm->mmap_sem);
+	if (file)
+		fput (file);
+out:
+	return ret;
+}
+
+unsigned long sys_mmap2 (unsigned long addr, size_t len,
+			unsigned long prot, unsigned long flags,
+			unsigned long fd, unsigned long pgoff)
+{
+	return do_mmap2 (addr, len, prot, flags, fd, pgoff);
+}
+
+unsigned long sys_mmap (unsigned long addr, size_t len,
+		       unsigned long prot, unsigned long flags,
+		       unsigned long fd, off_t offset)
+{
+	int err = -EINVAL;
+
+	if (offset & ~PAGE_MASK)
+		goto out;
+
+	err = do_mmap2 (addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
+out:
+	return err;
+}
diff --git a/arch/v850/kernel/teg.c b/arch/v850/kernel/teg.c
new file mode 100644
index 0000000..495cf8f
--- /dev/null
+++ b/arch/v850/kernel/teg.c
@@ -0,0 +1,63 @@
+/*
+ * arch/v850/kernel/teg.c -- NB85E-TEG cpu chip
+ *
+ *  Copyright (C) 2001,02,03  NEC Electronics Corporation
+ *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/bootmem.h>
+#include <linux/irq.h>
+
+#include <asm/atomic.h>
+#include <asm/page.h>
+#include <asm/machdep.h>
+#include <asm/v850e_timer_d.h>
+
+#include "mach.h"
+
+void __init mach_sched_init (struct irqaction *timer_action)
+{
+	/* Select timer interrupt instead of external pin.  */
+	TEG_ISS |= 0x1;
+	/* Start hardware timer.  */
+	v850e_timer_d_configure (0, HZ);
+	/* Install timer interrupt handler.  */
+	setup_irq (IRQ_INTCMD(0), timer_action);
+}
+
+static struct v850e_intc_irq_init irq_inits[] = {
+	{ "IRQ", 0,		NUM_CPU_IRQS,	1, 7 },
+	{ "CMD", IRQ_INTCMD(0),	IRQ_INTCMD_NUM,	1, 5 },
+	{ "SER", IRQ_INTSER(0),	IRQ_INTSER_NUM,	1, 3 },
+	{ "SR",	 IRQ_INTSR(0),	IRQ_INTSR_NUM,	1, 4 },
+	{ "ST",	 IRQ_INTST(0),	IRQ_INTST_NUM,	1, 5 },
+	{ 0 }
+};
+#define NUM_IRQ_INITS ((sizeof irq_inits / sizeof irq_inits[0]) - 1)
+
+static struct hw_interrupt_type hw_itypes[NUM_IRQ_INITS];
+
+/* Initialize MA chip interrupts.  */
+void __init teg_init_irqs (void)
+{
+	v850e_intc_init_irq_types (irq_inits, hw_itypes);
+}
+
+/* Called before configuring an on-chip UART.  */
+void teg_uart_pre_configure (unsigned chan, unsigned cflags, unsigned baud)
+{
+	/* Enable UART I/O pins instead of external interrupt pins, and
+	   UART interrupts instead of external pin interrupts.  */
+	TEG_ISS |= 0x4E;
+}
diff --git a/arch/v850/kernel/time.c b/arch/v850/kernel/time.c
new file mode 100644
index 0000000..f722a26
--- /dev/null
+++ b/arch/v850/kernel/time.c
@@ -0,0 +1,198 @@
+/*
+ * linux/arch/v850/kernel/time.c -- Arch-dependent timer functions
+ *
+ *  Copyright (C) 1991, 1992, 1995, 2001, 2002  Linus Torvalds
+ *
+ * This file contains the v850-specific time handling details.
+ * Most of the stuff is located in the machine specific files.
+ *
+ * 1997-09-10	Updated NTP code according to technical memorandum Jan '96
+ *		"A Kernel Model for Precision Timekeeping" by Dave Mills
+ */
+
+#include <linux/config.h> /* CONFIG_HEARTBEAT */
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/timex.h>
+#include <linux/profile.h>
+
+#include <asm/io.h>
+
+#include "mach.h"
+
+u64 jiffies_64 = INITIAL_JIFFIES;
+
+EXPORT_SYMBOL(jiffies_64);
+
+#define TICK_SIZE	(tick_nsec / 1000)
+
+/*
+ * Scheduler clock - returns current time in nanosec units.
+ */
+unsigned long long sched_clock(void)
+{
+	return (unsigned long long)jiffies * (1000000000 / HZ);
+}
+
+/*
+ * timer_interrupt() needs to keep up the real-time clock,
+ * as well as call the "do_timer()" routine every clocktick
+ */
+static irqreturn_t timer_interrupt (int irq, void *dummy, struct pt_regs *regs)
+{
+#if 0
+	/* last time the cmos clock got updated */
+	static long last_rtc_update=0;
+#endif
+
+	/* may need to kick the hardware timer */
+	if (mach_tick)
+	  mach_tick ();
+
+	do_timer (regs);
+#ifndef CONFIG_SMP
+	update_process_times(user_mode(regs));
+#endif
+	profile_tick(CPU_PROFILING, regs);
+#if 0
+	/*
+	 * If we have an externally synchronized Linux clock, then update
+	 * CMOS 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 (set_rtc_mmss (xtime.tv_sec) == 0)
+	    last_rtc_update = xtime.tv_sec;
+	  else
+	    last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+	}
+#ifdef CONFIG_HEARTBEAT
+	/* use power LED as a heartbeat instead -- much more useful
+	   for debugging -- based on the version for PReP by Cort */
+	/* acts like an actual heart beat -- ie thump-thump-pause... */
+	if (mach_heartbeat) {
+	    static unsigned cnt = 0, period = 0, dist = 0;
+
+	    if (cnt == 0 || cnt == dist)
+		mach_heartbeat ( 1 );
+	    else if (cnt == 7 || cnt == dist+7)
+		mach_heartbeat ( 0 );
+
+	    if (++cnt > period) {
+		cnt = 0;
+		/* The hyperbolic function below modifies the heartbeat period
+		 * length in dependency of the current (5min) load. It goes
+		 * through the points f(0)=126, f(1)=86, f(5)=51,
+		 * f(inf)->30. */
+		period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
+		dist = period / 4;
+	    }
+	}
+#endif /* CONFIG_HEARTBEAT */
+#endif /* 0 */
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * This version of gettimeofday has near microsecond resolution.
+ */
+void do_gettimeofday (struct timeval *tv)
+{
+#if 0 /* DAVIDM later if possible */
+	extern volatile unsigned long lost_ticks;
+	unsigned long lost;
+#endif
+	unsigned long flags;
+	unsigned long usec, sec;
+	unsigned long seq;
+
+	do {
+		seq = read_seqbegin_irqsave(&xtime_lock, flags);
+
+#if 0
+		usec = mach_gettimeoffset ? mach_gettimeoffset () : 0;
+#else
+		usec = 0;
+#endif
+#if 0 /* DAVIDM later if possible */
+		lost = lost_ticks;
+		if (lost)
+			usec += lost * (1000000/HZ);
+#endif
+		sec = xtime.tv_sec;
+		usec += xtime.tv_nsec / 1000;
+	} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
+
+	while (usec >= 1000000) {
+		usec -= 1000000;
+		sec++;
+	}
+
+	tv->tv_sec = sec;
+	tv->tv_usec = usec;
+}
+
+EXPORT_SYMBOL(do_gettimeofday);
+
+int do_settimeofday(struct timespec *tv)
+{
+	if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
+		return -EINVAL;
+
+	write_seqlock_irq (&xtime_lock);
+
+	/* This is revolting. We need to set the xtime.tv_nsec
+	 * correctly. However, the value in this location is
+	 * is value at the last tick.
+	 * Discover what correction gettimeofday
+	 * would have done, and then undo it!
+	 */
+#if 0
+	tv->tv_nsec -= mach_gettimeoffset() * 1000;
+#endif
+
+	while (tv->tv_nsec < 0) {
+		tv->tv_nsec += NSEC_PER_SEC;
+		tv->tv_sec--;
+	}
+
+	xtime.tv_sec = tv->tv_sec;
+	xtime.tv_nsec = tv->tv_nsec;
+
+	time_adjust = 0;		/* stop active adjtime () */
+	time_status |= STA_UNSYNC;
+	time_maxerror = NTP_PHASE_LIMIT;
+	time_esterror = NTP_PHASE_LIMIT;
+
+	write_sequnlock_irq (&xtime_lock);
+	clock_was_set();
+	return 0;
+}
+
+EXPORT_SYMBOL(do_settimeofday);
+
+static int timer_dev_id;
+static struct irqaction timer_irqaction = {
+	timer_interrupt,
+	SA_INTERRUPT,
+	CPU_MASK_NONE,
+	"timer",
+	&timer_dev_id,
+	NULL
+};
+
+void time_init (void)
+{
+	mach_gettimeofday (&xtime);
+	mach_sched_init (&timer_irqaction);
+}
diff --git a/arch/v850/kernel/v850_ksyms.c b/arch/v850/kernel/v850_ksyms.c
new file mode 100644
index 0000000..0ca6490
--- /dev/null
+++ b/arch/v850/kernel/v850_ksyms.c
@@ -0,0 +1,78 @@
+#include <linux/module.h>
+#include <linux/linkage.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/user.h>
+#include <linux/elfcore.h>
+#include <linux/in6.h>
+#include <linux/interrupt.h>
+#include <linux/config.h>
+
+#include <asm/pgalloc.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/semaphore.h>
+#include <asm/checksum.h>
+#include <asm/current.h>
+
+
+extern void *trap_table;
+EXPORT_SYMBOL (trap_table);
+
+/* platform dependent support */
+extern void dump_thread (struct pt_regs *, struct user *);
+EXPORT_SYMBOL (dump_thread);
+EXPORT_SYMBOL (kernel_thread);
+EXPORT_SYMBOL (enable_irq);
+EXPORT_SYMBOL (disable_irq);
+EXPORT_SYMBOL (disable_irq_nosync);
+EXPORT_SYMBOL (__bug);
+
+/* Networking helper routines. */
+EXPORT_SYMBOL (csum_partial_copy);
+EXPORT_SYMBOL (csum_partial_copy_from_user);
+EXPORT_SYMBOL (ip_compute_csum);
+EXPORT_SYMBOL (ip_fast_csum);
+
+/* string / mem functions */
+EXPORT_SYMBOL (strcpy);
+EXPORT_SYMBOL (strncpy);
+EXPORT_SYMBOL (strcat);
+EXPORT_SYMBOL (strncat);
+EXPORT_SYMBOL (strcmp);
+EXPORT_SYMBOL (strncmp);
+EXPORT_SYMBOL (strchr);
+EXPORT_SYMBOL (strlen);
+EXPORT_SYMBOL (strnlen);
+EXPORT_SYMBOL (strpbrk);
+EXPORT_SYMBOL (strrchr);
+EXPORT_SYMBOL (strstr);
+EXPORT_SYMBOL (memset);
+EXPORT_SYMBOL (memcpy);
+EXPORT_SYMBOL (memmove);
+EXPORT_SYMBOL (memcmp);
+EXPORT_SYMBOL (memscan);
+
+/* semaphores */
+EXPORT_SYMBOL (__down);
+EXPORT_SYMBOL (__down_interruptible);
+EXPORT_SYMBOL (__down_trylock);
+EXPORT_SYMBOL (__up);
+
+/*
+ * libgcc functions - functions that are used internally by the
+ * compiler...  (prototypes are not correct though, but that
+ * doesn't really matter since they're not versioned).
+ */
+extern void __ashldi3 (void);
+extern void __ashrdi3 (void);
+extern void __lshrdi3 (void);
+extern void __muldi3 (void);
+extern void __negdi2 (void);
+
+EXPORT_SYMBOL (__ashldi3);
+EXPORT_SYMBOL (__ashrdi3);
+EXPORT_SYMBOL (__lshrdi3);
+EXPORT_SYMBOL (__muldi3);
+EXPORT_SYMBOL (__negdi2);
diff --git a/arch/v850/kernel/v850e2_cache.c b/arch/v850/kernel/v850e2_cache.c
new file mode 100644
index 0000000..4570312
--- /dev/null
+++ b/arch/v850/kernel/v850e2_cache.c
@@ -0,0 +1,127 @@
+/*
+ * arch/v850/kernel/v850e2_cache.c -- Cache control for V850E2 cache
+ * 	memories
+ *
+ *  Copyright (C) 2003  NEC Electronics Corporation
+ *  Copyright (C) 2003  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <linux/mm.h>
+
+#include <asm/v850e2_cache.h>
+
+/* Cache operations we can do.  The encoding corresponds directly to the
+   value we need to write into the COPR register.  */
+enum cache_op {
+	OP_SYNC_IF_DIRTY 	   = V850E2_CACHE_COPR_CFC(0), /* 000 */
+	OP_SYNC_IF_VALID 	   = V850E2_CACHE_COPR_CFC(1), /* 001 */
+	OP_SYNC_IF_VALID_AND_CLEAR = V850E2_CACHE_COPR_CFC(3), /* 011 */
+	OP_WAY_CLEAR 		   = V850E2_CACHE_COPR_CFC(4), /* 100 */
+	OP_FILL 		   = V850E2_CACHE_COPR_CFC(5), /* 101 */
+	OP_CLEAR 		   = V850E2_CACHE_COPR_CFC(6), /* 110 */
+	OP_CREATE_DIRTY 	   = V850E2_CACHE_COPR_CFC(7)  /* 111 */
+};
+
+/* Which cache to use.  This encoding also corresponds directly to the
+   value we need to write into the COPR register. */
+enum cache {
+	ICACHE = 0,
+	DCACHE = V850E2_CACHE_COPR_LBSL
+};
+
+/* Returns ADDR rounded down to the beginning of its cache-line.  */
+#define CACHE_LINE_ADDR(addr)  \
+   ((addr) & ~(V850E2_CACHE_LINE_SIZE - 1))
+/* Returns END_ADDR rounded up to the `limit' of its cache-line.  */
+#define CACHE_LINE_END_ADDR(end_addr)  \
+   CACHE_LINE_ADDR(end_addr + (V850E2_CACHE_LINE_SIZE - 1))
+
+
+/* Low-level cache ops.  */
+
+/* Apply cache-op OP to all entries in CACHE.  */
+static inline void cache_op_all (enum cache_op op, enum cache cache)
+{
+	int cmd = op | cache | V850E2_CACHE_COPR_WSLE | V850E2_CACHE_COPR_STRT;
+
+	if (op != OP_WAY_CLEAR) {
+		/* The WAY_CLEAR operation does the whole way, but other
+		   ops take begin-index and count params; we just indicate
+		   the entire cache.  */
+		V850E2_CACHE_CADL = 0;
+		V850E2_CACHE_CADH = 0;
+		V850E2_CACHE_CCNT = V850E2_CACHE_WAY_SIZE - 1;
+	}
+
+	V850E2_CACHE_COPR = cmd | V850E2_CACHE_COPR_WSL(0); /* way 0 */
+	V850E2_CACHE_COPR = cmd | V850E2_CACHE_COPR_WSL(1); /* way 1 */
+	V850E2_CACHE_COPR = cmd | V850E2_CACHE_COPR_WSL(2); /* way 2 */
+	V850E2_CACHE_COPR = cmd | V850E2_CACHE_COPR_WSL(3); /* way 3 */
+}
+
+/* Apply cache-op OP to all entries in CACHE covering addresses ADDR
+   through ADDR+LEN.  */
+static inline void cache_op_range (enum cache_op op, u32 addr, u32 len,
+				   enum cache cache)
+{
+	u32 start = CACHE_LINE_ADDR (addr);
+	u32 end = CACHE_LINE_END_ADDR (addr + len);
+	u32 num_lines = (end - start) >> V850E2_CACHE_LINE_SIZE_BITS;
+
+	V850E2_CACHE_CADL = start & 0xFFFF;
+	V850E2_CACHE_CADH = start >> 16;
+	V850E2_CACHE_CCNT = num_lines - 1;
+
+	V850E2_CACHE_COPR = op | cache | V850E2_CACHE_COPR_STRT;
+}
+
+
+/* High-level ops.  */
+
+static void cache_exec_after_store_all (void)
+{
+	cache_op_all (OP_SYNC_IF_DIRTY, DCACHE);
+	cache_op_all (OP_WAY_CLEAR, ICACHE);
+}
+
+static void cache_exec_after_store_range (u32 start, u32 len)
+{
+	cache_op_range (OP_SYNC_IF_DIRTY, start, len, DCACHE);
+	cache_op_range (OP_CLEAR, start, len, ICACHE);
+}
+
+
+/* Exported functions.  */
+
+void flush_icache (void)
+{
+	cache_exec_after_store_all ();
+}
+
+void flush_icache_range (unsigned long start, unsigned long end)
+{
+	cache_exec_after_store_range (start, end - start);
+}
+
+void flush_icache_page (struct vm_area_struct *vma, struct page *page)
+{
+	cache_exec_after_store_range (page_to_virt (page), PAGE_SIZE);
+}
+
+void flush_icache_user_range (struct vm_area_struct *vma, struct page *page,
+			      unsigned long addr, int len)
+{
+	cache_exec_after_store_range (addr, len);
+}
+
+void flush_cache_sigtramp (unsigned long addr)
+{
+	/* For the exact size, see signal.c, but 16 bytes should be enough.  */
+	cache_exec_after_store_range (addr, 16);
+}
diff --git a/arch/v850/kernel/v850e_cache.c b/arch/v850/kernel/v850e_cache.c
new file mode 100644
index 0000000..ea3e51c
--- /dev/null
+++ b/arch/v850/kernel/v850e_cache.c
@@ -0,0 +1,174 @@
+/*
+ * arch/v850/kernel/v850e_cache.c -- Cache control for V850E cache memories
+ *
+ *  Copyright (C) 2003  NEC Electronics Corporation
+ *  Copyright (C) 2003  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+/* This file implements cache control for the rather simple cache used on
+   some V850E CPUs, specifically the NB85E/TEG CPU-core and the V850E/ME2
+   CPU.  V850E2 processors have their own (better) cache
+   implementation.  */
+
+#include <asm/entry.h>
+#include <asm/cacheflush.h>
+#include <asm/v850e_cache.h>
+
+#define WAIT_UNTIL_CLEAR(value) while (value) {}
+
+/* Set caching params via the BHC and DCC registers.  */
+void v850e_cache_enable (u16 bhc, u16 icc, u16 dcc)
+{
+	unsigned long *r0_ram = (unsigned long *)R0_RAM_ADDR;
+	register u16 bhc_val asm ("r6") = bhc;
+
+	/* Read the instruction cache control register (ICC) and confirm
+	   that bits 0 and 1 (TCLR0, TCLR1) are all cleared.  */
+	WAIT_UNTIL_CLEAR (V850E_CACHE_ICC & 0x3);
+	V850E_CACHE_ICC = icc;
+
+#ifdef V850E_CACHE_DCC
+	/* Configure data-cache.  */
+	V850E_CACHE_DCC = dcc;
+#endif /* V850E_CACHE_DCC */
+
+	/* Configure caching for various memory regions by writing the BHC
+	   register.  The documentation says that an instruction _cannot_
+	   enable/disable caching for the memory region in which the
+	   instruction itself exists; to work around this, we store
+	   appropriate instructions into the on-chip RAM area (which is never
+	   cached), and briefly jump there to do the work.  */
+#ifdef V850E_CACHE_WRITE_IBS
+	*r0_ram++ 	= 0xf0720760;	/* st.h r0, 0xfffff072[r0] */
+#endif
+	*r0_ram++ 	= 0xf06a3760;	/* st.h r6, 0xfffff06a[r0] */
+	*r0_ram 	= 0x5640006b;	/* jmp [r11] */
+
+	asm ("mov hilo(1f), r11; jmp [%1]; 1:;"
+	     :: "r" (bhc_val), "r" (R0_RAM_ADDR) : "r11");
+}
+
+static void clear_icache (void)
+{
+	/* 1. Read the instruction cache control register (ICC) and confirm
+	      that bits 0 and 1 (TCLR0, TCLR1) are all cleared.  */
+	WAIT_UNTIL_CLEAR (V850E_CACHE_ICC & 0x3);
+
+	/* 2. Read the ICC register and confirm that bit 12 (LOCK0) is
+  	      cleared.  Bit 13 of the ICC register is always cleared.  */
+	WAIT_UNTIL_CLEAR (V850E_CACHE_ICC & 0x1000);
+
+	/* 3. Set the TCLR0 and TCLR1 bits of the ICC register as follows,
+	      when clearing way 0 and way 1 at the same time:
+	        (a) Set the TCLR0 and TCLR1 bits.
+		(b) Read the TCLR0 and TCLR1 bits to confirm that these bits
+		    are cleared.
+		(c) Perform (a) and (b) above again.  */
+	V850E_CACHE_ICC |= 0x3;
+	WAIT_UNTIL_CLEAR (V850E_CACHE_ICC & 0x3);
+
+#ifdef V850E_CACHE_REPEAT_ICC_WRITE
+	/* Do it again.  */
+	V850E_CACHE_ICC |= 0x3;
+	WAIT_UNTIL_CLEAR (V850E_CACHE_ICC & 0x3);
+#endif
+}
+
+#ifdef V850E_CACHE_DCC
+/* Flush or clear (or both) the data cache, depending on the value of FLAGS;
+   the procedure is the same for both, just the control bits used differ (and
+   both may be performed simultaneously).  */
+static void dcache_op (unsigned short flags)
+{
+	/* 1. Read the data cache control register (DCC) and confirm that bits
+	      0, 1, 4, and 5 (DC00, DC01, DC04, DC05) are all cleared.  */
+	WAIT_UNTIL_CLEAR (V850E_CACHE_DCC & 0x33);
+
+	/* 2. Clear DCC register bit 12 (DC12), bit 13 (DC13), or both
+	      depending on the way for which tags are to be cleared.  */
+	V850E_CACHE_DCC &= ~0xC000;
+
+	/* 3. Set DCC register bit 0 (DC00), bit 1 (DC01) or both depending on
+	      the way for which tags are to be cleared.
+	      ...
+	      Set DCC register bit 4 (DC04), bit 5 (DC05), or both depending
+	      on the way to be data flushed.  */
+	V850E_CACHE_DCC |= flags;
+
+	/* 4. Read DCC register bit DC00, DC01 [DC04, DC05], or both depending
+	      on the way for which tags were cleared [flushed] and confirm
+	      that that bit is cleared.  */
+	WAIT_UNTIL_CLEAR (V850E_CACHE_DCC & flags);
+}
+#endif /* V850E_CACHE_DCC */
+
+/* Flushes the contents of the dcache to memory.  */
+static inline void flush_dcache (void)
+{
+#ifdef V850E_CACHE_DCC
+	/* We only need to do something if in write-back mode.  */
+	if (V850E_CACHE_DCC & 0x0400)
+		dcache_op (0x30);
+#endif /* V850E_CACHE_DCC */
+}
+
+/* Flushes the contents of the dcache to memory, and then clears it.  */
+static inline void clear_dcache (void)
+{
+#ifdef V850E_CACHE_DCC
+	/* We only need to do something if the dcache is enabled.  */
+	if (V850E_CACHE_DCC & 0x0C00)
+		dcache_op (0x33);
+#endif /* V850E_CACHE_DCC */
+}
+
+/* Clears the dcache without flushing to memory first.  */
+static inline void clear_dcache_no_flush (void)
+{
+#ifdef V850E_CACHE_DCC
+	/* We only need to do something if the dcache is enabled.  */
+	if (V850E_CACHE_DCC & 0x0C00)
+		dcache_op (0x3);
+#endif /* V850E_CACHE_DCC */
+}
+
+static inline void cache_exec_after_store (void)
+{
+	flush_dcache ();
+	clear_icache ();
+}
+
+
+/* Exported functions.  */
+
+void flush_icache (void)
+{
+	cache_exec_after_store ();
+}
+
+void flush_icache_range (unsigned long start, unsigned long end)
+{
+	cache_exec_after_store ();
+}
+
+void flush_icache_page (struct vm_area_struct *vma, struct page *page)
+{
+	cache_exec_after_store ();
+}
+
+void flush_icache_user_range (struct vm_area_struct *vma, struct page *page,
+			      unsigned long adr, int len)
+{
+	cache_exec_after_store ();
+}
+
+void flush_cache_sigtramp (unsigned long addr)
+{
+	cache_exec_after_store ();
+}
diff --git a/arch/v850/kernel/v850e_intc.c b/arch/v850/kernel/v850e_intc.c
new file mode 100644
index 0000000..8d39a52
--- /dev/null
+++ b/arch/v850/kernel/v850e_intc.c
@@ -0,0 +1,104 @@
+/*
+ * arch/v850/kernel/v850e_intc.c -- V850E interrupt controller (INTC)
+ *
+ *  Copyright (C) 2001,02,03  NEC Electronics Corporation
+ *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+
+#include <asm/v850e_intc.h>
+
+static void irq_nop (unsigned irq) { }
+
+static unsigned v850e_intc_irq_startup (unsigned irq)
+{
+	v850e_intc_clear_pending_irq (irq);
+	v850e_intc_enable_irq (irq);
+	return 0;
+}
+
+static void v850e_intc_end_irq (unsigned irq)
+{
+	unsigned long psw, temp;
+
+	/* Clear the highest-level bit in the In-service priority register
+	   (ISPR), to allow this interrupt (or another of the same or
+	   lesser priority) to happen again.
+
+	   The `reti' instruction normally does this automatically when the
+	   PSW bits EP and NP are zero, but we can't always rely on reti
+	   being used consistently to return after an interrupt (another
+	   process can be scheduled, for instance, which can delay the
+	   associated reti for a long time, or this process may be being
+	   single-stepped, which uses the `dbret' instruction to return
+	   from the kernel).
+
+	   We also set the PSW EP bit, which prevents reti from also
+	   trying to modify the ISPR itself.  */
+
+	/* Get PSW and disable interrupts.  */
+	asm volatile ("stsr psw, %0; di" : "=r" (psw));
+	/* We don't want to do anything for NMIs (they don't use the ISPR).  */
+	if (! (psw & 0xC0)) {
+		/* Transition to `trap' state, so that an eventual real
+		   reti instruction won't modify the ISPR.  */
+		psw |= 0x40;
+		/* Fake an interrupt return, which automatically clears the
+		   appropriate bit in the ISPR.  */
+		asm volatile ("mov hilo(1f), %0;"
+			      "ldsr %0, eipc; ldsr %1, eipsw;"
+			      "reti;"
+			      "1:"
+			      : "=&r" (temp) : "r" (psw));
+	}
+}
+
+/* Initialize HW_IRQ_TYPES for INTC-controlled irqs described in array
+   INITS (which is terminated by an entry with the name field == 0).  */
+void __init v850e_intc_init_irq_types (struct v850e_intc_irq_init *inits,
+				       struct hw_interrupt_type *hw_irq_types)
+{
+	struct v850e_intc_irq_init *init;
+	for (init = inits; init->name; init++) {
+		unsigned i;
+		struct hw_interrupt_type *hwit = hw_irq_types++;
+
+		hwit->typename = init->name;
+
+		hwit->startup  = v850e_intc_irq_startup;
+		hwit->shutdown = v850e_intc_disable_irq;
+		hwit->enable   = v850e_intc_enable_irq;
+		hwit->disable  = v850e_intc_disable_irq;
+		hwit->ack      = irq_nop;
+		hwit->end      = v850e_intc_end_irq;
+		
+		/* Initialize kernel IRQ infrastructure for this interrupt.  */
+		init_irq_handlers(init->base, init->num, init->interval, hwit);
+
+		/* Set the interrupt priorities.  */
+		for (i = 0; i < init->num; i++) {
+			unsigned irq = init->base + i * init->interval;
+
+			/* If the interrupt is currently enabled (all
+			   interrupts are initially disabled), then
+			   assume whoever enabled it has set things up
+			   properly, and avoid messing with it.  */
+			if (! v850e_intc_irq_enabled (irq))
+				/* This write also (1) disables the
+				   interrupt, and (2) clears any pending
+				   interrupts.  */
+				V850E_INTC_IC (irq)
+					= (V850E_INTC_IC_PR (init->priority)
+					   | V850E_INTC_IC_MK);
+		}
+	}
+}
diff --git a/arch/v850/kernel/v850e_timer_d.c b/arch/v850/kernel/v850e_timer_d.c
new file mode 100644
index 0000000..d2a4ece
--- /dev/null
+++ b/arch/v850/kernel/v850e_timer_d.c
@@ -0,0 +1,54 @@
+/*
+ * include/asm-v850/v850e_timer_d.c -- `Timer D' component often used
+ *	with V850E CPUs
+ *
+ *  Copyright (C) 2001,02,03  NEC Electronics Corporation
+ *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <linux/kernel.h>
+
+#include <asm/v850e_utils.h>
+#include <asm/v850e_timer_d.h>
+
+/* Start interval timer TIMER (0-3).  The timer will issue the
+   corresponding INTCMD interrupt RATE times per second.
+   This function does not enable the interrupt.  */
+void v850e_timer_d_configure (unsigned timer, unsigned rate)
+{
+	unsigned divlog2, count;
+
+	/* Calculate params for timer.  */
+	if (! calc_counter_params (
+		    V850E_TIMER_D_BASE_FREQ, rate,
+		    V850E_TIMER_D_TMCD_CS_MIN, V850E_TIMER_D_TMCD_CS_MAX, 16,
+		    &divlog2, &count))
+		printk (KERN_WARNING
+			"Cannot find interval timer %d setting suitable"
+			" for rate of %dHz.\n"
+			"Using rate of %dHz instead.\n",
+			timer, rate,
+			(V850E_TIMER_D_BASE_FREQ >> divlog2) >> 16);
+
+	/* Do the actual hardware timer initialization:  */
+
+	/* Enable timer.  */
+	V850E_TIMER_D_TMCD(timer) = V850E_TIMER_D_TMCD_CAE;
+	/* Set clock divider.  */
+	V850E_TIMER_D_TMCD(timer)
+		= V850E_TIMER_D_TMCD_CAE
+		| V850E_TIMER_D_TMCD_CS(divlog2);
+	/* Set timer compare register.  */
+	V850E_TIMER_D_CMD(timer) = count;
+	/* Start counting.  */
+	V850E_TIMER_D_TMCD(timer)
+		= V850E_TIMER_D_TMCD_CAE
+		| V850E_TIMER_D_TMCD_CS(divlog2)
+		| V850E_TIMER_D_TMCD_CE;
+}
diff --git a/arch/v850/kernel/v850e_utils.c b/arch/v850/kernel/v850e_utils.c
new file mode 100644
index 0000000..e6807ef
--- /dev/null
+++ b/arch/v850/kernel/v850e_utils.c
@@ -0,0 +1,62 @@
+/*
+ * include/asm-v850/v850e_utils.h -- Utility functions associated with
+ *	V850E CPUs
+ *
+ *  Copyright (C) 2001,02,03  NEC Electronics Corporation
+ *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <asm/v850e_utils.h>
+
+/* Calculate counter clock-divider and count values to attain the
+   desired frequency RATE from the base frequency BASE_FREQ.  The
+   counter is expected to have a clock-divider, which can divide the
+   system cpu clock by a power of two value from MIN_DIVLOG2 to
+   MAX_DIV_LOG2, and a word-size of COUNTER_SIZE bits (the counter
+   counts up and resets whenever it's equal to the compare register,
+   generating an interrupt or whatever when it does so).  The returned
+   values are: *DIVLOG2 -- log2 of the desired clock divider and *COUNT
+   -- the counter compare value to use.  Returns true if it was possible
+   to find a reasonable value, otherwise false (and the other return
+   values will be set to be as good as possible).  */
+int calc_counter_params (unsigned long base_freq,
+			 unsigned long rate,
+			 unsigned min_divlog2, unsigned max_divlog2,
+			 unsigned counter_size,
+			 unsigned *divlog2, unsigned *count)
+{
+	unsigned _divlog2;
+	int ok = 0;
+
+	/* Find the lowest clock divider setting that can represent RATE.  */
+	for (_divlog2 = min_divlog2; _divlog2 <= max_divlog2; _divlog2++) {
+		/* Minimum interrupt rate possible using this divider.  */
+		unsigned min_int_rate
+			= (base_freq >> _divlog2) >> counter_size;
+
+		if (min_int_rate <= rate) {
+			/* This setting is the highest resolution
+			   setting that's slow enough enough to attain
+			   RATE interrupts per second, so use it.  */
+			ok = 1;
+			break;
+		}
+	}
+
+	if (_divlog2 > max_divlog2)
+		/* Can't find correct setting.  */
+		_divlog2 = max_divlog2;
+
+	if (divlog2)
+		*divlog2 = _divlog2;
+	if (count)
+		*count = ((base_freq >> _divlog2) + rate/2) / rate;
+
+	return ok;
+}
diff --git a/arch/v850/kernel/vmlinux.lds.S b/arch/v850/kernel/vmlinux.lds.S
new file mode 100644
index 0000000..bbd3429
--- /dev/null
+++ b/arch/v850/kernel/vmlinux.lds.S
@@ -0,0 +1,285 @@
+/*
+ * arch/v850/vmlinux.lds.S -- kernel linker script for v850 platforms
+ *
+ *  Copyright (C) 2002,03,04  NEC Electronics Corporation
+ *  Copyright (C) 2002,03,04  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <linux/config.h>
+#define VMLINUX_SYMBOL(_sym_) _##_sym_
+#include <asm-generic/vmlinux.lds.h>
+
+/* For most platforms, this will define useful things like RAM addr/size.  */
+#include <asm/machdep.h>
+
+
+/* The following macros contain the usual definitions for various data areas.
+   The prefix `RAMK_' is used to indicate macros suitable for kernels loaded
+   into RAM, and similarly `ROMK_' for ROM-resident kernels.  Note that all
+   symbols are prefixed with an extra `_' for compatibility with the v850
+   toolchain.  */
+
+	
+/* Interrupt vectors.  */
+#define INTV_CONTENTS							      \
+		. = ALIGN (0x10) ;					      \
+		__intv_start = . ;					      \
+			*(.intv.reset)	/* Reset vector */		      \
+		. = __intv_start + 0x10 ;				      \
+			*(.intv.common)	/* Vectors common to all v850e proc */\
+		. = __intv_start + 0x80 ;				      \
+			*(.intv.mach)	/* Machine-specific int. vectors.  */ \
+		__intv_end = . ;
+
+#define RODATA_CONTENTS							      \
+		. = ALIGN (16) ;					      \
+			*(.rodata) *(.rodata.*)				      \
+			*(__vermagic)		/* Kernel version magic */    \
+			*(.rodata1)					      \
+		/* Kernel symbol table: Normal symbols */		      \
+		___start___ksymtab = .;					      \
+			*(__ksymtab)					      \
+		___stop___ksymtab = .;					      \
+		/* Kernel symbol table: GPL-only symbols */		      \
+		___start___ksymtab_gpl = .;				      \
+			*(__ksymtab_gpl)				      \
+		___stop___ksymtab_gpl = .;				      \
+		/* Kernel symbol table: strings */			      \
+			*(__ksymtab_strings)				      \
+		/* Kernel symbol table: Normal symbols */		      \
+		___start___kcrctab = .;					      \
+			*(__kcrctab)					      \
+		___stop___kcrctab = .;					      \
+		/* Kernel symbol table: GPL-only symbols */		      \
+		___start___kcrctab_gpl = .;				      \
+			*(__kcrctab_gpl)				      \
+		___stop___kcrctab_gpl = .;				      \
+		/* Built-in module parameters */			      \
+		___start___param = .;					      \
+		*(__param)						      \
+		___stop___param = .;
+
+
+/* Kernel text segment, and some constant data areas.  */
+#define TEXT_CONTENTS							      \
+		__stext = . ;						      \
+        	*(.text)						      \
+		SCHED_TEXT						      \
+			*(.exit.text)	/* 2.5 convention */		      \
+			*(.text.exit)	/* 2.4 convention */		      \
+			*(.text.lock)					      \
+			*(.exitcall.exit)				      \
+		__real_etext = . ;	/* There may be data after here.  */  \
+		RODATA_CONTENTS						      \
+		. = ALIGN (4) ;						      \
+		    	*(.call_table_data)				      \
+			*(.call_table_text)				      \
+		. = ALIGN (16) ;	/* Exception table.  */		      \
+		___start___ex_table = . ;				      \
+			*(__ex_table)					      \
+		___stop___ex_table = . ;				      \
+		. = ALIGN (4) ;						      \
+		__etext = . ;
+
+/* Kernel data segment.  */
+#define DATA_CONTENTS							      \
+		__sdata = . ;						      \
+        	*(.data)						      \
+			*(.exit.data)	/* 2.5 convention */		      \
+			*(.data.exit)	/* 2.4 convention */		      \
+		. = ALIGN (16) ;					      \
+		*(.data.cacheline_aligned)				      \
+		. = ALIGN (0x2000) ;					      \
+        	*(.data.init_task)					      \
+		. = ALIGN (0x2000) ;					      \
+		__edata = . ;
+
+/* Kernel BSS segment.  */
+#define BSS_CONTENTS							      \
+		__sbss = . ;						      \
+			*(.bss)						      \
+			*(COMMON)					      \
+		. = ALIGN (4) ;						      \
+		__init_stack_end = . ;					      \
+		__ebss = . ;
+
+/* `initcall' tables.  */
+#define INITCALL_CONTENTS						      \
+		. = ALIGN (16) ;					      \
+		___setup_start = . ;					      \
+			*(.init.setup)	/* 2.5 convention */		      \
+			*(.setup.init)	/* 2.4 convention */		      \
+		___setup_end = . ;					      \
+		___initcall_start = . ;					      \
+			*(.initcall.init)				      \
+			*(.initcall1.init)				      \
+			*(.initcall2.init)				      \
+			*(.initcall3.init)				      \
+			*(.initcall4.init)				      \
+			*(.initcall5.init)				      \
+			*(.initcall6.init)				      \
+			*(.initcall7.init)				      \
+		. = ALIGN (4) ;						      \
+		___initcall_end = . ;					      \
+		___con_initcall_start = .;				      \
+			*(.con_initcall.init)				      \
+		___con_initcall_end = .;
+
+/* Contents of `init' section for a kernel that's loaded into RAM.  */
+#define RAMK_INIT_CONTENTS						      \
+		RAMK_INIT_CONTENTS_NO_END				      \
+		__init_end = . ;
+/* Same as RAMK_INIT_CONTENTS, but doesn't define the `__init_end' symbol.  */
+#define RAMK_INIT_CONTENTS_NO_END					      \
+		. = ALIGN (4096) ;					      \
+		__init_start = . ;					      \
+			__sinittext = .;				      \
+			*(.init.text)	/* 2.5 convention */		      \
+			__einittext = .;				      \
+			*(.init.data)					      \
+			*(.text.init)	/* 2.4 convention */		      \
+			*(.data.init)					      \
+		INITCALL_CONTENTS					      \
+		INITRAMFS_CONTENTS
+
+/* The contents of `init' section for a ROM-resident kernel which
+   should go into RAM.  */	
+#define ROMK_INIT_RAM_CONTENTS						      \
+		. = ALIGN (4096) ;					      \
+		__init_start = . ;					      \
+			*(.init.data)	/* 2.5 convention */		      \
+			*(.data.init)	/* 2.4 convention */		      \
+		__init_end = . ;					      \
+		. = ALIGN (4096) ;
+
+/* The contents of `init' section for a ROM-resident kernel which
+   should go into ROM.  */	
+#define ROMK_INIT_ROM_CONTENTS						      \
+			_sinittext = .;					      \
+			*(.init.text)	/* 2.5 convention */		      \
+			_einittext = .;					      \
+			*(.text.init)	/* 2.4 convention */		      \
+		INITCALL_CONTENTS					      \
+		INITRAMFS_CONTENTS
+
+/* A root filesystem image, for kernels with an embedded root filesystem.  */
+#define ROOT_FS_CONTENTS						      \
+		__root_fs_image_start = . ;				      \
+		*(.root)						      \
+		__root_fs_image_end = . ;
+/* The initramfs archive.  */
+#define INITRAMFS_CONTENTS						      \
+		. = ALIGN (4) ;						      \
+		___initramfs_start = . ;				      \
+			*(.init.ramfs)					      \
+		___initramfs_end = . ;
+/* Where the initial bootmap (bitmap for the boot-time memory allocator) 
+   should be place.  */
+#define BOOTMAP_CONTENTS						      \
+		. = ALIGN (4096) ;					      \
+		__bootmap = . ;						      \
+		. = . + 4096 ;		/* enough for 128MB.   */
+
+/* The contents of a `typical' kram area for a kernel in RAM.  */
+#define RAMK_KRAM_CONTENTS						      \
+		__kram_start = . ;					      \
+		TEXT_CONTENTS						      \
+		DATA_CONTENTS						      \
+		BSS_CONTENTS						      \
+		RAMK_INIT_CONTENTS					      \
+		__kram_end = . ;					      \
+		BOOTMAP_CONTENTS
+
+
+/* Define output sections normally used for a ROM-resident kernel.  
+   ROM and RAM should be appropriate memory areas to use for kernel
+   ROM and RAM data.  This assumes that ROM starts at 0 (and thus can
+   hold the interrupt vectors).  */
+#define ROMK_SECTIONS(ROM, RAM)						      \
+	.rom : {							      \
+		INTV_CONTENTS						      \
+		TEXT_CONTENTS						      \
+		ROMK_INIT_ROM_CONTENTS					      \
+		ROOT_FS_CONTENTS					      \
+	} > ROM								      \
+									      \
+	__rom_copy_src_start = . ;					      \
+									      \
+	.data : {							      \
+		__kram_start = . ;					      \
+		__rom_copy_dst_start = . ;				      \
+		DATA_CONTENTS						      \
+		ROMK_INIT_RAM_CONTENTS					      \
+		__rom_copy_dst_end = . ;				      \
+	} > RAM  AT> ROM						      \
+									      \
+	.bss ALIGN (4) : {						      \
+		BSS_CONTENTS						      \
+		__kram_end = . ;					      \
+		BOOTMAP_CONTENTS					      \
+	} > RAM
+
+
+/* The 32-bit variable `jiffies' is just the lower 32-bits of `jiffies_64'.  */
+_jiffies = _jiffies_64 ;
+
+
+/* Include an appropriate platform-dependent linker-script (which
+   usually should use the above macros to do most of the work).  */
+
+#ifdef CONFIG_V850E_SIM
+# include "sim.ld"
+#endif
+
+#ifdef CONFIG_V850E2_SIM85E2
+# include "sim85e2.ld"
+#endif
+
+#ifdef CONFIG_V850E2_FPGA85E2C
+# include "fpga85e2c.ld"
+#endif
+
+#ifdef CONFIG_V850E2_ANNA
+# ifdef CONFIG_ROM_KERNEL
+#  include "anna-rom.ld"
+# else
+#  include "anna.ld"
+# endif
+#endif
+
+#ifdef CONFIG_V850E_AS85EP1
+# ifdef CONFIG_ROM_KERNEL
+#  include "as85ep1-rom.ld"
+# else
+#  include "as85ep1.ld"
+# endif
+#endif
+
+#ifdef CONFIG_RTE_CB_MA1
+# ifdef CONFIG_ROM_KERNEL
+#  include "rte_ma1_cb-rom.ld"
+# else
+#  include "rte_ma1_cb.ld"
+# endif
+#endif
+
+#ifdef CONFIG_RTE_CB_NB85E
+# ifdef CONFIG_ROM_KERNEL
+#  include "rte_nb85e_cb-rom.ld"
+# elif defined(CONFIG_RTE_CB_MULTI)
+#  include "rte_nb85e_cb-multi.ld"
+# else
+#  include "rte_nb85e_cb.ld"
+# endif
+#endif
+
+#ifdef CONFIG_RTE_CB_ME2
+#  include "rte_me2_cb.ld"
+#endif
+
diff --git a/arch/v850/lib/Makefile b/arch/v850/lib/Makefile
new file mode 100644
index 0000000..1c78b72
--- /dev/null
+++ b/arch/v850/lib/Makefile
@@ -0,0 +1,6 @@
+#
+# arch/v850/lib/Makefile
+#
+
+lib-y  = ashrdi3.o ashldi3.o lshrdi3.o muldi3.o negdi2.o \
+	 checksum.o memcpy.o memset.o
diff --git a/arch/v850/lib/ashldi3.c b/arch/v850/lib/ashldi3.c
new file mode 100644
index 0000000..9e792d5
--- /dev/null
+++ b/arch/v850/lib/ashldi3.c
@@ -0,0 +1,62 @@
+/* ashldi3.c extracted from gcc-2.95.2/libgcc2.c which is: */
+/* Copyright (C) 1989, 92-98, 1999 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+#define BITS_PER_UNIT 8
+
+typedef 	 int SItype	__attribute__ ((mode (SI)));
+typedef unsigned int USItype	__attribute__ ((mode (SI)));
+typedef		 int DItype	__attribute__ ((mode (DI)));
+typedef int word_type __attribute__ ((mode (__word__)));
+
+struct DIstruct {SItype high, low;};
+
+typedef union
+{
+  struct DIstruct s;
+  DItype ll;
+} DIunion;
+
+DItype
+__ashldi3 (DItype u, word_type b)
+{
+  DIunion w;
+  word_type bm;
+  DIunion uu;
+
+  if (b == 0)
+    return u;
+
+  uu.ll = u;
+
+  bm = (sizeof (SItype) * BITS_PER_UNIT) - b;
+  if (bm <= 0)
+    {
+      w.s.low = 0;
+      w.s.high = (USItype)uu.s.low << -bm;
+    }
+  else
+    {
+      USItype carries = (USItype)uu.s.low >> bm;
+      w.s.low = (USItype)uu.s.low << b;
+      w.s.high = ((USItype)uu.s.high << b) | carries;
+    }
+
+  return w.ll;
+}
diff --git a/arch/v850/lib/ashrdi3.c b/arch/v850/lib/ashrdi3.c
new file mode 100644
index 0000000..78efb65
--- /dev/null
+++ b/arch/v850/lib/ashrdi3.c
@@ -0,0 +1,63 @@
+/* ashrdi3.c extracted from gcc-2.7.2/libgcc2.c which is: */
+/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+#define BITS_PER_UNIT 8
+
+typedef 	 int SItype	__attribute__ ((mode (SI)));
+typedef unsigned int USItype	__attribute__ ((mode (SI)));
+typedef		 int DItype	__attribute__ ((mode (DI)));
+typedef int word_type __attribute__ ((mode (__word__)));
+
+struct DIstruct {SItype high, low;};
+
+typedef union
+{
+  struct DIstruct s;
+  DItype ll;
+} DIunion;
+
+DItype
+__ashrdi3 (DItype u, word_type b)
+{
+  DIunion w;
+  word_type bm;
+  DIunion uu;
+
+  if (b == 0)
+    return u;
+
+  uu.ll = u;
+
+  bm = (sizeof (SItype) * BITS_PER_UNIT) - b;
+  if (bm <= 0)
+    {
+      /* w.s.high = 1..1 or 0..0 */
+      w.s.high = uu.s.high >> (sizeof (SItype) * BITS_PER_UNIT - 1);
+      w.s.low = uu.s.high >> -bm;
+    }
+  else
+    {
+      USItype carries = (USItype)uu.s.high << bm;
+      w.s.high = uu.s.high >> b;
+      w.s.low = ((USItype)uu.s.low >> b) | carries;
+    }
+
+  return w.ll;
+}
diff --git a/arch/v850/lib/checksum.c b/arch/v850/lib/checksum.c
new file mode 100644
index 0000000..d308b72
--- /dev/null
+++ b/arch/v850/lib/checksum.c
@@ -0,0 +1,154 @@
+/*
+ * INET		An implementation of the TCP/IP protocol suite for the LINUX
+ *		operating system.  INET is implemented using the  BSD Socket
+ *		interface as the means of communication with the user level.
+ *
+ *		MIPS specific IP/TCP/UDP checksumming routines
+ *
+ * Authors:	Ralf Baechle, <ralf@waldorf-gmbh.de>
+ *		Lots of code moved from tcp.c and ip.c; see those files
+ *		for more names.
+ *
+ *		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.
+ *
+ * $Id: checksum.c,v 1.1 2002/09/28 14:58:40 gerg Exp $
+ */
+#include <net/checksum.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
+#include <asm/string.h>
+#include <asm/uaccess.h>
+
+static inline unsigned short from32to16 (unsigned long sum)
+{
+	unsigned int result;
+	/*
+			        %0		%1
+	      hsw %1, %0	H     L		L     H
+	      add %1, %0	H     L		H+L+C H+L
+	*/
+	asm ("hsw %1, %0; add %1, %0" : "=&r" (result) : "r" (sum));
+	return result >> 16;
+}
+
+static inline unsigned int do_csum(const unsigned char * buff, int len)
+{
+	int odd, count;
+	unsigned int result = 0;
+
+	if (len <= 0)
+		goto out;
+	odd = 1 & (unsigned long) buff;
+	if (odd) {
+		result = be16_to_cpu(*buff);
+		len--;
+		buff++;
+	}
+	count = len >> 1;		/* nr of 16-bit words.. */
+	if (count) {
+		if (2 & (unsigned long) buff) {
+			result += *(unsigned short *) buff;
+			count--;
+			len -= 2;
+			buff += 2;
+		}
+		count >>= 1;		/* nr of 32-bit words.. */
+		if (count) {
+			unsigned int carry = 0;
+			do {
+				unsigned int w = *(unsigned int *) buff;
+				count--;
+				buff += 4;
+				result += carry;
+				result += w;
+				carry = (w > result);
+			} while (count);
+			result += carry;
+			result = (result & 0xffff) + (result >> 16);
+		}
+		if (len & 2) {
+			result += *(unsigned short *) buff;
+			buff += 2;
+		}
+	}
+	if (len & 1)
+		result += le16_to_cpu(*buff);
+	result = from32to16(result);
+	if (odd)
+		result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
+out:
+	return result;
+}
+
+/*
+ *	This is a version of ip_compute_csum() optimized for IP headers,
+ *	which always checksum on 4 octet boundaries.
+ */
+unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl)
+{
+	return ~do_csum(iph,ihl*4);
+}
+
+/*
+ * this routine is used for miscellaneous IP-like checksums, mainly
+ * in icmp.c
+ */
+unsigned short ip_compute_csum(const unsigned char * buff, int len)
+{
+	return ~do_csum(buff,len);
+}
+
+/*
+ * computes a partial checksum, e.g. for TCP/UDP fragments
+ */
+unsigned int csum_partial(const unsigned char *buff, int len, unsigned int sum)
+{
+	unsigned int result = do_csum(buff, len);
+
+	/* add in old sum, and carry.. */
+	result += sum;
+	if(sum > result)
+		result += 1;
+	return result;
+}
+
+EXPORT_SYMBOL(csum_partial);
+
+/*
+ * copy while checksumming, otherwise like csum_partial
+ */
+unsigned int csum_partial_copy(const unsigned char *src, unsigned char *dst,
+                               int len, unsigned int sum)
+{
+	/*
+	 * It's 2:30 am and I don't feel like doing it real ...
+	 * This is lots slower than the real thing (tm)
+	 */
+	sum = csum_partial(src, len, sum);
+	memcpy(dst, src, len);
+
+	return sum;
+}
+
+/*
+ * Copy from userspace and compute checksum.  If we catch an exception
+ * then zero the rest of the buffer.
+ */
+unsigned int csum_partial_copy_from_user (const unsigned char *src, unsigned char *dst,
+                                          int len, unsigned int sum,
+                                          int *err_ptr)
+{
+	int missing;
+
+	missing = copy_from_user(dst, src, len);
+	if (missing) {
+		memset(dst + len - missing, 0, missing);
+		*err_ptr = -EFAULT;
+	}
+		
+	return csum_partial(dst, len, sum);
+}
diff --git a/arch/v850/lib/lshrdi3.c b/arch/v850/lib/lshrdi3.c
new file mode 100644
index 0000000..93b1cb6
--- /dev/null
+++ b/arch/v850/lib/lshrdi3.c
@@ -0,0 +1,62 @@
+/* lshrdi3.c extracted from gcc-2.7.2/libgcc2.c which is: */
+/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+#define BITS_PER_UNIT 8
+
+typedef 	 int SItype	__attribute__ ((mode (SI)));
+typedef unsigned int USItype	__attribute__ ((mode (SI)));
+typedef		 int DItype	__attribute__ ((mode (DI)));
+typedef int word_type __attribute__ ((mode (__word__)));
+
+struct DIstruct {SItype high, low;};
+
+typedef union
+{
+  struct DIstruct s;
+  DItype ll;
+} DIunion;
+
+DItype
+__lshrdi3 (DItype u, word_type b)
+{
+  DIunion w;
+  word_type bm;
+  DIunion uu;
+
+  if (b == 0)
+    return u;
+
+  uu.ll = u;
+
+  bm = (sizeof (SItype) * BITS_PER_UNIT) - b;
+  if (bm <= 0)
+    {
+      w.s.high = 0;
+      w.s.low = (USItype)uu.s.high >> -bm;
+    }
+  else
+    {
+      USItype carries = (USItype)uu.s.high << bm;
+      w.s.high = (USItype)uu.s.high >> b;
+      w.s.low = ((USItype)uu.s.low >> b) | carries;
+    }
+
+  return w.ll;
+}
diff --git a/arch/v850/lib/memcpy.c b/arch/v850/lib/memcpy.c
new file mode 100644
index 0000000..492847b
--- /dev/null
+++ b/arch/v850/lib/memcpy.c
@@ -0,0 +1,92 @@
+/*
+ * arch/v850/lib/memcpy.c -- Memory copying
+ *
+ *  Copyright (C) 2001,02  NEC Corporation
+ *  Copyright (C) 2001,02  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <linux/types.h>
+#include <asm/string.h>
+
+#define CHUNK_SIZE		32 /* bytes */
+#define CHUNK_ALIGNED(addr)	(((unsigned long)addr & 0x3) == 0)
+
+/* Note that this macro uses 8 call-clobbered registers (not including
+   R1), which are few enough so that the following functions don't need
+   to spill anything to memory.  It also uses R1, which is nominally
+   reserved for the assembler, but here it should be OK.  */
+#define COPY_CHUNK(src, dst)			\
+   asm ("mov %0, ep;"				\
+	"sld.w 0[ep], r1; sld.w 4[ep], r12;"	\
+	"sld.w 8[ep], r13; sld.w 12[ep], r14;"	\
+	"sld.w 16[ep], r15; sld.w 20[ep], r17;"	\
+	"sld.w 24[ep], r18; sld.w 28[ep], r19;"	\
+	"mov %1, ep;"				\
+	"sst.w r1, 0[ep]; sst.w r12, 4[ep];"	\
+	"sst.w r13, 8[ep]; sst.w r14, 12[ep];"	\
+	"sst.w r15, 16[ep]; sst.w r17, 20[ep];"	\
+	"sst.w r18, 24[ep]; sst.w r19, 28[ep]"	\
+	:: "r" (src), "r" (dst)			\
+	: "r1", "r12", "r13", "r14", "r15",	\
+	  "r17", "r18", "r19", "ep", "memory");
+
+void *memcpy (void *dst, const void *src, __kernel_size_t size)
+{
+	char *_dst = dst;
+	const char *_src = src;
+
+	if (size >= CHUNK_SIZE && CHUNK_ALIGNED(_src) && CHUNK_ALIGNED(_dst)) {
+		/* Copy large blocks efficiently.  */
+		unsigned count;
+		for (count = size / CHUNK_SIZE; count; count--) {
+			COPY_CHUNK (_src, _dst);
+			_src += CHUNK_SIZE;
+			_dst += CHUNK_SIZE;
+		}
+		size %= CHUNK_SIZE;
+	}
+
+	if (size > 0)
+		do
+			*_dst++ = *_src++;
+		while (--size);
+
+	return dst;
+}
+
+void *memmove (void *dst, const void *src, __kernel_size_t size)
+{
+	if ((unsigned long)dst < (unsigned long)src
+	    || (unsigned long)src + size < (unsigned long)dst)
+		return memcpy (dst, src, size);
+	else {
+		char *_dst = dst + size;
+		const char *_src = src + size;
+
+		if (size >= CHUNK_SIZE
+		    && CHUNK_ALIGNED (_src) && CHUNK_ALIGNED (_dst))
+		{
+			/* Copy large blocks efficiently.  */
+			unsigned count;
+			for (count = size / CHUNK_SIZE; count; count--) {
+				_src -= CHUNK_SIZE;
+				_dst -= CHUNK_SIZE;
+				COPY_CHUNK (_src, _dst);
+			}
+			size %= CHUNK_SIZE;
+		}
+
+		if (size > 0)
+			do
+				*--_dst = *--_src;
+			while (--size);
+
+		return _dst;
+	}
+}
diff --git a/arch/v850/lib/memset.c b/arch/v850/lib/memset.c
new file mode 100644
index 0000000..d1b2ad8
--- /dev/null
+++ b/arch/v850/lib/memset.c
@@ -0,0 +1,68 @@
+/*
+ * arch/v850/lib/memset.c -- Memory initialization
+ *
+ *  Copyright (C) 2001,02,04  NEC Corporation
+ *  Copyright (C) 2001,02,04  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <linux/types.h>
+
+void *memset (void *dst, int val, __kernel_size_t count)
+{
+	if (count) {
+		register unsigned loop;
+		register void *ptr asm ("ep") = dst;
+
+		/* replicate VAL into a long.  */
+		val &= 0xff;
+		val |= val << 8;
+		val |= val << 16;
+
+		/* copy initial unaligned bytes.  */
+		if ((long)ptr & 1) {
+			*(char *)ptr = val;
+			ptr = (void *)((char *)ptr + 1);
+			count--;
+		}
+		if (count > 2 && ((long)ptr & 2)) {
+			*(short *)ptr = val;
+			ptr = (void *)((short *)ptr + 1);
+			count -= 2;
+		}
+
+		/* 32-byte copying loop.  */
+		for (loop = count / 32; loop; loop--) {
+			asm ("sst.w %0, 0[ep]; sst.w %0, 4[ep];"
+			     "sst.w %0, 8[ep]; sst.w %0, 12[ep];"
+			     "sst.w %0, 16[ep]; sst.w %0, 20[ep];"
+			     "sst.w %0, 24[ep]; sst.w %0, 28[ep]"
+			     :: "r" (val) : "memory");
+			ptr += 32;
+		}
+		count %= 32;
+
+		/* long copying loop.  */
+		for (loop = count / 4; loop; loop--) {
+			*(long *)ptr = val;
+			ptr = (void *)((long *)ptr + 1);
+		}
+		count %= 4;
+
+		/* finish up with any trailing bytes.  */
+		if (count & 2) {
+			*(short *)ptr = val;
+			ptr = (void *)((short *)ptr + 1);
+		}
+		if (count & 1) {
+			*(char *)ptr = val;
+		}
+	}
+
+	return dst;
+}
diff --git a/arch/v850/lib/muldi3.c b/arch/v850/lib/muldi3.c
new file mode 100644
index 0000000..277ca25
--- /dev/null
+++ b/arch/v850/lib/muldi3.c
@@ -0,0 +1,61 @@
+/* muldi3.c extracted from gcc-2.7.2.3/libgcc2.c and 
+			   gcc-2.7.2.3/longlong.h which is: */
+/* Copyright (C) 1989, 1992, 1993, 1994, 1995, 2001 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("mulu %3, %0, %1"						\
+           : "=r" ((USItype)(w0)),					\
+             "=r" ((USItype)(w1))					\
+           : "%0" ((USItype)(u)),					\
+             "r" ((USItype)(v)))
+
+#define __umulsidi3(u, v) \
+  ({DIunion __w;							\
+    umul_ppmm (__w.s.high, __w.s.low, u, v);				\
+    __w.ll; })
+
+typedef 	 int SItype	__attribute__ ((mode (SI)));
+typedef unsigned int USItype	__attribute__ ((mode (SI)));
+typedef		 int DItype	__attribute__ ((mode (DI)));
+typedef int word_type __attribute__ ((mode (__word__)));
+
+struct DIstruct {SItype high, low;};
+
+typedef union
+{
+  struct DIstruct s;
+  DItype ll;
+} DIunion;
+
+DItype
+__muldi3 (DItype u, DItype v)
+{
+  DIunion w;
+  DIunion uu, vv;
+
+  uu.ll = u,
+  vv.ll = v;
+
+  w.ll = __umulsidi3 (uu.s.low, vv.s.low);
+  w.s.high += ((USItype) uu.s.low * (USItype) vv.s.high
+	       + (USItype) uu.s.high * (USItype) vv.s.low);
+
+  return w.ll;
+}
diff --git a/arch/v850/lib/negdi2.c b/arch/v850/lib/negdi2.c
new file mode 100644
index 0000000..571e04f
--- /dev/null
+++ b/arch/v850/lib/negdi2.c
@@ -0,0 +1,25 @@
+/*
+ * arch/v850/lib/negdi2.c -- 64-bit negation
+ *
+ *  Copyright (C) 2001  NEC Corporation
+ *  Copyright (C) 2001  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+typedef		 int DItype	__attribute__ ((mode (DI)));
+
+DItype __negdi2 (DItype x)
+{
+	__asm__ __volatile__
+		("not	r6, r10;"
+		 "add	1, r10;"
+		 "setf	c, r6;"
+		 "not	r7, r11;"
+		 "add	r6, r11"
+		 ::: "r6", "r7", "r10", "r11");
+}