# This patch adds s390 (31-bit) to UML.
# 
# SKAS0 and SKAS3 are tested a bit at least system boots and
# shuts down correctly, network (tun/tap) works and we even could
# start YaST on it.
# 
# Note:s
# We use a host running SuSE SLES8 with a "private" kernel named
# 2.4.21-fsc.11, that contains special adaptions and drivers for
# Fujitsu-Siemens mainframes. This means, our current SKAS3-patch
# doesn't fit to vanilla kernels. We will create a reworked patch for
# vanilla later (2.4 and 2.6).
# Our 2.4 kernel also contains two fixes and one enhancement, that all
# are essential to make UML run, even in SKAS0. The enhancement is to
# support PT_TRACESYSGOOD, that generally is available in 2.6 kernels
# but not in 2.4 for s390. So I would suggest to use 2.6 host for the
# moment.
# The fixes meanwhile are included into mainline. I don't know precisely
# the first version containing them, in 2.6.13-rc5 they are present.
# As those two patches are very small, they are inserted here as as
# comment (AFAICS, its easy to do the changes by hand on older kernel
# versions):
# 
# First patch to fix signal stack handling:
# --- a/arch/s390/kernel/signal.c 2005-03-22 11:07:39.000000000 +0100
# +++ b/arch/s390/kernel/signal.c 2005-03-22 11:08:44.000000000 +0100
# @@ -285,7 +285,7 @@
# 
#         /* This is the X/Open sanctioned signal stack switching.  */
#         if (ka->sa.sa_flags & SA_ONSTACK) {
# -               if (! on_sig_stack(sp))
# +               if (! sas_ss_flags(sp))
#                         sp = current->sas_ss_sp + current->sas_ss_size;
#         }
# 
# Second patch to allow skipping of syscall restart:
# --- a/arch/s390/kernel/ptrace.c 2005-05-07 07:20:31.000000000 +0200
# +++ b/arch/s390/kernel/ptrace.c 2005-08-02 06:45:48.000000000 +0200
# @@ -723,6 +761,13 @@
#                                  ? 0x80 : 0));
# 
#         /*
# +        * If the debugger has set an invalid system call number,
# +        * we prepare to skip the system call restart handling.
# +        */
# +       if (!entryexit && regs->gprs[2] >= NR_syscalls)
# +               regs->trap = -1;
# +
# +       /*
#          * 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
# 
Index: linux-2.6.16/arch/um/Kconfig_s390
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/Kconfig_s390	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,39 @@
+config 64_BIT
+	bool
+	default n
+
+config TOP_ADDR
+ 	hex
+ 	default 0x80000000
+
+config 3_LEVEL_PGTABLES
+	bool "Three-level pagetables"
+	default n
+	help
+	Three-level pagetables will let UML have more than 4G of physical
+	memory.  All the memory that can't be mapped directly will be treated
+	as high memory.
+
+config STUB_CODE
+	hex
+	default 0x7fffe000
+
+config STUB_DATA
+	hex
+	default 0x7ffff000
+
+config STUB_START
+	hex
+	default STUB_CODE
+
+config ARCH_HAS_SC_SIGNALS
+	bool
+	default y
+
+config ARCH_REUSE_HOST_VSYSCALL_AREA
+	bool
+	default n
+
+config ARCH_S390_31
+	bool
+	default y
Index: linux-2.6.16/arch/um/Makefile-s390
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/Makefile-s390	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,57 @@
+core-y += arch/um/sys-s390/
+
+TOP_ADDR := $(CONFIG_TOP_ADDR)
+
+ifeq ($(CONFIG_MODE_SKAS),y)
+  ifneq ($(CONFIG_MODE_TT),y)
+     START := 0x8048000
+  endif
+endif
+
+LDFLAGS			+= -m elf_s390
+ELF_ARCH		:= $(SUBARCH)
+ELF_FORMAT 		:= elf32-$(SUBARCH)
+JIFFIES_OFS		:= 4
+OBJCOPYFLAGS  		:= -O binary -R .note -R .comment -S
+
+ifeq ("$(origin SUBARCH)", "command line")
+ifneq ("$(shell uname -m)", "$(SUBARCH)")
+CFLAGS			+= $(call cc-option,-m31)
+USER_CFLAGS		+= $(call cc-option,-m31)
+HOSTCFLAGS		+= $(call cc-option,-m31)
+HOSTLDFLAGS		+= $(call cc-option,-m31)
+AFLAGS			+= $(call cc-option,-m31)
+LINK-y			+= $(call cc-option,-m31)
+UML_OBJCOPYFLAGS	+= -F $(ELF_FORMAT)
+
+export LDFLAGS HOSTCFLAGS HOSTLDFLAGS UML_OBJCOPYFLAGS
+endif
+endif
+
+CFLAGS += -U__$(SUBARCH)__ -U$(SUBARCH) $(STUB_CFLAGS)
+
+ifneq ($(CONFIG_GPROF),y)
+ARCH_CFLAGS += -DUM_FASTCALL
+endif
+
+SYS_UTIL_DIR	:= $(ARCH_DIR)/sys-s390/util
+SYS_HEADERS	:= $(SYS_DIR)/sc.h $(SYS_DIR)/thread.h
+
+prepare: $(SYS_HEADERS)
+
+$(SYS_DIR)/sc.h: $(SYS_UTIL_DIR)/mk_sc
+	$(call filechk,gen_header)
+
+$(SYS_DIR)/thread.h: $(SYS_UTIL_DIR)/mk_thread
+	$(call filechk,gen_header)
+
+$(SYS_UTIL_DIR)/mk_sc: scripts_basic $(ARCH_DIR)/user-offsets.h FORCE
+	$(Q)$(MAKE) $(build)=$(SYS_UTIL_DIR) $@
+
+$(SYS_UTIL_DIR)/mk_thread: scripts_basic $(ARCH_DIR)/kernel-offsets.h FORCE
+	$(Q)$(MAKE) $(build)=$(SYS_UTIL_DIR) $@
+
+$(SYS_UTIL_DIR): scripts_basic include/asm FORCE
+	$(Q)$(MAKE) $(build)=$(SYS_UTIL_DIR)
+
+CLEAN_FILES += $(SYS_HEADERS)
Index: linux-2.6.16/arch/um/include/sysdep-s390/breakpoint.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/include/sysdep-s390/breakpoint.h	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2005 Fujitsu Siemens Computers GmbH
+ * Author: Bodo Stroesser (bstroesser@fujitsu-siemens.com)
+ *
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSDEP_BREAKPOINT_H
+#define __SYSDEP_BREAKPOINT_H
+
+#include "skas_ptregs.h"
+
+static inline long trap_myself(void)
+{
+	__asm__ __volatile__ (
+		"   .word   %0, 0"
+                : : "i" (HOST_S390_BREAKPOINT) );
+}
+
+#endif
Index: linux-2.6.16/arch/um/include/sysdep-s390/checksum.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/include/sysdep-s390/checksum.h	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,238 @@
+#ifndef UM_S390_CHECKSUM_H
+#define UM_S390_CHECKSUM_H
+
+/* This is  modified for UML by Bodo Stroesser (bstroesser@fujitsu-siemens.com)
+ */
+
+/*
+ *  include/asm-s390/checksum.h
+ *    S390 fast network checksum routines
+ *    see also arch/S390/lib/checksum.c
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Ulrich Hild        (first version)
+ *               Martin Schwidefsky (heavily optimized CKSM version)
+ *               D.J. Barrow        (third attempt)
+ */
+
+#include <asm/uaccess.h>
+
+/*
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * returns a 32-bit number suitable for feeding into itself
+ * or csum_tcpudp_magic
+ *
+ * this function must be called with even lengths, except
+ * for the last fragment, which may be odd
+ *
+ * it's best to have buff aligned on a 32-bit boundary
+ */
+
+static inline unsigned int
+csum_partial(const unsigned char * buff, int len, unsigned int sum)
+{
+	/*
+	 * Experiments with ethernet and slip connections show that buf
+	 * is aligned on either a 2-byte or 4-byte boundary.
+	 */
+#ifndef __s390x__
+	register_pair rp;
+
+	rp.subreg.even = (unsigned long) buff;
+	rp.subreg.odd = (unsigned long) len;
+	__asm__ __volatile__ (
+		"0:  cksm %0,%1\n"	/* do checksum on longs */
+		"    jo   0b\n"
+		: "+&d" (sum), "+&a" (rp) : : "cc", "memory" );
+#else /* __s390x__ */
+        __asm__ __volatile__ (
+                "    lgr  2,%1\n"    /* address in gpr 2 */
+                "    lgfr 3,%2\n"    /* length in gpr 3 */
+                "0:  cksm %0,2\n"    /* do checksum on longs */
+                "    jo   0b\n"
+                : "+&d" (sum)
+                : "d" (buff), "d" (len)
+                : "cc", "memory", "2", "3" );
+#endif /* __s390x__ */
+	return sum;
+}
+
+/*
+ * the same as csum_partial_copy, but copies from user space.
+ *
+ * here even more important to align src and dst on a 32-bit (or even
+ * better 64-bit) boundary
+ *
+ * Copy from userspace and compute checksum.  If we catch an exception
+ * then zero the rest of the buffer.
+ */
+static inline unsigned int
+csum_partial_copy_from_user(const char __user *src, 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);
+}
+
+
+static inline unsigned int
+csum_partial_copy_nocheck (const char *src, char *dst, int len, unsigned int sum)
+{
+        memcpy(dst,src,len);
+        return csum_partial(dst, len, sum);
+}
+
+/*
+ *      Fold a partial checksum without adding pseudo headers
+ */
+static inline unsigned short
+csum_fold(unsigned int sum)
+{
+#ifndef __s390x__
+	register_pair rp;
+
+	__asm__ __volatile__ (
+		"    slr  %N1,%N1\n" /* %0 = H L */
+		"    lr   %1,%0\n"   /* %0 = H L, %1 = H L 0 0 */
+		"    srdl %1,16\n"   /* %0 = H L, %1 = 0 H L 0 */
+		"    alr  %1,%N1\n"  /* %0 = H L, %1 = L H L 0 */
+		"    alr  %0,%1\n"   /* %0 = H+L+C L+H */
+		"    srl  %0,16\n"   /* %0 = H+L+C */
+		: "+&d" (sum), "=d" (rp) : : "cc" );
+#else /* __s390x__ */
+	__asm__ __volatile__ (
+		"    sr   3,3\n"   /* %0 = H*65536 + L */
+		"    lr   2,%0\n"  /* %0 = H L, R2/R3 = H L / 0 0 */
+		"    srdl 2,16\n"  /* %0 = H L, R2/R3 = 0 H / L 0 */
+		"    alr  2,3\n"   /* %0 = H L, R2/R3 = L H / L 0 */
+		"    alr  %0,2\n"  /* %0 = H+L+C L+H */
+                "    srl  %0,16\n" /* %0 = H+L+C */
+		: "+&d" (sum) : : "cc", "2", "3");
+#endif /* __s390x__ */
+	return ((unsigned short) ~sum);
+}
+
+/*
+ *	This is a version of ip_compute_csum() optimized for IP headers,
+ *	which always checksum on 4 octet boundaries.
+ *
+ */
+static inline unsigned short
+ip_fast_csum(unsigned char *iph, unsigned int ihl)
+{
+	unsigned long sum;
+#ifndef __s390x__
+	register_pair rp;
+
+	rp.subreg.even = (unsigned long) iph;
+	rp.subreg.odd = (unsigned long) ihl*4;
+        __asm__ __volatile__ (
+		"    sr   %0,%0\n"   /* set sum to zero */
+                "0:  cksm %0,%1\n"   /* do checksum on longs */
+                "    jo   0b\n"
+                : "=&d" (sum), "+&a" (rp) : : "cc", "memory" );
+#else /* __s390x__ */
+        __asm__ __volatile__ (
+		"    slgr %0,%0\n"   /* set sum to zero */
+                "    lgr  2,%1\n"    /* address in gpr 2 */
+                "    lgfr 3,%2\n"    /* length in gpr 3 */
+                "0:  cksm %0,2\n"    /* do checksum on ints */
+                "    jo   0b\n"
+                : "=&d" (sum)
+                : "d" (iph), "d" (ihl*4)
+                : "cc", "memory", "2", "3" );
+#endif /* __s390x__ */
+        return csum_fold(sum);
+}
+
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 32-bit checksum
+ */
+static inline unsigned int
+csum_tcpudp_nofold(unsigned long saddr, unsigned long daddr,
+                   unsigned short len, unsigned short proto,
+                   unsigned int sum)
+{
+#ifndef __s390x__
+	__asm__ __volatile__ (
+                "    alr   %0,%1\n"  /* sum += saddr */
+                "    brc   12,0f\n"
+		"    ahi   %0,1\n"   /* add carry */
+		"0:"
+		: "+&d" (sum) : "d" (saddr) : "cc" );
+	__asm__ __volatile__ (
+                "    alr   %0,%1\n"  /* sum += daddr */
+                "    brc   12,1f\n"
+                "    ahi   %0,1\n"   /* add carry */
+		"1:"
+		: "+&d" (sum) : "d" (daddr) : "cc" );
+	__asm__ __volatile__ (
+                "    alr   %0,%1\n"  /* sum += (len<<16) + (proto<<8) */
+		"    brc   12,2f\n"
+		"    ahi   %0,1\n"   /* add carry */
+		"2:"
+		: "+&d" (sum)
+		: "d" (((unsigned int) len<<16) + (unsigned int) proto)
+		: "cc" );
+#else /* __s390x__ */
+	__asm__ __volatile__ (
+                "    lgfr  %0,%0\n"
+                "    algr  %0,%1\n"  /* sum += saddr */
+                "    brc   12,0f\n"
+		"    aghi  %0,1\n"   /* add carry */
+		"0:  algr  %0,%2\n"  /* sum += daddr */
+                "    brc   12,1f\n"
+                "    aghi  %0,1\n"   /* add carry */
+		"1:  algfr %0,%3\n"  /* sum += (len<<16) + proto */
+		"    brc   12,2f\n"
+		"    aghi  %0,1\n"   /* add carry */
+		"2:  srlg  0,%0,32\n"
+                "    alr   %0,0\n"   /* fold to 32 bits */
+                "    brc   12,3f\n"
+                "    ahi   %0,1\n"   /* add carry */
+                "3:  llgfr %0,%0"
+		: "+&d" (sum)
+		: "d" (saddr), "d" (daddr),
+		  "d" (((unsigned int) len<<16) + (unsigned int) proto)
+		: "cc", "0" );
+#endif /* __s390x__ */
+	return sum;
+}
+
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
+ */
+
+static inline unsigned short int
+csum_tcpudp_magic(unsigned long saddr, unsigned long daddr,
+                  unsigned short len, unsigned short proto,
+                  unsigned int sum)
+{
+	return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
+}
+
+/*
+ * this routine is used for miscellaneous IP-like checksums, mainly
+ * in icmp.c
+ */
+
+static inline unsigned short
+ip_compute_csum(unsigned char * buff, int len)
+{
+	return csum_fold(csum_partial(buff, len, 0));
+}
+
+#endif /* _S390_CHECKSUM_H */
Index: linux-2.6.16/arch/um/include/sysdep-s390/faultinfo.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/include/sysdep-s390/faultinfo.h	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2004, 2005 Fujitsu Siemens Computers GmbH
+ * Author: Bodo Stroesser <bstroesser@fujitsu-siemens.com>
+ * Licensed under the GPL
+ */
+
+#ifndef __FAULTINFO_S390_H
+#define __FAULTINFO_S390_H
+
+/* On s390, this is just the same as struct ptrace_faultinfo */
+struct faultinfo {
+	unsigned long address;
+	int trap_no;
+};
+
+#define FAULT_WRITE(fi) ((fi).trap_no == 4)
+#define FAULT_ADDRESS(fi) ((fi).address)
+
+#define PTRACE_FULL_FAULTINFO 1
+
+#define ARCH_STUB_SEGV_MASK_SIGNAL -1
+
+#endif
Index: linux-2.6.16/arch/um/include/sysdep-s390/ptrace.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/include/sysdep-s390/ptrace.h	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2004, 2005 Fujitsu Siemens Computer GmbH
+ * Author: Bodo Stroesser (bstroesser@fujitsu-siemens.com)
+ *
+ * This is derived from arch/um/include/sysdep-i386/ptrace.h
+ *  Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ *
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSDEP_S390_PTRACE_H
+#define __SYSDEP_S390_PTRACE_H
+
+#include "uml-config.h"
+
+#ifdef UML_CONFIG_MODE_TT
+#include "sysdep/sc.h"
+#endif
+
+#ifdef UML_CONFIG_MODE_SKAS
+
+/* syscall emulation path in ptrace */
+
+#ifndef PTRACE_SYSEMU
+#define PTRACE_SYSEMU 31
+#endif
+#ifndef PTRACE_SYSEMU_SINGLESTEP
+#define PTRACE_SYSEMU_SINGLESTEP 32
+#endif
+
+void set_using_sysemu(int value);
+int get_using_sysemu(void);
+extern int sysemu_supported;
+
+extern void update_debugregs(int seq);
+
+#include "skas_ptregs.h"
+#include "sysdep/faultinfo.h"
+
+#define REGS_MASK(r) ((r)[HOST_MASK])
+#define REGS_ADDR(r) ((r)[HOST_ADDR])
+#define REGS_IP(r) \
+	(((struct { unsigned long amode: 1; \
+	            unsigned long addr31: 31; \
+	          } *)&REGS_ADDR(r))->addr31)
+#define REGS_GPRS(r) ((r)+HOST_GPRS)
+#define REGS_GPR(r,n) (REGS_GPRS(r)[n])
+#define REGS_ACRS(r) ((r)+HOST_ACRS)
+#define REGS_ACR(r,n) (REGS_ACRS(r)[n])
+#define REGS_ORIGGPR2(r) ((r)[HOST_ORIGGPR2])
+#define REGS_SP(r) (REGS_GPR(r,15))
+
+#define REGS_SET_SYSCALL_RETURN(r, res) REGS_GPR(r,2) = (res)
+
+#endif
+
+#include "choose-mode.h"
+
+union uml_pt_regs {
+#ifdef UML_CONFIG_MODE_TT
+	struct tt_regs {
+		long syscall;
+		unsigned long origgpr2;
+		void *sc;
+		struct faultinfo faultinfo;
+	} tt;
+#endif
+#ifdef UML_CONFIG_MODE_SKAS
+	struct skas_regs {
+		unsigned long regs[HOST_FRAME_SIZE];
+		unsigned long fpregs[HOST_FP_SIZE];
+		struct faultinfo faultinfo;
+		long syscall;
+		int is_user;
+	} skas;
+#endif
+};
+
+#define EMPTY_UML_PT_REGS { }
+
+extern int mode_tt;
+
+#define SC_GPR(r,n) ((SC_GPRS(r))[n])
+#define SC_ACR(r,n) ((SC_ACRS(r))[n])
+
+#define UPT_SC(r) ((r)->tt.sc)
+#define UPT_MASK(r) \
+	CHOOSE_MODE(SC_PSWMASK(UPT_SC(r)), REGS_MASK((r)->skas.regs))
+#define UPT_ADDR(r) \
+	CHOOSE_MODE(SC_PSWADDR(UPT_SC(r)), REGS_ADDR((r)->skas.regs))
+#define UPT_IP(r) \
+	CHOOSE_MODE(SC_IP(UPT_SC(r)), REGS_IP((r)->skas.regs))
+#define UPT_SP(r) \
+	CHOOSE_MODE(SC_GPR(UPT_SC(r),15), REGS_SP((r)->skas.regs))
+#define UPT_GPRS(r) \
+	CHOOSE_MODE(SC_GPRS(UPT_SC(r)), REGS_GPRS((r)->skas.regs))
+#define UPT_GPR(r,n) \
+	CHOOSE_MODE(SC_GPR(UPT_SC(r),n), REGS_GPR((r)->skas.regs,n))
+#define UPT_ACRS(r) \
+	CHOOSE_MODE(SC_ACRS(UPT_SC(r)), REGS_ACRS((r)->skas.regs))
+#define UPT_ACR(r,n) \
+	CHOOSE_MODE(SC_ACR(UPT_SC(r),n), REGS_ACR((r)->skas.regs,n))
+#define UPT_ORIGGPR2(r) \
+	CHOOSE_MODE((r)->tt.origgpr2, REGS_ORIGGPR2((r)->skas.regs))
+#define UPT_FPRS(r) \
+	CHOOSE_MODE(SC_FPREGS(UPT_SC(r)), ((r)->skas.fpregs))
+#define UPT_FPR(r,n) \
+	((UPT_FPRS(r))[n])
+
+#define UPT_SYSCALL_ARG1(r) UPT_ORIGGPR2(r)
+#define UPT_SYSCALL_ARG2(r) UPT_GPR(r,3)
+#define UPT_SYSCALL_ARG3(r) UPT_GPR(r,4)
+#define UPT_SYSCALL_ARG4(r) UPT_GPR(r,5)
+#define UPT_SYSCALL_ARG5(r) UPT_GPR(r,6)
+#define UPT_SYSCALL_ARG6(r) UPT_GPR(r,7)
+
+extern int user_context(unsigned long sp);
+
+#define UPT_IS_USER(r) \
+	CHOOSE_MODE(user_context(UPT_SP(r)), (r)->skas.is_user)
+
+#define SYSCALL_ARGS(r) UPT_SYSCALL_ARG1(r), \
+                        UPT_SYSCALL_ARG2(r), \
+ 			UPT_SYSCALL_ARG3(r), \
+                        UPT_SYSCALL_ARG4(r), \
+		        UPT_SYSCALL_ARG5(r), \
+                        UPT_SYSCALL_ARG6(r)
+
+#define UPT_SET_SYSCALL_RETURN(r, res) \
+	CHOOSE_MODE(SC_SET_SYSCALL_RETURN(UPT_SC(r), (res)), \
+                    REGS_SET_SYSCALL_RETURN((r)->skas.regs, (res)))
+
+#define UPT_RESTART_SYSCALL(r) \
+	set_tsk_thread_flag(current, TIF_RESTART_SVC)
+
+#define UPT_ORIG_SYSCALL(r) UPT_GPR(r,2)
+#define UPT_SYSCALL_NR(r) \
+	CHOOSE_MODE((r)->tt.syscall, (r)->skas.syscall)
+#define UPT_SYSCALL_RET(r) UPT_GPR(r,2)
+
+#define UPT_FAULTINFO(r) \
+	CHOOSE_MODE((&(r)->tt.faultinfo), (&(r)->skas.faultinfo))
+
+#define SUBARCH_SET_SINGLESTEPPING(task, onoff) \
+	{ \
+		extern void FixPerRegisters(struct task_struct *tsk); \
+		task->thread.arch.per_info.single_step = onoff; \
+		FixPerRegisters(task); \
+	}
+
+#define SUBARCH_PTRACE_SPECIAL(task, request, addr, data) \
+	{ \
+		struct user *dummy = NULL; \
+		if (task == current && \
+		    addr == (long )&dummy->regs->ieee_instruction_pointer) { \
+			if (request == PEEKUSER) { \
+				ret = peek_user(task,addr,data); \
+				goto out_tsk; \
+			} \
+			else if (request == POKEUSER) { \
+				ret = poke_user(task,addr,data); \
+				goto out_tsk; \
+			} \
+		} \
+	}
+
+#define SUBARCH_EXECVE1(uptregs) \
+	{ /* reset FPC register */ \
+	UPT_FPR((uptregs),0) = 0; }
+
+#endif
Index: linux-2.6.16/arch/um/include/sysdep-s390/ptrace_user.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/include/sysdep-s390/ptrace_user.h	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2004, 2005 Fujitsu Siemens Computer GmbH
+ * Author: Bodo Stroesser (bstroesser@fujitsu-siemens.com)
+ *
+ * This is derived from arch/um/include/sysdep-i386/ptrace_user.h
+ *  Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ *
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSDEP_S390_PTRACE_USER_H__
+#define __SYSDEP_S390_PTRACE_USER_H__
+
+#include <sys/ptrace.h>
+#include <linux/ptrace.h>
+#include <asm/ptrace.h>
+
+#define PT_SYSCALL_NR(regs) ((regs)[PT_GPR2/sizeof(long)])
+#define PT_SYSCALL_NR_OFFSET PT_GPR2
+
+#define PT_SYSCALL_NR_SKIP_RESTART -1
+
+#define PT_SYSCALL_ARG1_OFFSET PT_ORIGGPR2
+#define PT_SYSCALL_ARG2_OFFSET PT_GPR3
+#define PT_SYSCALL_ARG3_OFFSET PT_GPR4
+#define PT_SYSCALL_ARG4_OFFSET PT_GPR5
+#define PT_SYSCALL_ARG5_OFFSET PT_GPR6
+#define PT_SYSCALL_ARG6_OFFSET PT_GPR7
+
+#define PT_SYSCALL_RET_OFFSET PT_GPR2
+
+#define PT_IP_OFFSET PT_PSWADDR
+#define PT_IP(regs) ((regs)[PT_PSWADDR/sizeof(long)]&0x7fffffff)
+#define PT_SP(regs) ((regs)[PT_GPR15])
+
+#define REGS_IP_INDEX (PT_PSWADDR/sizeof(long))
+#define REGS_SP_INDEX (PT_GPR15/sizeof(long))
+
+#ifndef FRAME_SIZE
+#define FRAME_SIZE (PT_FPC/sizeof(long))
+#endif
+#define FRAME_SIZE_OFFSET (FRAME_SIZE * sizeof(unsigned long))
+
+#define FP_FRAME_SIZE ((PT_CR9-PTFPC)/sizeof(long))
+
+#define MAX_REG_OFFSET (FRAME_SIZE_OFFSET)
+#define MAX_REG_NR (FRAME_SIZE)
+
+/* These are for the old s390 2.4 kernels, that
+ * dont have PTRACE_SETOPTIONS normally
+ */
+#ifndef PTRACE_SETOPTIONS
+#define PTRACE_SETOPTIONS 0x4200
+#endif
+
+#ifndef PTRACE_O_TRACESYSGOOD
+#define PTRACE_O_TRACESYSGOOD 0x00000001
+#endif
+
+#ifndef PTRACE_GETREGS
+#define PTRACE_GETREGS 12
+#endif
+#ifndef PTRACE_SETREGS
+#define PTRACE_SETREGS 13
+#endif
+
+#ifndef PTRACE_GETFPREGS
+#define PTRACE_GETFPREGS 14
+#endif
+#ifndef PTRACE_SETFPREGS
+#define PTRACE_SETFPREGS 15
+#endif
+
+#endif
Index: linux-2.6.16/arch/um/include/sysdep-s390/sigcontext.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/include/sysdep-s390/sigcontext.h	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2004, 2005 Fujitsu Siemens Computer GmbH
+ * Author: Bodo Stroesser (bstroesser@fujitsu-siemens.com)
+ *
+ * This is derived from arch/um/include/sysdep-i386/sigcontext.h
+ *  Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ *
+ * Licensed under the GPL
+ */
+
+#ifndef __SYS_SIGCONTEXT_S390_H
+#define __SYS_SIGCONTEXT_S390_H
+
+#include "sc.h"
+
+#define SC_SIGMASK(sc) (*SC_SIGMASK_P(sc))
+
+#define IP_RESTART_SYSCALL(ip) ((ip) -= 2)
+
+#define SC_RESTART_SYSCALL(sc) IP_RESTART_SYSCALL(SC_IP(sc))
+#define SC_SET_SYSCALL_RETURN(sc, result) SC_GPR(sc,2) = (result)
+
+#define SC_SP(sc) SC_GPR(sc,15)
+
+#define GET_FAULTINFO_FROM_SC(fi,sc) \
+	(fi = *(struct faultinfo *)*SC_ERRINFO_P(sc))
+
+#define SC_START_SYSCALL(sc) do SC_GPR(sc,2) = -ENOSYS; while(0)
+
+/* This is Page Fault */
+#define SEGV_IS_FIXABLE(fi) \
+	((fi)->trap_no == 0x04 || (fi)->trap_no == 0x10 || (fi)->trap_no == 0x11)
+
+#endif
Index: linux-2.6.16/arch/um/include/sysdep-s390/signal.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/include/sysdep-s390/signal.h	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2004, 2005 Fujitsu Siemens Computer GmbH
+ * Author: Bodo Stroesser (bstroesser@fujitsu-siemens.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __S390_SIGNAL_H_
+#define __S390_SIGNAL_H_
+
+#include <signal.h>
+
+#define ARCH_SIGHDLR_PARAM \
+	struct sigcontext * contxt, int trap, unsigned long addr
+
+#define ARCH_GET_SIGCONTEXT(sc, sig) \
+	struct faultinfo fi; \
+	fi.trap_no = trap; \
+	fi.address = addr; \
+	sc = contxt; \
+	*SC_ERRINFO_P(sc) = (long )&fi;
+
+#endif
Index: linux-2.6.16/arch/um/include/sysdep-s390/skas_ptrace.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/include/sysdep-s390/skas_ptrace.h	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSDEP_S390_SKAS_PTRACE_H
+#define __SYSDEP_S390_SKAS_PTRACE_H
+
+/* Just the same as struct faultinfo */
+struct ptrace_faultinfo {
+	unsigned long address;
+	int trap_no;
+};
+
+#endif
Index: linux-2.6.16/arch/um/include/sysdep-s390/stub.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/include/sysdep-s390/stub.h	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2004, 2005 Fujitsu Siemens Computer GmbH
+ * Author: Bodo Stroesser (bstroesser@fujitsu-siemens.com)
+ *
+ * This is derived from arch/um/include/sysdep-i386/stub.h
+ *  Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ *
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSDEP_STUB_H
+#define __SYSDEP_STUB_H
+
+#include "uml-config.h"
+#include <asm/unistd.h>
+#include "sysdep/breakpoint.h"
+
+/* on 2.4 s390, CLONE_PARENT isn't defined in bits/sched.h */
+#ifndef CLONE_PARENT
+#define CLONE_PARENT  0x00008000
+#endif
+
+extern void stub_segv_handler(int sig);
+extern void stub_clone_handler(void);
+
+#define ARCH_STUB_NO_SIGRETURN 1
+
+#define STUB_SYSCALL_RET GPR2
+#define STUB_MMAP_NR __NR_mmap2
+#define MMAP_OFFSET(o) ((o) >> PAGE_SHIFT)
+
+/*
+ * All stub_syscallX routines use the syscall-array via
+ * calling stub_syscall_entry.
+ * Entry and array are defined in stub.S
+ */
+
+static inline long stub_syscall1(long syscall, long arg1)
+{
+	extern int __syscall_stub_start;
+	extern int stub_syscall_entry;
+
+	register long __syscall asm("1") = syscall;
+	register long __arg1 asm("2") = arg1;
+	register long __svcres asm("2");
+	register long __entry asm("8") = UML_CONFIG_STUB_CODE +
+		(long )&stub_syscall_entry - (long )&__syscall_stub_start;
+
+	__asm__ __volatile__ (
+		"    basr %%r14,%%r8"
+		: "=d" (__svcres)
+		: "d" (__syscall),
+		  "0" (__arg1),
+		  "d" (__entry)
+		: "9", "14", "cc");
+	return __svcres;
+}
+
+static inline long stub_syscall2(long syscall, long arg1, long arg2)
+{
+	extern int __syscall_stub_start;
+	extern int stub_syscall_entry;
+
+	register long __syscall asm("1") = syscall;
+	register long __arg1 asm("2");
+	register long __arg2 asm("3");
+	register long __svcres asm("2");
+	register long __entry asm("8") = UML_CONFIG_STUB_CODE +
+		(long )&stub_syscall_entry - (long )&__syscall_stub_start;
+
+	if(syscall == __NR_clone) {
+		/* Switch params before calling sys_clone, as s390
+		 * uses changed sequence of params compared to i386
+		 */
+		__arg1 = arg2;
+		__arg2 = arg1;
+	}
+	else{
+		__arg1 = arg1;
+		__arg2 = arg2;
+	}
+	__asm__ __volatile__ (
+		"    basr %%r14,%%r8"
+		: "=d" (__svcres)
+		: "d" (__syscall),
+		  "0" (__arg1),
+		  "d" (__arg2),
+		  "d" (__entry)
+		: "9", "14", "cc");
+	return __svcres;
+}
+
+static inline long stub_syscall3(long syscall, long arg1, long arg2, long arg3)
+{
+	extern int __syscall_stub_start;
+	extern int stub_syscall_entry;
+
+	register long __syscall asm("1") = syscall;
+	register long __arg1 asm("2") = arg1;
+	register long __arg2 asm("3") = arg2;
+	register long __arg3 asm("4") = arg3;
+	register long __svcres asm("2");
+	register long __entry asm("8") = UML_CONFIG_STUB_CODE +
+		(long )&stub_syscall_entry - (long )&__syscall_stub_start;
+
+	__asm__ __volatile__ (
+		"    basr %%r14,%%r8"
+		: "=d" (__svcres)
+		: "d" (__syscall),
+		  "0" (__arg1),
+		  "d" (__arg2),
+		  "d" (__arg3),
+		  "d" (__entry)
+		: "9", "14", "cc");
+	return __svcres;
+}
+
+static inline long stub_syscall4(long syscall, long arg1, long arg2, long arg3,
+				 long arg4)
+{
+	extern int __syscall_stub_start;
+	extern int stub_syscall_entry;
+
+	register long __syscall asm("1") = syscall;
+	register long __arg1 asm("2") = arg1;
+	register long __arg2 asm("3") = arg2;
+	register long __arg3 asm("4") = arg3;
+	register long __arg4 asm("5") = arg4;
+	register long __svcres asm("2");
+	register long __entry asm("8") = UML_CONFIG_STUB_CODE +
+		(long )&stub_syscall_entry - (long )&__syscall_stub_start;
+
+	__asm__ __volatile__ (
+		"    basr %%r14,%%r8"
+		: "=d" (__svcres)
+		: "d" (__syscall),
+		  "0" (__arg1),
+		  "d" (__arg2),
+		  "d" (__arg3),
+		  "d" (__arg4),
+		  "d" (__entry)
+		: "9", "14", "cc");
+	return __svcres;
+}
+
+static inline long _stub_syscall6(long syscall, long arg1, long arg2, long arg3,
+				  long arg4, long arg5, long arg6)
+{
+	extern int __syscall_stub_start;
+	extern int stub_syscall_entry;
+
+	register long __syscall asm("1") = syscall;
+	register long __arg1 asm("2") = arg1;
+	register long __arg2 asm("3") = arg2;
+	register long __arg3 asm("4") = arg3;
+	register long __arg4 asm("5") = arg4;
+	register long __arg5 asm("6") = arg5;
+	register long __arg6 asm("7") = arg6;
+	register long __svcres asm("2");
+	register long __entry asm("8") = UML_CONFIG_STUB_CODE +
+		(long )&stub_syscall_entry - (long )&__syscall_stub_start;
+
+	__asm__ __volatile__ (
+		"    basr %%r14,%%r8"
+		: "=d" (__svcres)
+		: "d" (__syscall),
+		  "0" (__arg1),
+		  "d" (__arg2),
+		  "d" (__arg3),
+		  "d" (__arg4),
+		  "d" (__arg5),
+		  "d" (__arg6),
+		  "d" (__entry)
+		: "9", "14", "cc");
+	return __svcres;
+}
+
+static inline long stub_syscall6(long syscall, long arg1, long arg2, long arg3,
+				  long arg4, long arg5, long arg6)
+{
+	long args[6];
+
+	if(syscall != __NR_mmap && syscall != __NR_mmap2)
+		return _stub_syscall6(syscall, arg1, arg2, arg3,
+					       arg4, arg5, arg6);
+
+	args[0] = arg1;
+	args[1] = arg2;
+	args[2] = arg3;
+	args[3] = arg4;
+	args[4] = arg5;
+	args[5] = arg6;
+
+	return stub_syscall1(syscall, (long )args);
+}
+
+#endif
Index: linux-2.6.16/arch/um/include/sysdep-s390/syscalls.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/include/sysdep-s390/syscalls.h	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2004, 2005 Fujitsu Siemens Computer GmbH
+ * Author: Bodo Stroesser (bstroesser@fujitsu-siemens.com)
+ * Licensed under the GPL
+ */
+
+#include "sysdep/ptrace.h"
+
+typedef long syscall_handler_t(struct pt_regs);
+
+extern syscall_handler_t *sys_call_table[];
+
+#define EXECUTE_SYSCALL(syscall, regs) \
+	((long (*)(unsigned long, unsigned long, unsigned long, \
+	           unsigned long, unsigned long, unsigned long)) \
+			(*sys_call_table[syscall]))(SYSCALL_ARGS(&regs->regs))
Index: linux-2.6.16/arch/um/os-Linux/skas/util/mk_ptregs_s390.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/os-Linux/skas/util/mk_ptregs_s390.c	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,29 @@
+#include <stdio.h>
+#include "../../../user-offsets.h"
+
+#define SHOW(name) printf("#define %s %d\n", #name, name)
+
+int main(int argc, char **argv)
+{
+	printf("/* Automatically generated by "
+	       "arch/um/kernel/skas/util/mk_ptregs */\n");
+	printf("\n");
+	printf("#ifndef __SKAS_PT_REGS_\n");
+	printf("#define __SKAS_PT_REGS_\n");
+	printf("\n");
+	SHOW(HOST_FRAME_SIZE);
+	SHOW(HOST_FP_SIZE);
+	SHOW(HOST_XFP_SIZE);
+
+	SHOW(HOST_MASK);
+	SHOW(HOST_ADDR);
+	SHOW(HOST_GPRS);
+	SHOW(HOST_ACRS);
+	SHOW(HOST_ORIGGPR2);
+
+	SHOW(HOST_S390_BREAKPOINT);
+
+	printf("\n");
+	printf("#endif\n");
+	return(0);
+}
Index: linux-2.6.16/arch/um/os-Linux/sys-s390/Makefile
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/os-Linux/sys-s390/Makefile	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,10 @@
+#
+# Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+# Licensed under the GPL
+#
+
+obj-$(CONFIG_MODE_SKAS) = registers.o
+
+USER_OBJS := $(obj-y)
+
+include arch/um/scripts/Makefile.rules
Index: linux-2.6.16/arch/um/os-Linux/sys-s390/registers.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/os-Linux/sys-s390/registers.c	2006-04-27 18:43:44.000000000 -0400
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2004, 2005 Fujitsu Siemens Computer GmbH
+ * Author: Bodo Stroesser (bstroesser@fujitsu-siemens.com)
+ *
+ * This is derived from arch/um/os-Linux/sys-i386/registers.c
+ *  Copyright (C) 2004 PathScale, Inc
+ *
+ * Licensed under the GPL
+ */
+
+#include <errno.h>
+#include <string.h>
+#include "sysdep/ptrace_user.h"
+#include "sysdep/ptrace.h"
+#include "uml-config.h"
+#include "skas_ptregs.h"
+#include "registers.h"
+#include "user.h"
+
+/* These are set once at boot time and not changed thereafter */
+/* Do not change sequence and do not split, as this is used
+ * as a consecutive buffer in init_registers */
+static unsigned long exec_regs[HOST_FRAME_SIZE];
+static unsigned long exec_fp_regs[HOST_FP_SIZE];
+
+void init_thread_registers(union uml_pt_regs *to)
+{
+	memcpy(to->skas.regs, exec_regs, sizeof(to->skas.regs));
+	memcpy(to->skas.fpregs, exec_fp_regs, sizeof(to->skas.fpregs));
+}
+
+int ptrace_getregs(long pid, unsigned long * regs)
+{
+	int err;
+
+	ptrace_area parea = {
+		.process_addr = (unsigned long)regs,
+		.kernel_addr = PT_PSWMASK,
+		.len = HOST_FRAME_SIZE * sizeof(long)
+	};
+	err = ptrace(PTRACE_PEEKUSR_AREA, pid, &parea, 0);
+	if(err)
+		return -errno;
+	return 0;
+}
+
+int ptrace_setregs(long pid, unsigned long * regs)
+{
+	int err;
+
+	ptrace_area parea = {
+		.process_addr = (unsigned long)regs,
+		.kernel_addr = PT_PSWMASK,
+		.len = HOST_FRAME_SIZE * sizeof(long)
+	};
+	err = ptrace(PTRACE_POKEUSR_AREA, pid, &parea, 0);
+	if(err)
+		return -errno;
+	return 0;
+}
+
+void save_registers(int pid, union uml_pt_regs *regs)
+{
+	int err;
+
+	ptrace_area parea = {
+		.process_addr = (unsigned long)regs->skas.regs,
+		.kernel_addr = PT_PSWMASK,
+		.len = (HOST_FRAME_SIZE + HOST_FP_SIZE) * sizeof(long)
+	};
+	err = ptrace(PTRACE_PEEKUSR_AREA, pid, &parea, 0);
+	if(err)
+		panic("save_registers - saving registers failed, errno = %d\n",
+		      -errno);
+}
+
+void restore_registers(int pid, union uml_pt_regs *regs)
+{
+	int err;
+
+	ptrace_area parea = {
+		.process_addr = (unsigned long)regs->skas.regs,
+		.kernel_addr = PT_PSWMASK,
+		.len = (HOST_FRAME_SIZE + HOST_FP_SIZE) * sizeof(long)
+	};
+	err = ptrace(PTRACE_POKEUSR_AREA, pid, &parea, 0);
+	if(err)
+		panic("restore_registers - restoring registers failed, "
+		      "errno = %d\n", -errno);
+}
+
+void init_registers(int pid)
+{
+	int err;
+
+	ptrace_area parea = {
+		.process_addr = (unsigned long)exec_regs,
+		.kernel_addr = PT_PSWMASK,
+		.len = (HOST_FRAME_SIZE + HOST_FP_SIZE) * sizeof(long)
+	};
+	err = ptrace(PTRACE_PEEKUSR_AREA, pid, &parea, 0);
+	if(err)
+		panic("check_ptrace : PTRACE_PEEKUSR_AREA failed, errno = %d",
+		      errno);
+}
+
+void get_safe_registers(unsigned long *regs)
+{
+	memcpy(regs, exec_regs, HOST_FRAME_SIZE * sizeof(unsigned long));
+}
Index: linux-2.6.16/arch/um/sys-s390/Makefile
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/sys-s390/Makefile	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,30 @@
+obj-y = bugs.o delay.o fault.o ksyms.o ptrace.o bitmap.o string.o \
+	ptrace_user.o semaphore.o signal.o sigcontext.o stub.o stub_segv.o \
+	syscalls.o sysrq.o sys_call_table.o gate_vma.o glibc-bug.o
+
+obj-$(CONFIG_HIGHMEM) += highmem.o
+obj-$(CONFIG_MODULES) += module.o
+
+USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o glibc-bug.o
+
+SYMLINKS = semaphore.c highmem.c module.c bitmap.S string.c
+
+include arch/um/scripts/Makefile.rules
+
+semaphore.c-dir = kernel
+highmem.c-dir = mm
+module.c-dir = kernel
+bitmap.S-dir = kernel
+string.c-dir = lib
+
+STUB_CFLAGS = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS))
+
+# _cflags works with kernel files, not with userspace ones, but c_flags does,
+# why ask why?
+$(obj)/stub_segv.o : c_flags = $(STUB_CFLAGS)
+
+$(obj)/stub.o : a_flags = $(STUB_CFLAGS)
+
+subdir- := util
+
+include arch/um/scripts/Makefile.unmap
Index: linux-2.6.16/arch/um/sys-s390/bugs.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/sys-s390/bugs.c	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2004, 2005 Fujitsu Siemens Computer GmbH
+ * Author: Bodo Stroesser (bstroesser@fujitsu-siemens.com)
+ *
+ * This is derived from arch/um/sys-i386/bugs.c
+ *  Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ *
+ * Licensed under the GPL
+ */
+
+#include "kern_util.h"
+#include "user.h"
+#include "sysdep/ptrace.h"
+
+int cpu_feature(char *what, char *buf, int len)
+{
+	return 0;
+}
+
+
+void arch_init_thread(void)
+{
+}
+
+void arch_check_bugs(void)
+{
+}
+
+int arch_handle_signal(int sig, union uml_pt_regs *regs)
+{
+	return 0;
+}
Index: linux-2.6.16/arch/um/sys-s390/delay.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/sys-s390/delay.c	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,45 @@
+/*
+ *  arch/um/sys-s390/delay.c
+ *    Precise Delay Loops for S390
+ *
+ * Derived from arch/s390/lib/delay.c
+ *
+ *  S390 version
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ *
+ *  Derived from "arch/i386/lib/delay.c"
+ *    Copyright (C) 1993 Linus Torvalds
+ *    Copyright (C) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ */
+
+#include <linux/delay.h>
+
+void __delay(unsigned long loops)
+{
+        /*
+         * To end the bloody studid and useless discussion about the
+         * BogoMips number I took the liberty to define the __delay
+         * function in a way that that resulting BogoMips number will
+         * yield the megahertz number of the cpu. The important function
+         * is udelay and that is done using the tod clock. -- martin.
+         */
+        __asm__ __volatile__(
+                "0: brct %0,0b"
+                : /* no outputs */ : "r" (loops/2) );
+}
+
+/*
+ * Waits for 'usecs' microseconds using the tod clock
+ */
+void __udelay(unsigned long usecs)
+{
+        unsigned long long start_cc, end_cc;
+
+        if (usecs == 0)
+                return;
+        asm volatile ("STCK %0" : "=m" (start_cc));
+        do {
+                asm volatile ("STCK %0" : "=m" (end_cc));
+        } while (((end_cc - start_cc)/4096) < usecs);
+}
Index: linux-2.6.16/arch/um/sys-s390/fault.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/sys-s390/fault.c	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,6 @@
+#include "user.h"
+
+int arch_fixup(unsigned long address, void *sc_ptr)
+{
+	return(0);
+}
Index: linux-2.6.16/arch/um/sys-s390/gate_vma.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/sys-s390/gate_vma.c	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,266 @@
+#include "linux/mm.h"
+#include "linux/sched.h"
+#include "linux/seq_file.h"
+#include "skas.h"
+
+static struct vm_area_struct gate_vmas[3];
+
+static int vma_count;
+
+/* Dummy to make fs/proc/task_mmu.c happy */
+struct vm_area_struct *get_gate_vma(struct task_struct *tsk)
+{
+	if(vma_count) return gate_vmas;
+
+        return NULL;
+}
+
+int in_gate_area(struct task_struct *task, unsigned long addr)
+{
+	int i;
+
+	for(i = 0; i < vma_count; i++)
+		if(gate_vmas[i].vm_start <= addr && gate_vmas[i].vm_end > addr)
+			return 1;
+
+	return 0;
+}
+
+struct vm_area_struct *uml_get_gate_vma(struct task_struct *task,
+					unsigned long addr)
+{
+	int i;
+
+	for(i = 0; i < vma_count; i++)
+		if(gate_vmas[i].vm_start <= addr && gate_vmas[i].vm_end > addr)
+			return gate_vmas + i;
+
+	return NULL;
+}
+
+struct vm_area_struct * get_next_gate_vma(struct task_struct *task,
+					  struct vm_area_struct *vma)
+{
+	int i;
+
+	if(vma == NULL)
+		return vma_count ? gate_vmas : NULL;
+
+	for(i = 0; i < vma_count-1; i++)
+		if(gate_vmas + i == vma)
+			return gate_vmas + i + 1;
+
+	return NULL;
+}
+
+int is_gate_vma(struct task_struct *task, struct vm_area_struct *vma)
+{
+	int i;
+
+	for(i = 0; i < vma_count; i++)
+		if(gate_vmas + i == vma) return 1;
+
+	return 0;
+}
+
+/* sysbols in vsyscall only, not in stub-pages */
+int in_gate_area_no_task(unsigned long addr)
+{
+	return 0;
+}
+
+extern struct seq_operations proc_pid_maps_op;
+static int uml_map_show(struct seq_file *m, void *v);
+static void *uml_map_start(struct seq_file *m, loff_t *pos);
+static void uml_map_stop(struct seq_file *m, void *v);
+static void *uml_map_next(struct seq_file *m, void *v, loff_t *pos);
+
+static int __init gate_vma_init(void)
+{
+	struct vm_area_struct * vma = gate_vmas;
+
+	if(skas_needs_stub){
+		vma->vm_mm = NULL;
+		vma->vm_start = CONFIG_STUB_CODE;
+		vma->vm_end = CONFIG_STUB_CODE + PAGE_SIZE;
+		vma->vm_page_prot = PAGE_READONLY;
+		vma->vm_flags = VM_READ | VM_EXEC;
+		vma->vm_private_data = "[stub-code]";
+		vma_count++;
+		vma++;
+
+		vma->vm_mm = NULL;
+		vma->vm_start = CONFIG_STUB_DATA;
+		vma->vm_end = CONFIG_STUB_DATA + PAGE_SIZE;
+		vma->vm_page_prot = PAGE_SHARED;
+		vma->vm_flags = VM_READ | VM_WRITE;
+		vma->vm_private_data = "[stub-stack]";
+		vma_count++;
+		vma++;
+	}
+
+	proc_pid_maps_op.start = uml_map_start;
+	proc_pid_maps_op.next = uml_map_next;
+	proc_pid_maps_op.stop = uml_map_stop;
+	proc_pid_maps_op.show = uml_map_show;
+
+	return 0;
+}
+__initcall(gate_vma_init);
+
+/*
+ * The following routines are stolen from fs/proc/task_mmu.c
+ */
+static void pad_len_spaces(struct seq_file *m, int len)
+{
+	len = 25 + sizeof(void*) * 6 - len;
+	if (len < 1)
+		len = 1;
+	seq_printf(m, "%*c", len, ' ');
+}
+
+static int uml_map_show(struct seq_file *m, void *v)
+{
+	struct task_struct *task = m->private;
+	struct vm_area_struct *map = v;
+	struct mm_struct *mm = map->vm_mm;
+	struct file *file = map->vm_file;
+	int flags = map->vm_flags;
+	unsigned long ino = 0;
+	dev_t dev = 0;
+	int len;
+
+	if (file) {
+		struct inode *inode = map->vm_file->f_dentry->d_inode;
+		dev = inode->i_sb->s_dev;
+		ino = inode->i_ino;
+	}
+
+	seq_printf(m, "%08lx-%08lx %c%c%c%c %08lx %02x:%02x %lu %n",
+			map->vm_start,
+			map->vm_end,
+			flags & VM_READ ? 'r' : '-',
+			flags & VM_WRITE ? 'w' : '-',
+			flags & VM_EXEC ? 'x' : '-',
+			flags & VM_MAYSHARE ? 's' : 'p',
+			map->vm_pgoff << PAGE_SHIFT,
+			MAJOR(dev), MINOR(dev), ino, &len);
+
+	/*
+	 * Print the dentry name for named mappings, and a
+	 * special [heap] marker for the heap:
+	 */
+	if (map->vm_file) {
+		pad_len_spaces(m, len);
+		seq_path(m, file->f_vfsmnt, file->f_dentry, "");
+	} else {
+		if (mm) {
+			if (map->vm_start <= mm->start_brk &&
+						map->vm_end >= mm->brk) {
+				pad_len_spaces(m, len);
+				seq_puts(m, "[heap]");
+			} else {
+				if (map->vm_start <= mm->start_stack &&
+					map->vm_end >= mm->start_stack) {
+
+					pad_len_spaces(m, len);
+					seq_puts(m, "[stack]");
+				}
+			}
+		} else {
+			pad_len_spaces(m, len);
+			if(map->vm_private_data)
+				seq_puts(m, map->vm_private_data);
+			else seq_puts(m, "[vdso]");
+		}
+	}
+	seq_putc(m, '\n');
+	if (m->count < m->size)  /* map is copied successfully */
+		m->version = is_gate_vma(task, map)? 0: map->vm_start;
+	return 0;
+}
+
+static void *uml_map_start(struct seq_file *m, loff_t *pos)
+{
+	struct task_struct *task = m->private;
+	unsigned long last_addr = m->version;
+	struct mm_struct *mm;
+	struct vm_area_struct *map;
+	loff_t l = *pos;
+
+	/*
+	 * We remember last_addr rather than next_addr to hit with
+	 * mmap_cache most of the time. We have zero last_addr at
+	 * the begining and also after lseek. We will have -1 last_addr
+	 * after the end of the maps.
+	 */
+
+	if (last_addr == -1UL)
+		return NULL;
+
+	mm = get_task_mm(task);
+	if (!mm)
+		return NULL;
+
+	down_read(&mm->mmap_sem);
+
+	m->version = 0;
+
+	/* Start with last addr hint */
+	if (last_addr && (map = find_vma(mm, last_addr))) {
+		map = map->vm_next;
+		goto out;
+	}
+
+	/*
+	 * Check the map index is within the range and do
+	 * sequential scan until m_index.
+	 */
+	map = NULL;
+	if ((unsigned long)l < mm->map_count) {
+		map = mm->mmap;
+		while (l-- && map)
+			map = map->vm_next;
+		goto out;
+	}
+
+	/* End of maps has reached */
+	up_read(&mm->mmap_sem);
+	mmput(mm);
+
+	l -= mm->map_count;
+	do {
+		map = get_next_gate_vma(task, map);
+	} while(l-- && map);
+
+	m->version = (map != NULL)? 0: -1UL;
+
+out:
+	return map;
+}
+
+static void uml_map_stop(struct seq_file *m, void *v)
+{
+	struct task_struct *task = m->private;
+	struct vm_area_struct *map = v;
+	if (map && !is_gate_vma(task, map)) {
+		struct mm_struct *mm = map->vm_mm;
+		up_read(&mm->mmap_sem);
+		mmput(mm);
+	}
+}
+
+static void *uml_map_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	struct task_struct *task = m->private;
+	struct vm_area_struct *map = v;
+	int is_gate = is_gate_vma(task, map);
+
+	(*pos)++;
+	if (map && !is_gate && map->vm_next)
+		return map->vm_next;
+	uml_map_stop(m, v);
+	if (map && !is_gate)
+		map = NULL;
+	return get_next_gate_vma(task, map);
+}
Index: linux-2.6.16/arch/um/sys-s390/glibc-bug.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/sys-s390/glibc-bug.c	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,16 @@
+/* glibc 2.2.5 in SuSE-SLES 8 doesn't have a clone(), but a __clone()
+ * only. This is a bug in glibc, because there should be a weak_alias
+ * for clone(). We want to work with this old glibc correctly, so we
+ * declare a "weak" wrapper here.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+
+extern int __clone(int (*fn)(void *arg), void *child_stack,
+		   int flags, void *arg);
+
+int __attribute__((weak)) clone(int (*fn)(void *arg), void *child_stack,
+				int flags, void *arg)
+{
+	return __clone( fn, child_stack, flags, arg);
+}
Index: linux-2.6.16/arch/um/sys-s390/kernel-offsets.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/sys-s390/kernel-offsets.c	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,25 @@
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <asm/page.h>
+
+#define DEFINE(sym, val) \
+        asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+
+#define STR(x) #x
+#define DEFINE_STR(sym, val) asm volatile("\n->" #sym " " STR(val) " " #val: : )
+
+#define BLANK() asm volatile("\n->" : : )
+
+#define OFFSET(sym, str, mem) \
+	DEFINE(sym, offsetof(struct str, mem));
+
+void foo(void)
+{
+	OFFSET(TASK_PER_STRUCT, task_struct, thread.arch.per_info);
+#ifdef CONFIG_MODE_TT
+	OFFSET(TASK_EXTERN_PID, task_struct, thread.mode.tt.extern_pid);
+#endif
+#include <common-offsets.h>
+}
Index: linux-2.6.16/arch/um/sys-s390/ksyms.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/sys-s390/ksyms.c	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,23 @@
+#include "linux/module.h"
+#include "linux/in6.h"
+#include "linux/rwsem.h"
+#include "asm/byteorder.h"
+#include "asm/delay.h"
+#include "asm/semaphore.h"
+#include "asm/uaccess.h"
+#include "asm/checksum.h"
+#include "asm/errno.h"
+
+/* delay core functions */
+EXPORT_SYMBOL(__udelay);
+
+/* semaphore ops */
+EXPORT_SYMBOL(__up);
+EXPORT_SYMBOL(__down);
+EXPORT_SYMBOL(__down_interruptible);
+
+/* used by bitops.h */
+EXPORT_SYMBOL(_oi_bitmap);
+EXPORT_SYMBOL(_ni_bitmap);
+EXPORT_SYMBOL(_zb_findmap);
+EXPORT_SYMBOL(_sb_findmap);
Index: linux-2.6.16/arch/um/sys-s390/ptrace.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/sys-s390/ptrace.c	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2004, 2005 Fujitsu Siemens Computer GmbH
+ * Author: Bodo Stroesser (bstroesser@fujitsu-siemens.com)
+ *
+ * This is derived from arch/um/sys-s390/ptrace.c
+ *  Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ *
+ * and arch/s390/kernel/ptrace.c
+ *  Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *  Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
+ *             Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *
+ * Licensed under the GPL
+ */
+
+#include "linux/sched.h"
+#include "asm/elf.h"
+#include "asm/ptrace.h"
+#include "asm/uaccess.h"
+#include "asm/unistd.h"
+#include "sysdep/ptrace.h"
+#include "sysdep/sigcontext.h"
+#include "sysdep/sc.h"
+
+void arch_switch(void)
+{
+	update_debugregs(current->thread.arch.per_struct_seq);
+}
+
+int is_syscall(unsigned long addr)
+{
+	union uml_pt_regs * regs;
+	unsigned char instr[4];
+	int reg;
+
+	if (copy_from_user(instr, (void *) addr, 2)) {
+		printk("is_syscall : failed to read instruction from 0x%lx\n",
+		       addr);
+		return 0;
+	}
+	if (instr[0] == 0x0a ) /* SVC */
+		return 1;
+
+	if (instr[0] != 0x44 ) /* EXECUTE */
+		return 0;
+
+	/* Now, we have handled the simple cases.
+	 * EXECUTE instruction needs more care!
+	 */
+
+	/* Read the rest of EXECUTE instruction */
+	if (copy_from_user(instr+2, (void *)(addr+2), 2)) {
+		printk("is_syscall : failed to read instruction from 0x%lx\n",
+		       addr);
+		return 0;
+	}
+
+	/* Compute 2nd operand address */
+	regs = &current->thread.regs.regs;
+	addr = *(unsigned short *)(instr+2) & 0xfff; /* Displacement */
+	reg = instr[1] & 0x0f; /* X2 */
+	if (reg)
+		addr += UPT_GPR(regs,reg);
+	reg = instr[2] >> 4; /* B2 */
+	if (reg)
+		addr += UPT_GPR(regs,reg);
+
+	/* Read the EXECUTEd instruction from 2nd operand address */
+	if (copy_from_user(instr, (void *) addr, 2)) {
+		printk("is_syscall : failed to read EXECed instruction from 0x%lx\n",
+		       addr);
+		return 0;
+	}
+	if (instr[0] == 0x0a ) /* SVC */
+		return 1;
+
+	return 0;
+}
+
+#define PSW_MASK_USERBITS	0x00003f00UL
+#define PSW_MASK_PER		0x40000000UL
+#define PSW_ADDR_AMODE		0x80000000UL
+
+#define FPC_INVALID_MASK	0x070700fcUL
+
+#define PER_MAX_ADDR 0x7fffffffUL
+
+void FixPerRegisters(struct task_struct *task)
+{
+	per_struct *per_info = &task->thread.arch.per_info;
+
+	per_info->control_regs.bits.em_instruction_fetch =
+		per_info->single_step | per_info->instruction_fetch;
+
+	if (per_info->single_step) {
+		per_info->control_regs.bits.starting_addr = 0;
+		per_info->control_regs.bits.ending_addr = PER_MAX_ADDR;
+	}
+
+	/*
+	 * if any of the control reg tracing bits are on
+	 * we switch on per in the psw
+	 */
+	if (per_info->control_regs.bits.em_branching ||
+	    per_info->control_regs.bits.em_instruction_fetch ||
+	    per_info->control_regs.bits.em_storage_alteration ||
+	    per_info->control_regs.bits.em_store_real_address )
+		UPT_MASK(&task->thread.regs.regs) |= PSW_MASK_PER;
+	else
+		UPT_MASK(&task->thread.regs.regs) &= ~PSW_MASK_PER;
+
+	if (per_info->control_regs.bits.em_storage_alteration)
+		per_info->control_regs.bits.storage_alt_space_ctl = 1;
+	else
+		per_info->control_regs.bits.storage_alt_space_ctl = 0;
+}
+
+int poke_user(struct task_struct *child, long addr, long data)
+{
+	struct user *dummy = NULL;
+	union uml_pt_regs *regs = &child->thread.regs.regs;
+
+	if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
+		return -EIO;
+
+	if (addr == (long )&dummy->regs.psw.mask) {
+		if ( (data|PSW_MASK_USERBITS) !=
+		     (UPT_MASK(regs)|PSW_MASK_USERBITS) )
+			return -EINVAL;
+		UPT_MASK(regs) = data;
+		FixPerRegisters(child);
+	}
+	else if (addr == (long )&dummy->regs.psw.addr) {
+		UPT_ADDR(regs) = data|PSW_ADDR_AMODE;
+	}
+	else if (addr <= (long )(dummy->regs.gprs+NUM_GPRS-1)) {
+		UPT_GPR(regs, (addr-(long )dummy->regs.gprs)/sizeof(long)) = data;
+	}
+	else if (addr <= (long )(dummy->regs.acrs+NUM_ACRS-1)) {
+		UPT_ACR(regs, (addr-(long )dummy->regs.acrs)/sizeof(int)) = data;
+	}
+	else if (addr == (long )&dummy->regs.orig_gpr2) {
+		UPT_ORIGGPR2(regs) = data;
+	}
+	else if (addr == (long )&dummy->regs.fp_regs.fpc) {
+		if (data&FPC_INVALID_MASK)
+			return -EINVAL;
+		UPT_FPR(regs,0) = data;
+	}
+	else if (addr < (long )(&dummy->regs.fp_regs + 1)) {
+		UPT_FPR(regs, (addr-(long )&dummy->regs.fp_regs)/sizeof(long)) = data;
+	}
+	else if (addr < (long )(&dummy->regs.per_info + 1)) {
+		((long *)&child->thread.arch.per_info)
+			[(addr-(long )&dummy->regs.per_info)/sizeof(long)] = data;
+		FixPerRegisters(child);
+	}
+	return 0;
+}
+
+int peek_user(struct task_struct *child, long addr, long data)
+{
+	struct user *dummy = NULL;
+	union uml_pt_regs *regs = &child->thread.regs.regs;
+	long tmp = 0;
+
+	if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
+		return -EIO;
+
+	if (addr == (long )&dummy->regs.psw.mask) {
+		tmp = UPT_MASK(regs) & ~PSW_MASK_PER;
+	}
+	else if (addr == (long )&dummy->regs.psw.addr) {
+		tmp = UPT_ADDR(regs);
+	}
+	else if (addr <= (long )(dummy->regs.gprs+NUM_GPRS-1)) {
+		tmp = UPT_GPR(regs, (addr-(long )dummy->regs.gprs)/sizeof(long));
+	}
+	else if (addr <= (long )(dummy->regs.acrs+NUM_ACRS-1)) {
+		tmp = UPT_ACR(regs, (addr-(long )dummy->regs.acrs)/sizeof(int));
+	}
+	else if (addr == (long )&dummy->regs.orig_gpr2) {
+		tmp = UPT_ORIGGPR2(regs);
+	}
+	else if (addr == (long )&dummy->regs.fp_regs.fpc) {
+		if (data&FPC_INVALID_MASK)
+			return -EINVAL;
+		tmp = UPT_FPR(regs,0);
+	}
+	else if (addr < (long )(&dummy->regs.fp_regs + 1)) {
+		tmp = UPT_FPR(regs, (addr-(long )&dummy->regs.fp_regs)/sizeof(long));
+	}
+	else if (addr < (long )(&dummy->regs.per_info + 1)) {
+		tmp = ((long *)&child->thread.arch.per_info)
+			[(addr-(long )&dummy->regs.per_info)/sizeof(long)];
+	}
+	return put_user(tmp, (addr_t __user *)data);
+}
+
+
+int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu )
+{
+	s390_fp_regs * from = (s390_fp_regs *)UPT_FPRS(&regs->regs);
+	memcpy(fpu, from, sizeof(s390_fp_regs));
+	return(1);
+}
Index: linux-2.6.16/arch/um/sys-s390/ptrace_user.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/sys-s390/ptrace_user.c	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2004, 2005 Fujitsu Siemens Computer GmbH
+ * Author: Bodo Stroesser (bstroesser@fujitsu-siemens.com)
+ *
+ * This is derived from arch/um/sys-i386/ptrace_user.c
+ *  Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ *
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <linux/stddef.h>
+#include <sys/ptrace.h>
+#include <asm/ptrace.h>
+#include <asm/user.h>
+#include "kern_util.h"
+#include "sysdep/thread.h"
+#include "user.h"
+#include "os.h"
+
+static void write_debugregs(int pid, per_struct *per)
+{
+	struct user *dummy = NULL;;
+	ptrace_area parea;
+
+	parea.len = sizeof(per_struct);
+	parea.kernel_addr = (unsigned long)&dummy->regs.per_info;
+	parea.process_addr = (unsigned long)per;
+	if (ptrace(PTRACE_POKEUSR_AREA, pid, &parea, 0)) {
+		printk("write_debugregs - ptrace(PTRACE_POKEUSR_AREA failed "
+		       ", errno = %d\n", errno);
+	}
+}
+
+static void read_debugregs(int pid, per_struct *per)
+{
+	struct user *dummy = NULL;
+	ptrace_area parea;
+
+	parea.len = sizeof(per_struct);
+	parea.kernel_addr = (unsigned long)&dummy->regs.per_info;
+	parea.process_addr = (unsigned long)per;
+	if (ptrace(PTRACE_PEEKUSR_AREA, pid, &parea, 0)) {
+		printk("read_debugregs - ptrace(PTRACE_PEEKUSR_AREA failed "
+		       ", errno = %d\n", errno);
+		*per = (per_struct){{{{0,}}},0,0,0,0,{{0,}}};
+	}
+}
+
+/* Accessed only by the tracing thread */
+static per_struct kernel_per_struct = (per_struct){{{{0,}}},0,0,0,0,{{0,}}};
+static int per_struct_seq = 0;
+
+void arch_enter_kernel(void *task, int pid)
+{
+	read_debugregs(pid, (per_struct *)TASK_PER_STRUCT(task));
+	write_debugregs(pid, &kernel_per_struct);
+}
+
+void arch_leave_kernel(void *task, int pid)
+{
+	read_debugregs(pid, &kernel_per_struct);
+	write_debugregs(pid, (per_struct *)TASK_PER_STRUCT(task));
+}
+
+void ptrace_pokeuser(unsigned long addr, unsigned long data)
+{
+	struct user *dummy = NULL;
+
+	addr -= (unsigned long)&dummy->regs.per_info;
+	if (addr >= sizeof(per_struct))
+		return;
+
+	addr /= sizeof(unsigned long);
+	if(((unsigned long *)&kernel_per_struct)[addr] == data) return;
+
+	((unsigned long *)&kernel_per_struct)[addr] = data;
+	per_struct_seq++;
+}
+
+static void update_debugregs_cb(void *arg)
+{
+	int pid = *((int *) arg);
+
+	write_debugregs(pid, &kernel_per_struct);
+}
+
+void update_debugregs(int seq)
+{
+	int me;
+
+	if(seq == per_struct_seq) return;
+
+	me = os_getpid();
+	initial_thread_cb(update_debugregs_cb, &me);
+}
Index: linux-2.6.16/arch/um/sys-s390/sigcontext.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/sys-s390/sigcontext.c	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2004, 2005 Fujitsu Siemens Computer GmbH
+ * Author: Bodo Stroesser (bstroesser@fujitsu-siemens.com)
+ * Licensed under the GPL
+ */
+
+#include <string.h>
+#include <asm/sigcontext.h>
+
+void sc_to_sc(void *to, void *from)
+{
+	memcpy(((struct sigcontext *)to)->oldmask,
+	       ((struct sigcontext *)from)->oldmask,
+	       sizeof(((struct sigcontext *)to)->oldmask));
+	memcpy(((struct sigcontext *)to)->sregs,
+	       ((struct sigcontext *)from)->sregs, sizeof(_sigregs));
+}
Index: linux-2.6.16/arch/um/sys-s390/signal.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/sys-s390/signal.c	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2004, 2005 Fujitsu Siemens Computer GmbH
+ * Author: Bodo Stroesser (bstroesser@fujitsu-siemens.com)
+ *
+ * This is derived from arch/um/sys-i386/signal.c
+ *  Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ *
+ * and arch/s390/kernel/signal.c
+ *  Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *  Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ *
+ * Licensed under the GPL
+ */
+
+#include "linux/signal.h"
+#include "linux/ptrace.h"
+#include "asm/current.h"
+#include "asm/ucontext.h"
+#include "asm/uaccess.h"
+#include "asm/unistd.h"
+#include "frame_kern.h"
+#include "signal_user.h"
+#include "sigcontext.h"
+#include "registers.h"
+#include "mode.h"
+
+#ifdef CONFIG_MODE_SKAS
+
+#include "skas.h"
+
+static int restore_sigregs_skas(struct pt_regs *regs, _sigregs *from)
+{
+	return copy_from_user(regs->regs.skas.regs, &from->regs,
+	                      sizeof(from->regs)) ||
+	       copy_from_user(regs->regs.skas.fpregs, &from->fpregs,
+	                      sizeof(from->fpregs));
+}
+
+int save_sigregs_skas(struct pt_regs *regs, _sigregs *to)
+{
+	return copy_to_user(&to->regs, regs->regs.skas.regs,
+	                    sizeof(to->regs)) ||
+	       copy_to_user(&to->fpregs, regs->regs.skas.fpregs,
+	                    sizeof(to->fpregs));
+}
+
+#endif
+
+#ifdef CONFIG_MODE_TT
+
+/* These copy a sigcontext to/from userspace.  They copy the fpstate pointer,
+ * blowing away the old, good one.  So, that value is saved, and then restored
+ * after the sigcontext copy.  In copy_from, the variable holding the saved
+ * fpstate pointer, and the sigcontext that it should be restored to are both
+ * in the kernel, so we can just restore using an assignment.  In copy_to, the
+ * saved pointer is in the kernel, but the sigcontext is in userspace, so we
+ * copy_to_user it.
+ */
+static inline int restore_sigregs_tt(_sigregs *to, _sigregs *from)
+{
+	return copy_from_user(to, from, sizeof(*to));
+}
+
+static inline int save_sigregs_tt(_sigregs *from, _sigregs *to)
+{
+	return copy_to_user(to, from, sizeof(*to));
+}
+#endif
+
+static int restore_sigregs(struct pt_regs *to, _sigregs __user *from)
+{
+	unsigned long old_mask = PT_REGS_MASK(to);
+	int ret;
+
+	ret = CHOOSE_MODE(restore_sigregs_tt(((struct sigcontext *)
+	                                     UPT_SC(&to->regs))->sregs, from),
+			  restore_sigregs_skas(to, from));
+
+	PT_REGS_MASK(to) = PSW_MASK_MERGE(old_mask, PT_REGS_MASK(to));
+	PT_REGS_ADDR(to) |= PSW_ADDR_AMODE;
+	PT_REGS_FPC(to) &= FPC_VALID_MASK;
+
+	/* Avoid ERESTART handling */
+	PT_REGS_SYSCALL_NR(to) = -1;
+
+	return(ret);
+}
+
+static int save_sigregs(struct pt_regs *from, _sigregs *to)
+{
+	int ret;
+	unsigned long orig_mask = PT_REGS_MASK(from);
+
+	PT_REGS_MASK(from) = PSW_MASK_MERGE(PSW_USER_BITS, PT_REGS_MASK(from));
+
+	ret = CHOOSE_MODE(save_sigregs_tt(((struct sigcontext *)
+	                                  UPT_SC(&from->regs))->sregs, to),
+			  save_sigregs_skas(from, to));
+
+	PT_REGS_MASK(from) = orig_mask;
+
+	return ret;
+}
+
+typedef struct
+{
+	__u8 callee_used_stack[__SIGNAL_FRAMESIZE];
+	struct sigcontext sc;
+	_sigregs sregs;
+	int signo;
+	__u8 retcode[S390_SYSCALL_SIZE];
+} sigframe;
+
+typedef struct
+{
+	__u8 callee_used_stack[__SIGNAL_FRAMESIZE];
+	__u8 retcode[S390_SYSCALL_SIZE];
+	struct siginfo info;
+	struct ucontext uc;
+} rt_sigframe;
+
+int setup_signal_stack_sc(unsigned long stack_top, int sig,
+			  struct k_sigaction *ka, struct pt_regs *regs,
+			  sigset_t *set)
+{
+	sigframe __user *frame;
+
+	frame = (sigframe __user *) ((stack_top - sizeof(sigframe)) & -8L);
+	if(!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+		return 1;
+
+	if (__copy_to_user(&frame->sc.oldmask, &set->sig,
+	                   sizeof(frame->sc.oldmask)) ||
+	    save_sigregs(regs, &frame->sregs) ||
+	    __put_user(&frame->sregs, &frame->sc.sregs))
+		return 1;
+
+	if(ka->sa.sa_flags & SA_RESTORER) {
+		PT_REGS_GPR(regs,14) = (unsigned long)
+			ka->sa.sa_restorer | PSW_ADDR_AMODE;
+	} else {
+		PT_REGS_GPR(regs,14) = (unsigned long)
+			frame->retcode | PSW_ADDR_AMODE;
+		if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn,
+		               (u16 __user *)(frame->retcode)))
+			return 1;
+	}
+
+	/* Set up backchain. */
+	if (__put_user(PT_REGS_GPR(regs,15), (addr_t __user *) frame))
+		return 1;
+
+	/* Set up registers for signal handler */
+	PT_REGS_GPR(regs,15) = (unsigned long) frame;
+	PT_REGS_ADDR(regs) = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE;
+
+	PT_REGS_GPR(regs,2) = sig;
+	PT_REGS_GPR(regs,3) = (unsigned long) &frame->sc;
+
+	/* We forgot to include these in the sigcontext.
+	   To avoid breaking binary compatibility, they are passed as args. */
+	PT_REGS_GPR(regs,4) = current->thread.arch.faultinfo.trap_no;
+	PT_REGS_GPR(regs,5) = current->thread.arch.faultinfo.address;
+
+	/* Place signal number on stack to allow backtrace from handler.  */
+	if (__put_user(PT_REGS_GPR(regs,2), (int __user *) &frame->signo))
+		return 1;
+
+	return(0);
+}
+
+int setup_signal_stack_si(unsigned long stack_top, int sig,
+			  struct k_sigaction *ka, struct pt_regs *regs,
+			  siginfo_t *info, sigset_t *set)
+{
+	rt_sigframe __user *frame;
+
+	frame = (rt_sigframe __user *)((stack_top - sizeof(rt_sigframe)) & -8L);
+	if(!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+		return 1;
+
+	if (copy_siginfo_to_user(&frame->info, info))
+		return 1;
+
+	if (__put_user(0, &frame->uc.uc_flags) ||
+	    __put_user(0, &frame->uc.uc_link) ||
+	    __put_user((void *)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp) ||
+	    __put_user(sas_ss_flags(PT_REGS_GPR(regs,15)),
+	               &frame->uc.uc_stack.ss_flags) ||
+	    __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size) ||
+	    save_sigregs(regs, &frame->uc.uc_mcontext) ||
+	    __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)))
+		return 1;
+
+	if(ka->sa.sa_flags & SA_RESTORER) {
+		PT_REGS_GPR(regs,14) = (unsigned long)
+			ka->sa.sa_restorer | PSW_ADDR_AMODE;
+	} else {
+		PT_REGS_GPR(regs,14) = (unsigned long)
+			frame->retcode | PSW_ADDR_AMODE;
+		if (__put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn,
+		               (u16 __user *)(frame->retcode)))
+			return 1;
+	}
+
+	/* Set up backchain. */
+	if (__put_user(PT_REGS_GPR(regs,15), (addr_t __user *) frame))
+		return 1;
+
+	/* Set up registers for signal handler */
+	PT_REGS_GPR(regs,15) = (unsigned long) frame;
+	PT_REGS_ADDR(regs) = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE;
+
+	PT_REGS_GPR(regs,2) = sig;
+	PT_REGS_GPR(regs,3) = (unsigned long) &frame->info;
+	PT_REGS_GPR(regs,4) = (unsigned long) &frame->uc;
+
+	return(0);
+}
+
+long sys_sigreturn(struct pt_regs dummy)
+{
+	struct pt_regs * regs = &current->thread.regs;
+	sigframe __user *frame = (sigframe __user *)PT_REGS_GPR(regs,15);
+	sigset_t set;
+
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+		goto segfault;
+	if(__copy_from_user(&set.sig, &frame->sc.oldmask,
+	                    sizeof(frame->sc.oldmask)))
+		goto segfault;
+
+	sigdelsetmask(&set, ~_BLOCKABLE);
+	spin_lock_irq(&current->sighand->siglock);
+	current->blocked = set;
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+
+	if(restore_sigregs(regs, &frame->sregs))
+		goto segfault;
+
+	return PT_REGS_GPR(regs,2);
+
+ segfault:
+	force_sig(SIGSEGV, current);
+	return 0;
+}
+
+long sys_rt_sigreturn(struct pt_regs dummy)
+{
+	struct pt_regs * regs = &current->thread.regs;
+	rt_sigframe __user *frame = (rt_sigframe __user *)PT_REGS_GPR(regs,15);
+	sigset_t set;
+
+	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+		goto segfault;
+	if(copy_from_user(&set.sig, &frame->uc.uc_sigmask, sizeof(set)))
+		goto segfault;
+
+	sigdelsetmask(&set, ~_BLOCKABLE);
+	spin_lock_irq(&current->sighand->siglock);
+	current->blocked = set;
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+
+	if(restore_sigregs(regs, &frame->uc.uc_mcontext))
+		goto segfault;
+
+	/* It is more difficult to avoid calling this function than to
+	   call it and ignore errors.  */
+	do_sigaltstack(&frame->uc.uc_stack, NULL, PT_REGS_GPR(regs,15));
+
+	return PT_REGS_GPR(regs,2);
+
+ segfault:
+	force_sig(SIGSEGV, current);
+	return 0;
+}
Index: linux-2.6.16/arch/um/sys-s390/stub.S
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/sys-s390/stub.S	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2004, 2005 Fujitsu Siemens Computer GmbH
+ * Author: Bodo Stroesser (bstroesser@fujitsu-siemens.com)
+ * Licensed under the GPL
+ */
+
+#include <asm/unistd.h>
+#include "uml-config.h"
+#include "skas_ptregs.h"
+
+	.globl syscall_stub
+.section .__syscall_stub, "x"
+
+	.globl batch_syscall_stub
+batch_syscall_stub:
+	/* load base register */
+	basr	%r12, 0
+base:
+	/* load pointer to UML_CONFIG_STUB_DATA */
+	l	%r13, stub_data_p-base(%r12)
+
+	/* load pointer to first operation */
+	la	%r15, 8(%r13)
+
+again:
+	/* load length of additional data */
+	/* and test if == 0 */
+	icm	%r1, 15, 0(%r15)
+
+	/* write possible 0 to header */
+	st	%r1, 4(%r13)
+
+	/* if(length == 0) : end of list */
+	jz	done
+
+	/* save current pointer */
+	st	%r15, 4(%r13)
+
+	/* skip additional data */
+	ar	%r15, %r1
+
+	/* load syscall-# */
+	l       %r1, 0(%r15)
+
+	/* load pointer to mmap2-struct */
+	la	%r2, 4(%r15)
+	/* if syscall is mmap2, do the call */
+	chi     %r1, __NR_mmap2
+	je      do_syscall
+
+	/* load syscall params */
+	lm      %r2, %r7, 4(%r15)
+
+do_syscall:
+	/* execute syscall */
+	bas	%r14, stub_syscall_entry-base(%r12)
+
+	/* check return value */
+check_retcode:
+	c	%r2, 28(%r15)
+	la	%r15, 32(%r15)
+	je	again
+
+done:
+	/* save return value */
+	st	%r2, 0(%r13)
+
+	/* stop */
+	.short	HOST_S390_BREAKPOINT
+
+stub_data_p:
+	.long	UML_CONFIG_STUB_DATA
+
+	.macro	SYSCALL nr
+	svc	\nr
+	br	14
+	.endm
+
+	.globl stub_syscall_entry
+
+stub_syscall_entry:
+	basr	%r9, 0
+base2:
+	sll	%r1, 2
+	chi	%r1, 4*256
+	bl	syscall_array-base2(%r9,%r1)
+	srl	%r1, 2
+	/* fall through */
+
+syscall_array:
+	SYSCALL	  0
+	SYSCALL	  1
+	SYSCALL	  2
+	SYSCALL	  3
+	SYSCALL	  4
+	SYSCALL	  5
+	SYSCALL	  6
+	SYSCALL	  7
+	SYSCALL	  8
+	SYSCALL	  9
+	SYSCALL	 10
+	SYSCALL	 11
+	SYSCALL	 12
+	SYSCALL	 13
+	SYSCALL	 14
+	SYSCALL	 15
+	SYSCALL	 16
+	SYSCALL	 17
+	SYSCALL	 18
+	SYSCALL	 19
+	SYSCALL	 20
+	SYSCALL	 21
+	SYSCALL	 22
+	SYSCALL	 23
+	SYSCALL	 24
+	SYSCALL	 25
+	SYSCALL	 26
+	SYSCALL	 27
+	SYSCALL	 28
+	SYSCALL	 29
+	SYSCALL	 30
+	SYSCALL	 31
+	SYSCALL	 32
+	SYSCALL	 33
+	SYSCALL	 34
+	SYSCALL	 35
+	SYSCALL	 36
+	SYSCALL	 37
+	SYSCALL	 38
+	SYSCALL	 39
+	SYSCALL	 40
+	SYSCALL	 41
+	SYSCALL	 42
+	SYSCALL	 43
+	SYSCALL	 44
+	SYSCALL	 45
+	SYSCALL	 46
+	SYSCALL	 47
+	SYSCALL	 48
+	SYSCALL	 49
+	SYSCALL	 50
+	SYSCALL	 51
+	SYSCALL	 52
+	SYSCALL	 53
+	SYSCALL	 54
+	SYSCALL	 55
+	SYSCALL	 56
+	SYSCALL	 57
+	SYSCALL	 58
+	SYSCALL	 59
+	SYSCALL	 60
+	SYSCALL	 61
+	SYSCALL	 62
+	SYSCALL	 63
+	SYSCALL	 64
+	SYSCALL	 65
+	SYSCALL	 66
+	SYSCALL	 67
+	SYSCALL	 68
+	SYSCALL	 69
+	SYSCALL	 70
+	SYSCALL	 71
+	SYSCALL	 72
+	SYSCALL	 73
+	SYSCALL	 74
+	SYSCALL	 75
+	SYSCALL	 76
+	SYSCALL	 77
+	SYSCALL	 78
+	SYSCALL	 79
+	SYSCALL	 80
+	SYSCALL	 81
+	SYSCALL	 82
+	SYSCALL	 83
+	SYSCALL	 84
+	SYSCALL	 85
+	SYSCALL	 86
+	SYSCALL	 87
+	SYSCALL	 88
+	SYSCALL	 89
+	SYSCALL	 90
+	SYSCALL	 91
+	SYSCALL	 92
+	SYSCALL	 93
+	SYSCALL	 94
+	SYSCALL	 95
+	SYSCALL	 96
+	SYSCALL	 97
+	SYSCALL	 98
+	SYSCALL	 99
+	SYSCALL	100
+	SYSCALL	101
+	SYSCALL	102
+	SYSCALL	103
+	SYSCALL	104
+	SYSCALL	105
+	SYSCALL	106
+	SYSCALL	107
+	SYSCALL	108
+	SYSCALL	109
+	SYSCALL	110
+	SYSCALL	111
+	SYSCALL	112
+	SYSCALL	113
+	SYSCALL	114
+	SYSCALL	115
+	SYSCALL	116
+	SYSCALL	117
+	SYSCALL	118
+	SYSCALL	119
+	SYSCALL	120
+	SYSCALL	121
+	SYSCALL	122
+	SYSCALL	123
+	SYSCALL	124
+	SYSCALL	125
+	SYSCALL	126
+	SYSCALL	127
+	SYSCALL	128
+	SYSCALL	129
+	SYSCALL	130
+	SYSCALL	131
+	SYSCALL	132
+	SYSCALL	133
+	SYSCALL	134
+	SYSCALL	135
+	SYSCALL	136
+	SYSCALL	137
+	SYSCALL	138
+	SYSCALL	139
+	SYSCALL	140
+	SYSCALL	141
+	SYSCALL	142
+	SYSCALL	143
+	SYSCALL	144
+	SYSCALL	145
+	SYSCALL	146
+	SYSCALL	147
+	SYSCALL	148
+	SYSCALL	149
+	SYSCALL	150
+	SYSCALL	151
+	SYSCALL	152
+	SYSCALL	153
+	SYSCALL	154
+	SYSCALL	155
+	SYSCALL	156
+	SYSCALL	157
+	SYSCALL	158
+	SYSCALL	159
+	SYSCALL	160
+	SYSCALL	161
+	SYSCALL	162
+	SYSCALL	163
+	SYSCALL	164
+	SYSCALL	165
+	SYSCALL	166
+	SYSCALL	167
+	SYSCALL	168
+	SYSCALL	169
+	SYSCALL	170
+	SYSCALL	171
+	SYSCALL	172
+	SYSCALL	173
+	SYSCALL	174
+	SYSCALL	175
+	SYSCALL	176
+	SYSCALL	177
+	SYSCALL	178
+	SYSCALL	179
+	SYSCALL	180
+	SYSCALL	181
+	SYSCALL	182
+	SYSCALL	183
+	SYSCALL	184
+	SYSCALL	185
+	SYSCALL	186
+	SYSCALL	187
+	SYSCALL	188
+	SYSCALL	189
+	SYSCALL	190
+	SYSCALL	191
+	SYSCALL	192
+	SYSCALL	193
+	SYSCALL	194
+	SYSCALL	195
+	SYSCALL	196
+	SYSCALL	197
+	SYSCALL	198
+	SYSCALL	199
+	SYSCALL	200
+	SYSCALL	201
+	SYSCALL	202
+	SYSCALL	203
+	SYSCALL	204
+	SYSCALL	205
+	SYSCALL	206
+	SYSCALL	207
+	SYSCALL	208
+	SYSCALL	209
+	SYSCALL	210
+	SYSCALL	211
+	SYSCALL	212
+	SYSCALL	213
+	SYSCALL	214
+	SYSCALL	215
+	SYSCALL	216
+	SYSCALL	217
+	SYSCALL	218
+	SYSCALL	219
+	SYSCALL	220
+	SYSCALL	221
+	SYSCALL	222
+	SYSCALL	223
+	SYSCALL	224
+	SYSCALL	225
+	SYSCALL	226
+	SYSCALL	227
+	SYSCALL	228
+	SYSCALL	229
+	SYSCALL	230
+	SYSCALL	231
+	SYSCALL	232
+	SYSCALL	233
+	SYSCALL	234
+	SYSCALL	235
+	SYSCALL	236
+	SYSCALL	237
+	SYSCALL	238
+	SYSCALL	239
+	SYSCALL	240
+	SYSCALL	241
+	SYSCALL	242
+	SYSCALL	243
+	SYSCALL	244
+	SYSCALL	245
+	SYSCALL	246
+	SYSCALL	247
+	SYSCALL	248
+	SYSCALL	249
+	SYSCALL	250
+	SYSCALL	251
+	SYSCALL	252
+	SYSCALL	253
+	SYSCALL	254
+	SYSCALL	255
Index: linux-2.6.16/arch/um/sys-s390/stub_segv.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/sys-s390/stub_segv.c	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2004, 2005 Fujitsu Siemens Computer GmbH
+ * Author: Bodo Stroesser (bstroesser@fujitsu-siemens.com)
+ * Licensed under the GPL
+ */
+
+#include <signal.h>
+// #include <asm/unistd.h>
+#include "uml-config.h"
+#include "sysdep/faultinfo.h"
+#include "sysdep/breakpoint.h"
+
+void __attribute__ ((__section__ (".__syscall_stub")))
+stub_segv_handler(int sig, struct sigcontext * sc, int trap, void * addr)
+{
+	*((struct faultinfo *) UML_CONFIG_STUB_DATA) =
+		(struct faultinfo) {
+			.trap_no = trap,
+                	.address = (unsigned long)addr
+		};
+
+	trap_myself();
+
+/*	__asm__("svc %b0\n"
+		"la  %%r3,%b1\n"
+		"svc %b2\n"
+		"lr  %%r15,%3\n"
+		"svc %b4\n"
+		: : "i" (__NR_getpid),
+		    "i" (SIGUSR1),
+		    "i" (__NR_kill),
+		    "d" ((unsigned long)sc - __SIGNAL_FRAMESIZE),
+		    "i" (__NR_sigreturn)
+		: "2", "3"); */
+}
Index: linux-2.6.16/arch/um/sys-s390/sys_call_table.S
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/sys-s390/sys_call_table.S	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,26 @@
+/* Steal s390 syscall table for our purposes, but with some slight changes.*/
+/* The code,to do this, again is stolen from arch/s390/kernel/entry.S */
+
+#define SYSCALL(esa,esame,emu)	.long esa
+
+#define sys_time		um_time
+#define sys_stime		um_stime
+
+#define sys_fork_glue		sys_fork
+#define sys_execve_glue		sys_execve
+#define sys_sigsuspend_glue	sys_sigsuspend
+#define sys_sigreturn_glue	sys_sigreturn
+#define sys_clone_glue		sys_clone
+#define sys_rt_sigreturn_glue	sys_rt_sigreturn
+#define sys_rt_sigsuspend_glue	sys_rt_sigsuspend
+#define sys_sigaltstack_glue	sys_sigaltstack
+#define sys_vfork_glue		sys_vfork
+
+#define old_mmap		s390_old_mmap
+#define sys_mmap2		s390_mmap2
+
+
+	.globl  sys_call_table
+sys_call_table:
+
+#include "../../s390/kernel/syscalls.S"
Index: linux-2.6.16/arch/um/sys-s390/syscalls.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/sys-s390/syscalls.c	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2004, 2005 Fujitsu Siemens Computer GmbH
+ * Author: Bodo Stroesser (bstroesser@fujitsu-siemens.com)
+ *
+ * This is derived from arch/um/sys-i386/syscalls.c
+ *  Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
+ *
+ * and arch/s390/kernel/sys_s390.c
+ *  Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *  Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ *             Thomas Spatzier (tspat@de.ibm.com)
+ *
+ * Licensed under the GPL
+ */
+
+#include "linux/sched.h"
+#include "linux/shm.h"
+#include "asm/ipc.h"
+#include "asm/mman.h"
+#include "asm/uaccess.h"
+#include "asm/unistd.h"
+
+/*
+ * Perform the mmap() and mmap2() system calls.
+ * Linux/s390 didn't use to be able to handle more than
+ * 5 system call parameters, so these system calls use a
+ * memory block for parameter passing..
+ */
+
+struct mmap_arg_struct {
+	unsigned long addr;
+	unsigned long len;
+	unsigned long prot;
+	unsigned long flags;
+	unsigned long fd;
+	unsigned long offset;
+};
+
+extern long old_mmap(unsigned long addr, unsigned long len,
+		     unsigned long prot, unsigned long flags,
+		     unsigned long fd, unsigned long offset);
+
+long s390_old_mmap(struct mmap_arg_struct __user *arg)
+{
+	struct mmap_arg_struct a;
+	int err = -EFAULT;
+
+	if (copy_from_user(&a, arg, sizeof(a)))
+		goto out;
+
+	err = old_mmap(a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
+ out:
+	return err;
+}
+
+extern long sys_mmap2(unsigned long addr, unsigned long len,
+		      unsigned long prot, unsigned long flags,
+		      unsigned long fd, unsigned long pgoff);
+
+long s390_mmap2(struct mmap_arg_struct __user *arg)
+{
+	struct mmap_arg_struct a;
+	int err = -EFAULT;
+
+	if (copy_from_user(&a, arg, sizeof(a)))
+		goto out;
+	err = sys_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
+out:
+	return err;
+}
+
+
+long sys_clone(unsigned long newsp, unsigned long clone_flags, int *parent_tid,
+	       int *child_tid, unsigned long newtls)
+{
+	long ret;
+
+	if (!newsp)
+		newsp = UPT_SP(&current->thread.regs.regs);
+	current->thread.forking = 1;
+
+	{
+	/*
+	 * Special processing for TLS support in s390:
+	 * If CLONE_SETTLS is set, newtls will hold a new TLS pointer for the
+	 * new thread to be created. Normally, this should be loaded into ACR0
+	 * in copy_thread. Therefore, we would have to add some aubarch stuff
+	 * to copy_thread. We avoid this by saving current ACR0, loading newtls
+	 * into ACR0, from where it will be copied to the new thread's ACR0.
+	 * When do_fork returns, we reload current ACR0 with the original value.
+	 */
+	union uml_pt_regs * regs = &current->thread.regs.regs;
+	unsigned long origtls = UPT_ACR(regs,0);
+	if (clone_flags & CLONE_SETTLS)
+		UPT_ACR(regs,0) = newtls;
+	ret = do_fork(clone_flags, newsp, &current->thread.regs, 0, parent_tid,
+	              child_tid);
+	UPT_ACR(regs,0) = origtls;
+	}
+
+	current->thread.forking = 0;
+	return(ret);
+}
+
+/*
+ * sys_ipc() is the de-multiplexer for the SysV IPC calls..
+ *
+ * This is really horribly ugly.
+ */
+long sys_ipc (uint call, int first, int second,
+	      int third, void __user *ptr)
+{
+	struct ipc_kludge tmp;
+	int ret;
+
+	switch (call) {
+	case SEMOP:
+		return sys_semtimedop(first, (struct sembuf __user *) ptr,
+				      (unsigned)second, NULL);
+	case SEMTIMEDOP:
+		return sys_semtimedop(first, (struct sembuf __user *) ptr,
+				      (unsigned)second,
+				      (const struct timespec __user *) third);
+	case SEMGET:
+		return sys_semget (first, (int)second, third);
+	case SEMCTL: {
+		union semun fourth;
+		if (!ptr)
+			return -EINVAL;
+		if (get_user(fourth.__pad, (void __user * __user *) ptr))
+			return -EFAULT;
+		return sys_semctl (first, (int)second, third, fourth);
+	}
+	case MSGSND:
+		return sys_msgsnd (first, (struct msgbuf __user *) ptr,
+				   (size_t)second, third);
+	case MSGRCV:
+		if (!ptr)
+			return -EINVAL;
+		if (copy_from_user(&tmp, (struct ipc_kludge __user *) ptr,
+				   sizeof (struct ipc_kludge)))
+			return -EFAULT;
+		return sys_msgrcv (first, tmp.msgp,
+				   (size_t)second, tmp.msgtyp, third);
+	case MSGGET:
+		return sys_msgget ((key_t) first, (int)second);
+	case MSGCTL:
+		return sys_msgctl (first, (int)second,
+				   (struct msqid_ds __user *) ptr);
+
+	case SHMAT: {
+		ulong raddr;
+		ret = do_shmat (first, (char __user *) ptr,
+				(int)second, &raddr);
+		if (ret)
+			return ret;
+		return put_user (raddr, (ulong __user *) third);
+	}
+	case SHMDT:
+		return sys_shmdt ((char __user *)ptr);
+	case SHMGET:
+		return sys_shmget (first, (size_t)second, third);
+	case SHMCTL:
+		return sys_shmctl (first, (int)second,
+				   (struct shmid_ds __user *) ptr);
+	default:
+		return -ENOSYS;
+	}
+}
+
+long sys_sigaction(int sig, const struct old_sigaction __user *act,
+			 struct old_sigaction __user *oact)
+{
+	struct k_sigaction new_ka, old_ka;
+	int ret;
+
+	if (act) {
+		old_sigset_t mask;
+		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
+		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
+		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+			return -EFAULT;
+		__get_user(new_ka.sa.sa_flags, &act->sa_flags);
+		__get_user(mask, &act->sa_mask);
+		siginitset(&new_ka.sa.sa_mask, mask);
+	}
+
+	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+	if (!ret && oact) {
+		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
+		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
+		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+			return -EFAULT;
+		__put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+		__put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
+	}
+
+	return ret;
+}
+
+long s390_fadvise64(int fd, u32 offset_high, u32 offset_low, size_t len, int advice)
+{
+	return sys_fadvise64(fd, (u64) offset_high << 32 | offset_low, len, advice);
+}
+
+struct fadvise64_64_args {
+	int fd;
+	long long offset;
+	long long len;
+	int advice;
+};
+
+long s390_fadvise64_64(struct fadvise64_64_args __user *args)
+{
+	struct fadvise64_64_args a;
+
+	if (copy_from_user(&a, args, sizeof(a)))
+		return -EFAULT;
+	return sys_fadvise64_64(a.fd, a.offset, a.len, a.advice);
+}
Index: linux-2.6.16/arch/um/sys-s390/sysrq.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/sys-s390/sysrq.c	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2004, 2005 Fujitsu Siemens Computer GmbH
+ * Author: Bodo Stroesser (bstroesser@fujitsu-siemens.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/kernel.h"
+#include "linux/smp.h"
+#include "linux/sched.h"
+#include "linux/kallsyms.h"
+#include "asm/ptrace.h"
+#include "asm/uaccess.h"
+#include "sysrq.h"
+
+void show_regs(struct pt_regs *regs)
+{
+	register unsigned long * __r15 asm ("15");
+	mm_segment_t old_fs;
+	char * mode = user_mode(regs) ? "User" : "Krnl";
+	int i;
+
+        printk("\n");
+        printk("CPU: %d %s\n", smp_processor_id(), print_tainted());
+	printk("%s PSW : %p %p\n", mode,
+	       (void *)PT_REGS_MASK(regs), (void *)PT_REGS_ADDR(regs));
+	print_symbol(" (%s)\n", PT_REGS_ADDR(regs) & PSW_ADDR_INSN);
+	printk("%s GPRS: %08lx %08lx %08lx %08lx\n", mode,
+	       PT_REGS_GPR(regs,0), PT_REGS_GPR(regs,1),
+	       PT_REGS_GPR(regs,2), PT_REGS_GPR(regs,3));
+	printk("           %08lx %08lx %08lx %08lx\n",
+	       PT_REGS_GPR(regs,4), PT_REGS_GPR(regs,5),
+	       PT_REGS_GPR(regs,6), PT_REGS_GPR(regs,7));
+	printk("           %08lx %08lx %08lx %08lx\n",
+	       PT_REGS_GPR(regs,8), PT_REGS_GPR(regs,9),
+	       PT_REGS_GPR(regs,10), PT_REGS_GPR(regs,11));
+	printk("           %08lx %08lx %08lx %08lx\n",
+	       PT_REGS_GPR(regs,12), PT_REGS_GPR(regs,13),
+	       PT_REGS_GPR(regs,14), PT_REGS_GPR(regs,15));
+
+	if(user_mode(regs)){
+		old_fs = get_fs();
+		set_fs(USER_DS);
+		printk("\nUser Code: ");
+		for (i = 0; i < 20; i++) {
+			unsigned char c;
+			if (__get_user(c, (char __user *)(PT_REGS_ADDR(regs) + i - 8))) {
+				printk(" Bad PSW.");
+				break;
+			}
+			printk("%02x ", c);
+		}
+		set_fs(old_fs);
+		printk("\n");
+	}
+
+        show_trace(current, __r15);
+}
Index: linux-2.6.16/arch/um/sys-s390/unmap.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/sys-s390/unmap.c	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2004, 2005 Fujitsu Siemens Computer GmbH
+ * Author: Bodo Stroesser (bstroesser@fujitsu-siemens.com)
+ *
+ * This is derived from arch/um/sys-i386/unmap.c
+ *  Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ *
+ * Licensed under the GPL
+ */
+
+#include <linux/mman.h>
+#include <asm/unistd.h>
+
+struct mmap_arg_struct {
+	unsigned long addr;
+	unsigned long len;
+	unsigned long prot;
+	unsigned long flags;
+	unsigned long fd;
+	unsigned long offset;
+};
+
+static int errno;
+
+static inline _syscall2(int, munmap, void *, start, size_t, len)
+static inline _syscall1(void *, mmap2, struct mmap_arg_struct *, argp)
+int switcheroo(int fd, int prot, void *from, void *to, int size)
+{
+	struct mmap_arg_struct mmap_args = {
+		(unsigned long)to, size, prot, MAP_SHARED | MAP_FIXED, fd, 0 };
+
+	if(munmap(to, size) < 0){
+		return(-1);
+	}
+	if(mmap2(&mmap_args) == (void*) -1 ){
+		return(-1);
+	}
+	if(munmap(from, size) < 0){
+		return(-1);
+	}
+	return(0);
+}
Index: linux-2.6.16/arch/um/sys-s390/user-offsets.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/sys-s390/user-offsets.c	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,50 @@
+#include <stdio.h>
+#include <signal.h>
+#include <asm/ptrace.h>
+#include <asm/user.h>
+#include <linux/stddef.h>
+
+#define DEFINE(sym, val) \
+        asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+
+#define OFFSET(sym, str, mem) \
+	DEFINE(sym, offsetof(str, mem));
+
+void foo(void)
+{
+	OFFSET(SC_SIGMASK_P, struct sigcontext, oldmask);
+	OFFSET(SC_SIGREGS_P, struct sigcontext, sregs);
+	/* S390 supplies trapno and error_addr in registers, when sighdlr
+	 * is called. We have to insert this into sigcontext. So we write
+	 * trapno and error_addr into a struct errinfo (sysdep/sigcontext.h)
+	 * located on sighdlr's stack. The address of this struct is written
+	 * immediately after the struct sigcontext, where fortunately is
+	 * space for an additional pointer.
+	 * The following "DEFINE" inserts just this additional pointer.
+	 */
+	DEFINE(SC_ERRINFO_P, offsetof(struct sigcontext, sregs)+sizeof(void *));
+
+	OFFSET(SC_PSWMASK, _sigregs, regs.psw.mask);
+	OFFSET(SC_PSWADDR, _sigregs, regs.psw.addr);
+	OFFSET(SC_GPRS, _sigregs, regs.gprs);
+	OFFSET(SC_ACRS, _sigregs, regs.acrs);
+	OFFSET(SC_FPREGS, _sigregs, fpregs);
+
+	DEFINE(HOST_FRAME_SIZE, PT_FPC/sizeof( unsigned long));
+	DEFINE(HOST_FP_SIZE, sizeof(s390_fp_regs) / sizeof(unsigned long));
+	DEFINE(HOST_XFP_SIZE, 0);
+	DEFINE(__UM_FRAME_SIZE, 0); /* This is a dummy only */
+
+	DEFINE(HOST_MASK, PT_PSWMASK / sizeof(unsigned long));
+	DEFINE(HOST_ADDR, PT_PSWADDR / sizeof(unsigned long));
+	DEFINE(HOST_GPRS, PT_GPR0 / sizeof(unsigned long));
+	DEFINE(HOST_ACRS, PT_ACR0 / sizeof(unsigned long));
+	DEFINE(HOST_ORIGGPR2, PT_ORIGGPR2 / sizeof(unsigned long));
+
+	/* This is for stub.S only.
+	 * S390_BREAKPOINT is defined in asm/ptrace.h inside of a
+	 * #ifndef __ASSEMBLY__. So we can't use this definition
+	 * directly.
+	 */
+	DEFINE(HOST_S390_BREAKPOINT, S390_BREAKPOINT_U16);
+}
Index: linux-2.6.16/arch/um/sys-s390/util/Makefile
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/sys-s390/util/Makefile	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,5 @@
+hostprogs-y	:= mk_sc mk_thread
+always		:= $(hostprogs-y)
+
+HOSTCFLAGS_mk_sc.o := -I$(objtree)/arch/um
+HOSTCFLAGS_mk_thread.o := -I$(objtree)/arch/um
Index: linux-2.6.16/arch/um/sys-s390/util/mk_sc.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/sys-s390/util/mk_sc.c	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,39 @@
+#include <stdio.h>
+#include "../../user-offsets.h"
+
+#define SC_PTR_OFFSET(name) \
+  printf("#define " #name "(sc) ((unsigned long *) (((char *) (sc)) + %d))\n",\
+	 name)
+
+#define SC_SIGREGS_OFFSET(name) \
+  printf("#define " #name \
+	 "(sc) (*(unsigned long *) (((char *)*SC_SIGREGS_P(sc)) + %d))\n",\
+	 name)
+
+#define SC_SIGREGS_PTR_OFFSET(name) \
+  printf("#define " #name \
+	 "(sc) ((unsigned long *) (((char *)*SC_SIGREGS_P(sc)) + %d))\n",\
+	 name)
+
+int main(int argc, char **argv)
+{
+  SC_PTR_OFFSET(SC_SIGMASK_P);
+  SC_PTR_OFFSET(SC_SIGREGS_P);
+  SC_PTR_OFFSET(SC_ERRINFO_P);
+
+  printf(	"#define SC_IP(sc) \\\n");
+  printf(	"	((unsigned long)\\\n");
+  printf(	"	 (((struct { unsigned long amode: 1; \\\n");
+  printf(	"		     unsigned long addr31: 31; \\\n");
+  printf(	"		   } *)&SC_PSWADDR(sc))->addr31))\n");
+
+  SC_SIGREGS_OFFSET(SC_PSWMASK);
+  SC_SIGREGS_OFFSET(SC_PSWADDR);
+
+  SC_SIGREGS_PTR_OFFSET(SC_GPRS);
+  SC_SIGREGS_PTR_OFFSET(SC_ACRS);
+
+  SC_SIGREGS_PTR_OFFSET(SC_FPREGS);
+
+  return(0);
+}
Index: linux-2.6.16/arch/um/sys-s390/util/mk_thread.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/arch/um/sys-s390/util/mk_thread.c	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,22 @@
+#include <stdio.h>
+#include "../../kernel-offsets.h"
+
+int main(int argc, char **argv)
+{
+  printf("/*\n");
+  printf(" * Generated by mk_thread\n");
+  printf(" */\n");
+  printf("\n");
+  printf("#ifndef __UM_THREAD_H\n");
+  printf("#define __UM_THREAD_H\n");
+  printf("\n");
+  printf("#define TASK_PER_STRUCT(task) ((unsigned long *) "
+	 "&(((char *) (task))[%d]))\n", TASK_PER_STRUCT);
+#ifdef TASK_EXTERN_PID
+  printf("#define TASK_EXTERN_PID(task) *((int *) &(((char *) (task))[%d]))\n",
+	 TASK_EXTERN_PID);
+#endif
+  printf("\n");
+  printf("#endif\n");
+  return(0);
+}
Index: linux-2.6.16/include/asm-um/archparam-s390.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/include/asm-um/archparam-s390.h	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2004, 2005 Fujitsu Siemens Computer GmbH
+ * Author: Bodo Stroesser (bstroesser@fujitsu-siemens.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_ARCHPARAM_S390_H
+#define __UM_ARCHPARAM_S390_H
+
+/* s390 doesn't support vsyscall-page */
+#define VSYSCALL_BASE 0
+#define VSYSCALL_END 0
+
+extern void __const_udelay(unsigned long usecs);
+
+#endif
Index: linux-2.6.16/include/asm-um/elf-s390.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/include/asm-um/elf-s390.h	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2004, 2005 Fujitsu Siemens Computer GmbH
+ * Author: Bodo Stroesser (bstroesser@fujitsu-siemens.com)
+ *
+ * This is derived from include/asm-s390/elf.h
+ */
+
+#ifndef __UM_ELF_S390_H
+#define __UM_ELF_S390_H
+
+/* s390 relocations defined by the ABIs */
+#define R_390_NONE		0	/* No reloc.  */
+#define R_390_8			1	/* Direct 8 bit.  */
+#define R_390_12		2	/* Direct 12 bit.  */
+#define R_390_16		3	/* Direct 16 bit.  */
+#define R_390_32		4	/* Direct 32 bit.  */
+#define R_390_PC32		5	/* PC relative 32 bit.	*/
+#define R_390_GOT12		6	/* 12 bit GOT offset.  */
+#define R_390_GOT32		7	/* 32 bit GOT offset.  */
+#define R_390_PLT32		8	/* 32 bit PC relative PLT address.  */
+#define R_390_COPY		9	/* Copy symbol at runtime.  */
+#define R_390_GLOB_DAT		10	/* Create GOT entry.  */
+#define R_390_JMP_SLOT		11	/* Create PLT entry.  */
+#define R_390_RELATIVE		12	/* Adjust by program base.  */
+#define R_390_GOTOFF32		13	/* 32 bit offset to GOT.	 */
+#define R_390_GOTPC		14	/* 32 bit PC rel. offset to GOT.  */
+#define R_390_GOT16		15	/* 16 bit GOT offset.  */
+#define R_390_PC16		16	/* PC relative 16 bit.	*/
+#define R_390_PC16DBL		17	/* PC relative 16 bit shifted by 1.  */
+#define R_390_PLT16DBL		18	/* 16 bit PC rel. PLT shifted by 1.  */
+#define R_390_PC32DBL		19	/* PC relative 32 bit shifted by 1.  */
+#define R_390_PLT32DBL		20	/* 32 bit PC rel. PLT shifted by 1.  */
+#define R_390_GOTPCDBL		21	/* 32 bit PC rel. GOT shifted by 1.  */
+#define R_390_64		22	/* Direct 64 bit.  */
+#define R_390_PC64		23	/* PC relative 64 bit.	*/
+#define R_390_GOT64		24	/* 64 bit GOT offset.  */
+#define R_390_PLT64		25	/* 64 bit PC relative PLT address.  */
+#define R_390_GOTENT		26	/* 32 bit PC rel. to GOT entry >> 1. */
+#define R_390_GOTOFF16		27	/* 16 bit offset to GOT. */
+#define R_390_GOTOFF64		28	/* 64 bit offset to GOT. */
+#define R_390_GOTPLT12		29	/* 12 bit offset to jump slot.	*/
+#define R_390_GOTPLT16		30	/* 16 bit offset to jump slot.	*/
+#define R_390_GOTPLT32		31	/* 32 bit offset to jump slot.	*/
+#define R_390_GOTPLT64		32	/* 64 bit offset to jump slot.	*/
+#define R_390_GOTPLTENT		33	/* 32 bit rel. offset to jump slot.  */
+#define R_390_PLTOFF16		34	/* 16 bit offset from GOT to PLT. */
+#define R_390_PLTOFF32		35	/* 32 bit offset from GOT to PLT. */
+#define R_390_PLTOFF64		36	/* 16 bit offset from GOT to PLT. */
+#define R_390_TLS_LOAD		37	/* Tag for load insn in TLS code. */
+#define R_390_TLS_GDCALL	38	/* Tag for function call in general
+                                           dynamic TLS code.  */
+#define R_390_TLS_LDCALL	39	/* Tag for function call in local
+                                           dynamic TLS code.  */
+#define R_390_TLS_GD32		40	/* Direct 32 bit for general dynamic
+                                           thread local data.  */
+#define R_390_TLS_GD64		41	/* Direct 64 bit for general dynamic
+                                           thread local data.  */
+#define R_390_TLS_GOTIE12	42	/* 12 bit GOT offset for static TLS
+                                           block offset.  */
+#define R_390_TLS_GOTIE32	43	/* 32 bit GOT offset for static TLS
+                                           block offset.  */
+#define R_390_TLS_GOTIE64	44	/* 64 bit GOT offset for static TLS
+                                           block offset.  */
+#define R_390_TLS_LDM32		45	/* Direct 32 bit for local dynamic
+                                           thread local data in LD code.  */
+#define R_390_TLS_LDM64		46	/* Direct 64 bit for local dynamic
+                                           thread local data in LD code.  */
+#define R_390_TLS_IE32		47	/* 32 bit address of GOT entry for
+                                           negated static TLS block offset.  */
+#define R_390_TLS_IE64		48	/* 64 bit address of GOT entry for
+                                           negated static TLS block offset.  */
+#define R_390_TLS_IEENT		49	/* 32 bit rel. offset to GOT entry for
+                                           negated static TLS block offset.  */
+#define R_390_TLS_LE32		50	/* 32 bit negated offset relative to
+                                           static TLS block.  */
+#define R_390_TLS_LE64		51	/* 64 bit negated offset relative to
+                                           static TLS block.  */
+#define R_390_TLS_LDO32		52	/* 32 bit offset relative to TLS
+                                           block.  */
+#define R_390_TLS_LDO64		53	/* 64 bit offset relative to TLS
+                                           block.  */
+#define R_390_TLS_DTPMOD	54	/* ID of module containing symbol.  */
+#define R_390_TLS_DTPOFF	55	/* Offset in TLS block.  */
+#define R_390_TLS_TPOFF		56	/* Negate offset in static TLS
+                                           block.  */
+#define R_390_20		57	/* Direct 20 bit.  */
+#define R_390_GOT20		58	/* 20 bit GOT offset.  */
+#define R_390_GOTPLT20		59	/* 20 bit offset to jump slot.  */
+#define R_390_TLS_GOTIE20	60	/* 20 bit GOT offset for static TLS
+					   block offset.  */
+/* Keep this the last entry.  */
+#define R_390_NUM	61
+
+#include "asm/ptrace.h"
+#include "asm/user.h"
+
+typedef s390_fp_regs elf_fpregset_t;
+typedef s390_regs elf_gregset_t;
+
+#define ELF_CLASS	ELFCLASS32
+#define ELF_DATA        ELFDATA2MSB
+#define ELF_ARCH        EM_S390
+
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_arch(x) \
+	(((x)->e_machine == EM_S390 || (x)->e_machine == EM_S390_OLD) \
+	 && (x)->e_ident[EI_CLASS] == ELF_CLASS)
+
+#define ELF_PLAT_INIT(regs, load_addr) \
+	do { \
+		PT_REGS_GPR(regs,14) = 0; \
+	} while(0)
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE 4096
+
+#define ELF_ET_DYN_BASE	((TASK_SIZE & 0x80000000) \
+			? TASK_SIZE / 3 * 2 \
+			: 2 * TASK_SIZE / 3)
+
+#define ELF_CORE_COPY_REGS(pr_reg, regs) do {				\
+	pr_reg.psw.mask = PT_REGS_MASK(regs);				\
+	pr_reg.psw.addr = PT_REGS_ADDR(regs);				\
+	memcpy(pr_reg.gprs, PT_REGS_GPRS(regs), sizeof(pr_reg.gprs));	\
+	memcpy(pr_reg.acrs, PT_REGS_ACRS(regs), sizeof(pr_reg.acrs));	\
+	pr_reg.orig_gpr2 = PT_REGS_ORIGGPR2(regs);			\
+} while(0);
+
+#define ELF_HWCAP (0)
+
+#define ELF_PLATFORM (NULL)
+
+#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
+
+#endif
Index: linux-2.6.16/include/asm-um/ldt-s390.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/include/asm-um/ldt-s390.h	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2004 Fujitsu Siemens Computers GmbH
+ * Licensed under the GPL
+ *
+ * Author: Bodo Stroesser <bstroesser@fujitsu-siemens.com>
+ */
+
+#ifndef __ASM_LDT_S390_H
+#define __ASM_LDT_S390_H
+
+struct mmu_context_skas;
+
+static inline void ldt_host_info(void)
+{
+}
+
+static inline long init_new_ldt(struct mmu_context_skas * to_mm,
+			 struct mmu_context_skas * from_mm)
+{
+	return 0;
+}
+
+static inline void free_ldt(struct mmu_context_skas * mm) { }
+
+typedef char uml_ldt_t[0];
+
+#endif
Index: linux-2.6.16/include/asm-um/lowcore.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/include/asm-um/lowcore.h	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,6 @@
+#ifndef __UM_LOWCORE_H
+#define __UM_LOWCORE_H
+
+/* Fake s390 only */
+
+#endif
Index: linux-2.6.16/include/asm-um/module-s390.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/include/asm-um/module-s390.h	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,6 @@
+#ifndef __UM_MODULE_S390_H
+#define __UM_MODULE_S390_H
+
+#include "asm/arch/module.h"
+
+#endif
Index: linux-2.6.16/include/asm-um/processor-s390.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/include/asm-um/processor-s390.h	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2004, 2005 Fujitsu Siemens Computer GmbH
+ * Author: Bodo Stroesser (bstroesser@fujitsu-siemens.com)
+ *
+ * This is derived from include/asm-um/processor-i386.h
+ *  Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ *
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_PROCESSOR_S390_H
+#define __UM_PROCESSOR_S390_H
+
+#include "asm/arch/user.h"
+#include "sysdep/faultinfo.h"
+
+struct arch_thread {
+	per_struct per_info;
+	int per_struct_seq;
+	struct faultinfo faultinfo;
+};
+
+#define INIT_ARCH_THREAD { \
+	.per_info  	= (per_struct) {{{{0,}}},0,0,0,0,{{0,}}}, \
+	.per_struct_seq	= 0, \
+	.faultinfo	= { 0, 0 } }
+
+/*
+ * Default implementation of macro that returns current
+ * instruction pointer ("program counter"). Stolen
+ * from asm-s390/processor.h
+ */
+#define current_text_addr() ({ void *pc; __asm__("basr %0,0":"=a"(pc)); pc; })
+
+#define cpu_relax() barrier()
+
+#define ARCH_IS_STACKGROW(address) (1==1)
+
+#define TIF_RESTART_SVC        7 /* restart svc with new svc number */
+#define _TIF_RESTART_SVC       (1 << TIF_RESTART_SVC)
+
+#include "asm/processor-generic.h"
+
+#endif
Index: linux-2.6.16/include/asm-um/ptrace-s390.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/include/asm-um/ptrace-s390.h	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2004, 2005 Fujitsu Siemens Computer GmbH
+ * Author: Bodo Stroesser (bstroesser@fujitsu-siemens.com)
+ *
+ * This is derived from include/asm-um/ptrace-i386.h
+ *  Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ *
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_PTRACE_S390_H
+#define __UM_PTRACE_S390_H
+
+#define HOST_AUDIT_ARCH AUDIT_ARCH_S390
+
+/* Normally defined in include/asm-s390/page.h,
+ * but used in macros imported via include/asm-um/arch/ptrace.h
+ * So, we need to have our own definition here.
+ */
+#define PAGE_DEFAULT_ACC 0
+
+#include "sysdep/ptrace.h"
+#include "asm/ptrace-generic.h"
+
+#define PT_REGS_ADDR(r) UPT_ADDR(&(r)->regs)
+#define PT_REGS_MASK(r) UPT_MASK(&(r)->regs)
+#define PT_REGS_GPR(r,inx) UPT_GPR(&(r)->regs,inx)
+#define PT_REGS_GPRS(r) UPT_GPRS(&(r)->regs)
+#define PT_REGS_ACRS(r) UPT_ACRS(&(r)->regs)
+#define PT_REGS_ORIGGPR2(r) UPT_ORIGGPR2(&(r)->regs)
+#define PT_REGS_FPC(r) UPT_FPR(&(r)->regs,0)
+
+#define PT_REGS_ORIG_SYSCALL(r) PT_REGS_SYSCALL_NR(r)
+#define PT_REGS_SYSCALL_RET(r) PT_REGS_GPR(r,2)
+#define PT_FIX_EXEC_STACK(sp) do ; while(0)
+
+#define user_mode(r) UPT_IS_USER(&(r)->regs)
+
+#undef profile_pc
+#define profile_pc(regs) PT_REGS_IP(regs)
+
+#endif
Index: linux-2.6.16/include/asm-um/sigcontext-s390.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/include/asm-um/sigcontext-s390.h	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,6 @@
+#ifndef __UM_SIGCONTEXT_S390_H
+#define __UM_SIGCONTEXT_S390_H
+
+#include "asm/sigcontext-generic.h"
+
+#endif
Index: linux-2.6.16/include/asm-um/system-s390.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/include/asm-um/system-s390.h	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,14 @@
+#ifndef __UM_SYSTEM_S390_H
+#define __UM_SYSTEM_S390_H
+
+/* Fake this to make asm-s390/system.h compile */
+#define MACHINE_HAS_IEEE 1
+extern void __load_psw_mask(unsigned long mask);
+
+#include "asm/system-generic.h"
+
+#undef prepare_arch_switch
+#undef finish_arch_switch
+#undef task_running
+
+#endif
Index: linux-2.6.16/include/asm-um/vm-flags-s390.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.16/include/asm-um/vm-flags-s390.h	2006-04-27 18:43:31.000000000 -0400
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2004, 2005 Fujitsu Siemens Computer GmbH
+ * Author: Bodo Stroesser (bstroesser@fujitsu-siemens.com)
+ *
+ * This is derived from include/asm-um/vm-flags-i386.h
+ *  Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ *
+ * Licensed under the GPL
+ */
+
+#ifndef __VM_FLAGS_S390_H
+#define __VM_FLAGS_S390_H
+
+#define VM_DATA_DEFAULT_FLAGS   (VM_READ | VM_WRITE | VM_EXEC | \
+				 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+
+#endif